Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from agno.memory.db.sqlite import SqliteMemoryDb
from agno.memory.memory import Memory
from agno.models.anthropic.claude import Claude
from agno.session.summarizer import SessionSummarizer
from agno.session.summary import SessionSummarizer
from rich.pretty import pprint

memory_db = SqliteMemoryDb(table_name="memory", db_file="tmp/memory.db")
Expand Down
1 change: 0 additions & 1 deletion cookbook/agent_concepts/memory/v2/chat_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
session_id="chat_history",
instructions="You are a helpful assistant that can answer questions about space and oceans.",
add_history_to_messages=True,
store_chat_history=True,
)

agent.print_response("Tell me a new interesting fact about space")
Expand Down
106 changes: 50 additions & 56 deletions libs/agno/agno/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ class Agent:
add_memory_references: Optional[bool] = None
# Extra data stored with this agent
extra_data: Optional[Dict[str, Any]] = None
# If True, stores the flat list of messages in the chat_history field of the session
store_chat_history: bool = False

# --- Agent History ---
# add_history_to_messages=true adds messages from the chat history to the messages list sent to the Model.
Expand Down Expand Up @@ -351,7 +349,6 @@ def __init__(
retriever: Optional[Callable[..., Optional[List[Union[Dict, str]]]]] = None,
references_format: Literal["json", "yaml"] = "json",
extra_data: Optional[Dict[str, Any]] = None,
store_chat_history: bool = False,
tools: Optional[List[Union[Toolkit, Callable, Function, Dict]]] = None,
show_tool_calls: bool = True,
tool_call_limit: Optional[int] = None,
Expand Down Expand Up @@ -429,7 +426,6 @@ def __init__(

self.add_history_to_messages = add_history_to_messages
self.num_history_runs = num_history_runs
self.store_chat_history = store_chat_history

self.knowledge = knowledge
self.knowledge_filters = knowledge_filters
Expand Down Expand Up @@ -567,6 +563,13 @@ def set_default_model(self) -> None:
log_info("Setting default model to OpenAI Chat")
self.model = OpenAIChat(id="gpt-4o")

def set_memory(self) -> None:
if self.memory is None:
self.memory = Memory()
Comment on lines +567 to +568
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would this still be needed? Before this was the only source of runs, so it was needed, but now I don't think it is needed by default?


if (self.enable_agentic_memory or self.enable_user_memories) and self.memory.model is None:
self.memory.set_model(self.model)

def set_defaults(self) -> None:
if self.add_memory_references is None:
self.add_memory_references = self.enable_user_memories or self.enable_agentic_memory
Expand Down Expand Up @@ -596,17 +599,10 @@ def initialize_agent(self) -> None:
self.set_default_model()
self.set_debug()
self.set_agent_id()
self.set_memory()

log_debug(f"Agent ID: {self.agent_id}", center=True)

if self.memory is None:
self.memory = Memory()

# Default to the agent's model if no model is provided
if isinstance(self.memory, Memory):
if self.memory.model is None and self.model is not None:
self.memory.set_model(self.model)

if self._formatter is None:
self._formatter = SafeFormatter()

Expand Down Expand Up @@ -643,11 +639,12 @@ def _run(
Steps:
1. Reason about the task if reasoning is enabled
2. Generate a response from the Model (includes running function calls)
3. Add the run to memory
4. Update Agent Memory
5. Calculate session metrics
6. Save session to storage
7. Save output to file if save_response_to_file is set
3. Update the RunResponse with the model response
4. Add RunResponse to Agent Session
5. Update Agent Memory
6. Calculate session metrics
7. Save session to storage
8. Optional: Save output to file if save_response_to_file is set
"""
log_debug(f"Agent Run Start: {run_response.run_id}", center=True)

Expand All @@ -668,9 +665,10 @@ def _run(
# If a parser model is provided, structure the response separately
self._parse_response_with_parser_model(model_response, run_messages)

# 3. Update the RunResponse with the model response
self._update_run_response(model_response=model_response, run_response=run_response, run_messages=run_messages)

# 3. Add the RunResponse to Agent Session
# 4. Add the RunResponse to Agent Session
self.add_run_to_session(
run_response=run_response,
)
Expand All @@ -681,7 +679,7 @@ def _run(
run_response=run_response, run_messages=run_messages, session_id=session_id, user_id=user_id
)

# 4. Update Agent Memory
# 5. Update Agent Memory
response_iterator = self.update_memory(
run_messages=run_messages,
session_id=session_id,
Expand All @@ -690,18 +688,18 @@ def _run(
# Consume the response iterator to ensure the memory is updated before the run is completed
deque(response_iterator, maxlen=0)

# 5. Calculate session metrics
# 6. Calculate session metrics
self.set_session_metrics(run_messages)

self.run_response.status = RunStatus.completed

# Convert the response to the structured format if needed
self._convert_response_to_structured_format(run_response)

# 6. Save session to memory
# 7. Save session to memory
self.save_session(user_id=user_id, session_id=session_id)

# 7. Save output to file if save_response_to_file is set
# 8. Optional: Save output to file if save_response_to_file is set
self.save_run_response_to_file(message=run_messages.user_message, session_id=session_id)

# Log Agent Run
Expand All @@ -725,11 +723,11 @@ def _run_stream(
Steps:
1. Reason about the task if reasoning is enabled
2. Generate a response from the Model (includes running function calls)
3. Add the run to memory
3. Add the RunResponse to the Agent Session
4. Update Agent Memory
5. Calculate session metrics
6. Save output to file if save_response_to_file is set
7. Save session to storage
6. Save session to storage
7. Optional: Save output to file if save_response_to_file is set
"""
log_debug(f"Agent Run Start: {run_response.run_id}", center=True)

Expand All @@ -754,7 +752,7 @@ def _run_stream(
run_response=run_response, stream_intermediate_steps=stream_intermediate_steps
)

# 3. Add the run to memory
# 3. Add RunResponse to Agent Session
self.add_run_to_session(
run_response=run_response,
)
Expand Down Expand Up @@ -784,7 +782,7 @@ def _run_stream(
# 6. Save session to storage
self.save_session(user_id=user_id, session_id=session_id)

# 6. Save output to file if save_response_to_file is set
# 7. Optional: Save output to file if save_response_to_file is set
self.save_run_response_to_file(message=run_messages.user_message, session_id=session_id)

log_debug(f"Agent Run End: {run_response.run_id}", center=True, symbol="*")
Expand Down Expand Up @@ -1060,11 +1058,12 @@ async def _arun(
Steps:
1. Reason about the task if reasoning is enabled
2. Generate a response from the Model (includes running function calls)
3. Add the run to memory
4. Update Agent Memory
5. Calculate session metrics
6. Save session to storage
7. Save output to file if save_response_to_file is set
3. Update the RunResponse with the model response
4. Add RunResponse to Agent Session
5. Update Agent Memory
6. Calculate session metrics
7. Save session to storage
8. Optional: Save output to file if save_response_to_file is set
"""
log_debug(f"Agent Run Start: {run_response.run_id}", center=True)

Expand All @@ -1085,9 +1084,10 @@ async def _arun(
# If a parser model is provided, structure the response separately
await self._aparse_response_with_parser_model(model_response=model_response, run_messages=run_messages)

# 3. Update the RunResponse with the model response
self._update_run_response(model_response=model_response, run_response=run_response, run_messages=run_messages)

# 3. Add the run to memory
# 4. Add RunResponse to Agent Session
self.add_run_to_session(
run_response=run_response,
)
Expand All @@ -1098,26 +1098,26 @@ async def _arun(
run_response=run_response, run_messages=run_messages, session_id=session_id, user_id=user_id
)

# 4. Update Agent Memory
# 5. Update Agent Memory
async for _ in self._aupdate_memory(
run_messages=run_messages,
session_id=session_id,
user_id=user_id,
):
pass

# 5. Calculate session metrics
# 6. Calculate session metrics
self.set_session_metrics(run_messages)

self.run_response.status = RunStatus.completed

# Convert the response to the structured format if needed
self._convert_response_to_structured_format(run_response)

# 6. Save session to storage
# 7. Save session to storage
self.save_session(user_id=user_id, session_id=session_id)

# 7. Save output to file if save_response_to_file is set
# 8. Optional: Save output to file if save_response_to_file is set
self.save_run_response_to_file(message=run_messages.user_message, session_id=session_id)

# Log Agent Run
Expand All @@ -1140,12 +1140,12 @@ async def _arun_stream(

Steps:
1. Reason about the task if reasoning is enabled
2. Generate a response from the Model
3. Add the run to memory
2. Generate a response from the Model (includes running function calls)
3. Add the RunResponse to the Agent Session
4. Update Agent Memory
5. Calculate session metrics
6. Save output to file if save_response_to_file is set
7. Save session to storage
6. Save session to storage
7. Optional: Save output to file if save_response_to_file is set
"""
log_debug(f"Agent Run Start: {run_response.run_id}", center=True)
# Start the Run by yielding a RunStarted event
Expand All @@ -1171,7 +1171,7 @@ async def _arun_stream(
):
yield event

# 3. Add the run to memory
# 3. Add RunResponse to Agent Session
self.add_run_to_session(
run_response=run_response,
)
Expand All @@ -1184,15 +1184,15 @@ async def _arun_stream(
yield item
return

# 4. Update Agent Memory
# 5. Update Agent Memory
async for event in self._aupdate_memory(
run_messages=run_messages,
session_id=session_id,
user_id=user_id,
):
yield event

# 5. Calculate session metrics
# 6. Calculate session metrics
self.set_session_metrics(run_messages)

self.run_response.status = RunStatus.completed
Expand All @@ -1203,7 +1203,7 @@ async def _arun_stream(
# 6. Save session to storage
self.save_session(user_id=user_id, session_id=session_id)

# 7. Save output to file if save_response_to_file is set
# 8. Optional: Save output to file if save_response_to_file is set
self.save_run_response_to_file(message=run_messages.user_message, session_id=session_id)

log_debug(f"Agent Run End: {run_response.run_id}", center=True, symbol="*")
Expand Down Expand Up @@ -3756,8 +3756,6 @@ def save_session(self, session_id: str, user_id: Optional[str] = None) -> Option
session = self.get_agent_session(session_id=session_id, user_id=user_id)
# Update the session_data with the latest data
session.session_data = self.get_agent_session_data()
if self.store_chat_history:
session.chat_history = session.get_chat_history()

self.memory.upsert_session(session=session)

Expand Down Expand Up @@ -3816,12 +3814,8 @@ def new_session(self) -> None:

def get_chat_history(self) -> List[Message]:
"""Read the chat history from the session"""
# If the chat history is already set, return it
if self.agent_session is not None and self.agent_session.chat_history is not None:
return self.agent_session.chat_history
# Else read from the db
if self.memory is not None and self.memory.db is not None:
return self.memory.read_chat_history(session_id=self.session_id, session_type="agent")
if self.agent_session is not None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the interest of removing state we might have to only do this on the DB object

return self.agent_session.get_chat_history()
return []

def format_message_with_state_variables(self, msg: Any) -> Any:
Expand Down Expand Up @@ -4044,7 +4038,7 @@ def get_system_message(self, user_id: Optional[str] = None) -> Optional[Message]
)
system_message_content += "<memories_from_previous_interactions>"
for _memory in user_memories: # type: ignore
system_message_content += f"\n- {_memory.memory}"
system_message_content += f"\n- {_memory}"
system_message_content += "\n</memories_from_previous_interactions>\n\n"
system_message_content += (
"Note: this information is from previous interactions and may be updated in this conversation. "
Expand Down Expand Up @@ -4890,7 +4884,7 @@ def generate_session_name(self, session_id: str) -> str:
raise Exception("Model not set")

gen_session_name_prompt = "Conversation\n"
messages_for_generating_session_name = self.memory.get_messages_for_session(session_id=session_id)
messages_for_generating_session_name = self.agent_session.get_messages_for_session(session_id=session_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not now but in a next iteration we should try and pass the session around as opposed to having it set on the agent. In an effort to make things stateless

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that is interesting


for message in messages_for_generating_session_name:
gen_session_name_prompt += f"{message.role.upper()}: {message.content}\n"
Expand Down Expand Up @@ -5710,7 +5704,7 @@ def get_chat_history(num_chats: Optional[int] = None) -> str:

history: List[Dict[str, Any]] = []
if isinstance(self.memory, Memory):
all_chats = self.memory.get_messages_for_session(session_id=session_id)
all_chats = self.agent_session.get_messages_for_session(session_id=session_id)

if len(all_chats) == 0:
return ""
Expand Down
Loading