Skip to content

Commit 4a4921f

Browse files
committed
2 parents 0adf974 + 580b883 commit 4a4921f

File tree

3 files changed

+657
-32
lines changed

3 files changed

+657
-32
lines changed

agents/conversation_memory.py

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
# agents/conversation_memory.py
2+
from .base import BaseAgent
3+
import json
4+
import os
5+
import time
6+
from datetime import datetime
7+
import re
8+
from collections import defaultdict
9+
10+
class ConversationMemoryAgent(BaseAgent):
11+
"""Agent responsible for maintaining conversation context and user preferences."""
12+
13+
def __init__(self, memory_file="conversation_memory.json"):
14+
"""Initialize the conversation memory agent."""
15+
self.memory_file = memory_file
16+
self.current_session_id = None
17+
self.session_memory = {}
18+
self.global_memory = self._load_memory()
19+
self.conversation_state = "greeting" # greeting, exploration, learning, wrap-up
20+
self.rapport_level = 0 # 0-10 scale of relationship development
21+
22+
def _load_memory(self):
23+
"""Load memory from file if available."""
24+
if os.path.exists(self.memory_file):
25+
try:
26+
with open(self.memory_file, 'r') as f:
27+
return json.load(f)
28+
except Exception as e:
29+
print(f"Error loading conversation memory: {e}")
30+
return {
31+
"global_topics": {},
32+
"session_history": {},
33+
"user_preferences": {
34+
"explanation_style": "balanced", # detailed, balanced, concise
35+
"interests": [],
36+
"difficulty_level": "medium", # basic, medium, advanced
37+
"previously_understood_concepts": []
38+
}
39+
}
40+
41+
def _save_memory(self):
42+
"""Save memory to file."""
43+
try:
44+
with open(self.memory_file, 'w') as f:
45+
json.dump(self.global_memory, f, indent=2)
46+
except Exception as e:
47+
print(f"Error saving conversation memory: {e}")
48+
49+
def start_new_session(self, session_id=None):
50+
"""Start a new conversation session."""
51+
if not session_id:
52+
session_id = f"session_{int(time.time())}"
53+
54+
self.current_session_id = session_id
55+
self.conversation_state = "greeting"
56+
self.rapport_level = 0
57+
58+
# Initialize session memory
59+
self.session_memory = {
60+
"messages": [],
61+
"topics_discussed": [],
62+
"concepts_explained": [],
63+
"user_questions": [],
64+
"session_start": datetime.now().isoformat(),
65+
"interaction_count": 0
66+
}
67+
68+
# Add to global memory
69+
if session_id not in self.global_memory["session_history"]:
70+
self.global_memory["session_history"][session_id] = {
71+
"start_time": datetime.now().isoformat(),
72+
"topics": [],
73+
"summary": ""
74+
}
75+
76+
return session_id
77+
78+
def add_message(self, sender, message, metadata=None):
79+
"""Add a message to the current conversation history."""
80+
if not self.current_session_id:
81+
self.start_new_session()
82+
83+
if not metadata:
84+
metadata = {}
85+
86+
# Add message to session memory
87+
message_entry = {
88+
"sender": sender,
89+
"message": message,
90+
"timestamp": datetime.now().isoformat(),
91+
"metadata": metadata
92+
}
93+
94+
self.session_memory["messages"].append(message_entry)
95+
self.session_memory["interaction_count"] += 1
96+
97+
# Update conversation state
98+
if len(self.session_memory["messages"]) <= 2:
99+
self.conversation_state = "greeting"
100+
elif len(self.session_memory["messages"]) >= 8:
101+
self.conversation_state = "learning"
102+
else:
103+
self.conversation_state = "exploration"
104+
105+
# Update rapport level based on interaction count
106+
if self.rapport_level < 10:
107+
self.rapport_level = min(10, self.session_memory["interaction_count"] // 2)
108+
109+
# Analyze user messages for topics and concepts
110+
if sender == "user":
111+
# Extract topics from user message
112+
self._extract_topics(message)
113+
114+
# Track as a question for follow-up management
115+
if self._is_question(message):
116+
self.session_memory["user_questions"].append({
117+
"question": message,
118+
"timestamp": datetime.now().isoformat()
119+
})
120+
121+
# Save after updates
122+
self._save_memory()
123+
124+
return self.conversation_state
125+
126+
def _extract_topics(self, message):
127+
"""Extract potential historical topics from a message."""
128+
# Simple topic extraction using keywords
129+
historical_topics = [
130+
"industrial revolution", "world war", "cold war", "civil war",
131+
"french revolution", "american revolution", "sri lanka", "colonization",
132+
"independence", "monarchy", "democracy", "empire", "ancient", "medieval",
133+
"renaissance", "enlightenment", "modern history", "war", "treaty",
134+
"civilization", "culture", "economy", "politics", "society"
135+
]
136+
137+
found_topics = []
138+
message_lower = message.lower()
139+
140+
for topic in historical_topics:
141+
if topic in message_lower:
142+
found_topics.append(topic)
143+
144+
# Add to global topics tracking
145+
if topic not in self.global_memory["global_topics"]:
146+
self.global_memory["global_topics"][topic] = 0
147+
self.global_memory["global_topics"][topic] += 1
148+
149+
if found_topics:
150+
self.session_memory["topics_discussed"].extend(found_topics)
151+
# Remove duplicates
152+
self.session_memory["topics_discussed"] = list(set(self.session_memory["topics_discussed"]))
153+
154+
def _is_question(self, message):
155+
"""Determine if a message is likely a question."""
156+
# Check for question marks
157+
if "?" in message:
158+
return True
159+
160+
# Check for question words
161+
question_starters = ["what", "why", "how", "when", "where", "who", "which", "can", "do", "did", "is", "are", "was", "were"]
162+
message_words = message.lower().split()
163+
if message_words and message_words[0] in question_starters:
164+
return True
165+
166+
return False
167+
168+
def record_explained_concept(self, concept):
169+
"""Record that a concept has been explained to the user."""
170+
if not self.current_session_id:
171+
return
172+
173+
if concept not in self.session_memory["concepts_explained"]:
174+
self.session_memory["concepts_explained"].append(concept)
175+
176+
# Add to global user preferences
177+
if concept not in self.global_memory["user_preferences"]["previously_understood_concepts"]:
178+
self.global_memory["user_preferences"]["previously_understood_concepts"].append(concept)
179+
180+
self._save_memory()
181+
182+
def has_concept_been_explained(self, concept):
183+
"""Check if a concept has already been explained in this session or before."""
184+
if not self.current_session_id:
185+
return False
186+
187+
# Check current session
188+
if concept in self.session_memory["concepts_explained"]:
189+
return True
190+
191+
# Check global memory
192+
return concept in self.global_memory["user_preferences"]["previously_understood_concepts"]
193+
194+
def update_user_preference(self, preference_type, value):
195+
"""Update a user preference."""
196+
if preference_type in self.global_memory["user_preferences"]:
197+
if isinstance(self.global_memory["user_preferences"][preference_type], list):
198+
if value not in self.global_memory["user_preferences"][preference_type]:
199+
self.global_memory["user_preferences"][preference_type].append(value)
200+
else:
201+
self.global_memory["user_preferences"][preference_type] = value
202+
203+
self._save_memory()
204+
205+
def get_recurring_topics(self):
206+
"""Get topics the user seems most interested in based on frequency."""
207+
if not self.global_memory["global_topics"]:
208+
return []
209+
210+
# Sort topics by frequency
211+
sorted_topics = sorted(
212+
self.global_memory["global_topics"].items(),
213+
key=lambda x: x[1],
214+
reverse=True
215+
)
216+
217+
return [topic for topic, count in sorted_topics if count > 1][:5]
218+
219+
def get_recent_questions(self, count=3):
220+
"""Get the most recent user questions."""
221+
if not self.current_session_id:
222+
return []
223+
224+
questions = self.session_memory.get("user_questions", [])
225+
return [q["question"] for q in questions[-count:]]
226+
227+
def generate_personalized_context(self):
228+
"""Generate conversation context for personalization."""
229+
context = {
230+
"conversation_state": self.conversation_state,
231+
"rapport_level": self.rapport_level,
232+
"topics_of_interest": self.get_recurring_topics(),
233+
"recent_questions": self.get_recent_questions(),
234+
"concepts_already_explained": self.session_memory.get("concepts_explained", []),
235+
"user_preferences": self.global_memory["user_preferences"],
236+
"interaction_count": self.session_memory.get("interaction_count", 0)
237+
}
238+
239+
return context
240+
241+
def get_chat_history(self, max_messages=10):
242+
"""Get recent chat history."""
243+
if not self.current_session_id or not self.session_memory.get("messages"):
244+
return []
245+
246+
return self.session_memory["messages"][-max_messages:]
247+
248+
def reset(self):
249+
"""Reset the current session memory."""
250+
self.current_session_id = None
251+
self.session_memory = {}
252+
self.conversation_state = "greeting"
253+
self.rapport_level = 0
254+
255+
def run(self, action="update", **kwargs):
256+
"""Run the agent with specified action and parameters."""
257+
if action == "start_session":
258+
session_id = kwargs.get("session_id")
259+
return self.start_new_session(session_id)
260+
elif action == "add_message":
261+
sender = kwargs.get("sender")
262+
message = kwargs.get("message")
263+
metadata = kwargs.get("metadata")
264+
return self.add_message(sender, message, metadata)
265+
elif action == "get_context":
266+
return self.generate_personalized_context()
267+
elif action == "get_history":
268+
max_messages = kwargs.get("max_messages", 10)
269+
return self.get_chat_history(max_messages)
270+
elif action == "record_concept":
271+
concept = kwargs.get("concept")
272+
return self.record_explained_concept(concept)
273+
elif action == "update_preference":
274+
preference_type = kwargs.get("preference_type")
275+
value = kwargs.get("value")
276+
return self.update_user_preference(preference_type, value)
277+
else:
278+
return {"error": "Unknown action"}

0 commit comments

Comments
 (0)