Spaces:
Configuration error
Configuration error
EZTIME2025 commited on
Commit ·
61ad06f
1
Parent(s): 6887a34
create plan and config
Browse files- .env.example +65 -0
- .github/instructions/AI_AGENT_PRINCIPLES.md +210 -0
- .github/instructions/WORK_PLAN.md +484 -0
- .github/instructions/updated.instructions.md +30 -0
- .gitignore +30 -0
- QUICKSTART_API.md +31 -0
- docs/AI_SETUP.md +367 -0
- example_answer.md +12 -0
- examples/demo_ai_config.py +222 -0
- examples/test_ai_config.py +241 -0
- promt_format.text +86 -0
- pycatan/ai/__init__.py +34 -0
- pycatan/ai/config.py +341 -0
- pycatan/ai/config_example.yaml +164 -0
.env.example
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ============================================================================
|
| 2 |
+
# Environment Variables Template for PyCatan AI
|
| 3 |
+
# ============================================================================
|
| 4 |
+
# This file is a TEMPLATE - it will be committed to Git.
|
| 5 |
+
# Copy this file to .env and fill in your actual API keys.
|
| 6 |
+
#
|
| 7 |
+
# SETUP INSTRUCTIONS:
|
| 8 |
+
# 1. Copy this file: cp .env.example .env
|
| 9 |
+
# 2. Edit .env and paste your actual API keys
|
| 10 |
+
# 3. NEVER commit the .env file to Git!
|
| 11 |
+
# ============================================================================
|
| 12 |
+
|
| 13 |
+
# ----------------------------------------------------------------------------
|
| 14 |
+
# LLM API Keys
|
| 15 |
+
# ----------------------------------------------------------------------------
|
| 16 |
+
# Get your API keys from:
|
| 17 |
+
# - Gemini: https://aistudio.google.com/app/apikey
|
| 18 |
+
# - OpenAI: https://platform.openai.com/api-keys
|
| 19 |
+
# - Anthropic: https://console.anthropic.com/settings/keys
|
| 20 |
+
|
| 21 |
+
# Google Gemini API Key (recommended for development)
|
| 22 |
+
GEMINI_API_KEY=
|
| 23 |
+
|
| 24 |
+
# OpenAI API Key (optional)
|
| 25 |
+
OPENAI_API_KEY=
|
| 26 |
+
|
| 27 |
+
# Anthropic Claude API Key (optional)
|
| 28 |
+
ANTHROPIC_API_KEY=
|
| 29 |
+
|
| 30 |
+
# Azure OpenAI (optional)
|
| 31 |
+
AZURE_OPENAI_KEY=
|
| 32 |
+
AZURE_OPENAI_ENDPOINT=
|
| 33 |
+
|
| 34 |
+
# ----------------------------------------------------------------------------
|
| 35 |
+
# Optional: LLM Configuration Overrides
|
| 36 |
+
# ----------------------------------------------------------------------------
|
| 37 |
+
# You can override default settings via environment variables
|
| 38 |
+
|
| 39 |
+
# Default LLM provider (gemini, openai, anthropic, azure)
|
| 40 |
+
# DEFAULT_LLM_PROVIDER=gemini
|
| 41 |
+
|
| 42 |
+
# Default model name
|
| 43 |
+
# DEFAULT_MODEL_NAME=gemini-2.0-flash-exp
|
| 44 |
+
|
| 45 |
+
# Default temperature (0.0 to 2.0)
|
| 46 |
+
# DEFAULT_TEMPERATURE=0.7
|
| 47 |
+
|
| 48 |
+
# ----------------------------------------------------------------------------
|
| 49 |
+
# Development Settings
|
| 50 |
+
# ----------------------------------------------------------------------------
|
| 51 |
+
|
| 52 |
+
# Enable debug mode for detailed logging
|
| 53 |
+
# DEBUG_MODE=false
|
| 54 |
+
|
| 55 |
+
# Log directory
|
| 56 |
+
# LOG_DIRECTORY=logs/ai_agents
|
| 57 |
+
|
| 58 |
+
# ----------------------------------------------------------------------------
|
| 59 |
+
# Notes
|
| 60 |
+
# ----------------------------------------------------------------------------
|
| 61 |
+
# - The .env file is ignored by Git (see .gitignore)
|
| 62 |
+
# - Never share your .env file or commit it to version control
|
| 63 |
+
# - Keep your API keys secret and rotate them regularly
|
| 64 |
+
# - Each developer should have their own .env file with their own keys
|
| 65 |
+
# ============================================================================
|
.github/instructions/AI_AGENT_PRINCIPLES.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🎮 AI Agent Design Principles
|
| 2 |
+
|
| 3 |
+
**Date:** January 3, 2026
|
| 4 |
+
**Status:** 📋 In Planning
|
| 5 |
+
|
| 6 |
+
## 🎯 Core Philosophy: "Give Tools and Let Go"
|
| 7 |
+
|
| 8 |
+
The AI agent architecture follows a **tool-based autonomy approach** where we provide the agent with:
|
| 9 |
+
- Rich game state context
|
| 10 |
+
- Available tools and actions
|
| 11 |
+
- Clear constraints and rules
|
| 12 |
+
- Memory management capabilities
|
| 13 |
+
|
| 14 |
+
Then we **let the agent play** - making its own decisions based on the context and available options.
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
## 🏗️ Architecture Principles
|
| 19 |
+
|
| 20 |
+
### 1️⃣ Event-Driven LLM Invocation
|
| 21 |
+
|
| 22 |
+
The agent calls the LLM under specific scenarios:
|
| 23 |
+
- **Game Events**: Something happened in the game that affects the agent
|
| 24 |
+
- **Action Required**: The agent must make a decision (build, trade, play card, etc.)
|
| 25 |
+
- **Social Interaction**: Another player sent a message or made an offer
|
| 26 |
+
- **Turn Changes**: Beginning or end of turn phases
|
| 27 |
+
|
| 28 |
+
The agent doesn't continuously "think" - it responds to events and prompts.
|
| 29 |
+
|
| 30 |
+
### 2️⃣ Self-Managed Memory
|
| 31 |
+
|
| 32 |
+
The agent maintains its own memory in a simple, accessible format:
|
| 33 |
+
- **Short-term memory**: Recent events and observations
|
| 34 |
+
- **Strategic notes**: Things to remember for future decisions
|
| 35 |
+
- **Social tracking**: Observations about other players' behavior
|
| 36 |
+
- **Game insights**: Patterns noticed during play
|
| 37 |
+
|
| 38 |
+
The memory structure is minimal but effective, allowing the agent to maintain context across turns.
|
| 39 |
+
|
| 40 |
+
### 3️⃣ Generic and Configurable Design
|
| 41 |
+
|
| 42 |
+
The agent implementation should be:
|
| 43 |
+
- **Modular**: Easy to swap components or strategies
|
| 44 |
+
- **Configurable**: Support different play styles and behaviors
|
| 45 |
+
- **Extensible**: Simple to add new capabilities or tools
|
| 46 |
+
- **Reusable**: Same base agent class for different AI personalities
|
| 47 |
+
|
| 48 |
+
This allows experimentation with different AI approaches without rewriting core logic.
|
| 49 |
+
|
| 50 |
+
### 4️⃣ Centralized Configuration
|
| 51 |
+
|
| 52 |
+
All critical parameters are managed in one place:
|
| 53 |
+
- **LLM Configuration**: Model selection, temperature, max tokens
|
| 54 |
+
- **API Credentials**: Keys and endpoints for LLM services
|
| 55 |
+
- **Agent Parameters**: Personality traits, risk tolerance, strategy preferences
|
| 56 |
+
- **Performance Settings**: Timeout limits, retry policies, caching options
|
| 57 |
+
|
| 58 |
+
This centralization simplifies tuning and experimentation.
|
| 59 |
+
|
| 60 |
+
---
|
| 61 |
+
|
| 62 |
+
## 📨 Prompt Processing Pipeline
|
| 63 |
+
|
| 64 |
+
### Context Filtering and Preparation
|
| 65 |
+
|
| 66 |
+
Before sending prompts to the agent, game state undergoes processing:
|
| 67 |
+
|
| 68 |
+
1. **Information Hiding**: Remove data the player shouldn't know
|
| 69 |
+
- Other players' cards and resources (unless revealed)
|
| 70 |
+
- Hidden development cards
|
| 71 |
+
- Future planned moves by other players
|
| 72 |
+
|
| 73 |
+
2. **Perspective Adaptation**: Present information from agent's viewpoint
|
| 74 |
+
- "You received 1 Wood" instead of "Player Blue received 1 Wood"
|
| 75 |
+
- "Your resources" vs "Player resources"
|
| 76 |
+
- Relative positioning and strategic context
|
| 77 |
+
|
| 78 |
+
3. **Custom Instructions**: Tailor prompts per agent instance
|
| 79 |
+
- Different personality instructions
|
| 80 |
+
- Unique strategic guidance
|
| 81 |
+
- Role-specific context
|
| 82 |
+
|
| 83 |
+
4. **Context Enrichment**: Add relevant computed information
|
| 84 |
+
- Tile probabilities (based on dice numbers)
|
| 85 |
+
- Resource scarcity analysis
|
| 86 |
+
- Build opportunity assessment
|
| 87 |
+
|
| 88 |
+
### Management Layer
|
| 89 |
+
|
| 90 |
+
A **prompt management layer** sits between GameManager and AI agents to:
|
| 91 |
+
- Transform raw game state into agent-specific context
|
| 92 |
+
- Filter and format information appropriately
|
| 93 |
+
- Handle simultaneous different messages to different agents
|
| 94 |
+
- Manage conversation history and memory updates
|
| 95 |
+
|
| 96 |
+
---
|
| 97 |
+
|
| 98 |
+
## 📋 Prompt Structure Principles
|
| 99 |
+
|
| 100 |
+
Based on the format in `promt_format.text`, prompts follow this structure:
|
| 101 |
+
|
| 102 |
+
### Core Components:
|
| 103 |
+
|
| 104 |
+
1. **Meta Data**: Agent identity and role
|
| 105 |
+
- Agent name/identifier
|
| 106 |
+
- Player color
|
| 107 |
+
- Personality or role description
|
| 108 |
+
|
| 109 |
+
2. **Task Context**: Current situation
|
| 110 |
+
- What just happened in the game
|
| 111 |
+
- What action is now required
|
| 112 |
+
- Instructions for decision-making
|
| 113 |
+
|
| 114 |
+
3. **Game State**: World information from agent perspective
|
| 115 |
+
- Agent's private information (resources, cards, points)
|
| 116 |
+
- Visible board state
|
| 117 |
+
- Other players' public information
|
| 118 |
+
|
| 119 |
+
4. **Social Context**: Communication and relationships
|
| 120 |
+
- Recent chat messages
|
| 121 |
+
- Trade offers and negotiations
|
| 122 |
+
- Historical summaries of interactions
|
| 123 |
+
|
| 124 |
+
5. **Memory**: Agent's self-maintained notes
|
| 125 |
+
- Strategic observations
|
| 126 |
+
- Plans and intentions
|
| 127 |
+
- Social dynamics tracking
|
| 128 |
+
|
| 129 |
+
6. **Constraints**: Available actions and rules
|
| 130 |
+
- List of allowed actions at this moment
|
| 131 |
+
- Parameter structure for each action
|
| 132 |
+
- Usage instructions and examples
|
| 133 |
+
|
| 134 |
+
### Flexibility Note:
|
| 135 |
+
While this structure provides a solid foundation, it should remain **adaptable**. Specific fields and formats may evolve as we test and refine the agent's performance.
|
| 136 |
+
|
| 137 |
+
---
|
| 138 |
+
|
| 139 |
+
## 🔄 Structured Response Format
|
| 140 |
+
|
| 141 |
+
The LLM response is **strictly structured** to enable programmatic processing:
|
| 142 |
+
|
| 143 |
+
### Response Components:
|
| 144 |
+
|
| 145 |
+
1. **Reasoning**: Agent's thought process (for debugging/logging)
|
| 146 |
+
- Current situation analysis
|
| 147 |
+
- Strategic considerations
|
| 148 |
+
- Decision rationale
|
| 149 |
+
|
| 150 |
+
2. **Selected Action**: The chosen action with parameters
|
| 151 |
+
- Action type (BUILD_ROAD, OFFER_TRADE, etc.)
|
| 152 |
+
- Required parameters for that action
|
| 153 |
+
- Validation-ready format
|
| 154 |
+
|
| 155 |
+
3. **Communication**: Optional message to other players
|
| 156 |
+
- Chat message content
|
| 157 |
+
- Target audience (all or specific player)
|
| 158 |
+
|
| 159 |
+
4. **Memory Update**: What to remember for next time
|
| 160 |
+
- New notes to add
|
| 161 |
+
- Observations to store
|
| 162 |
+
- Strategy adjustments
|
| 163 |
+
|
| 164 |
+
### Example Response Structure:
|
| 165 |
+
```json
|
| 166 |
+
{
|
| 167 |
+
"reasoning": "I have enough resources for a settlement and node 23 gives me access to wheat...",
|
| 168 |
+
"action": {
|
| 169 |
+
"type": "BUILD_SETTLEMENT",
|
| 170 |
+
"parameters": {
|
| 171 |
+
"node_id": 23
|
| 172 |
+
}
|
| 173 |
+
},
|
| 174 |
+
"chat_message": "Building near the wheat fields!",
|
| 175 |
+
"memory_update": {
|
| 176 |
+
"add_note": "Focused on wheat production for development cards"
|
| 177 |
+
}
|
| 178 |
+
}
|
| 179 |
+
```
|
| 180 |
+
|
| 181 |
+
This structured format allows the game loop to:
|
| 182 |
+
- Parse and validate the agent's decision
|
| 183 |
+
- Execute the action through GameManager
|
| 184 |
+
- Update agent memory automatically
|
| 185 |
+
- Continue the game flow seamlessly
|
| 186 |
+
|
| 187 |
+
---
|
| 188 |
+
|
| 189 |
+
## 🔧 Tool Integration
|
| 190 |
+
|
| 191 |
+
Agents have access to computational tools for enhanced decision-making:
|
| 192 |
+
|
| 193 |
+
- **Probability Calculator**: Dice roll probabilities for tiles
|
| 194 |
+
- **Resource Tracker**: Historical resource generation analysis
|
| 195 |
+
- **Path Finder**: Optimal road placement calculations
|
| 196 |
+
- **Trade Evaluator**: Fair trade assessment
|
| 197 |
+
|
| 198 |
+
**Tool Usage Limits**: To prevent excessive computation, agents are limited in tool calls per decision (e.g., maximum 3 tool executions).
|
| 199 |
+
|
| 200 |
+
---
|
| 201 |
+
|
| 202 |
+
## 🎭 Multi-Agent Considerations
|
| 203 |
+
|
| 204 |
+
When multiple AI agents play simultaneously:
|
| 205 |
+
- Each receives their own filtered game state
|
| 206 |
+
- Agents can negotiate with each other
|
| 207 |
+
- Social dynamics emerge naturally from LLM interactions
|
| 208 |
+
- No direct agent-to-agent communication (all goes through game system)
|
| 209 |
+
|
| 210 |
+
This creates emergent gameplay where AI strategies adapt to each other's behavior.
|
.github/instructions/WORK_PLAN.md
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🗺️ AI Agent Development Work Plan
|
| 2 |
+
|
| 3 |
+
**Date:** January 3, 2026
|
| 4 |
+
**Status:** 📋 Planning Phase
|
| 5 |
+
|
| 6 |
+
## 🎯 Project Goal
|
| 7 |
+
|
| 8 |
+
Build a fully functional LLM-based AI agent that can play Settlers of Catan autonomously, making intelligent strategic decisions and interacting naturally with other players.
|
| 9 |
+
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
## 📊 Development Phases
|
| 13 |
+
|
| 14 |
+
> **Note:** Phase 4 (Monitoring & Debugging) should be developed **early and in parallel** with Phase 3.
|
| 15 |
+
> The web dashboard and logging are **critical** for observing agent behavior during development!
|
| 16 |
+
|
| 17 |
+
### Phase 1: Foundation & Infrastructure 🏗️
|
| 18 |
+
**Goal:** Build the core infrastructure needed to support AI agents
|
| 19 |
+
|
| 20 |
+
#### 1.1 Configuration Management
|
| 21 |
+
- [ ] Create centralized configuration system
|
| 22 |
+
- [ ] LLM settings (model, temperature, max_tokens, etc.)
|
| 23 |
+
- [ ] API credentials management
|
| 24 |
+
- [ ] Agent parameters (personality, risk tolerance, etc.)
|
| 25 |
+
- [ ] Performance settings (timeouts, retries, caching)
|
| 26 |
+
- [ ] Create config file format (YAML/JSON)
|
| 27 |
+
- [ ] Build configuration loader and validator
|
| 28 |
+
- [ ] Add environment variable support for sensitive data
|
| 29 |
+
|
| 30 |
+
**Files to create:**
|
| 31 |
+
- `pycatan/ai/config.py` - Configuration management
|
| 32 |
+
- `pycatan/ai/config_example.yaml` - Example configuration file
|
| 33 |
+
|
| 34 |
+
---
|
| 35 |
+
|
| 36 |
+
#### 1.2 Prompt Management Layer
|
| 37 |
+
- [ ] Design prompt processing pipeline
|
| 38 |
+
- [ ] Implement game state filtering
|
| 39 |
+
- [ ] Hide opponent's private information
|
| 40 |
+
- [ ] Filter development cards
|
| 41 |
+
- [ ] Remove non-visible game elements
|
| 42 |
+
- [ ] Build perspective transformation
|
| 43 |
+
- [ ] Convert game state to agent's viewpoint
|
| 44 |
+
- [ ] Format resources and points
|
| 45 |
+
- [ ] Present relative positioning
|
| 46 |
+
- [ ] Create prompt template system
|
| 47 |
+
- [ ] Meta data section
|
| 48 |
+
- [ ] Task context section
|
| 49 |
+
- [ ] Game state section
|
| 50 |
+
- [ ] Social context section
|
| 51 |
+
- [ ] Memory section
|
| 52 |
+
- [ ] Constraints section
|
| 53 |
+
- [ ] Build custom instruction injection per agent
|
| 54 |
+
|
| 55 |
+
**Files to create:**
|
| 56 |
+
- `pycatan/ai/prompt_manager.py` - Main prompt processing
|
| 57 |
+
- `pycatan/ai/state_filter.py` - Game state filtering logic
|
| 58 |
+
- `pycatan/ai/prompt_templates.py` - Template definitions
|
| 59 |
+
|
| 60 |
+
---
|
| 61 |
+
|
| 62 |
+
#### 1.3 Response Parser
|
| 63 |
+
- [ ] Define structured response format (JSON schema)
|
| 64 |
+
- [ ] Build response parser and validator
|
| 65 |
+
- [ ] Implement error handling for malformed responses
|
| 66 |
+
- [ ] Create fallback mechanisms for parsing failures
|
| 67 |
+
- [ ] Add response logging for debugging
|
| 68 |
+
|
| 69 |
+
**Files to create:**
|
| 70 |
+
- `pycatan/ai/response_parser.py` - Parse and validate LLM responses
|
| 71 |
+
- `pycatan/ai/schemas.py` - JSON schemas for requests/responses
|
| 72 |
+
|
| 73 |
+
---
|
| 74 |
+
|
| 75 |
+
### Phase 2: Memory System 🧠
|
| 76 |
+
**Goal:** Enable agents to maintain context and learning across turns
|
| 77 |
+
|
| 78 |
+
#### 2.1 Memory Structure
|
| 79 |
+
- [ ] Design memory data model
|
| 80 |
+
- [ ] Short-term observations (last N turns)
|
| 81 |
+
- [ ] Strategic notes (persistent)
|
| 82 |
+
- [ ] Social tracking (player relationships)
|
| 83 |
+
- [ ] Game insights (patterns observed)
|
| 84 |
+
- [ ] Implement memory storage (in-memory for now)
|
| 85 |
+
- [ ] Build memory retrieval and formatting
|
| 86 |
+
|
| 87 |
+
**Files to create:**
|
| 88 |
+
- `pycatan/ai/memory.py` - Memory management system
|
| 89 |
+
|
| 90 |
+
---
|
| 91 |
+
|
| 92 |
+
#### 2.2 Memory Operations
|
| 93 |
+
- [ ] Add note creation and updates
|
| 94 |
+
- [ ] Implement memory pruning (keep relevant, remove old)
|
| 95 |
+
- [ ] Build memory summarization for context limits
|
| 96 |
+
- [ ] Create memory persistence (save/load between games)
|
| 97 |
+
|
| 98 |
+
---
|
| 99 |
+
|
| 100 |
+
#### 2.3 Chat History Summarization ⚡
|
| 101 |
+
- [ ] Implement automatic chat summarization
|
| 102 |
+
- [ ] Configure separate smaller LLM for summarization (cost-effective)
|
| 103 |
+
- [ ] Monitor chat history length (e.g., last 10 messages)
|
| 104 |
+
- [ ] Trigger summarization when threshold reached
|
| 105 |
+
- [ ] Create summarization prompt template
|
| 106 |
+
- [ ] Build chat memory management
|
| 107 |
+
- [ ] Keep only most recent message after summarization
|
| 108 |
+
- [ ] Store summary in agent's memory
|
| 109 |
+
- [ ] Maintain summary history for context
|
| 110 |
+
- [ ] Add configuration for summarization settings
|
| 111 |
+
- [ ] Summarization model selection
|
| 112 |
+
- [ ] Message threshold for triggering
|
| 113 |
+
- [ ] Summary format and length
|
| 114 |
+
|
| 115 |
+
**Files to update:**
|
| 116 |
+
- `pycatan/ai/memory.py` - Add chat summarization logic
|
| 117 |
+
- `pycatan/ai/config.py` - Add summarization configuration
|
| 118 |
+
- `pycatan/ai/llm_client.py` - Support multiple models (main + summarization)
|
| 119 |
+
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
### Phase 3: Core AI Agent 🤖
|
| 123 |
+
**Goal:** Implement the main AI agent class
|
| 124 |
+
|
| 125 |
+
#### 3.1 Base Agent Implementation
|
| 126 |
+
- [ ] Create `AIAgent` class inheriting from `User`
|
| 127 |
+
- [ ] Implement required User interface methods
|
| 128 |
+
- [ ] `get_choice()` for decision-making
|
| 129 |
+
- [ ] Other interaction methods as needed
|
| 130 |
+
- [ ] Integrate with prompt manager
|
| 131 |
+
- [ ] Integrate with memory system
|
| 132 |
+
- [ ] Add agent state management
|
| 133 |
+
|
| 134 |
+
**Files to create:**
|
| 135 |
+
- `pycatan/players/ai_agent.py` - Main AI agent implementation (update existing stub)
|
| 136 |
+
|
| 137 |
+
---
|
| 138 |
+
|
| 139 |
+
#### 3.2 LLM Integration
|
| 140 |
+
- [ ] Create LLM client abstraction
|
| 141 |
+
- [ ] Support for OpenAI API
|
| 142 |
+
- [ ] Support for Anthropic Claude
|
| 143 |
+
- [ ] Support for other providers (Azure, etc.)
|
| 144 |
+
- [ ] Implement API call handling
|
| 145 |
+
- [ ] Request formatting
|
| 146 |
+
- [ ] Response parsing
|
| 147 |
+
- [ ] Error handling and retries
|
| 148 |
+
- [ ] Rate limiting
|
| 149 |
+
- [ ] Add logging for all LLM interactions
|
| 150 |
+
- [ ] Implement cost tracking
|
| 151 |
+
|
| 152 |
+
**Files to create:**
|
| 153 |
+
- `pycatan/ai/llm_client.py` - LLM API abstraction
|
| 154 |
+
- `pycatan/ai/providers/` - Provider-specific implementations
|
| 155 |
+
- `openai_provider.py`
|
| 156 |
+
- `anthropic_provider.py`
|
| 157 |
+
|
| 158 |
+
---
|
| 159 |
+
|
| 160 |
+
#### 3.3 Decision Pipeline
|
| 161 |
+
- [ ] Build event-to-prompt conversion
|
| 162 |
+
- [ ] Implement action extraction from responses
|
| 163 |
+
- [ ] Create action validation before execution
|
| 164 |
+
- [ ] Add decision logging and debugging
|
| 165 |
+
- [ ] Implement decision timeout handling
|
| 166 |
+
|
| 167 |
+
---
|
| 168 |
+
|
| 169 |
+
### Phase 4: Monitoring & Debugging Infrastructure 🔍
|
| 170 |
+
**Goal:** Build essential tools for observing and debugging agent behavior
|
| 171 |
+
|
| 172 |
+
**⚠️ CRITICAL: These tools are essential for development and must be built early!**
|
| 173 |
+
|
| 174 |
+
---
|
| 175 |
+
|
| 176 |
+
#### 4.1 Web Dashboard for Real-Time Monitoring 🌐
|
| 177 |
+
**Priority: HIGH - Required before agent testing**
|
| 178 |
+
|
| 179 |
+
- [ ] Design web dashboard UI
|
| 180 |
+
- [ ] Multi-agent view (tabs or split screen per agent)
|
| 181 |
+
- [ ] Live prompt display with syntax highlighting
|
| 182 |
+
- [ ] Agent reasoning/thinking display
|
| 183 |
+
- [ ] Action selection visualization
|
| 184 |
+
- [ ] Chat window with all messages
|
| 185 |
+
- [ ] Game state summary panel
|
| 186 |
+
- [ ] Build backend API for dashboard
|
| 187 |
+
- [ ] WebSocket connection for live updates
|
| 188 |
+
- [ ] Endpoints for prompt/response history
|
| 189 |
+
- [ ] Agent state endpoints
|
| 190 |
+
- [ ] Chat history endpoint
|
| 191 |
+
- [ ] Implement prompt logging and streaming
|
| 192 |
+
- [ ] Capture all prompts sent to LLM
|
| 193 |
+
- [ ] Capture all responses from LLM
|
| 194 |
+
- [ ] Stream to dashboard in real-time
|
| 195 |
+
- [ ] Format for readability
|
| 196 |
+
- [ ] Build agent reasoning viewer
|
| 197 |
+
- [ ] Display internal_thinking/reasoning
|
| 198 |
+
- [ ] Show action selection process
|
| 199 |
+
- [ ] Highlight tool usage
|
| 200 |
+
- [ ] Show memory updates
|
| 201 |
+
|
| 202 |
+
**Files to create:**
|
| 203 |
+
- `pycatan/monitoring/` - NEW monitoring package
|
| 204 |
+
- `dashboard_server.py` - Flask/FastAPI server for dashboard
|
| 205 |
+
- `event_logger.py` - Captures and broadcasts events
|
| 206 |
+
- `prompt_tracker.py` - Tracks all LLM interactions
|
| 207 |
+
- `pycatan/monitoring/web/` - Dashboard frontend
|
| 208 |
+
- `index.html` - Main dashboard page
|
| 209 |
+
- `dashboard.js` - Dashboard functionality
|
| 210 |
+
- `dashboard.css` - Dashboard styling
|
| 211 |
+
|
| 212 |
+
---
|
| 213 |
+
|
| 214 |
+
#### 4.2 Local Documentation & Logging 📁
|
| 215 |
+
**Priority: HIGH - Required for debugging**
|
| 216 |
+
|
| 217 |
+
- [ ] Design local documentation structure
|
| 218 |
+
- [ ] One folder per game session
|
| 219 |
+
- [ ] One file per agent with structured log
|
| 220 |
+
- [ ] Timestamp-based organization
|
| 221 |
+
- [ ] Implement per-agent documentation
|
| 222 |
+
- [ ] Agent configuration snapshot
|
| 223 |
+
- [ ] All prompts sent (formatted)
|
| 224 |
+
- [ ] All responses received (formatted)
|
| 225 |
+
- [ ] Decision timeline with reasoning
|
| 226 |
+
- [ ] Memory state snapshots
|
| 227 |
+
- [ ] Tool usage log
|
| 228 |
+
- [ ] Errors and warnings
|
| 229 |
+
- [ ] Build structured logging format
|
| 230 |
+
- [ ] JSON-based for easy parsing
|
| 231 |
+
- [ ] Markdown reports for human reading
|
| 232 |
+
- [ ] Searchable and filterable
|
| 233 |
+
- [ ] Add game session documentation
|
| 234 |
+
- [ ] Game state at each turn
|
| 235 |
+
- [ ] All chat messages with timestamps
|
| 236 |
+
- [ ] Final game results and statistics
|
| 237 |
+
|
| 238 |
+
**Files to create:**
|
| 239 |
+
- `pycatan/monitoring/local_logger.py` - Local file logging
|
| 240 |
+
- `pycatan/monitoring/session_recorder.py` - Game session recording
|
| 241 |
+
- `pycatan/monitoring/report_generator.py` - Generate readable reports
|
| 242 |
+
|
| 243 |
+
**Output structure:**
|
| 244 |
+
```
|
| 245 |
+
logs/
|
| 246 |
+
└── game_sessions/
|
| 247 |
+
└── 2026-01-03_15-30-45/
|
| 248 |
+
├── game_summary.json
|
| 249 |
+
├── chat_log.txt
|
| 250 |
+
├── agent_blue/
|
| 251 |
+
│ ├── config.json
|
| 252 |
+
│ ├── prompts.log
|
| 253 |
+
│ ├── decisions.log
|
| 254 |
+
│ └── memory_snapshots.json
|
| 255 |
+
├── agent_red/
|
| 256 |
+
│ └── ...
|
| 257 |
+
└── agent_white/
|
| 258 |
+
└── ...
|
| 259 |
+
```
|
| 260 |
+
|
| 261 |
+
---
|
| 262 |
+
|
| 263 |
+
#### 4.3 Chat Management System 💬
|
| 264 |
+
**Priority: HIGH - Core game feature**
|
| 265 |
+
|
| 266 |
+
- [ ] Design chat system architecture
|
| 267 |
+
- [ ] Centralized chat manager
|
| 268 |
+
- [ ] Message routing between players
|
| 269 |
+
- [ ] Chat history per game
|
| 270 |
+
- [ ] Public vs private messages
|
| 271 |
+
- [ ] Implement chat manager component
|
| 272 |
+
- [ ] Message queue/buffer
|
| 273 |
+
- [ ] Broadcast to all players
|
| 274 |
+
- [ ] Direct messages between players
|
| 275 |
+
- [ ] Integration with GameManager
|
| 276 |
+
- [ ] Build chat observation interface
|
| 277 |
+
- [ ] Real-time chat display in web dashboard
|
| 278 |
+
- [ ] Chat log export
|
| 279 |
+
- [ ] Filter by sender/time
|
| 280 |
+
- [ ] Define chat protocol
|
| 281 |
+
- [ ] Message format (sender, content, timestamp, type)
|
| 282 |
+
- [ ] Chat commands (if any)
|
| 283 |
+
- [ ] Trade negotiation messages
|
| 284 |
+
|
| 285 |
+
**Files to create:**
|
| 286 |
+
- `pycatan/management/chat_manager.py` - Central chat management
|
| 287 |
+
- `pycatan/management/message.py` - Message data structure
|
| 288 |
+
|
| 289 |
+
**Integration points:**
|
| 290 |
+
- GameManager receives messages from players
|
| 291 |
+
- ChatManager distributes to other players and dashboard
|
| 292 |
+
- AI agents see messages in their prompt context
|
| 293 |
+
- Web dashboard shows live chat
|
| 294 |
+
- Local logs record all messages
|
| 295 |
+
|
| 296 |
+
---
|
| 297 |
+
|
| 298 |
+
### Phase 5: Tool System 🔧
|
| 299 |
+
**Goal:** Provide computational tools for agent decision-making
|
| 300 |
+
|
| 301 |
+
#### 5.1 Core Tools
|
| 302 |
+
- [ ] **Probability Calculator**
|
| 303 |
+
- [ ] Dice roll probabilities for tiles
|
| 304 |
+
- [ ] Expected resource generation rates
|
| 305 |
+
- [ ] Statistical analysis helpers
|
| 306 |
+
- [ ] **Resource Tracker**
|
| 307 |
+
- [ ] Historical resource generation
|
| 308 |
+
- [ ] Resource scarcity analysis
|
| 309 |
+
- [ ] Production trend analysis
|
| 310 |
+
- [ ] **Path Finder**
|
| 311 |
+
- [ ] Optimal road placement
|
| 312 |
+
- [ ] Longest road calculation
|
| 313 |
+
- [ ] Connectivity analysis
|
| 314 |
+
- [ ] **Trade Evaluator**
|
| 315 |
+
- [ ] Fair trade assessment
|
| 316 |
+
- [ ] Trade benefit calculation
|
| 317 |
+
- [ ] Market value estimation
|
| 318 |
+
|
| 319 |
+
**Files to create:**
|
| 320 |
+
- `pycatan/ai/tools/` - Tool implementations
|
| 321 |
+
- `probability_tool.py`
|
| 322 |
+
- `resource_tool.py`
|
| 323 |
+
- `pathfinding_tool.py`
|
| 324 |
+
- `trade_tool.py`
|
| 325 |
+
- `tool_manager.py` - Tool orchestration
|
| 326 |
+
|
| 327 |
+
---
|
| 328 |
+
|
| 329 |
+
#### 5.2 Tool Integration
|
| 330 |
+
- [ ] Define tool interface/protocol
|
| 331 |
+
- [ ] Implement tool calling from prompts
|
| 332 |
+
- [ ] Add tool usage limits per decision
|
| 333 |
+
- [ ] Create tool result formatting
|
| 334 |
+
- [ ] Build tool usage logging
|
| 335 |
+
|
| 336 |
+
---
|
| 337 |
+
|
| 338 |
+
### Phase 6: Testing & Validation ✅
|
| 339 |
+
**Goal:** Ensure agent works correctly and plays reasonably
|
| 340 |
+
|
| 341 |
+
#### 6.1 Unit Tests
|
| 342 |
+
- [ ] Test prompt manager filtering
|
| 343 |
+
- [ ] Test response parser with various inputs
|
| 344 |
+
- [ ] Test memory operations
|
| 345 |
+
- [ ] Test each tool independently
|
| 346 |
+
- [ ] Test configuration loading
|
| 347 |
+
|
| 348 |
+
**Files to create:**
|
| 349 |
+
- `tests/unit/test_ai_agent.py`
|
| 350 |
+
- `tests/unit/test_prompt_manager.py`
|
| 351 |
+
- `tests/unit/test_memory.py`
|
| 352 |
+
- `tests/unit/test_tools.py`
|
| 353 |
+
|
| 354 |
+
---
|
| 355 |
+
|
| 356 |
+
#### 6.2 Integration Tests
|
| 357 |
+
- [ ] Test agent in complete game loop
|
| 358 |
+
- [ ] Test agent vs human player
|
| 359 |
+
- [ ] Test multiple AI agents playing together
|
| 360 |
+
- [ ] Test edge cases and error scenarios
|
| 361 |
+
- [ ] Test long-running games (memory management)
|
| 362 |
+
|
| 363 |
+
**Files to create:**
|
| 364 |
+
- `tests/integration/test_ai_gameplay.py`
|
| 365 |
+
- `tests/integration/test_multi_agent.py`
|
| 366 |
+
|
| 367 |
+
---
|
| 368 |
+
|
| 369 |
+
#### 6.3 Gameplay Validation
|
| 370 |
+
- [ ] Verify legal moves only
|
| 371 |
+
- [ ] Check strategic decision quality
|
| 372 |
+
- [ ] Evaluate social interaction naturalness
|
| 373 |
+
- [ ] Monitor LLM costs and performance
|
| 374 |
+
- [ ] Collect agent behavior metrics
|
| 375 |
+
|
| 376 |
+
---
|
| 377 |
+
|
| 378 |
+
### Phase 7: Optimization & Enhancement 🚀
|
| 379 |
+
**Goal:** Improve agent performance and capabilities
|
| 380 |
+
|
| 381 |
+
#### 7.1 Performance Optimization
|
| 382 |
+
- [ ] Reduce prompt token usage
|
| 383 |
+
- [ ] Implement response caching for similar situations
|
| 384 |
+
- [ ] Optimize tool execution
|
| 385 |
+
- [ ] Improve decision speed
|
| 386 |
+
|
| 387 |
+
---
|
| 388 |
+
|
| 389 |
+
#### 7.2 Strategy Enhancement
|
| 390 |
+
- [ ] Tune agent personalities
|
| 391 |
+
- [ ] Improve opening game strategy
|
| 392 |
+
- [ ] Enhance mid-game adaptation
|
| 393 |
+
- [ ] Refine end-game tactics
|
| 394 |
+
- [ ] Better negotiation and trading
|
| 395 |
+
|
| 396 |
+
---
|
| 397 |
+
|
| 398 |
+
#### 7.3 Advanced Features
|
| 399 |
+
- [ ] Multi-turn planning capability
|
| 400 |
+
- [ ] Opponent modeling
|
| 401 |
+
- [ ] Meta-strategy learning
|
| 402 |
+
- [ ] Tournament play support
|
| 403 |
+
- [ ] Statistical performance tracking
|
| 404 |
+
|
| 405 |
+
---
|
| 406 |
+
|
| 407 |
+
## 📁 Project Structure (Proposed)
|
| 408 |
+
|
| 409 |
+
```
|
| 410 |
+
pycatan/
|
| 411 |
+
├── ai/ # NEW: AI agent infrastructure
|
| 412 |
+
│ ├── __init__.py
|
| 413 |
+
│ ├── config.py # Configuration management
|
| 414 |
+
│ ├── prompt_manager.py # Prompt processing pipeline
|
| 415 |
+
│ ├── state_filter.py # Game state filtering
|
| 416 |
+
│ ├── prompt_templates.py # Prompt templates
|
| 417 |
+
│ ├── response_parser.py # Response parsing
|
| 418 |
+
│ ├── schemas.py # JSON schemas
|
| 419 |
+
│ ├── memory.py # Memory system + chat summarization
|
| 420 |
+
│ ├── llm_client.py # LLM abstraction (multi-model)
|
| 421 |
+
│ ├── providers/ # LLM provider implementations
|
| 422 |
+
│ │ ├── __init__.py
|
| 423 |
+
│ │ ├── openai_provider.py
|
| 424 |
+
│ │ └── anthropic_provider.py
|
| 425 |
+
│ └── tools/ # Agent tools
|
| 426 |
+
│ ├── __init__.py
|
| 427 |
+
│ ├── tool_manager.py
|
| 428 |
+
│ ├── probability_tool.py
|
| 429 |
+
│ ├── resource_tool.py
|
| 430 |
+
│ ├── pathfinding_tool.py
|
| 431 |
+
│ └── trade_tool.py
|
| 432 |
+
├── monitoring/ # NEW: Monitoring & debugging
|
| 433 |
+
│ ├── __init__.py
|
| 434 |
+
│ ├── dashboard_server.py # Web dashboard backend
|
| 435 |
+
│ ├── event_logger.py # Event capture and broadcast
|
| 436 |
+
│ ├── prompt_tracker.py # LLM interaction tracking
|
| 437 |
+
│ ├── local_logger.py # Local file logging
|
| 438 |
+
│ ├── session_recorder.py # Game session recording
|
| 439 |
+
│ ├── report_generator.py # Report generation
|
| 440 |
+
│ └── web/ # Dashboard frontend
|
| 441 |
+
│ ├── index.html
|
| 442 |
+
│ ├── dashboard.js
|
| 443 |
+
│ └── dashboard.css
|
| 444 |
+
├── management/
|
| 445 |
+
│ ├── actions.py # Existing
|
| 446 |
+
│ ├── game_manager.py # Existing
|
| 447 |
+
│ ├── log_events.py # Existing
|
| 448 |
+
│ ├── chat_manager.py # NEW: Chat management
|
| 449 |
+
│ └── message.py # NEW: Message data structure
|
| 450 |
+
├── players/
|
| 451 |
+
│ ├── ai_agent.py # UPDATE: Full AI agent implementation
|
| 452 |
+
│ ├── human_user.py # Existing
|
| 453 |
+
│ └── user.py # Existing
|
| 454 |
+
└── ... # Existing structure
|
| 455 |
+
|
| 456 |
+
logs/ # NEW: Local documentation
|
| 457 |
+
└── game_sessions/
|
| 458 |
+
└── YYYY-MM-DD_HH-MM-SS/
|
| 459 |
+
├── game_summary.json
|
| 460 |
+
├── chat_log.txt
|
| 461 |
+
└── agent_<color>/
|
| 462 |
+
├── config.json
|
| 463 |
+
├── prompts.log
|
| 464 |
+
├── decisions.log
|
| 465 |
+
└── memory_snapshots.json
|
| 466 |
+
|
| 467 |
+
examples/
|
| 468 |
+
├── ai_testing/
|
| 469 |
+
│ ├── config_example.yaml # NEW: Example configuration
|
| 470 |
+
│ ├── test_single_agent.py # NEW: Test script
|
| 471 |
+
│ └── test_multi_agent.py # NEW: Multi-agent test
|
| 472 |
+
└── ...
|
| 473 |
+
|
| 474 |
+
tests/
|
| 475 |
+
├── unit/
|
| 476 |
+
│ ├── test_ai_agent.py # NEW
|
| 477 |
+
│ ├── test_prompt_manager.py # NEW
|
| 478 |
+
│ ├── test_memory.py # NEW
|
| 479 |
+
│ └── test_tools.py # NEW
|
| 480 |
+
├── integration/
|
| 481 |
+
│ ├── test_ai_gameplay.py # NEW
|
| 482 |
+
│ └── test_multi_agent.py # NEW
|
| 483 |
+
└── ...
|
| 484 |
+
```
|
.github/instructions/updated.instructions.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
applyTo: '**'
|
| 3 |
+
---
|
| 4 |
+
|
| 5 |
+
# PyCatan AI Project Instructions
|
| 6 |
+
|
| 7 |
+
## 📋 Project Overview
|
| 8 |
+
|
| 9 |
+
**PyCatan_AI** is a Python implementation of the Settlers of Catan board game with a focus on AI agent development. The project consists of:
|
| 10 |
+
|
| 11 |
+
- **Core Game Engine**: Complete implementation of Catan game rules, board management, and resource mechanics
|
| 12 |
+
- **Game Management**: Turn-based coordination, action validation, and game state management
|
| 13 |
+
- **Player Types**: Support for both human players (CLI) and AI agents
|
| 14 |
+
- **Visualization**: Console and web-based game state visualization
|
| 15 |
+
- **AI Development**: Framework for building and testing LLM-based AI agents to play Catan
|
| 16 |
+
|
| 17 |
+
The primary goal is to create intelligent AI agents that can play Settlers of Catan autonomously, making strategic decisions about resource management, building placement, trading, and overall game strategy.
|
| 18 |
+
|
| 19 |
+
## 📚 Related Documentation
|
| 20 |
+
|
| 21 |
+
For detailed information about specific aspects of the project, refer to:
|
| 22 |
+
|
| 23 |
+
- **[AI_ARCHITECTURE.md](.github/instructions/AI_ARCHITECTURE.md)** - Architecture and design of the AI agent system
|
| 24 |
+
- **[AI_AGENT_PRINCIPLES.md](.github/instructions/AI_AGENT_PRINCIPLES.md)** - Core design principles and philosophy for AI agent implementation
|
| 25 |
+
- **[WORK_PLAN.md](.github/instructions/WORK_PLAN.md)** - Detailed development work plan and roadmap
|
| 26 |
+
- *(Additional documentation files will be referenced here as they are created)*
|
| 27 |
+
|
| 28 |
+
## 🎯 Project Context
|
| 29 |
+
|
| 30 |
+
This instruction file provides general coding guidelines and project context that AI assistants should follow when generating code, answering questions, or reviewing changes across the entire codebase.
|
.gitignore
CHANGED
|
@@ -70,8 +70,38 @@ pip-selfcheck.json
|
|
| 70 |
|
| 71 |
# Log files
|
| 72 |
*.log
|
|
|
|
| 73 |
|
| 74 |
# Temporary files
|
| 75 |
*.tmp
|
| 76 |
*.bak
|
| 77 |
*~
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
|
| 71 |
# Log files
|
| 72 |
*.log
|
| 73 |
+
logs/
|
| 74 |
|
| 75 |
# Temporary files
|
| 76 |
*.tmp
|
| 77 |
*.bak
|
| 78 |
*~
|
| 79 |
+
|
| 80 |
+
# ============================================================================
|
| 81 |
+
# AI Agent - Security and Privacy
|
| 82 |
+
# ============================================================================
|
| 83 |
+
|
| 84 |
+
# Environment variables with API keys (CRITICAL - NEVER COMMIT!)
|
| 85 |
+
.env
|
| 86 |
+
.env.local
|
| 87 |
+
.env.*.local
|
| 88 |
+
|
| 89 |
+
# AI Configuration files with sensitive data
|
| 90 |
+
# Note: *_example.yaml files WILL be committed as templates
|
| 91 |
+
pycatan/ai/*.yaml
|
| 92 |
+
!pycatan/ai/*_example.yaml
|
| 93 |
+
!pycatan/ai/*_example.yml
|
| 94 |
+
config.yaml
|
| 95 |
+
config.yml
|
| 96 |
+
*_config.yaml
|
| 97 |
+
*_config.yml
|
| 98 |
+
|
| 99 |
+
# AI Agent memory and game state files (may contain private data)
|
| 100 |
+
agent_memory.json
|
| 101 |
+
pycatan/ai/memory/*.json
|
| 102 |
+
logs/ai_agents/
|
| 103 |
+
logs/game_states/
|
| 104 |
+
|
| 105 |
+
# Test configuration files
|
| 106 |
+
test_config.yaml
|
| 107 |
+
test_*.yaml
|
QUICKSTART_API.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Quick Start - API Key Setup
|
| 2 |
+
|
| 3 |
+
## 🚀 Fast Setup (2 minutes)
|
| 4 |
+
|
| 5 |
+
### 1. Copy the template:
|
| 6 |
+
```bash
|
| 7 |
+
copy .env.example .env
|
| 8 |
+
```
|
| 9 |
+
|
| 10 |
+
### 2. Get your Gemini API key:
|
| 11 |
+
- Go to: https://aistudio.google.com/app/apikey
|
| 12 |
+
- Click "Create API Key"
|
| 13 |
+
- Copy the key
|
| 14 |
+
|
| 15 |
+
### 3. Edit `.env` file and paste your key:
|
| 16 |
+
```
|
| 17 |
+
GEMINI_API_KEY=AIzaSyC_paste_your_key_here
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
### 4. Test it works:
|
| 21 |
+
```bash
|
| 22 |
+
python examples/test_ai_config.py
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
## 📚 Full Documentation
|
| 26 |
+
See [docs/AI_SETUP.md](docs/AI_SETUP.md) for complete setup guide.
|
| 27 |
+
|
| 28 |
+
## ✅ Security
|
| 29 |
+
- `.env` is NOT committed to Git (safe!)
|
| 30 |
+
- Only `.env.example` (template) is in Git
|
| 31 |
+
- Your API keys stay on your machine only
|
docs/AI_SETUP.md
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🤖 AI Agent Setup Guide
|
| 2 |
+
|
| 3 |
+
This guide explains how to set up and configure AI agents for PyCatan.
|
| 4 |
+
|
| 5 |
+
## 📋 Table of Contents
|
| 6 |
+
|
| 7 |
+
1. [Quick Start](#quick-start)
|
| 8 |
+
2. [API Key Setup](#api-key-setup)
|
| 9 |
+
3. [Configuration System](#configuration-system)
|
| 10 |
+
4. [Security Best Practices](#security-best-practices)
|
| 11 |
+
5. [Development Workflow](#development-workflow)
|
| 12 |
+
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
## 🚀 Quick Start
|
| 16 |
+
|
| 17 |
+
### Step 1: Get an API Key
|
| 18 |
+
|
| 19 |
+
You need an API key from an LLM provider. We recommend **Google Gemini** for development:
|
| 20 |
+
|
| 21 |
+
1. Go to [Google AI Studio](https://aistudio.google.com/app/apikey)
|
| 22 |
+
2. Click "Create API Key"
|
| 23 |
+
3. Copy your API key
|
| 24 |
+
|
| 25 |
+
**Other providers:**
|
| 26 |
+
- OpenAI: https://platform.openai.com/api-keys
|
| 27 |
+
- Anthropic: https://console.anthropic.com/settings/keys
|
| 28 |
+
|
| 29 |
+
### Step 2: Setup Environment Variables
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
# Copy the template file
|
| 33 |
+
cp .env.example .env
|
| 34 |
+
|
| 35 |
+
# Edit .env and paste your API key
|
| 36 |
+
# (Use any text editor)
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
Example `.env` file:
|
| 40 |
+
```bash
|
| 41 |
+
GEMINI_API_KEY=AIzaSyC_your_actual_api_key_here
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
### Step 3: Install Dependencies
|
| 45 |
+
|
| 46 |
+
```bash
|
| 47 |
+
pip install pyyaml
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
### Step 4: Test the Configuration
|
| 51 |
+
|
| 52 |
+
```bash
|
| 53 |
+
python examples/test_ai_config.py
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
You should see:
|
| 57 |
+
```
|
| 58 |
+
🎉 All tests passed!
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
---
|
| 62 |
+
|
| 63 |
+
## 🔑 API Key Setup
|
| 64 |
+
|
| 65 |
+
### Where API Keys Are Stored
|
| 66 |
+
|
| 67 |
+
**API keys are stored in the `.env` file**, which is:
|
| 68 |
+
- ✅ **NOT** committed to Git (protected by `.gitignore`)
|
| 69 |
+
- ✅ Stored locally on your machine only
|
| 70 |
+
- ✅ Easy to update without changing code
|
| 71 |
+
|
| 72 |
+
### `.env` File Structure
|
| 73 |
+
|
| 74 |
+
```bash
|
| 75 |
+
# .env - YOUR PRIVATE FILE (never commit this!)
|
| 76 |
+
GEMINI_API_KEY=your_actual_key_here
|
| 77 |
+
OPENAI_API_KEY=your_openai_key_here # Optional
|
| 78 |
+
ANTHROPIC_API_KEY=your_anthropic_key # Optional
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
### `.env.example` File
|
| 82 |
+
|
| 83 |
+
The **`.env.example`** file is a template that:
|
| 84 |
+
- ✅ **IS** committed to Git
|
| 85 |
+
- ✅ Shows what variables are needed
|
| 86 |
+
- ✅ Contains NO actual secrets
|
| 87 |
+
- ✅ Helps other developers know what to set up
|
| 88 |
+
|
| 89 |
+
**Never put real API keys in `.env.example`!**
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
## ⚙️ Configuration System
|
| 94 |
+
|
| 95 |
+
### Overview
|
| 96 |
+
|
| 97 |
+
PyCatan uses a **two-file configuration system**:
|
| 98 |
+
|
| 99 |
+
```
|
| 100 |
+
📁 Project Root
|
| 101 |
+
├── .env # ❌ NOT in Git - API keys
|
| 102 |
+
├── .env.example # ✅ IN Git - Template
|
| 103 |
+
├── pycatan/ai/
|
| 104 |
+
│ ├── config_example.yaml # ✅ IN Git - Documentation
|
| 105 |
+
│ ├── config_dev.yaml # ✅ IN Git - Dev defaults
|
| 106 |
+
│ └── my_agent_config.yaml # ❌ NOT in Git - Your custom config
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
### File Types Explained
|
| 110 |
+
|
| 111 |
+
#### 1. `.env` - Environment Variables (API Keys)
|
| 112 |
+
- **Purpose:** Store sensitive API keys
|
| 113 |
+
- **Git:** ❌ **NEVER** committed
|
| 114 |
+
- **Contains:** `GEMINI_API_KEY=actual_secret_key`
|
| 115 |
+
- **Who creates it:** Each developer on their machine
|
| 116 |
+
|
| 117 |
+
#### 2. `.env.example` - Environment Template
|
| 118 |
+
- **Purpose:** Template showing what variables are needed
|
| 119 |
+
- **Git:** ✅ Committed to Git
|
| 120 |
+
- **Contains:** `GEMINI_API_KEY=` (empty)
|
| 121 |
+
- **Who creates it:** Already created in the project
|
| 122 |
+
|
| 123 |
+
#### 3. `config_dev.yaml` - Development Defaults
|
| 124 |
+
- **Purpose:** Default configuration for development
|
| 125 |
+
- **Git:** ✅ Committed to Git
|
| 126 |
+
- **Contains:** All settings EXCEPT API keys
|
| 127 |
+
- **Who uses it:** Everyone, automatically
|
| 128 |
+
|
| 129 |
+
#### 4. `config_example.yaml` - Configuration Documentation
|
| 130 |
+
- **Purpose:** Complete documentation of all options
|
| 131 |
+
- **Git:** ✅ Committed to Git
|
| 132 |
+
- **Contains:** All possible settings with explanations
|
| 133 |
+
- **Who uses it:** Reference when creating custom configs
|
| 134 |
+
|
| 135 |
+
#### 5. Your Custom Config (e.g., `my_agent_config.yaml`)
|
| 136 |
+
- **Purpose:** Your personal agent configuration
|
| 137 |
+
- **Git:** ❌ NOT committed (optional)
|
| 138 |
+
- **Contains:** Custom personality, strategies, etc.
|
| 139 |
+
- **Who uses it:** You, when you want special behavior
|
| 140 |
+
|
| 141 |
+
---
|
| 142 |
+
|
| 143 |
+
## 🔒 Security Best Practices
|
| 144 |
+
|
| 145 |
+
### ✅ DO:
|
| 146 |
+
- Keep your `.env` file local only
|
| 147 |
+
- Use different API keys for development and production
|
| 148 |
+
- Rotate your API keys regularly
|
| 149 |
+
- Review `.gitignore` to ensure `.env` is excluded
|
| 150 |
+
- Use `.env.example` as a template for team members
|
| 151 |
+
|
| 152 |
+
### ❌ DON'T:
|
| 153 |
+
- Never commit `.env` to Git
|
| 154 |
+
- Never put API keys in configuration YAML files
|
| 155 |
+
- Never share your `.env` file
|
| 156 |
+
- Never hardcode API keys in Python code
|
| 157 |
+
- Never put API keys in commit messages or PR descriptions
|
| 158 |
+
|
| 159 |
+
### Checking Security
|
| 160 |
+
|
| 161 |
+
```bash
|
| 162 |
+
# Make sure .env is ignored by Git
|
| 163 |
+
git status
|
| 164 |
+
|
| 165 |
+
# .env should NOT appear in the list
|
| 166 |
+
# If it does, remove it:
|
| 167 |
+
git rm --cached .env
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## 🛠️ Development Workflow
|
| 173 |
+
|
| 174 |
+
### Using the Default Development Config
|
| 175 |
+
|
| 176 |
+
The simplest way - just use `config_dev.yaml`:
|
| 177 |
+
|
| 178 |
+
```python
|
| 179 |
+
from pycatan.ai.config import AIConfig
|
| 180 |
+
|
| 181 |
+
# Loads config_dev.yaml by default
|
| 182 |
+
config = AIConfig.from_file('pycatan/ai/config_dev.yaml')
|
| 183 |
+
|
| 184 |
+
# API key is automatically loaded from .env
|
| 185 |
+
api_key = config.get_api_key() # Reads GEMINI_API_KEY from .env
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
### Creating a Custom Agent
|
| 189 |
+
|
| 190 |
+
1. **Copy the example config:**
|
| 191 |
+
```bash
|
| 192 |
+
cp pycatan/ai/config_example.yaml my_aggressive_agent.yaml
|
| 193 |
+
```
|
| 194 |
+
|
| 195 |
+
2. **Edit your config:**
|
| 196 |
+
```yaml
|
| 197 |
+
agent_name: "Aggressive Trader"
|
| 198 |
+
agent:
|
| 199 |
+
personality: "aggressive"
|
| 200 |
+
risk_tolerance: 0.8
|
| 201 |
+
trade_willingness: 0.9
|
| 202 |
+
```
|
| 203 |
+
|
| 204 |
+
3. **Use it in your code:**
|
| 205 |
+
```python
|
| 206 |
+
config = AIConfig.from_file('my_aggressive_agent.yaml')
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
4. **The API key is still loaded from `.env`** - you don't need to specify it!
|
| 210 |
+
|
| 211 |
+
### Multiple Agents with Different Personalities
|
| 212 |
+
|
| 213 |
+
```python
|
| 214 |
+
# Agent 1: Aggressive
|
| 215 |
+
config1 = AIConfig.from_file('configs/aggressive.yaml')
|
| 216 |
+
|
| 217 |
+
# Agent 2: Defensive
|
| 218 |
+
config2 = AIConfig.from_file('configs/defensive.yaml')
|
| 219 |
+
|
| 220 |
+
# Agent 3: Balanced (default)
|
| 221 |
+
config3 = AIConfig.from_file('pycatan/ai/config_dev.yaml')
|
| 222 |
+
|
| 223 |
+
# All three use the same API key from .env
|
| 224 |
+
```
|
| 225 |
+
|
| 226 |
+
---
|
| 227 |
+
|
| 228 |
+
## 📝 Configuration Options
|
| 229 |
+
|
| 230 |
+
### LLM Settings
|
| 231 |
+
|
| 232 |
+
```yaml
|
| 233 |
+
llm:
|
| 234 |
+
provider: "gemini" # or "openai", "anthropic"
|
| 235 |
+
model_name: "gemini-2.0-flash-exp"
|
| 236 |
+
temperature: 0.7 # 0.0 = deterministic, 1.0 = creative
|
| 237 |
+
max_tokens: 4096
|
| 238 |
+
```
|
| 239 |
+
|
| 240 |
+
### Agent Personality
|
| 241 |
+
|
| 242 |
+
```yaml
|
| 243 |
+
agent:
|
| 244 |
+
personality: "balanced" # aggressive, defensive, balanced, trading
|
| 245 |
+
risk_tolerance: 0.5 # 0.0 = safe, 1.0 = risky
|
| 246 |
+
|
| 247 |
+
# Strategic focus (0.0 to 1.0)
|
| 248 |
+
focus_on_settlements: 0.6
|
| 249 |
+
focus_on_cities: 0.7
|
| 250 |
+
focus_on_roads: 0.5
|
| 251 |
+
focus_on_dev_cards: 0.6
|
| 252 |
+
|
| 253 |
+
# Trading behavior
|
| 254 |
+
trade_willingness: 0.5 # 0.0 = never, 1.0 = always
|
| 255 |
+
trade_fairness: 0.7 # How fair are trades
|
| 256 |
+
```
|
| 257 |
+
|
| 258 |
+
### Debug Settings
|
| 259 |
+
|
| 260 |
+
```yaml
|
| 261 |
+
debug:
|
| 262 |
+
debug_mode: true # Enable detailed logging
|
| 263 |
+
log_prompts: true # Log prompts sent to LLM
|
| 264 |
+
log_responses: true # Log LLM responses
|
| 265 |
+
save_game_states: true # Save states for analysis
|
| 266 |
+
```
|
| 267 |
+
|
| 268 |
+
---
|
| 269 |
+
|
| 270 |
+
## 🧪 Testing Your Setup
|
| 271 |
+
|
| 272 |
+
### Test 1: Check API Key
|
| 273 |
+
|
| 274 |
+
```python
|
| 275 |
+
from pycatan.ai.config import AIConfig
|
| 276 |
+
|
| 277 |
+
config = AIConfig()
|
| 278 |
+
try:
|
| 279 |
+
api_key = config.get_api_key()
|
| 280 |
+
print("✓ API key loaded successfully")
|
| 281 |
+
except ValueError as e:
|
| 282 |
+
print(f"✗ Error: {e}")
|
| 283 |
+
```
|
| 284 |
+
|
| 285 |
+
### Test 2: Load Configuration
|
| 286 |
+
|
| 287 |
+
```python
|
| 288 |
+
config = AIConfig.from_file('pycatan/ai/config_dev.yaml')
|
| 289 |
+
print(f"✓ Loaded config for: {config.agent_name}")
|
| 290 |
+
print(f" Provider: {config.llm.provider}")
|
| 291 |
+
print(f" Model: {config.llm.model_name}")
|
| 292 |
+
```
|
| 293 |
+
|
| 294 |
+
### Test 3: Run Full Test Suite
|
| 295 |
+
|
| 296 |
+
```bash
|
| 297 |
+
python examples/test_ai_config.py
|
| 298 |
+
```
|
| 299 |
+
|
| 300 |
+
---
|
| 301 |
+
|
| 302 |
+
## 🎯 Common Scenarios
|
| 303 |
+
|
| 304 |
+
### Scenario 1: "I just cloned the repo"
|
| 305 |
+
|
| 306 |
+
1. Create `.env`: `cp .env.example .env`
|
| 307 |
+
2. Add your API key to `.env`
|
| 308 |
+
3. Run tests: `python examples/test_ai_config.py`
|
| 309 |
+
|
| 310 |
+
### Scenario 2: "I want to test different personalities"
|
| 311 |
+
|
| 312 |
+
Use the existing configs:
|
| 313 |
+
- `config_dev.yaml` - Balanced agent
|
| 314 |
+
- Or create custom configs based on `config_example.yaml`
|
| 315 |
+
|
| 316 |
+
### Scenario 3: "I want to switch LLM providers"
|
| 317 |
+
|
| 318 |
+
Edit your config file:
|
| 319 |
+
```yaml
|
| 320 |
+
llm:
|
| 321 |
+
provider: "openai"
|
| 322 |
+
model_name: "gpt-4-turbo-preview"
|
| 323 |
+
api_key_env_var: "OPENAI_API_KEY"
|
| 324 |
+
```
|
| 325 |
+
|
| 326 |
+
Add the key to `.env`:
|
| 327 |
+
```bash
|
| 328 |
+
OPENAI_API_KEY=sk-your-key-here
|
| 329 |
+
```
|
| 330 |
+
|
| 331 |
+
### Scenario 4: "My API key changed"
|
| 332 |
+
|
| 333 |
+
Just edit `.env` - no code changes needed!
|
| 334 |
+
|
| 335 |
+
---
|
| 336 |
+
|
| 337 |
+
## 📚 Next Steps
|
| 338 |
+
|
| 339 |
+
- Read [AI_ARCHITECTURE.md](AI_ARCHITECTURE.md) for system design
|
| 340 |
+
- Read [WORK_PLAN.md](WORK_PLAN.md) for development roadmap
|
| 341 |
+
- See [config_example.yaml](../pycatan/ai/config_example.yaml) for all options
|
| 342 |
+
|
| 343 |
+
---
|
| 344 |
+
|
| 345 |
+
## 🆘 Troubleshooting
|
| 346 |
+
|
| 347 |
+
### "ModuleNotFoundError: No module named 'yaml'"
|
| 348 |
+
```bash
|
| 349 |
+
pip install pyyaml
|
| 350 |
+
```
|
| 351 |
+
|
| 352 |
+
### "API key not found"
|
| 353 |
+
1. Check `.env` exists in project root
|
| 354 |
+
2. Check the API key variable name matches
|
| 355 |
+
3. Try: `cat .env` to verify content
|
| 356 |
+
|
| 357 |
+
### "Configuration file not found"
|
| 358 |
+
- Use absolute paths or run from project root
|
| 359 |
+
- Check file extension (`.yaml` not `.yml`)
|
| 360 |
+
|
| 361 |
+
### "Still stuck?"
|
| 362 |
+
- Check [GitHub Issues](your-repo-url/issues)
|
| 363 |
+
- Review the test output: `python examples/test_ai_config.py`
|
| 364 |
+
|
| 365 |
+
---
|
| 366 |
+
|
| 367 |
+
**Last Updated:** January 3, 2026
|
example_answer.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"internal_thinking": "I have 3 Sheep and 2 Wheat. I need Wood and Brick to build. I see Red asked for Sheep in the chat. My note says to trade with Red. I will offer him a deal verbally first to see if he accepts, before committing to a formal trade action. I won't pass turn yet.",
|
| 3 |
+
|
| 4 |
+
"note_to_self": "Waiting for Red's response. If he says yes, I will use OFFER_TRADE action next.",
|
| 5 |
+
|
| 6 |
+
"say_outloud": "Red, I have plenty of sheep. Can you give me 1 Wood and 1 Brick for 2 Sheep?",
|
| 7 |
+
|
| 8 |
+
"action": {
|
| 9 |
+
"type": "WAIT_FOR_RESPONSE",
|
| 10 |
+
"parameters": {}
|
| 11 |
+
}
|
| 12 |
+
}
|
examples/demo_ai_config.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Quick demo showing how the AI configuration system works.
|
| 3 |
+
|
| 4 |
+
This script demonstrates:
|
| 5 |
+
1. How API keys are loaded from environment variables
|
| 6 |
+
2. How to use config files
|
| 7 |
+
3. The difference between config_example.yaml and config_dev.yaml
|
| 8 |
+
4. How to create custom agent configurations
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import os
|
| 12 |
+
import sys
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
# Add project root to path
|
| 16 |
+
project_root = Path(__file__).parent.parent
|
| 17 |
+
sys.path.insert(0, str(project_root))
|
| 18 |
+
|
| 19 |
+
from pycatan.ai.config import AIConfig, load_config
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def demo_api_key_loading():
|
| 23 |
+
"""Demo 1: How API keys are loaded from environment variables."""
|
| 24 |
+
print("\n" + "="*80)
|
| 25 |
+
print("DEMO 1: API Key Loading from Environment")
|
| 26 |
+
print("="*80)
|
| 27 |
+
|
| 28 |
+
print("\n1. API keys are stored in the .env file (NOT in Git)")
|
| 29 |
+
print(" Example .env file:")
|
| 30 |
+
print(" ┌─────────────────────────────────────┐")
|
| 31 |
+
print(" │ GEMINI_API_KEY=AIzaSyC...your_key │")
|
| 32 |
+
print(" │ OPENAI_API_KEY=sk-...your_key │")
|
| 33 |
+
print(" └─────────────────────────────────────┘")
|
| 34 |
+
|
| 35 |
+
print("\n2. The config system reads from environment variables:")
|
| 36 |
+
config = AIConfig()
|
| 37 |
+
|
| 38 |
+
print(f" Provider: {config.llm.provider}")
|
| 39 |
+
print(f" Env var name: {config.llm.api_key_env_var}")
|
| 40 |
+
|
| 41 |
+
# Try to get API key
|
| 42 |
+
try:
|
| 43 |
+
api_key = config.get_api_key()
|
| 44 |
+
# Hide most of the key for security
|
| 45 |
+
masked_key = api_key[:10] + "..." + api_key[-4:] if len(api_key) > 14 else "***"
|
| 46 |
+
print(f" ✓ API key loaded: {masked_key}")
|
| 47 |
+
print(f" ✓ Full length: {len(api_key)} characters")
|
| 48 |
+
except ValueError as e:
|
| 49 |
+
print(f" ✗ No API key found: {e}")
|
| 50 |
+
print("\n 👉 To fix this:")
|
| 51 |
+
print(" 1. Copy .env.example to .env")
|
| 52 |
+
print(" 2. Add your API key to .env")
|
| 53 |
+
print(" 3. The .env file will NOT be committed to Git")
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def demo_config_files():
|
| 57 |
+
"""Demo 2: Different types of config files."""
|
| 58 |
+
print("\n" + "="*80)
|
| 59 |
+
print("DEMO 2: Configuration Files Explained")
|
| 60 |
+
print("="*80)
|
| 61 |
+
|
| 62 |
+
print("\n📁 THREE types of config files:")
|
| 63 |
+
|
| 64 |
+
print("\n1️⃣ config_example.yaml - DOCUMENTATION")
|
| 65 |
+
print(" ├─ Purpose: Shows ALL possible settings with explanations")
|
| 66 |
+
print(" ├─ Git: ✅ Committed (it's documentation)")
|
| 67 |
+
print(" ├─ Usage: Read it to understand options")
|
| 68 |
+
print(" └─ Don't use directly - copy and customize it")
|
| 69 |
+
|
| 70 |
+
print("\n2️⃣ config_dev.yaml - DEFAULT FOR DEVELOPMENT")
|
| 71 |
+
print(" ├─ Purpose: Ready-to-use config for development")
|
| 72 |
+
print(" ├─ Git: ✅ Committed (team shares same defaults)")
|
| 73 |
+
print(" ├─ Usage: Just load it and start coding!")
|
| 74 |
+
print(" └─ Example: AIConfig.from_file('pycatan/ai/config_dev.yaml')")
|
| 75 |
+
|
| 76 |
+
print("\n3️⃣ your_custom_config.yaml - YOUR PERSONAL AGENT")
|
| 77 |
+
print(" ├─ Purpose: Your custom agent configuration")
|
| 78 |
+
print(" ├─ Git: ❌ NOT committed (optional)")
|
| 79 |
+
print(" ├─ Usage: Create when you want custom behavior")
|
| 80 |
+
print(" └─ Example: Copy config_example.yaml and modify")
|
| 81 |
+
|
| 82 |
+
print("\n💡 WORKFLOW:")
|
| 83 |
+
print(" • During development: Use config_dev.yaml")
|
| 84 |
+
print(" • Want custom agent: Copy config_example.yaml → my_agent.yaml")
|
| 85 |
+
print(" • API keys: Always in .env (never in YAML files)")
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def demo_default_config():
|
| 89 |
+
"""Demo 3: Using the default development config."""
|
| 90 |
+
print("\n" + "="*80)
|
| 91 |
+
print("DEMO 3: Using the Default Development Config")
|
| 92 |
+
print("="*80)
|
| 93 |
+
|
| 94 |
+
print("\n▶ Loading config_dev.yaml...")
|
| 95 |
+
config_path = project_root / "pycatan" / "ai" / "config_dev.yaml"
|
| 96 |
+
|
| 97 |
+
if config_path.exists():
|
| 98 |
+
config = AIConfig.from_file(str(config_path))
|
| 99 |
+
|
| 100 |
+
print(f"\n✓ Loaded successfully!")
|
| 101 |
+
print(f"\n📋 Configuration Details:")
|
| 102 |
+
print(f" Agent Name: {config.agent_name}")
|
| 103 |
+
print(f" Provider: {config.llm.provider}")
|
| 104 |
+
print(f" Model: {config.llm.model_name}")
|
| 105 |
+
print(f" Temperature: {config.llm.temperature}")
|
| 106 |
+
print(f" Personality: {config.agent.personality}")
|
| 107 |
+
print(f" Risk Tolerance: {config.agent.risk_tolerance}")
|
| 108 |
+
print(f" Debug Mode: {config.debug.debug_mode}")
|
| 109 |
+
|
| 110 |
+
print(f"\n⚙️ Strategic Focus:")
|
| 111 |
+
print(f" Settlements: {config.agent.focus_on_settlements}")
|
| 112 |
+
print(f" Cities: {config.agent.focus_on_cities}")
|
| 113 |
+
print(f" Roads: {config.agent.focus_on_roads}")
|
| 114 |
+
print(f" Dev Cards: {config.agent.focus_on_dev_cards}")
|
| 115 |
+
|
| 116 |
+
print(f"\n💬 Social Behavior:")
|
| 117 |
+
print(f" Trade Willingness: {config.agent.trade_willingness}")
|
| 118 |
+
print(f" Chat Frequency: {config.agent.chat_frequency}")
|
| 119 |
+
print(f" Chattiness: {config.agent.chattiness}")
|
| 120 |
+
else:
|
| 121 |
+
print(f"✗ Config file not found: {config_path}")
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def demo_custom_config():
|
| 125 |
+
"""Demo 4: Creating a custom agent configuration."""
|
| 126 |
+
print("\n" + "="*80)
|
| 127 |
+
print("DEMO 4: Creating Custom Agent Configuration")
|
| 128 |
+
print("="*80)
|
| 129 |
+
|
| 130 |
+
print("\n▶ Creating an 'Aggressive Trader' agent...")
|
| 131 |
+
|
| 132 |
+
# Start with default config
|
| 133 |
+
config = AIConfig()
|
| 134 |
+
|
| 135 |
+
# Customize for aggressive trading
|
| 136 |
+
config.agent_name = "Aggressive Trader"
|
| 137 |
+
config.agent.personality = "trading"
|
| 138 |
+
config.agent.risk_tolerance = 0.8 # High risk
|
| 139 |
+
config.agent.trade_willingness = 0.9 # Trades a lot
|
| 140 |
+
config.agent.trade_fairness = 0.6 # Slightly unfair trades
|
| 141 |
+
config.agent.focus_on_settlements = 0.8 # Expand quickly
|
| 142 |
+
config.agent.chat_frequency = 0.7 # Very chatty
|
| 143 |
+
config.agent.chattiness = "chatty"
|
| 144 |
+
config.llm.temperature = 0.8 # More creative
|
| 145 |
+
|
| 146 |
+
print("\n✓ Custom config created!")
|
| 147 |
+
print(f"\n📋 Agent Profile:")
|
| 148 |
+
print(f" Name: {config.agent_name}")
|
| 149 |
+
print(f" Personality: {config.agent.personality}")
|
| 150 |
+
print(f" Risk Tolerance: {config.agent.risk_tolerance} (HIGH)")
|
| 151 |
+
print(f" Trade Willingness: {config.agent.trade_willingness} (VERY HIGH)")
|
| 152 |
+
print(f" Trade Fairness: {config.agent.trade_fairness} (Slightly unfair)")
|
| 153 |
+
print(f" Chattiness: {config.agent.chattiness}")
|
| 154 |
+
print(f" Temperature: {config.llm.temperature} (Creative)")
|
| 155 |
+
|
| 156 |
+
# Save to file
|
| 157 |
+
custom_file = project_root / "aggressive_trader_config.yaml"
|
| 158 |
+
config.to_file(str(custom_file))
|
| 159 |
+
print(f"\n💾 Saved to: {custom_file.name}")
|
| 160 |
+
print(" (This file will NOT be committed to Git)")
|
| 161 |
+
|
| 162 |
+
# Clean up
|
| 163 |
+
custom_file.unlink()
|
| 164 |
+
print(" (Cleaned up demo file)")
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def demo_security():
|
| 168 |
+
"""Demo 5: Security features."""
|
| 169 |
+
print("\n" + "="*80)
|
| 170 |
+
print("DEMO 5: Security Features")
|
| 171 |
+
print("="*80)
|
| 172 |
+
|
| 173 |
+
print("\n🔒 What's Protected:")
|
| 174 |
+
print(" ✅ .env file → NOT in Git")
|
| 175 |
+
print(" ✅ Your custom *.yaml configs → NOT in Git")
|
| 176 |
+
print(" ✅ Agent memory files → NOT in Git")
|
| 177 |
+
print(" ✅ Game state logs → NOT in Git")
|
| 178 |
+
|
| 179 |
+
print("\n📤 What's Committed:")
|
| 180 |
+
print(" ✅ .env.example → Template (no secrets)")
|
| 181 |
+
print(" ✅ config_example.yaml → Documentation")
|
| 182 |
+
print(" ✅ config_dev.yaml → Default settings")
|
| 183 |
+
print(" ✅ Python code → No secrets in code")
|
| 184 |
+
|
| 185 |
+
print("\n⚠️ Remember:")
|
| 186 |
+
print(" • NEVER commit your .env file")
|
| 187 |
+
print(" • NEVER put API keys in YAML files")
|
| 188 |
+
print(" • NEVER hardcode API keys in Python code")
|
| 189 |
+
print(" • Each developer has their own .env file")
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def main():
|
| 193 |
+
"""Run all demos."""
|
| 194 |
+
print("\n" + "="*80)
|
| 195 |
+
print("🎓 AI CONFIGURATION SYSTEM - INTERACTIVE DEMO")
|
| 196 |
+
print("="*80)
|
| 197 |
+
print("\nThis demo explains how the configuration system works")
|
| 198 |
+
print("and shows you the difference between the config files.")
|
| 199 |
+
|
| 200 |
+
demo_api_key_loading()
|
| 201 |
+
demo_config_files()
|
| 202 |
+
demo_default_config()
|
| 203 |
+
demo_custom_config()
|
| 204 |
+
demo_security()
|
| 205 |
+
|
| 206 |
+
print("\n" + "="*80)
|
| 207 |
+
print("✅ DEMO COMPLETE!")
|
| 208 |
+
print("="*80)
|
| 209 |
+
print("\n📚 Next Steps:")
|
| 210 |
+
print(" 1. Read: docs/AI_SETUP.md (complete setup guide)")
|
| 211 |
+
print(" 2. Read: QUICKSTART_API.md (2-minute setup)")
|
| 212 |
+
print(" 3. Look at: pycatan/ai/config_example.yaml (all options)")
|
| 213 |
+
print(" 4. Use: pycatan/ai/config_dev.yaml (start coding!)")
|
| 214 |
+
print("\n💡 Quick Start:")
|
| 215 |
+
print(" from pycatan.ai.config import AIConfig")
|
| 216 |
+
print(" config = AIConfig.from_file('pycatan/ai/config_dev.yaml')")
|
| 217 |
+
print(" api_key = config.get_api_key() # From .env file")
|
| 218 |
+
print("\n" + "="*80)
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
if __name__ == "__main__":
|
| 222 |
+
main()
|
examples/test_ai_config.py
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Test script for AI Configuration System
|
| 3 |
+
|
| 4 |
+
This script tests the configuration management functionality:
|
| 5 |
+
1. Create default configuration
|
| 6 |
+
2. Save to file
|
| 7 |
+
3. Load from file
|
| 8 |
+
4. Validate configuration
|
| 9 |
+
5. Test different personalities
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import sys
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
# Add project root to path
|
| 16 |
+
project_root = Path(__file__).parent.parent
|
| 17 |
+
sys.path.insert(0, str(project_root))
|
| 18 |
+
|
| 19 |
+
from pycatan.ai.config import AIConfig, load_config
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def test_default_config():
|
| 23 |
+
"""Test creating and using default configuration."""
|
| 24 |
+
print("\n" + "="*80)
|
| 25 |
+
print("TEST 1: Default Configuration")
|
| 26 |
+
print("="*80)
|
| 27 |
+
|
| 28 |
+
config = AIConfig()
|
| 29 |
+
print(f"\n✓ Created default config:\n{config}")
|
| 30 |
+
|
| 31 |
+
# Validate
|
| 32 |
+
try:
|
| 33 |
+
config.validate()
|
| 34 |
+
print("✓ Configuration is valid")
|
| 35 |
+
except ValueError as e:
|
| 36 |
+
print(f"✗ Validation failed: {e}")
|
| 37 |
+
return False
|
| 38 |
+
|
| 39 |
+
return True
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def test_save_and_load():
|
| 43 |
+
"""Test saving and loading configuration."""
|
| 44 |
+
print("\n" + "="*80)
|
| 45 |
+
print("TEST 2: Save and Load Configuration")
|
| 46 |
+
print("="*80)
|
| 47 |
+
|
| 48 |
+
# Create custom config
|
| 49 |
+
config = AIConfig()
|
| 50 |
+
config.agent_name = "Test Agent"
|
| 51 |
+
config.agent.personality = "aggressive"
|
| 52 |
+
config.agent.risk_tolerance = 0.8
|
| 53 |
+
config.llm.temperature = 0.9
|
| 54 |
+
|
| 55 |
+
# Save to file
|
| 56 |
+
test_file = "test_config.yaml"
|
| 57 |
+
config.to_file(test_file)
|
| 58 |
+
print(f"✓ Saved configuration to {test_file}")
|
| 59 |
+
|
| 60 |
+
# Load from file
|
| 61 |
+
loaded_config = AIConfig.from_file(test_file)
|
| 62 |
+
print(f"✓ Loaded configuration from {test_file}")
|
| 63 |
+
|
| 64 |
+
# Verify values
|
| 65 |
+
assert loaded_config.agent_name == "Test Agent", "Agent name mismatch"
|
| 66 |
+
assert loaded_config.agent.personality == "aggressive", "Personality mismatch"
|
| 67 |
+
assert loaded_config.agent.risk_tolerance == 0.8, "Risk tolerance mismatch"
|
| 68 |
+
assert loaded_config.llm.temperature == 0.9, "Temperature mismatch"
|
| 69 |
+
|
| 70 |
+
print("✓ All values match correctly")
|
| 71 |
+
|
| 72 |
+
# Clean up
|
| 73 |
+
Path(test_file).unlink()
|
| 74 |
+
print(f"✓ Cleaned up {test_file}")
|
| 75 |
+
|
| 76 |
+
return True
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def test_personalities():
|
| 80 |
+
"""Test creating configs with different personalities."""
|
| 81 |
+
print("\n" + "="*80)
|
| 82 |
+
print("TEST 3: Different Personalities")
|
| 83 |
+
print("="*80)
|
| 84 |
+
|
| 85 |
+
personalities = {
|
| 86 |
+
"aggressive": {
|
| 87 |
+
"personality": "aggressive",
|
| 88 |
+
"risk_tolerance": 0.8,
|
| 89 |
+
"trade_willingness": 0.7,
|
| 90 |
+
"focus_on_settlements": 0.8
|
| 91 |
+
},
|
| 92 |
+
"defensive": {
|
| 93 |
+
"personality": "defensive",
|
| 94 |
+
"risk_tolerance": 0.3,
|
| 95 |
+
"trade_willingness": 0.3,
|
| 96 |
+
"focus_on_cities": 0.9
|
| 97 |
+
},
|
| 98 |
+
"balanced": {
|
| 99 |
+
"personality": "balanced",
|
| 100 |
+
"risk_tolerance": 0.5,
|
| 101 |
+
"trade_willingness": 0.5
|
| 102 |
+
},
|
| 103 |
+
"trading": {
|
| 104 |
+
"personality": "trading",
|
| 105 |
+
"risk_tolerance": 0.6,
|
| 106 |
+
"trade_willingness": 0.9,
|
| 107 |
+
"chat_frequency": 0.7
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
for name, settings in personalities.items():
|
| 112 |
+
config = AIConfig()
|
| 113 |
+
config.agent_name = f"{name.capitalize()} Agent"
|
| 114 |
+
|
| 115 |
+
# Apply settings
|
| 116 |
+
for key, value in settings.items():
|
| 117 |
+
setattr(config.agent, key, value)
|
| 118 |
+
|
| 119 |
+
# Validate
|
| 120 |
+
config.validate()
|
| 121 |
+
print(f"✓ Created and validated '{name}' personality")
|
| 122 |
+
print(f" - Risk tolerance: {config.agent.risk_tolerance}")
|
| 123 |
+
print(f" - Trade willingness: {config.agent.trade_willingness}")
|
| 124 |
+
|
| 125 |
+
return True
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def test_validation():
|
| 129 |
+
"""Test configuration validation."""
|
| 130 |
+
print("\n" + "="*80)
|
| 131 |
+
print("TEST 4: Configuration Validation")
|
| 132 |
+
print("="*80)
|
| 133 |
+
|
| 134 |
+
# Test invalid temperature
|
| 135 |
+
config = AIConfig()
|
| 136 |
+
config.llm.temperature = 3.0 # Invalid (> 2.0)
|
| 137 |
+
|
| 138 |
+
try:
|
| 139 |
+
config.validate()
|
| 140 |
+
print("✗ Should have caught invalid temperature")
|
| 141 |
+
return False
|
| 142 |
+
except ValueError as e:
|
| 143 |
+
print(f"✓ Correctly caught invalid temperature: {e}")
|
| 144 |
+
|
| 145 |
+
# Test invalid risk tolerance
|
| 146 |
+
config = AIConfig()
|
| 147 |
+
config.agent.risk_tolerance = 1.5 # Invalid (> 1.0)
|
| 148 |
+
|
| 149 |
+
try:
|
| 150 |
+
config.validate()
|
| 151 |
+
print("✗ Should have caught invalid risk_tolerance")
|
| 152 |
+
return False
|
| 153 |
+
except ValueError as e:
|
| 154 |
+
print(f"✓ Correctly caught invalid risk_tolerance: {e}")
|
| 155 |
+
|
| 156 |
+
# Test valid config
|
| 157 |
+
config = AIConfig()
|
| 158 |
+
config.validate()
|
| 159 |
+
print("✓ Valid configuration passes validation")
|
| 160 |
+
|
| 161 |
+
return True
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def test_to_dict_and_back():
|
| 165 |
+
"""Test dictionary conversion."""
|
| 166 |
+
print("\n" + "="*80)
|
| 167 |
+
print("TEST 5: Dictionary Conversion")
|
| 168 |
+
print("="*80)
|
| 169 |
+
|
| 170 |
+
# Create config
|
| 171 |
+
config = AIConfig()
|
| 172 |
+
config.agent_name = "Dict Test Agent"
|
| 173 |
+
config.agent.personality = "trading"
|
| 174 |
+
config.llm.temperature = 0.8
|
| 175 |
+
|
| 176 |
+
# Convert to dict
|
| 177 |
+
config_dict = config.to_dict()
|
| 178 |
+
print("✓ Converted config to dictionary")
|
| 179 |
+
|
| 180 |
+
# Create from dict
|
| 181 |
+
new_config = AIConfig.from_dict(config_dict)
|
| 182 |
+
print("✓ Created config from dictionary")
|
| 183 |
+
|
| 184 |
+
# Verify values
|
| 185 |
+
assert new_config.agent_name == config.agent_name
|
| 186 |
+
assert new_config.agent.personality == config.agent.personality
|
| 187 |
+
assert new_config.llm.temperature == config.llm.temperature
|
| 188 |
+
print("✓ All values preserved correctly")
|
| 189 |
+
|
| 190 |
+
return True
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def main():
|
| 194 |
+
"""Run all tests."""
|
| 195 |
+
print("\n" + "="*80)
|
| 196 |
+
print("AI CONFIGURATION SYSTEM - TEST SUITE")
|
| 197 |
+
print("="*80)
|
| 198 |
+
|
| 199 |
+
tests = [
|
| 200 |
+
("Default Configuration", test_default_config),
|
| 201 |
+
("Save and Load", test_save_and_load),
|
| 202 |
+
("Different Personalities", test_personalities),
|
| 203 |
+
("Validation", test_validation),
|
| 204 |
+
("Dictionary Conversion", test_to_dict_and_back)
|
| 205 |
+
]
|
| 206 |
+
|
| 207 |
+
results = []
|
| 208 |
+
for name, test_func in tests:
|
| 209 |
+
try:
|
| 210 |
+
result = test_func()
|
| 211 |
+
results.append((name, result))
|
| 212 |
+
except Exception as e:
|
| 213 |
+
print(f"\n✗ Test '{name}' failed with exception: {e}")
|
| 214 |
+
import traceback
|
| 215 |
+
traceback.print_exc()
|
| 216 |
+
results.append((name, False))
|
| 217 |
+
|
| 218 |
+
# Summary
|
| 219 |
+
print("\n" + "="*80)
|
| 220 |
+
print("TEST SUMMARY")
|
| 221 |
+
print("="*80)
|
| 222 |
+
|
| 223 |
+
passed = sum(1 for _, result in results if result)
|
| 224 |
+
total = len(results)
|
| 225 |
+
|
| 226 |
+
for name, result in results:
|
| 227 |
+
status = "✓ PASS" if result else "✗ FAIL"
|
| 228 |
+
print(f"{status}: {name}")
|
| 229 |
+
|
| 230 |
+
print(f"\nTotal: {passed}/{total} tests passed")
|
| 231 |
+
|
| 232 |
+
if passed == total:
|
| 233 |
+
print("\n🎉 All tests passed!")
|
| 234 |
+
return 0
|
| 235 |
+
else:
|
| 236 |
+
print(f"\n❌ {total - passed} test(s) failed")
|
| 237 |
+
return 1
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
if __name__ == "__main__":
|
| 241 |
+
sys.exit(main())
|
promt_format.text
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
// מידע על זהות השחקן
|
| 3 |
+
"meta_data": {
|
| 4 |
+
"agent_name": "Dani",
|
| 5 |
+
"my_color": "Blue",
|
| 6 |
+
"role": "You are a pro Catan player.",
|
| 7 |
+
},
|
| 8 |
+
// מידע על מה קרה עכשיו בעולם
|
| 9 |
+
"task_context": {
|
| 10 |
+
"what_just_happened": "Player 'Red' rolled a 6. You received 1 Wood.",
|
| 11 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. You may use the provided tools to gather more data (e.g., calculate probabilities), but limit yourself to a maximum of 3 tool executions per decision. If you wish to negotiate or wait for other players, select the 'WAIT_FOR_RESPONSE' action.",
|
| 12 |
+
},
|
| 13 |
+
// קונטקסט על הSTATE של העולם מותאם לנקודת המבט של השחקן
|
| 14 |
+
"game_state": {
|
| 15 |
+
"my_private_info": {
|
| 16 |
+
"resources": {"wood": 0, "brick": 0, "sheep": 3, "wheat": 1, "ore": 0},
|
| 17 |
+
"development_cards": [],
|
| 18 |
+
"victory_points": 2
|
| 19 |
+
},....
|
| 20 |
+
},
|
| 21 |
+
|
| 22 |
+
"social_context": {
|
| 23 |
+
// ההודעות האחרונות בצאט
|
| 24 |
+
"recent_chat": [
|
| 25 |
+
{"sender": "Red", "content": "I need sheep desperately."}
|
| 26 |
+
],
|
| 27 |
+
|
| 28 |
+
"last_summaries": [1: "Dana is off to a quick start with a lucky roll and a trade with Alex to build toward the wood port. I’ve warned the table about her strategy, but she’s already trying to downplay her early advantage.",2: "I’m frustrated by the lack of 8s and Dana’s blatant betrayal after she snubbed my brick trade for a secret deal with Alex. It seems those two are continuing to work together to dominate the game despite my warnings to the table."]
|
| 29 |
+
},
|
| 30 |
+
|
| 31 |
+
"memory": {
|
| 32 |
+
// דברים שאני רוצה לזכור להמשך
|
| 33 |
+
"notes_for_myself": [1 : "My plan is to trade Sheep for Wood with Red to build a settlement." , 2: "shani been an ashole to me"]
|
| 34 |
+
},
|
| 35 |
+
|
| 36 |
+
"constraints": {
|
| 37 |
+
"usage_instructions": "Choose one action type from the list below. Populate the 'parameters' field in your response strictly according to the 'example_parameters' structure provided.",
|
| 38 |
+
|
| 39 |
+
"allowed_actions": [
|
| 40 |
+
{
|
| 41 |
+
"type": "BUILD_ROAD",
|
| 42 |
+
"description": "Build a road on a specific edge ID.",
|
| 43 |
+
"example_parameters": { "edge_id": 12 }
|
| 44 |
+
},
|
| 45 |
+
{
|
| 46 |
+
"type": "BUILD_SETTLEMENT",
|
| 47 |
+
"description": "Build a settlement on a specific node ID.",
|
| 48 |
+
"example_parameters": { "node_id": 45 }
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"type": "BUILD_CITY",
|
| 52 |
+
"description": "Upgrade an existing settlement to a city.",
|
| 53 |
+
"example_parameters": { "node_id": 45 }
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"type": "OFFER_TRADE",
|
| 57 |
+
"description": "Propose a trade to all players or a specific one.",
|
| 58 |
+
"example_parameters": {
|
| 59 |
+
"give": {"wood": 1, "sheep": 1},
|
| 60 |
+
"receive": {"ore": 1},
|
| 61 |
+
"target_player_color": "Red" // Optional, remove key for public offer
|
| 62 |
+
}
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"type": "PLAY_DEV_CARD",
|
| 66 |
+
"description": "Play a development card. Specific params depend on the card.",
|
| 67 |
+
"example_parameters": [
|
| 68 |
+
{ "card": "KNIGHT", "robber_hex": 7, "target_victim": "Red" },
|
| 69 |
+
{ "card": "MONOPOLY", "resource": "sheep" },
|
| 70 |
+
{ "card": "YEAR_OF_PLENTY", "resources": ["wood", "brick"] },
|
| 71 |
+
{ "card": "ROAD_BUILDING", "edges": [12, 13] }
|
| 72 |
+
]
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"type": "WAIT_FOR_RESPONSE",
|
| 76 |
+
"description": "Do nothing on the board, just chat or wait.",
|
| 77 |
+
"example_parameters": {}
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"type": "END_TURN",
|
| 81 |
+
"description": "Pass the dice to the next player.",
|
| 82 |
+
"example_parameters": {}
|
| 83 |
+
}
|
| 84 |
+
]
|
| 85 |
+
}
|
| 86 |
+
}
|
pycatan/ai/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AI Agent Infrastructure for PyCatan
|
| 3 |
+
|
| 4 |
+
This package contains the infrastructure for building LLM-based AI agents
|
| 5 |
+
that can play Settlers of Catan autonomously.
|
| 6 |
+
|
| 7 |
+
Components:
|
| 8 |
+
- config: Configuration management for AI agents
|
| 9 |
+
- prompt_manager: Prompt construction and game state filtering
|
| 10 |
+
- response_parser: LLM response parsing and validation
|
| 11 |
+
- memory: Agent memory and learning systems
|
| 12 |
+
- llm_client: LLM API abstraction and client
|
| 13 |
+
|
| 14 |
+
Architecture Overview:
|
| 15 |
+
┌─────────────────────────────────────────────────────────┐
|
| 16 |
+
│ AIAgent │
|
| 17 |
+
│ (Main AI player implementation) │
|
| 18 |
+
├─────────────────────────────────────────────────────────┤
|
| 19 |
+
│ │
|
| 20 |
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
| 21 |
+
│ │ Config │ │ Prompt │ │ Response │ │
|
| 22 |
+
│ │ Management │ │ Manager │ │ Parser │ │
|
| 23 |
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
| 24 |
+
│ │
|
| 25 |
+
│ ┌──────────────┐ ┌──────────────┐ │
|
| 26 |
+
│ │ Memory │ │ LLM Client │ │
|
| 27 |
+
│ │ System │ │ (Multi-API) │ │
|
| 28 |
+
│ └──────────────┘ └──────────────┘ │
|
| 29 |
+
│ │
|
| 30 |
+
└─────────────────────────────────────────────────────────┘
|
| 31 |
+
"""
|
| 32 |
+
|
| 33 |
+
__version__ = "0.1.0"
|
| 34 |
+
__all__ = ["config"]
|
pycatan/ai/config.py
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Configuration Management for AI Agents
|
| 3 |
+
|
| 4 |
+
This module provides centralized configuration management for AI agents,
|
| 5 |
+
including LLM settings, API credentials, agent parameters, and performance settings.
|
| 6 |
+
|
| 7 |
+
Features:
|
| 8 |
+
- Load configuration from YAML files
|
| 9 |
+
- Environment variable support for sensitive data
|
| 10 |
+
- Configuration validation
|
| 11 |
+
- Default values with override capability
|
| 12 |
+
- Multiple LLM provider support
|
| 13 |
+
|
| 14 |
+
Usage:
|
| 15 |
+
from pycatan.ai.config import AIConfig
|
| 16 |
+
|
| 17 |
+
# Load from file
|
| 18 |
+
config = AIConfig.from_file('my_agent_config.yaml')
|
| 19 |
+
|
| 20 |
+
# Or create with defaults
|
| 21 |
+
config = AIConfig()
|
| 22 |
+
|
| 23 |
+
# Access settings
|
| 24 |
+
model = config.llm.model_name
|
| 25 |
+
temperature = config.llm.temperature
|
| 26 |
+
api_key = config.get_api_key()
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
import os
|
| 30 |
+
import yaml
|
| 31 |
+
from typing import Dict, Any, Optional
|
| 32 |
+
from dataclasses import dataclass, field, asdict
|
| 33 |
+
from pathlib import Path
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
@dataclass
|
| 37 |
+
class LLMConfig:
|
| 38 |
+
"""Configuration for LLM provider and model settings."""
|
| 39 |
+
|
| 40 |
+
# Provider settings
|
| 41 |
+
provider: str = "gemini" # "gemini", "openai", "anthropic", "azure"
|
| 42 |
+
model_name: str = "gemini-2.0-flash-exp"
|
| 43 |
+
|
| 44 |
+
# Generation parameters
|
| 45 |
+
temperature: float = 0.7
|
| 46 |
+
max_tokens: int = 4096
|
| 47 |
+
top_p: float = 0.95
|
| 48 |
+
top_k: int = 40
|
| 49 |
+
|
| 50 |
+
# API settings
|
| 51 |
+
api_key_env_var: str = "GEMINI_API_KEY" # Environment variable name
|
| 52 |
+
api_base_url: Optional[str] = None # For custom endpoints
|
| 53 |
+
|
| 54 |
+
# Performance
|
| 55 |
+
timeout_seconds: int = 30
|
| 56 |
+
max_retries: int = 3
|
| 57 |
+
retry_delay_seconds: float = 1.0
|
| 58 |
+
|
| 59 |
+
# Cost tracking
|
| 60 |
+
track_usage: bool = True
|
| 61 |
+
log_requests: bool = True
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@dataclass
|
| 65 |
+
class AgentConfig:
|
| 66 |
+
"""Configuration for agent personality and behavior."""
|
| 67 |
+
|
| 68 |
+
# Agent identity
|
| 69 |
+
personality: str = "balanced" # "aggressive", "defensive", "balanced", "trading"
|
| 70 |
+
risk_tolerance: float = 0.5 # 0.0 (conservative) to 1.0 (risky)
|
| 71 |
+
|
| 72 |
+
# Strategic preferences
|
| 73 |
+
focus_on_settlements: float = 0.6 # Relative priority
|
| 74 |
+
focus_on_cities: float = 0.7
|
| 75 |
+
focus_on_roads: float = 0.5
|
| 76 |
+
focus_on_dev_cards: float = 0.6
|
| 77 |
+
|
| 78 |
+
# Trading behavior
|
| 79 |
+
trade_willingness: float = 0.5 # 0.0 (never trades) to 1.0 (trades often)
|
| 80 |
+
trade_fairness: float = 0.7 # How fair are trade offers
|
| 81 |
+
|
| 82 |
+
# Social behavior
|
| 83 |
+
chat_frequency: float = 0.3 # How often to send chat messages
|
| 84 |
+
use_emojis: bool = True
|
| 85 |
+
chattiness: str = "medium" # "quiet", "medium", "chatty"
|
| 86 |
+
|
| 87 |
+
# Custom instructions
|
| 88 |
+
custom_instructions: Optional[str] = None # Additional instructions for this agent
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
@dataclass
|
| 92 |
+
class MemoryConfig:
|
| 93 |
+
"""Configuration for agent memory system."""
|
| 94 |
+
|
| 95 |
+
# Short-term memory
|
| 96 |
+
short_term_turns: int = 5 # Remember last N turns
|
| 97 |
+
|
| 98 |
+
# Chat history
|
| 99 |
+
chat_history_size: int = 10 # Keep last N messages
|
| 100 |
+
enable_chat_summarization: bool = True
|
| 101 |
+
chat_summary_threshold: int = 10 # Summarize when reaching N messages
|
| 102 |
+
|
| 103 |
+
# Summarization settings
|
| 104 |
+
summarization_provider: str = "gemini"
|
| 105 |
+
summarization_model: str = "gemini-2.0-flash-exp"
|
| 106 |
+
summarization_max_tokens: int = 500
|
| 107 |
+
|
| 108 |
+
# Memory persistence
|
| 109 |
+
save_memory_to_file: bool = True
|
| 110 |
+
memory_file_path: str = "agent_memory.json"
|
| 111 |
+
|
| 112 |
+
# Memory limits
|
| 113 |
+
max_strategic_notes: int = 20
|
| 114 |
+
max_observations: int = 50
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
@dataclass
|
| 118 |
+
class DebugConfig:
|
| 119 |
+
"""Configuration for debugging and logging."""
|
| 120 |
+
|
| 121 |
+
# Logging levels
|
| 122 |
+
debug_mode: bool = False
|
| 123 |
+
log_prompts: bool = True
|
| 124 |
+
log_responses: bool = True
|
| 125 |
+
log_decisions: bool = True
|
| 126 |
+
|
| 127 |
+
# Log file settings
|
| 128 |
+
log_to_file: bool = True
|
| 129 |
+
log_directory: str = "logs/ai_agents"
|
| 130 |
+
log_format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
| 131 |
+
|
| 132 |
+
# Performance monitoring
|
| 133 |
+
track_decision_time: bool = True
|
| 134 |
+
track_token_usage: bool = True
|
| 135 |
+
|
| 136 |
+
# Development helpers
|
| 137 |
+
save_game_states: bool = False # Save game states for analysis
|
| 138 |
+
game_states_directory: str = "logs/game_states"
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
@dataclass
|
| 142 |
+
class AIConfig:
|
| 143 |
+
"""
|
| 144 |
+
Main configuration class for AI agents.
|
| 145 |
+
|
| 146 |
+
This class aggregates all configuration sections and provides
|
| 147 |
+
methods for loading, saving, and accessing configuration values.
|
| 148 |
+
"""
|
| 149 |
+
|
| 150 |
+
llm: LLMConfig = field(default_factory=LLMConfig)
|
| 151 |
+
agent: AgentConfig = field(default_factory=AgentConfig)
|
| 152 |
+
memory: MemoryConfig = field(default_factory=MemoryConfig)
|
| 153 |
+
debug: DebugConfig = field(default_factory=DebugConfig)
|
| 154 |
+
|
| 155 |
+
# Metadata
|
| 156 |
+
config_version: str = "1.0"
|
| 157 |
+
agent_name: str = "AI Agent"
|
| 158 |
+
|
| 159 |
+
@classmethod
|
| 160 |
+
def from_file(cls, file_path: str) -> "AIConfig":
|
| 161 |
+
"""
|
| 162 |
+
Load configuration from a YAML file.
|
| 163 |
+
|
| 164 |
+
Args:
|
| 165 |
+
file_path: Path to the YAML configuration file
|
| 166 |
+
|
| 167 |
+
Returns:
|
| 168 |
+
AIConfig instance with loaded settings
|
| 169 |
+
|
| 170 |
+
Raises:
|
| 171 |
+
FileNotFoundError: If config file doesn't exist
|
| 172 |
+
yaml.YAMLError: If config file is invalid
|
| 173 |
+
"""
|
| 174 |
+
config_path = Path(file_path)
|
| 175 |
+
|
| 176 |
+
if not config_path.exists():
|
| 177 |
+
raise FileNotFoundError(f"Configuration file not found: {file_path}")
|
| 178 |
+
|
| 179 |
+
with open(config_path, 'r', encoding='utf-8') as f:
|
| 180 |
+
data = yaml.safe_load(f)
|
| 181 |
+
|
| 182 |
+
return cls.from_dict(data)
|
| 183 |
+
|
| 184 |
+
@classmethod
|
| 185 |
+
def from_dict(cls, data: Dict[str, Any]) -> "AIConfig":
|
| 186 |
+
"""
|
| 187 |
+
Create configuration from a dictionary.
|
| 188 |
+
|
| 189 |
+
Args:
|
| 190 |
+
data: Dictionary with configuration values
|
| 191 |
+
|
| 192 |
+
Returns:
|
| 193 |
+
AIConfig instance
|
| 194 |
+
"""
|
| 195 |
+
# Extract nested configs
|
| 196 |
+
llm_data = data.get('llm', {})
|
| 197 |
+
agent_data = data.get('agent', {})
|
| 198 |
+
memory_data = data.get('memory', {})
|
| 199 |
+
debug_data = data.get('debug', {})
|
| 200 |
+
|
| 201 |
+
return cls(
|
| 202 |
+
llm=LLMConfig(**llm_data),
|
| 203 |
+
agent=AgentConfig(**agent_data),
|
| 204 |
+
memory=MemoryConfig(**memory_data),
|
| 205 |
+
debug=DebugConfig(**debug_data),
|
| 206 |
+
config_version=data.get('config_version', '1.0'),
|
| 207 |
+
agent_name=data.get('agent_name', 'AI Agent')
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
def to_dict(self) -> Dict[str, Any]:
|
| 211 |
+
"""
|
| 212 |
+
Convert configuration to dictionary.
|
| 213 |
+
|
| 214 |
+
Returns:
|
| 215 |
+
Dictionary representation of configuration
|
| 216 |
+
"""
|
| 217 |
+
return {
|
| 218 |
+
'config_version': self.config_version,
|
| 219 |
+
'agent_name': self.agent_name,
|
| 220 |
+
'llm': asdict(self.llm),
|
| 221 |
+
'agent': asdict(self.agent),
|
| 222 |
+
'memory': asdict(self.memory),
|
| 223 |
+
'debug': asdict(self.debug)
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
def to_file(self, file_path: str):
|
| 227 |
+
"""
|
| 228 |
+
Save configuration to a YAML file.
|
| 229 |
+
|
| 230 |
+
Args:
|
| 231 |
+
file_path: Path where to save the configuration
|
| 232 |
+
"""
|
| 233 |
+
config_path = Path(file_path)
|
| 234 |
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
| 235 |
+
|
| 236 |
+
with open(config_path, 'w', encoding='utf-8') as f:
|
| 237 |
+
yaml.dump(self.to_dict(), f, default_flow_style=False, sort_keys=False)
|
| 238 |
+
|
| 239 |
+
def get_api_key(self, provider: Optional[str] = None) -> str:
|
| 240 |
+
"""
|
| 241 |
+
Get API key from environment variable.
|
| 242 |
+
|
| 243 |
+
Args:
|
| 244 |
+
provider: Provider name (uses llm.provider if None)
|
| 245 |
+
|
| 246 |
+
Returns:
|
| 247 |
+
API key string
|
| 248 |
+
|
| 249 |
+
Raises:
|
| 250 |
+
ValueError: If API key environment variable is not set
|
| 251 |
+
"""
|
| 252 |
+
if provider is None:
|
| 253 |
+
provider = self.llm.provider
|
| 254 |
+
|
| 255 |
+
# Determine environment variable name
|
| 256 |
+
if provider == "gemini":
|
| 257 |
+
env_var = self.llm.api_key_env_var or "GEMINI_API_KEY"
|
| 258 |
+
elif provider == "openai":
|
| 259 |
+
env_var = "OPENAI_API_KEY"
|
| 260 |
+
elif provider == "anthropic":
|
| 261 |
+
env_var = "ANTHROPIC_API_KEY"
|
| 262 |
+
elif provider == "azure":
|
| 263 |
+
env_var = "AZURE_OPENAI_KEY"
|
| 264 |
+
else:
|
| 265 |
+
env_var = self.llm.api_key_env_var or f"{provider.upper()}_API_KEY"
|
| 266 |
+
|
| 267 |
+
api_key = os.getenv(env_var)
|
| 268 |
+
|
| 269 |
+
if not api_key:
|
| 270 |
+
raise ValueError(
|
| 271 |
+
f"API key not found. Please set the {env_var} environment variable."
|
| 272 |
+
)
|
| 273 |
+
|
| 274 |
+
return api_key
|
| 275 |
+
|
| 276 |
+
def validate(self) -> bool:
|
| 277 |
+
"""
|
| 278 |
+
Validate configuration values.
|
| 279 |
+
|
| 280 |
+
Returns:
|
| 281 |
+
True if configuration is valid
|
| 282 |
+
|
| 283 |
+
Raises:
|
| 284 |
+
ValueError: If configuration contains invalid values
|
| 285 |
+
"""
|
| 286 |
+
# Validate temperature
|
| 287 |
+
if not 0.0 <= self.llm.temperature <= 2.0:
|
| 288 |
+
raise ValueError(f"Temperature must be between 0.0 and 2.0, got {self.llm.temperature}")
|
| 289 |
+
|
| 290 |
+
# Validate token limits
|
| 291 |
+
if self.llm.max_tokens < 100:
|
| 292 |
+
raise ValueError(f"max_tokens must be at least 100, got {self.llm.max_tokens}")
|
| 293 |
+
|
| 294 |
+
# Validate risk tolerance
|
| 295 |
+
if not 0.0 <= self.agent.risk_tolerance <= 1.0:
|
| 296 |
+
raise ValueError(f"risk_tolerance must be between 0.0 and 1.0, got {self.agent.risk_tolerance}")
|
| 297 |
+
|
| 298 |
+
# Validate timeouts
|
| 299 |
+
if self.llm.timeout_seconds < 1:
|
| 300 |
+
raise ValueError(f"timeout_seconds must be at least 1, got {self.llm.timeout_seconds}")
|
| 301 |
+
|
| 302 |
+
# Validate memory settings
|
| 303 |
+
if self.memory.short_term_turns < 1:
|
| 304 |
+
raise ValueError(f"short_term_turns must be at least 1, got {self.memory.short_term_turns}")
|
| 305 |
+
|
| 306 |
+
# Check API key is available (warning, not error)
|
| 307 |
+
try:
|
| 308 |
+
self.get_api_key()
|
| 309 |
+
except ValueError as e:
|
| 310 |
+
print(f"Warning: {e}")
|
| 311 |
+
|
| 312 |
+
return True
|
| 313 |
+
|
| 314 |
+
def __repr__(self) -> str:
|
| 315 |
+
"""String representation of configuration."""
|
| 316 |
+
return (
|
| 317 |
+
f"AIConfig(\n"
|
| 318 |
+
f" agent_name='{self.agent_name}',\n"
|
| 319 |
+
f" provider='{self.llm.provider}',\n"
|
| 320 |
+
f" model='{self.llm.model_name}',\n"
|
| 321 |
+
f" personality='{self.agent.personality}',\n"
|
| 322 |
+
f" debug={self.debug.debug_mode}\n"
|
| 323 |
+
f")"
|
| 324 |
+
)
|
| 325 |
+
|
| 326 |
+
|
| 327 |
+
# Convenience function for quick config loading
|
| 328 |
+
def load_config(file_path: Optional[str] = None) -> AIConfig:
|
| 329 |
+
"""
|
| 330 |
+
Load AI configuration from file or create default.
|
| 331 |
+
|
| 332 |
+
Args:
|
| 333 |
+
file_path: Path to config file (optional)
|
| 334 |
+
|
| 335 |
+
Returns:
|
| 336 |
+
AIConfig instance
|
| 337 |
+
"""
|
| 338 |
+
if file_path and Path(file_path).exists():
|
| 339 |
+
return AIConfig.from_file(file_path)
|
| 340 |
+
else:
|
| 341 |
+
return AIConfig()
|
pycatan/ai/config_example.yaml
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ============================================================================
|
| 2 |
+
# AI Agent Configuration Example
|
| 3 |
+
# ============================================================================
|
| 4 |
+
# This is an example configuration file for PyCatan AI agents.
|
| 5 |
+
# Copy this file and customize it for your agent.
|
| 6 |
+
#
|
| 7 |
+
# Usage:
|
| 8 |
+
# from pycatan.ai.config import AIConfig
|
| 9 |
+
# config = AIConfig.from_file('my_agent_config.yaml')
|
| 10 |
+
# ============================================================================
|
| 11 |
+
|
| 12 |
+
config_version: "1.0"
|
| 13 |
+
agent_name: "AI Agent" # Name of your agent
|
| 14 |
+
|
| 15 |
+
# ============================================================================
|
| 16 |
+
# LLM Configuration
|
| 17 |
+
# ============================================================================
|
| 18 |
+
llm:
|
| 19 |
+
# Provider selection
|
| 20 |
+
# Options: "gemini", "openai", "anthropic", "azure"
|
| 21 |
+
provider: "gemini"
|
| 22 |
+
|
| 23 |
+
# Model name
|
| 24 |
+
# Gemini: "gemini-2.0-flash-exp", "gemini-1.5-pro", "gemini-1.5-flash"
|
| 25 |
+
# OpenAI: "gpt-4-turbo-preview", "gpt-4", "gpt-3.5-turbo"
|
| 26 |
+
# Anthropic: "claude-3-opus-20240229", "claude-3-sonnet-20240229"
|
| 27 |
+
model_name: "gemini-2.0-flash-exp"
|
| 28 |
+
|
| 29 |
+
# Generation parameters
|
| 30 |
+
temperature: 0.7 # 0.0 (deterministic) to 2.0 (creative)
|
| 31 |
+
max_tokens: 4096 # Maximum tokens in response
|
| 32 |
+
top_p: 0.95 # Nucleus sampling threshold
|
| 33 |
+
top_k: 40 # Top-k sampling (for supported models)
|
| 34 |
+
|
| 35 |
+
# API settings
|
| 36 |
+
# The API key is read from environment variables for security
|
| 37 |
+
# Set GEMINI_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY
|
| 38 |
+
api_key_env_var: "GEMINI_API_KEY"
|
| 39 |
+
api_base_url: null # Custom endpoint (if needed)
|
| 40 |
+
|
| 41 |
+
# Performance settings
|
| 42 |
+
timeout_seconds: 30 # Request timeout
|
| 43 |
+
max_retries: 3 # Number of retry attempts
|
| 44 |
+
retry_delay_seconds: 1.0 # Delay between retries
|
| 45 |
+
|
| 46 |
+
# Tracking
|
| 47 |
+
track_usage: true # Track token usage and costs
|
| 48 |
+
log_requests: true # Log all API requests
|
| 49 |
+
|
| 50 |
+
# ============================================================================
|
| 51 |
+
# Agent Configuration
|
| 52 |
+
# ============================================================================
|
| 53 |
+
agent:
|
| 54 |
+
# Personality types affect decision-making style
|
| 55 |
+
# Options: "aggressive", "defensive", "balanced", "trading"
|
| 56 |
+
personality: "balanced"
|
| 57 |
+
|
| 58 |
+
# Risk tolerance: 0.0 (conservative) to 1.0 (risky)
|
| 59 |
+
risk_tolerance: 0.5
|
| 60 |
+
|
| 61 |
+
# Strategic priorities (0.0 to 1.0)
|
| 62 |
+
# Higher values mean higher priority
|
| 63 |
+
focus_on_settlements: 0.6
|
| 64 |
+
focus_on_cities: 0.7
|
| 65 |
+
focus_on_roads: 0.5
|
| 66 |
+
focus_on_dev_cards: 0.6
|
| 67 |
+
|
| 68 |
+
# Trading behavior
|
| 69 |
+
trade_willingness: 0.5 # 0.0 (never) to 1.0 (always)
|
| 70 |
+
trade_fairness: 0.7 # How fair are trade offers
|
| 71 |
+
|
| 72 |
+
# Social behavior
|
| 73 |
+
chat_frequency: 0.3 # How often to chat (0.0 to 1.0)
|
| 74 |
+
use_emojis: true # Use emojis in chat
|
| 75 |
+
chattiness: "medium" # Options: "quiet", "medium", "chatty"
|
| 76 |
+
|
| 77 |
+
# Custom instructions (optional)
|
| 78 |
+
# Add any additional instructions for this specific agent
|
| 79 |
+
custom_instructions: null
|
| 80 |
+
# Example:
|
| 81 |
+
# custom_instructions: "Focus on building settlements near wheat and ore tiles."
|
| 82 |
+
|
| 83 |
+
# ============================================================================
|
| 84 |
+
# Memory Configuration
|
| 85 |
+
# ============================================================================
|
| 86 |
+
memory:
|
| 87 |
+
# Short-term memory
|
| 88 |
+
short_term_turns: 5 # Remember last N turns
|
| 89 |
+
|
| 90 |
+
# Chat history management
|
| 91 |
+
chat_history_size: 10 # Keep last N messages
|
| 92 |
+
enable_chat_summarization: true # Auto-summarize old chats
|
| 93 |
+
chat_summary_threshold: 10 # Summarize after N messages
|
| 94 |
+
|
| 95 |
+
# Summarization settings
|
| 96 |
+
# Use a smaller/cheaper model for summarization
|
| 97 |
+
summarization_provider: "gemini"
|
| 98 |
+
summarization_model: "gemini-2.0-flash-exp"
|
| 99 |
+
summarization_max_tokens: 500
|
| 100 |
+
|
| 101 |
+
# Memory persistence
|
| 102 |
+
save_memory_to_file: true
|
| 103 |
+
memory_file_path: "agent_memory.json"
|
| 104 |
+
|
| 105 |
+
# Memory limits
|
| 106 |
+
max_strategic_notes: 20 # Maximum strategic notes to keep
|
| 107 |
+
max_observations: 50 # Maximum observations to keep
|
| 108 |
+
|
| 109 |
+
# ============================================================================
|
| 110 |
+
# Debug Configuration
|
| 111 |
+
# ============================================================================
|
| 112 |
+
debug:
|
| 113 |
+
# Debug mode - shows detailed information
|
| 114 |
+
debug_mode: false
|
| 115 |
+
|
| 116 |
+
# Logging options
|
| 117 |
+
log_prompts: true # Log prompts sent to LLM
|
| 118 |
+
log_responses: true # Log LLM responses
|
| 119 |
+
log_decisions: true # Log decision-making process
|
| 120 |
+
|
| 121 |
+
# Log file settings
|
| 122 |
+
log_to_file: true
|
| 123 |
+
log_directory: "logs/ai_agents"
|
| 124 |
+
log_format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
| 125 |
+
|
| 126 |
+
# Performance tracking
|
| 127 |
+
track_decision_time: true # Track how long decisions take
|
| 128 |
+
track_token_usage: true # Track token consumption
|
| 129 |
+
|
| 130 |
+
# Development helpers
|
| 131 |
+
save_game_states: false # Save game states for analysis
|
| 132 |
+
game_states_directory: "logs/game_states"
|
| 133 |
+
|
| 134 |
+
# ============================================================================
|
| 135 |
+
# Example Configurations for Different Personalities
|
| 136 |
+
# ============================================================================
|
| 137 |
+
#
|
| 138 |
+
# AGGRESSIVE TRADER:
|
| 139 |
+
# ------------------
|
| 140 |
+
# agent:
|
| 141 |
+
# personality: "trading"
|
| 142 |
+
# risk_tolerance: 0.8
|
| 143 |
+
# trade_willingness: 0.9
|
| 144 |
+
# focus_on_settlements: 0.8
|
| 145 |
+
# chat_frequency: 0.6
|
| 146 |
+
#
|
| 147 |
+
# DEFENSIVE BUILDER:
|
| 148 |
+
# ------------------
|
| 149 |
+
# agent:
|
| 150 |
+
# personality: "defensive"
|
| 151 |
+
# risk_tolerance: 0.3
|
| 152 |
+
# trade_willingness: 0.3
|
| 153 |
+
# focus_on_cities: 0.9
|
| 154 |
+
# focus_on_roads: 0.7
|
| 155 |
+
#
|
| 156 |
+
# DEVELOPMENT CARD SPECIALIST:
|
| 157 |
+
# ----------------------------
|
| 158 |
+
# agent:
|
| 159 |
+
# personality: "balanced"
|
| 160 |
+
# risk_tolerance: 0.6
|
| 161 |
+
# focus_on_dev_cards: 0.9
|
| 162 |
+
# trade_willingness: 0.6
|
| 163 |
+
#
|
| 164 |
+
# ============================================================================
|