1- # src/agents/LLM_agent.py
1+ """
2+ LLM Agent Implementation for Market Simulation
3+
4+ This module provides the LLMAgent class that interfaces with Mistral API
5+ for strategic pricing decisions in oligopoly market experiments.
6+ """
7+
28import json
39import logging
410import asyncio
1420
1521
1622class LLMAgent (Agent ):
23+ """
24+ LLM-based agent for strategic pricing decisions in oligopoly markets.
25+
26+ This agent uses Mistral API to make pricing decisions based on market history
27+ and strategic context. It maintains a rolling memory window and validates
28+ responses using Pydantic models.
29+
30+ Args:
31+ name: Unique identifier for the agent
32+ prefix: Prompt prefix defining agent's strategic context
33+ api_key: Mistral API key for authentication
34+ model_name: Mistral model to use (e.g., 'mistral-large-2411')
35+ response_model: Pydantic model for response validation
36+ prompt_template: Optional template for prompt formatting
37+ memory_length: Number of periods to maintain in memory (default: 100)
38+ env_params: Market environment parameters
39+ logger: Logger instance for experiment tracking
40+ """
41+
1742 def __init__ (
1843 self ,
1944 name : str ,
@@ -54,6 +79,22 @@ def __init__(
5479 )
5580
5681 async def act (self , prompt : str ) -> Dict :
82+ """
83+ Execute pricing decision using LLM API.
84+
85+ Makes API call to Mistral with retry logic and validates response
86+ using the configured Pydantic model.
87+
88+ Args:
89+ prompt: Market context and decision prompt
90+
91+ Returns:
92+ Dict containing agent name and validated response content
93+
94+ Raises:
95+ ValidationError: If response validation fails after all retries
96+ Exception: If API call fails after all retries
97+ """
5798 async with Mistral (api_key = self .api_key ) as client :
5899 for attempt in range (1 , MAX_RETRIES + 1 ):
59100 self .logger .info (f"🔄 Attempt { attempt } for agent { self .name } " )
@@ -90,6 +131,18 @@ async def act(self, prompt: str) -> Dict:
90131 await asyncio .sleep (RETRY_DELAY_SECONDS * attempt )
91132
92133 def __filter_in_answer_fields (self , model : Type [BaseModel ]) -> Type [BaseModel ]:
134+ """
135+ Filter Pydantic model fields marked for inclusion in responses.
136+
137+ Creates a new model containing only fields with 'in_answer=True'
138+ in their json_schema_extra metadata.
139+
140+ Args:
141+ model: Source Pydantic model to filter
142+
143+ Returns:
144+ New Pydantic model with only filtered fields
145+ """
93146 # Filter the fields that have 'in_answer=True'
94147 in_answer_fields = {
95148 name : (field .annotation , field .default )
@@ -100,5 +153,6 @@ def __filter_in_answer_fields(self, model: Type[BaseModel]) -> Type[BaseModel]:
100153 return create_model (model .__name__ + "Filtered" , ** in_answer_fields )
101154
102155 @property
103- def type (self ) -> bool :
156+ def type (self ) -> str :
157+ """Return agent type identifier."""
104158 return "LLM_agent"
0 commit comments