Spaces:
Running
Running
File size: 6,771 Bytes
cab4c60 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | # agent.py
import os
from typing import List, Dict, Optional
from openai import OpenAI
from strategy import StrategyFactory, ExecutionStrategy
from persistence import AgentPersistence
from datetime import datetime
class Agent:
def __init__(self, name: str, persistence: Optional[AgentPersistence] = None):
"""
Initialize an agent with a name and optional persistence manager.
If no persistence manager is provided, a default one will be created.
"""
self._name = name
self._persona = ""
self._instruction = ""
self._task = ""
self._api_key = os.getenv('OPENAI_API_KEY', '')
self._model = "gpt-4o-mini"
self._history: List[Dict[str, str]] = []
self._strategy: Optional[ExecutionStrategy] = None
self._persistence = persistence or AgentPersistence()
# Try to load existing state
self._persistence.load_agent_state(self)
@property
def name(self) -> str:
"""Get the agent's name."""
return self._name
@property
def persona(self) -> str:
"""Get the agent's persona."""
return self._persona
@persona.setter
def persona(self, value: str):
"""Set the agent's persona."""
self._persona = value
@property
def instruction(self) -> str:
"""Get the agent's global instruction."""
return self._instruction
@instruction.setter
def instruction(self, value: str):
"""Set the agent's global instruction."""
self._instruction = value
@property
def task(self) -> str:
"""Get the current task."""
return self._task
@task.setter
def task(self, value: str):
"""Set the current task."""
self._task = value
@property
def strategy(self) -> Optional[ExecutionStrategy]:
"""Get the current execution strategy."""
return self._strategy
@strategy.setter
def strategy(self, strategy_name: str):
"""Set the execution strategy by name."""
self._strategy = StrategyFactory.create_strategy(strategy_name)
@property
def history(self) -> List[Dict[str, str]]:
"""Get the conversation history."""
return self._history
def get_history_states(self, limit: int = 10) -> List[Dict]:
"""
Retrieve the last N states with their timestamps.
"""
return self._persistence.get_agent_history(self.name, limit)
def _build_messages(self, task: Optional[str] = None) -> List[Dict[str, str]]:
"""Build the messages list including persona, instruction, and history."""
messages = [{"role": "system", "content": self.persona}]
if self.instruction:
messages.append({
"role": "user",
"content": f"Global Instruction: {self.instruction}"
})
# Add conversation history
messages.extend(self._history)
# Use provided task or stored task
current_task = task if task is not None else self._task
# Apply strategy if set
if self._strategy and current_task:
current_task = self._strategy.build_prompt(current_task, self.instruction)
# Add the current task if it exists
if current_task:
messages.append({"role": "user", "content": current_task})
return messages
def execute(self, task: Optional[str] = None) -> str:
"""Execute a task using the configured LLM."""
if task is not None:
self._task = task
if not self._api_key:
return "API key not found. Please set the OPENAI_API_KEY environment variable."
if not self._task:
return "No task specified. Please provide a task to execute."
client = OpenAI(api_key=self._api_key)
messages = self._build_messages()
try:
response = client.chat.completions.create(
model=self._model,
messages=messages
)
response_content = response.choices[0].message.content
# Process response through strategy if set
if self._strategy:
response_content = self._strategy.process_response(response_content)
# Store the interaction in history
self._history.append({"role": "user", "content": self._task})
self._history.append({
"role": "assistant",
"content": response_content
})
# Save state after successful execution
self.save_state()
# Clear the task after execution
self._task = ""
return response_content
except Exception as e:
return f"An error occurred: {str(e)}"
def save_state(self) -> bool:
"""Save the current state of the agent."""
return self._persistence.save_agent_state(self)
def load_state(self, agent_name: Optional[str] = None) -> bool:
"""Load a saved state into the agent."""
return self._persistence.load_agent_state(self, agent_name)
def clear_history(self, keep_last: int = 0):
"""
Clear the conversation history, optionally keeping the last N states.
If keep_last > 0, it will clean up old states but retain the specified number.
If keep_last = 0, it clears all history.
"""
if keep_last > 0:
self._persistence.cleanup_old_states(self.name, keep_last)
# Reload the state to get the kept history
self.load_state()
else:
self._history = []
self.save_state()
def pause(self) -> bool:
"""Pause the agent by saving its current state."""
return self.save_state()
def resume(self, agent_name: Optional[str] = None) -> bool:
"""Resume the agent by loading its saved state."""
return self.load_state(agent_name)
def available_strategies(self) -> List[str]:
"""Return a list of available strategy names."""
return StrategyFactory.available_strategies()
def delete_agent(self) -> bool:
"""Delete all data for this agent from the database."""
return self._persistence.delete_agent_state(self.name)
@staticmethod
def list_saved_agents() -> Dict[str, datetime]:
"""
List all saved agents and their last update times.
Returns a dictionary of agent names mapped to their last update timestamps.
"""
persistence = AgentPersistence()
return persistence.list_saved_agents() |