-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
Description
The PreHookStartedEvent resp. PreHookCompletedEvent contain a run_input object which in turn contains input_content. Usually the input_content is a string, but when using Teams and the team member agent has add_history_to_context=True, then input_content can also be a list of Message objects.
Furthermore, neither PreHookStartedEvent nor PreHookCompletedEvent override the to_dict() method of the base class, so when to_dict() is called, the run_input is not converted to dict. The PostgresDb calls to_dict() to convert the entire run data to JSON for persistence, but since input_content is not converted to dict, it can not be persisted as JSON.
This causes breakage when using PostgresDB and Agno tries to persist these events into the database at the end of the run:
ERROR Exception upserting into sessions table: Object of type Message is not JSON serializable
Steps to Reproduce
To reproduce this you need a Team with an Agent that has add_history_to_context=True and also has a pre_hook or post_hook installed (as otherwise no PreHookStartedEvent resp. PreHookCompletedEvent events are generated).
Here is a minimal code example:
from agno.agent import Agent
from agno.guardrails import BaseGuardrail
from agno.db.postgres import AsyncPostgresDb
from agno.models.openai import OpenAIResponses
from agno.team import Team
from agno.os import AgentOS
from agno.tools.mcp import MCPTools
from dotenv import load_dotenv
load_dotenv()
db_url = "postgresql+psycopg_async://agno:agno@localhost:5432/agno"
db = AsyncPostgresDb(db_url=db_url)
class TestGuardrail(BaseGuardrail):
def check(self, run_input):
print(f"Guardrail {run_input}")
async def async_check(self, run_input):
print(f"Async Guardrail {run_input}")
# Create the Agent
agno_agent = Agent(
name="Agno Agent",
model=OpenAIResponses(id="gpt-5.1"),
role="Expert on Agno framework",
db=db,
pre_hooks=[TestGuardrail()],
# Add the Agno MCP server to the Agent
tools=[MCPTools(transport="streamable-http", url="https://docs.agno.com/mcp")],
# Add the previous session history to the context
add_history_to_context=True,
markdown=True,
)
agno_team = Team(
name="Agno Team",
members=[agno_agent],
instructions="DO NOT RESPOND DIRECTLY. ALWAYS delegate to agno-agent, then summarize the results before responding to the user.",
db=db,
model=OpenAIResponses(id="gpt-5.1"),
add_history_to_context=True,
)
# Create the AgentOS
agent_os = AgentOS(teams=[agno_team])
# Get the FastAPI app for the AgentOS
app = agent_os.get_app()To trigger the issue, you need to execute at least TWO runs in the same session, so that the Team adds the history of the previous run (as Message objects) to the Agent's input.
Run the app and execute this twice:
curl -X 'POST' \
'http://127.0.0.1:8000/teams/agno-team/runs' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'message=Explain what Agno is' \
-F 'stream=true' \
-F 'session_id=test'
Agent Configuration (if applicable)
No response
Expected Behavior
The run including all events is persisted to the database.
Actual Behavior
The run data is lost and not persisted to the DB. This loss of data is almost silent - the only thing that gets logged to the console is
ERROR Exception upserting into sessions table: Object of type Message is not JSON serializable
Screenshots or Logs (if applicable)
No response
Environment
-Agno Version: 2.3.4Possible Solutions (optional)
No response
Additional Context
No response