agno 2.2.3__py3-none-any.whl → 2.2.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
agno/agent/agent.py CHANGED
@@ -220,7 +220,9 @@ class Agent:
220
220
  # add_history_to_context=true adds messages from the chat history to the messages list sent to the Model.
221
221
  add_history_to_context: bool = False
222
222
  # Number of historical runs to include in the messages
223
- num_history_runs: int = 3
223
+ num_history_runs: Optional[int] = None
224
+ # Number of historical messages to include in the messages list sent to the Model.
225
+ num_history_messages: Optional[int] = None
224
226
  # Maximum number of tool calls to include from history (None = no limit)
225
227
  max_tool_calls_from_history: Optional[int] = None
226
228
 
@@ -438,7 +440,8 @@ class Agent:
438
440
  add_session_summary_to_context: Optional[bool] = None,
439
441
  session_summary_manager: Optional[SessionSummaryManager] = None,
440
442
  add_history_to_context: bool = False,
441
- num_history_runs: int = 3,
443
+ num_history_runs: Optional[int] = None,
444
+ num_history_messages: Optional[int] = None,
442
445
  max_tool_calls_from_history: Optional[int] = None,
443
446
  store_media: bool = True,
444
447
  store_tool_messages: bool = True,
@@ -541,6 +544,15 @@ class Agent:
541
544
 
542
545
  self.add_history_to_context = add_history_to_context
543
546
  self.num_history_runs = num_history_runs
547
+ self.num_history_messages = num_history_messages
548
+ if self.num_history_messages is not None and self.num_history_runs is not None:
549
+ log_warning(
550
+ "num_history_messages and num_history_runs cannot be set at the same time. Using num_history_runs."
551
+ )
552
+ self.num_history_messages = None
553
+ if self.num_history_messages is None and self.num_history_runs is None:
554
+ self.num_history_runs = 3
555
+
544
556
  self.max_tool_calls_from_history = max_tool_calls_from_history
545
557
 
546
558
  self.store_media = store_media
@@ -5133,7 +5145,7 @@ class Agent:
5133
5145
  run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
5134
5146
  )
5135
5147
  if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
5136
- log_debug("Creating user memories.")
5148
+ log_debug("Managing user memories")
5137
5149
  self.memory_manager.create_user_memories( # type: ignore
5138
5150
  message=user_message_str,
5139
5151
  user_id=user_id,
@@ -5174,7 +5186,7 @@ class Agent:
5174
5186
  run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
5175
5187
  )
5176
5188
  if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
5177
- log_debug("Creating user memories.")
5189
+ log_debug("Managing user memories")
5178
5190
  await self.memory_manager.acreate_user_memories( # type: ignore
5179
5191
  message=user_message_str,
5180
5192
  user_id=user_id,
@@ -7461,6 +7473,7 @@ class Agent:
7461
7473
 
7462
7474
  history: List[Message] = session.get_messages_from_last_n_runs(
7463
7475
  last_n=self.num_history_runs,
7476
+ last_n_messages=self.num_history_messages,
7464
7477
  skip_role=skip_role,
7465
7478
  agent_id=self.id if self.team_id is not None else None,
7466
7479
  )
@@ -7658,9 +7671,17 @@ class Agent:
7658
7671
  if add_history_to_context:
7659
7672
  from copy import deepcopy
7660
7673
 
7674
+ # Only skip messages from history when system_message_role is NOT a standard conversation role.
7675
+ # Standard conversation roles ("user", "assistant", "tool") should never be filtered
7676
+ # to preserve conversation continuity.
7677
+ skip_role = (
7678
+ self.system_message_role if self.system_message_role not in ["user", "assistant", "tool"] else None
7679
+ )
7680
+
7661
7681
  history: List[Message] = session.get_messages_from_last_n_runs(
7662
7682
  last_n=self.num_history_runs,
7663
- skip_role=self.system_message_role,
7683
+ last_n_messages=self.num_history_messages,
7684
+ skip_role=skip_role,
7664
7685
  agent_id=self.id if self.team_id is not None else None,
7665
7686
  )
7666
7687
 
agno/db/dynamo/utils.py CHANGED
@@ -361,7 +361,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
361
361
  token_metrics[field] += session_metrics.get(field, 0)
362
362
  model_metrics = []
363
363
  for model, count in model_counts.items():
364
- model_id, model_provider = model.split(":")
364
+ model_id, model_provider = model.rsplit(":", 1)
365
365
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
366
366
  metrics["users_count"] = len(all_user_ids)
367
367
  current_time = int(time.time())
@@ -224,7 +224,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
224
224
 
225
225
  model_metrics = []
226
226
  for model, count in model_counts.items():
227
- model_id, model_provider = model.split(":")
227
+ model_id, model_provider = model.rsplit(":", 1)
228
228
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
229
229
 
230
230
  metrics["users_count"] = len(all_user_ids)
agno/db/gcs_json/utils.py CHANGED
@@ -99,7 +99,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
99
99
 
100
100
  model_metrics = []
101
101
  for model, count in model_counts.items():
102
- model_id, model_provider = model.split(":")
102
+ model_id, model_provider = model.rsplit(":", 1)
103
103
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
104
104
 
105
105
  metrics["users_count"] = len(all_user_ids)
@@ -99,7 +99,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
99
99
 
100
100
  model_metrics = []
101
101
  for model, count in model_counts.items():
102
- model_id, model_provider = model.split(":")
102
+ model_id, model_provider = model.rsplit(":", 1)
103
103
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
104
104
 
105
105
  metrics["users_count"] = len(all_user_ids)
agno/db/json/utils.py CHANGED
@@ -99,7 +99,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
99
99
 
100
100
  model_metrics = []
101
101
  for model, count in model_counts.items():
102
- model_id, model_provider = model.split(":")
102
+ model_id, model_provider = model.rsplit(":", 1)
103
103
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
104
104
 
105
105
  metrics["users_count"] = len(all_user_ids)
@@ -1089,7 +1089,7 @@ class AsyncMongoDb(AsyncBaseDb):
1089
1089
  if limit is not None:
1090
1090
  if page is not None:
1091
1091
  pipeline.append({"$skip": (page - 1) * limit}) # type: ignore
1092
- pipeline.append({"$limit": limit}) # type: ignore
1092
+ pipeline.append({"$limit": limit}) # type: ignore
1093
1093
 
1094
1094
  results = await collection.aggregate(pipeline).to_list(length=None)
1095
1095
 
agno/db/mongo/utils.py CHANGED
@@ -117,7 +117,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
117
117
 
118
118
  model_metrics = []
119
119
  for model, count in model_counts.items():
120
- model_id, model_provider = model.split(":")
120
+ model_id, model_provider = model.rsplit(":", 1)
121
121
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
122
122
 
123
123
  metrics["users_count"] = len(all_user_ids)
agno/db/mysql/utils.py CHANGED
@@ -226,7 +226,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
226
226
 
227
227
  model_metrics = []
228
228
  for model, count in model_counts.items():
229
- model_id, model_provider = model.split(":")
229
+ model_id, model_provider = model.rsplit(":", 1)
230
230
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
231
231
 
232
232
  metrics["users_count"] = len(all_user_ids)
@@ -37,7 +37,7 @@ except ImportError:
37
37
  class AsyncPostgresDb(AsyncBaseDb):
38
38
  def __init__(
39
39
  self,
40
- db_id: Optional[str] = None,
40
+ id: Optional[str] = None,
41
41
  db_url: Optional[str] = None,
42
42
  db_engine: Optional[AsyncEngine] = None,
43
43
  db_schema: Optional[str] = None,
@@ -47,6 +47,7 @@ class AsyncPostgresDb(AsyncBaseDb):
47
47
  eval_table: Optional[str] = None,
48
48
  knowledge_table: Optional[str] = None,
49
49
  culture_table: Optional[str] = None,
50
+ db_id: Optional[str] = None, # Deprecated, use id instead.
50
51
  ):
51
52
  """
52
53
  Async interface for interacting with a PostgreSQL database.
@@ -57,7 +58,7 @@ class AsyncPostgresDb(AsyncBaseDb):
57
58
  3. Raise an error if neither is provided
58
59
 
59
60
  Args:
60
- db_id (Optional[str]): The ID of the database.
61
+ id (Optional[str]): The ID of the database.
61
62
  db_url (Optional[str]): The database URL to connect to.
62
63
  db_engine (Optional[AsyncEngine]): The SQLAlchemy async database engine to use.
63
64
  db_schema (Optional[str]): The database schema to use.
@@ -67,13 +68,17 @@ class AsyncPostgresDb(AsyncBaseDb):
67
68
  eval_table (Optional[str]): Name of the table to store evaluation runs data.
68
69
  knowledge_table (Optional[str]): Name of the table to store knowledge content.
69
70
  culture_table (Optional[str]): Name of the table to store cultural knowledge.
71
+ db_id: Deprecated, use id instead.
70
72
 
71
73
  Raises:
72
74
  ValueError: If neither db_url nor db_engine is provided.
73
75
  ValueError: If none of the tables are provided.
74
76
  """
77
+ if db_id is not None:
78
+ log_warning("db_id is deprecated and will be removed in a future version, use id instead.")
79
+
75
80
  super().__init__(
76
- id=db_id,
81
+ id=id or db_id,
77
82
  session_table=session_table,
78
83
  memory_table=memory_table,
79
84
  metrics_table=metrics_table,
agno/db/postgres/utils.py CHANGED
@@ -313,7 +313,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
313
313
 
314
314
  model_metrics = []
315
315
  for model, count in model_counts.items():
316
- model_id, model_provider = model.split(":")
316
+ model_id, model_provider = model.rsplit(":", 1)
317
317
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
318
318
 
319
319
  metrics["users_count"] = len(all_user_ids)
agno/db/redis/utils.py CHANGED
@@ -221,7 +221,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
221
221
 
222
222
  model_metrics = []
223
223
  for model, count in model_counts.items():
224
- model_id, model_provider = model.split(":")
224
+ model_id, model_provider = model.rsplit(":", 1)
225
225
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
226
226
 
227
227
  metrics["users_count"] = len(all_user_ids)
@@ -255,7 +255,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
255
255
 
256
256
  model_metrics = []
257
257
  for model, count in model_counts.items():
258
- model_id, model_provider = model.split(":")
258
+ model_id, model_provider = model.rsplit(":", 1)
259
259
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
260
260
 
261
261
  metrics["users_count"] = len(all_user_ids)
agno/db/sqlite/utils.py CHANGED
@@ -298,7 +298,7 @@ def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
298
298
 
299
299
  model_metrics = []
300
300
  for model, count in model_counts.items():
301
- model_id, model_provider = model.split(":")
301
+ model_id, model_provider = model.rsplit(":", 1)
302
302
  model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
303
303
 
304
304
  metrics["users_count"] = len(all_user_ids)
@@ -85,6 +85,10 @@ class OllamaEmbedder(Embedder):
85
85
  if self.options is not None:
86
86
  kwargs["options"] = self.options
87
87
 
88
+ # Add dimensions parameter for models that support it
89
+ if self.dimensions is not None:
90
+ kwargs["dimensions"] = self.dimensions
91
+
88
92
  response = self.client.embed(input=text, model=self.id, **kwargs)
89
93
  if response and "embeddings" in response:
90
94
  embeddings = response["embeddings"]
@@ -117,6 +121,10 @@ class OllamaEmbedder(Embedder):
117
121
  if self.options is not None:
118
122
  kwargs["options"] = self.options
119
123
 
124
+ # Add dimensions parameter for models that support it
125
+ if self.dimensions is not None:
126
+ kwargs["dimensions"] = self.dimensions
127
+
120
128
  response = await self.aclient.embed(input=text, model=self.id, **kwargs)
121
129
  if response and "embeddings" in response:
122
130
  embeddings = response["embeddings"]
agno/memory/manager.py CHANGED
@@ -843,7 +843,7 @@ class MemoryManager:
843
843
  team_id=team_id,
844
844
  enable_add_memory=add_memories,
845
845
  enable_update_memory=update_memories,
846
- enable_delete_memory=False,
846
+ enable_delete_memory=True,
847
847
  enable_clear_memory=False,
848
848
  ),
849
849
  )
@@ -854,7 +854,7 @@ class MemoryManager:
854
854
  existing_memories=existing_memories,
855
855
  enable_update_memory=update_memories,
856
856
  enable_add_memory=add_memories,
857
- enable_delete_memory=False,
857
+ enable_delete_memory=True,
858
858
  enable_clear_memory=False,
859
859
  ),
860
860
  *messages,
@@ -906,7 +906,7 @@ class MemoryManager:
906
906
  team_id=team_id,
907
907
  enable_add_memory=add_memories,
908
908
  enable_update_memory=update_memories,
909
- enable_delete_memory=False,
909
+ enable_delete_memory=True,
910
910
  enable_clear_memory=False,
911
911
  ),
912
912
  )
@@ -920,7 +920,7 @@ class MemoryManager:
920
920
  team_id=team_id,
921
921
  enable_add_memory=add_memories,
922
922
  enable_update_memory=update_memories,
923
- enable_delete_memory=False,
923
+ enable_delete_memory=True,
924
924
  enable_clear_memory=False,
925
925
  ),
926
926
  )
@@ -931,7 +931,7 @@ class MemoryManager:
931
931
  existing_memories=existing_memories,
932
932
  enable_update_memory=update_memories,
933
933
  enable_add_memory=add_memories,
934
- enable_delete_memory=False,
934
+ enable_delete_memory=True,
935
935
  enable_clear_memory=False,
936
936
  ),
937
937
  *messages,
agno/os/app.py CHANGED
@@ -187,54 +187,96 @@ class AgentOS:
187
187
  self.mcp_tools: List[Any] = []
188
188
  self._mcp_app: Optional[Any] = None
189
189
 
190
- if self.agents:
191
- for agent in self.agents:
192
- # Track all MCP tools to later handle their connection
193
- if agent.tools:
194
- for tool in agent.tools:
195
- # Checking if the tool is a MCPTools or MultiMCPTools instance
196
- type_name = type(tool).__name__
197
- if type_name in ("MCPTools", "MultiMCPTools"):
198
- if tool not in self.mcp_tools:
199
- self.mcp_tools.append(tool)
200
-
201
- agent.initialize_agent()
190
+ self._initialize_agents()
191
+ self._initialize_teams()
192
+ self._initialize_workflows()
202
193
 
203
- # Required for the built-in routes to work
204
- agent.store_events = True
194
+ if self.telemetry:
195
+ from agno.api.os import OSLaunch, log_os_telemetry
205
196
 
206
- if self.teams:
207
- for team in self.teams:
208
- # Track all MCP tools recursively
209
- collect_mcp_tools_from_team(team, self.mcp_tools)
197
+ log_os_telemetry(launch=OSLaunch(os_id=self.id, data=self._get_telemetry_data()))
210
198
 
211
- team.initialize_team()
199
+ def _add_agent_os_to_lifespan_function(self, lifespan):
200
+ """
201
+ Inspect a lifespan function and wrap it to pass agent_os if it accepts it.
212
202
 
213
- for member in team.members:
214
- if isinstance(member, Agent):
215
- member.team_id = None
216
- member.initialize_agent()
217
- elif isinstance(member, Team):
218
- member.initialize_team()
203
+ Returns:
204
+ A wrapped lifespan that passes agent_os if the lifespan function expects it.
205
+ """
206
+ # Getting the actual function inside the lifespan
207
+ lifespan_function = lifespan
208
+ if hasattr(lifespan, "__wrapped__"):
209
+ lifespan_function = lifespan.__wrapped__
219
210
 
220
- # Required for the built-in routes to work
221
- team.store_events = True
211
+ try:
212
+ from inspect import signature
222
213
 
223
- if self.workflows:
224
- for workflow in self.workflows:
225
- # Track MCP tools recursively in workflow members
226
- collect_mcp_tools_from_workflow(workflow, self.mcp_tools)
214
+ # Inspecting the lifespan function signature to find its parameters
215
+ sig = signature(lifespan_function)
216
+ params = list(sig.parameters.keys())
227
217
 
228
- if not workflow.id:
229
- workflow.id = generate_id_from_name(workflow.name)
218
+ # If the lifespan function expects the 'agent_os' parameter, add it
219
+ if "agent_os" in params:
220
+ return partial(lifespan, agent_os=self)
221
+ else:
222
+ return lifespan
230
223
 
231
- # Required for the built-in routes to work
232
- workflow.store_events = True
224
+ except (ValueError, TypeError):
225
+ return lifespan
233
226
 
234
- if self.telemetry:
235
- from agno.api.os import OSLaunch, log_os_telemetry
227
+ def resync(self, app: FastAPI) -> None:
228
+ """Resync the AgentOS to discover, initialize and configure: agents, teams, workflows, databases and knowledge bases."""
229
+ self._initialize_agents()
230
+ self._initialize_teams()
231
+ self._initialize_workflows()
232
+ self._auto_discover_databases()
233
+ self._auto_discover_knowledge_instances()
234
+ self._reprovision_routers(app=app)
236
235
 
237
- log_os_telemetry(launch=OSLaunch(os_id=self.id, data=self._get_telemetry_data()))
236
+ def _reprovision_routers(self, app: FastAPI) -> None:
237
+ """Re-provision all routes for the AgentOS."""
238
+ updated_routers = [
239
+ get_session_router(dbs=self.dbs),
240
+ get_memory_router(dbs=self.dbs),
241
+ get_eval_router(dbs=self.dbs, agents=self.agents, teams=self.teams),
242
+ get_metrics_router(dbs=self.dbs),
243
+ get_knowledge_router(knowledge_instances=self.knowledge_instances),
244
+ ]
245
+
246
+ # Clear all previously existing routes
247
+ app.router.routes = []
248
+
249
+ # Add the updated routes
250
+ for router in updated_routers:
251
+ self._add_router(app, router)
252
+
253
+ # Add the built-in routes
254
+ self._add_built_in_routes(app=app)
255
+
256
+ def _add_built_in_routes(self, app: FastAPI) -> None:
257
+ """Add all AgentOSbuilt-in routes to the given app."""
258
+ self._add_router(app, get_base_router(self, settings=self.settings))
259
+ self._add_router(app, get_websocket_router(self, settings=self.settings))
260
+ self._add_router(app, get_health_router())
261
+ self._add_router(app, get_home_router(self))
262
+
263
+ # Add A2A interface if relevant
264
+ has_a2a_interface = False
265
+ for interface in self.interfaces:
266
+ if not has_a2a_interface and interface.__class__.__name__ == "A2A":
267
+ has_a2a_interface = True
268
+ interface_router = interface.get_router()
269
+ self._add_router(app, interface_router)
270
+ if self.a2a_interface and not has_a2a_interface:
271
+ from agno.os.interfaces.a2a import A2A
272
+
273
+ a2a_interface = A2A(agents=self.agents, teams=self.teams, workflows=self.workflows)
274
+ self.interfaces.append(a2a_interface)
275
+ self._add_router(app, a2a_interface.get_router())
276
+
277
+ # Add the home router if MCP server is not enabled
278
+ if not self.enable_mcp_server:
279
+ self._add_router(app, get_home_router(self))
238
280
 
239
281
  def _make_app(self, lifespan: Optional[Any] = None) -> FastAPI:
240
282
  # Adjust the FastAPI app lifespan to handle MCP connections if relevant
@@ -265,6 +307,63 @@ class AgentOS:
265
307
  lifespan=app_lifespan,
266
308
  )
267
309
 
310
+ def _initialize_agents(self) -> None:
311
+ """Initialize and configure all agents for AgentOS usage."""
312
+ if not self.agents:
313
+ return
314
+
315
+ for agent in self.agents:
316
+ # Track all MCP tools to later handle their connection
317
+ if agent.tools:
318
+ for tool in agent.tools:
319
+ # Checking if the tool is a MCPTools or MultiMCPTools instance
320
+ type_name = type(tool).__name__
321
+ if type_name in ("MCPTools", "MultiMCPTools"):
322
+ if tool not in self.mcp_tools:
323
+ self.mcp_tools.append(tool)
324
+
325
+ agent.initialize_agent()
326
+
327
+ # Required for the built-in routes to work
328
+ agent.store_events = True
329
+
330
+ def _initialize_teams(self) -> None:
331
+ """Initialize and configure all teams for AgentOS usage."""
332
+ if not self.teams:
333
+ return
334
+
335
+ for team in self.teams:
336
+ # Track all MCP tools recursively
337
+ collect_mcp_tools_from_team(team, self.mcp_tools)
338
+
339
+ team.initialize_team()
340
+
341
+ for member in team.members:
342
+ if isinstance(member, Agent):
343
+ member.team_id = None
344
+ member.initialize_agent()
345
+ elif isinstance(member, Team):
346
+ member.initialize_team()
347
+
348
+ # Required for the built-in routes to work
349
+ team.store_events = True
350
+
351
+ def _initialize_workflows(self) -> None:
352
+ """Initialize and configure all workflows for AgentOS usage."""
353
+ if not self.workflows:
354
+ return
355
+
356
+ if self.workflows:
357
+ for workflow in self.workflows:
358
+ # Track MCP tools recursively in workflow members
359
+ collect_mcp_tools_from_workflow(workflow, self.mcp_tools)
360
+
361
+ if not workflow.id:
362
+ workflow.id = generate_id_from_name(workflow.name)
363
+
364
+ # Required for the built-in routes to work
365
+ workflow.store_events = True
366
+
268
367
  def get_app(self) -> FastAPI:
269
368
  if self.base_app:
270
369
  fastapi_app = self.base_app
@@ -288,7 +387,9 @@ class AgentOS:
288
387
  lifespans.append(self._mcp_app.lifespan)
289
388
 
290
389
  if self.lifespan:
291
- lifespans.append(self.lifespan)
390
+ # Wrap the user lifespan with agent_os parameter
391
+ wrapped_lifespan = self._add_agent_os_to_lifespan_function(self.lifespan)
392
+ lifespans.append(wrapped_lifespan)
292
393
 
293
394
  # Combine lifespans and set them in the app
294
395
  if lifespans:
@@ -304,11 +405,14 @@ class AgentOS:
304
405
 
305
406
  final_lifespan = self._mcp_app.lifespan # type: ignore
306
407
  if self.lifespan is not None:
408
+ # Wrap the user lifespan with agent_os parameter
409
+ wrapped_lifespan = self._add_agent_os_to_lifespan_function(self.lifespan)
410
+
307
411
  # Combine both lifespans
308
412
  @asynccontextmanager
309
413
  async def combined_lifespan(app: FastAPI):
310
414
  # Run both lifespans
311
- async with self.lifespan(app): # type: ignore
415
+ async with wrapped_lifespan(app): # type: ignore
312
416
  async with self._mcp_app.lifespan(app): # type: ignore
313
417
  yield
314
418
 
@@ -316,28 +420,14 @@ class AgentOS:
316
420
 
317
421
  fastapi_app = self._make_app(lifespan=final_lifespan)
318
422
  else:
319
- fastapi_app = self._make_app(lifespan=self.lifespan)
320
-
321
- # Add routes
322
- self._add_router(fastapi_app, get_base_router(self, settings=self.settings))
323
- self._add_router(fastapi_app, get_websocket_router(self, settings=self.settings))
324
- self._add_router(fastapi_app, get_health_router())
325
- self._add_router(fastapi_app, get_home_router(self))
326
-
327
- has_a2a_interface = False
328
- for interface in self.interfaces:
329
- if not has_a2a_interface and interface.__class__.__name__ == "A2A":
330
- has_a2a_interface = True
331
- interface_router = interface.get_router()
332
- self._add_router(fastapi_app, interface_router)
423
+ # Wrap the user lifespan with agent_os parameter
424
+ wrapped_user_lifespan = None
425
+ if self.lifespan is not None:
426
+ wrapped_user_lifespan = self._add_agent_os_to_lifespan_function(self.lifespan)
333
427
 
334
- # Add A2A interface if requested and not provided in self.interfaces
335
- if self.a2a_interface and not has_a2a_interface:
336
- from agno.os.interfaces.a2a import A2A
428
+ fastapi_app = self._make_app(lifespan=wrapped_user_lifespan)
337
429
 
338
- a2a_interface = A2A(agents=self.agents, teams=self.teams, workflows=self.workflows)
339
- self.interfaces.append(a2a_interface)
340
- self._add_router(fastapi_app, a2a_interface.get_router())
430
+ self._add_built_in_routes(app=fastapi_app)
341
431
 
342
432
  self._auto_discover_databases()
343
433
  self._auto_discover_knowledge_instances()
agno/run/agent.py CHANGED
@@ -70,12 +70,39 @@ class RunInput:
70
70
  result["input_content"] = self.input_content.model_dump(exclude_none=True)
71
71
  elif isinstance(self.input_content, Message):
72
72
  result["input_content"] = self.input_content.to_dict()
73
+
74
+ # Handle input_content provided as a list of Message objects
73
75
  elif (
74
76
  isinstance(self.input_content, list)
75
77
  and self.input_content
76
78
  and isinstance(self.input_content[0], Message)
77
79
  ):
78
80
  result["input_content"] = [m.to_dict() for m in self.input_content]
81
+
82
+ # Handle input_content provided as a list of dicts
83
+ elif (
84
+ isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
85
+ ):
86
+ for content in self.input_content:
87
+ # Handle media input
88
+ if isinstance(content, dict):
89
+ if content.get("images"):
90
+ content["images"] = [
91
+ img.to_dict() if isinstance(img, Image) else img for img in content["images"]
92
+ ]
93
+ if content.get("videos"):
94
+ content["videos"] = [
95
+ vid.to_dict() if isinstance(vid, Video) else vid for vid in content["videos"]
96
+ ]
97
+ if content.get("audios"):
98
+ content["audios"] = [
99
+ aud.to_dict() if isinstance(aud, Audio) else aud for aud in content["audios"]
100
+ ]
101
+ if content.get("files"):
102
+ content["files"] = [
103
+ file.to_dict() if isinstance(file, File) else file for file in content["files"]
104
+ ]
105
+ result["input_content"] = self.input_content
79
106
  else:
80
107
  result["input_content"] = self.input_content
81
108
 
agno/run/team.py CHANGED
@@ -66,12 +66,39 @@ class TeamRunInput:
66
66
  result["input_content"] = self.input_content.model_dump(exclude_none=True)
67
67
  elif isinstance(self.input_content, Message):
68
68
  result["input_content"] = self.input_content.to_dict()
69
+
70
+ # Handle input_content provided as a list of Message objects
69
71
  elif (
70
72
  isinstance(self.input_content, list)
71
73
  and self.input_content
72
74
  and isinstance(self.input_content[0], Message)
73
75
  ):
74
76
  result["input_content"] = [m.to_dict() for m in self.input_content]
77
+
78
+ # Handle input_content provided as a list of dicts
79
+ elif (
80
+ isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
81
+ ):
82
+ for content in self.input_content:
83
+ # Handle media input
84
+ if isinstance(content, dict):
85
+ if content.get("images"):
86
+ content["images"] = [
87
+ img.to_dict() if isinstance(img, Image) else img for img in content["images"]
88
+ ]
89
+ if content.get("videos"):
90
+ content["videos"] = [
91
+ vid.to_dict() if isinstance(vid, Video) else vid for vid in content["videos"]
92
+ ]
93
+ if content.get("audios"):
94
+ content["audios"] = [
95
+ aud.to_dict() if isinstance(aud, Audio) else aud for aud in content["audios"]
96
+ ]
97
+ if content.get("files"):
98
+ content["files"] = [
99
+ file.to_dict() if isinstance(file, File) else file for file in content["files"]
100
+ ]
101
+ result["input_content"] = self.input_content
75
102
  else:
76
103
  result["input_content"] = self.input_content
77
104
 
agno/session/agent.py CHANGED
@@ -107,11 +107,25 @@ class AgentSession:
107
107
  return run
108
108
  return None
109
109
 
110
+ def _should_skip_message(
111
+ self, message: Message, skip_role: Optional[str] = None, skip_history_messages: bool = True
112
+ ) -> bool:
113
+ """Processes a message for history"""
114
+ # Skip messages that were tagged as history in previous runs
115
+ if hasattr(message, "from_history") and message.from_history and skip_history_messages:
116
+ return True
117
+
118
+ # Skip messages with specified role
119
+ if skip_role and message.role == skip_role:
120
+ return True
121
+ return False
122
+
110
123
  def get_messages_from_last_n_runs(
111
124
  self,
112
125
  agent_id: Optional[str] = None,
113
126
  team_id: Optional[str] = None,
114
127
  last_n: Optional[int] = None,
128
+ last_n_messages: Optional[int] = None,
115
129
  skip_role: Optional[str] = None,
116
130
  skip_status: Optional[List[RunStatus]] = None,
117
131
  skip_history_messages: bool = True,
@@ -121,6 +135,7 @@ class AgentSession:
121
135
  agent_id: The id of the agent to get the messages from.
122
136
  team_id: The id of the team to get the messages from.
123
137
  last_n: The number of runs to return from the end of the conversation. Defaults to all runs.
138
+ last_n_messages: The number of messages to return from the end of the conversation. Defaults to all messages.
124
139
  skip_role: Skip messages with this role.
125
140
  skip_status: Skip messages with this status.
126
141
  skip_history_messages: Skip messages that were tagged as history in previous runs.
@@ -146,30 +161,55 @@ class AgentSession:
146
161
  # Filter by status
147
162
  session_runs = [run for run in session_runs if hasattr(run, "status") and run.status not in skip_status] # type: ignore
148
163
 
149
- # Filter by last_n
150
- runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
151
164
  messages_from_history = []
152
165
  system_message = None
153
- for run_response in runs_to_process:
154
- if not (run_response and run_response.messages):
155
- continue
156
166
 
157
- for message in run_response.messages or []:
158
- # Skip messages that were tagged as history in previous runs
159
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
167
+ # Filter by last_n_messages
168
+ if last_n_messages is not None:
169
+ for run_response in session_runs:
170
+ if not run_response or not run_response.messages:
160
171
  continue
161
172
 
162
- # Skip messages with specified role
163
- if skip_role and message.role == skip_role:
173
+ for message in run_response.messages or []:
174
+ if self._should_skip_message(message, skip_role, skip_history_messages):
175
+ continue
176
+
177
+ if message.role == "system":
178
+ # Only add the system message once
179
+ if system_message is None:
180
+ system_message = message
181
+ else:
182
+ messages_from_history.append(message)
183
+
184
+ if system_message:
185
+ messages_from_history = [system_message] + messages_from_history[
186
+ -(last_n_messages - 1) :
187
+ ] # Grab one less message then add the system message
188
+ else:
189
+ messages_from_history = messages_from_history[-last_n_messages:]
190
+
191
+ # Remove tool result messages that don't have an associated assistant message with tool calls
192
+ while len(messages_from_history) > 0 and messages_from_history[0].role == "tool":
193
+ messages_from_history.pop(0)
194
+
195
+ else:
196
+ # Filter by last_n runs
197
+ runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
198
+ for run_response in runs_to_process:
199
+ if not run_response or not run_response.messages:
164
200
  continue
165
201
 
166
- if message.role == "system":
167
- # Only add the system message once
168
- if system_message is None:
169
- system_message = message
170
- messages_from_history.append(system_message)
171
- else:
172
- messages_from_history.append(message)
202
+ for message in run_response.messages or []:
203
+ if self._should_skip_message(message, skip_role, skip_history_messages):
204
+ continue
205
+
206
+ if message.role == "system":
207
+ # Only add the system message once
208
+ if system_message is None:
209
+ system_message = message
210
+ messages_from_history.append(system_message)
211
+ else:
212
+ messages_from_history.append(message)
173
213
 
174
214
  log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
175
215
  return messages_from_history
agno/session/team.py CHANGED
@@ -113,11 +113,25 @@ class TeamSession:
113
113
 
114
114
  log_debug("Added RunOutput to Team Session")
115
115
 
116
+ def _should_skip_message(
117
+ self, message: Message, skip_role: Optional[str] = None, skip_history_messages: bool = True
118
+ ) -> bool:
119
+ """Processes a message for history"""
120
+ # Skip messages that were tagged as history in previous runs
121
+ if hasattr(message, "from_history") and message.from_history and skip_history_messages:
122
+ return True
123
+
124
+ # Skip messages with specified role
125
+ if skip_role and message.role == skip_role:
126
+ return True
127
+ return False
128
+
116
129
  def get_messages_from_last_n_runs(
117
130
  self,
118
131
  agent_id: Optional[str] = None,
119
132
  team_id: Optional[str] = None,
120
133
  last_n: Optional[int] = None,
134
+ last_n_messages: Optional[int] = None,
121
135
  skip_role: Optional[str] = None,
122
136
  skip_status: Optional[List[RunStatus]] = None,
123
137
  skip_history_messages: bool = True,
@@ -129,6 +143,7 @@ class TeamSession:
129
143
  agent_id: The id of the agent to get the messages from.
130
144
  team_id: The id of the team to get the messages from.
131
145
  last_n: The number of runs to return from the end of the conversation. Defaults to all runs.
146
+ last_n_messages: The number of messages to return from the end of the conversation. Defaults to all messages.
132
147
  skip_role: Skip messages with this role.
133
148
  skip_status: Skip messages with this status.
134
149
  skip_history_messages: Skip messages that were tagged as history in previous runs.
@@ -155,31 +170,55 @@ class TeamSession:
155
170
  # Filter by status
156
171
  session_runs = [run for run in session_runs if hasattr(run, "status") and run.status not in skip_status] # type: ignore
157
172
 
158
- # Filter by last_n
159
- runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
160
173
  messages_from_history = []
161
174
  system_message = None
162
175
 
163
- for run_response in runs_to_process:
164
- if not (run_response and run_response.messages):
165
- continue
166
-
167
- for message in run_response.messages or []:
168
- # Skip messages that were tagged as history in previous runs
169
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
176
+ # Filter by last_n_messages
177
+ if last_n_messages is not None:
178
+ for run_response in session_runs:
179
+ if not run_response or not run_response.messages:
170
180
  continue
171
181
 
172
- # Skip messages with specified role
173
- if skip_role and message.role == skip_role:
182
+ for message in run_response.messages or []:
183
+ if self._should_skip_message(message, skip_role, skip_history_messages):
184
+ continue
185
+
186
+ if message.role == "system":
187
+ # Only add the system message once
188
+ if system_message is None:
189
+ system_message = message
190
+ else:
191
+ messages_from_history.append(message)
192
+
193
+ if system_message:
194
+ messages_from_history = [system_message] + messages_from_history[
195
+ -(last_n_messages - 1) :
196
+ ] # Grab one less message then add the system message
197
+ else:
198
+ messages_from_history = messages_from_history[-last_n_messages:]
199
+
200
+ # Remove tool result messages that don't have an associated assistant message with tool calls
201
+ while len(messages_from_history) > 0 and messages_from_history[0].role == "tool":
202
+ messages_from_history.pop(0)
203
+ else:
204
+ # Filter by last_n runs
205
+ runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
206
+
207
+ for run_response in runs_to_process:
208
+ if not (run_response and run_response.messages):
174
209
  continue
175
210
 
176
- if message.role == "system":
177
- # Only add the system message once
178
- if system_message is None:
179
- system_message = message
180
- messages_from_history.append(system_message)
181
- else:
182
- messages_from_history.append(message)
211
+ for message in run_response.messages or []:
212
+ if self._should_skip_message(message, skip_role, skip_history_messages):
213
+ continue
214
+
215
+ if message.role == "system":
216
+ # Only add the system message once
217
+ if system_message is None:
218
+ system_message = message
219
+ messages_from_history.append(system_message)
220
+ else:
221
+ messages_from_history.append(message)
183
222
 
184
223
  log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
185
224
  return messages_from_history
agno/team/team.py CHANGED
@@ -378,7 +378,9 @@ class Team:
378
378
  # add_history_to_context=true adds messages from the chat history to the messages list sent to the Model.
379
379
  add_history_to_context: bool = False
380
380
  # Number of historical runs to include in the messages
381
- num_history_runs: int = 3
381
+ num_history_runs: Optional[int] = None
382
+ # Number of historical messages to include in the messages list sent to the Model.
383
+ num_history_messages: Optional[int] = None
382
384
  # Maximum number of tool calls to include from history (None = no limit)
383
385
  max_tool_calls_from_history: Optional[int] = None
384
386
 
@@ -485,7 +487,9 @@ class Team:
485
487
  store_history_messages: bool = True,
486
488
  send_media_to_model: bool = True,
487
489
  add_history_to_context: bool = False,
488
- num_history_runs: int = 3,
490
+ num_history_runs: Optional[int] = None,
491
+ num_history_messages: Optional[int] = None,
492
+ max_tool_calls_from_history: Optional[int] = None,
489
493
  tools: Optional[List[Union[Toolkit, Callable, Function, Dict]]] = None,
490
494
  tool_call_limit: Optional[int] = None,
491
495
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
@@ -508,7 +512,6 @@ class Team:
508
512
  enable_session_summaries: bool = False,
509
513
  session_summary_manager: Optional[SessionSummaryManager] = None,
510
514
  add_session_summary_to_context: Optional[bool] = None,
511
- max_tool_calls_from_history: Optional[int] = None,
512
515
  metadata: Optional[Dict[str, Any]] = None,
513
516
  reasoning: bool = False,
514
517
  reasoning_model: Optional[Model] = None,
@@ -553,6 +556,17 @@ class Team:
553
556
 
554
557
  self.add_history_to_context = add_history_to_context
555
558
  self.num_history_runs = num_history_runs
559
+ self.num_history_messages = num_history_messages
560
+ if self.num_history_messages is not None and self.num_history_runs is not None:
561
+ log_warning(
562
+ "num_history_messages and num_history_runs cannot be set at the same time. Using num_history_runs."
563
+ )
564
+ self.num_history_messages = None
565
+ if self.num_history_messages is None and self.num_history_runs is None:
566
+ self.num_history_runs = 3
567
+
568
+ self.max_tool_calls_from_history = max_tool_calls_from_history
569
+
556
570
  self.add_team_history_to_members = add_team_history_to_members
557
571
  self.num_team_history_runs = num_team_history_runs
558
572
  self.search_session_history = search_session_history
@@ -620,9 +634,6 @@ class Team:
620
634
  self.enable_session_summaries = enable_session_summaries
621
635
  self.session_summary_manager = session_summary_manager
622
636
  self.add_session_summary_to_context = add_session_summary_to_context
623
- self.add_history_to_context = add_history_to_context
624
- self.num_history_runs = num_history_runs
625
- self.max_tool_calls_from_history = max_tool_calls_from_history
626
637
  self.metadata = metadata
627
638
 
628
639
  self.reasoning = reasoning
@@ -3457,7 +3468,7 @@ class Team:
3457
3468
  run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
3458
3469
  )
3459
3470
  if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
3460
- log_debug("Creating user memories.")
3471
+ log_debug("Managing user memories")
3461
3472
  self.memory_manager.create_user_memories(
3462
3473
  message=user_message_str,
3463
3474
  user_id=user_id,
@@ -3473,7 +3484,7 @@ class Team:
3473
3484
  run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
3474
3485
  )
3475
3486
  if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
3476
- log_debug("Creating user memories.")
3487
+ log_debug("Managing user memories")
3477
3488
  await self.memory_manager.acreate_user_memories(
3478
3489
  message=user_message_str,
3479
3490
  user_id=user_id,
@@ -5928,6 +5939,7 @@ class Team:
5928
5939
 
5929
5940
  history = session.get_messages_from_last_n_runs(
5930
5941
  last_n=self.num_history_runs,
5942
+ last_n_messages=self.num_history_messages,
5931
5943
  skip_role=skip_role,
5932
5944
  team_id=self.id if self.parent_team_id is not None else None,
5933
5945
  )
@@ -6059,9 +6071,16 @@ class Team:
6059
6071
  if add_history_to_context:
6060
6072
  from copy import deepcopy
6061
6073
 
6074
+ # Only skip messages from history when system_message_role is NOT a standard conversation role.
6075
+ # Standard conversation roles ("user", "assistant", "tool") should never be filtered
6076
+ # to preserve conversation continuity.
6077
+ skip_role = (
6078
+ self.system_message_role if self.system_message_role not in ["user", "assistant", "tool"] else None
6079
+ )
6062
6080
  history = session.get_messages_from_last_n_runs(
6063
6081
  last_n=self.num_history_runs,
6064
- skip_role=self.system_message_role,
6082
+ last_n_messages=self.num_history_messages,
6083
+ skip_role=skip_role,
6065
6084
  team_id=self.id,
6066
6085
  )
6067
6086
 
@@ -6765,6 +6784,7 @@ class Team:
6765
6784
 
6766
6785
  history = session.get_messages_from_last_n_runs(
6767
6786
  last_n=member_agent.num_history_runs or self.num_history_runs,
6787
+ last_n_messages=member_agent.num_history_messages,
6768
6788
  skip_role=skip_role,
6769
6789
  agent_id=member_agent_id,
6770
6790
  team_id=member_team_id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agno
3
- Version: 2.2.3
3
+ Version: 2.2.5
4
4
  Summary: Agno: a lightweight library for building Multi-Agent Systems
5
5
  Author-email: Ashpreet Bedi <ashpreet@agno.com>
6
6
  Project-URL: homepage, https://agno.com
@@ -4,7 +4,7 @@ agno/exceptions.py,sha256=7xqLur8sWHugnViIJz4PvPKSHljSiVKNAqaKQOJgZiU,4982
4
4
  agno/media.py,sha256=eTfYb_pwhX_PCIVPSrW4VYRqmoxKABEF1aZClrVvQ30,16500
5
5
  agno/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  agno/agent/__init__.py,sha256=s7S3FgsjZxuaabzi8L5n4aSH8IZAiZ7XaNNcySGR-EQ,1051
7
- agno/agent/agent.py,sha256=qsdcMth4tg1dOzn_vL4XMsMDWk1Y2sYmSrFvw7jcOYo,453093
7
+ agno/agent/agent.py,sha256=U0xx271S2I6WdzrJqyJMZ7z_6VY7Tc4PGvazsLKdAfk,454283
8
8
  agno/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  agno/api/agent.py,sha256=fKlQ62E_C9Rjd7Zus3Gs3R1RG-IhzFV-ICpkb6SLqYc,932
10
10
  agno/api/api.py,sha256=Z7iWbrjheJcGLeeDYrtTCWiKTVqjH0uJI35UNWOtAXw,973
@@ -36,40 +36,40 @@ agno/db/async_postgres/__init__.py,sha256=ja_thcYP3bP0DD3da6iUVDR_w2-S6B3M-UxBlk
36
36
  agno/db/dynamo/__init__.py,sha256=fZ7NwKbyhoIu7_4T6hVz44HkIINXMnTfFrDrgB6bpEo,67
37
37
  agno/db/dynamo/dynamo.py,sha256=SlpKYVbfb67q8r2tp48lDRWyW2wfURo6S1TjWuqzPks,78126
38
38
  agno/db/dynamo/schemas.py,sha256=Pdtpa0wV_M8G_inM2rA8pBn2LdxdjG-irltQpYIQPMo,12932
39
- agno/db/dynamo/utils.py,sha256=dKVLfZOGvyCrEcVZZ6t1mHwyqZvqSNFzq0l-xVhGyIU,27390
39
+ agno/db/dynamo/utils.py,sha256=2tt1poijpdsKqh4jipiP_ZeJ5tvwWlxNLqLrRzCnd2U,27394
40
40
  agno/db/firestore/__init__.py,sha256=lYAJjUs4jMxJFty1GYZw464K35zeuBlcoFR9uuIQYtI,79
41
41
  agno/db/firestore/firestore.py,sha256=ck2UtZzoSfOjXUOR_BXf2LuZ66pNidPkA5_-aKSWhq0,70496
42
42
  agno/db/firestore/schemas.py,sha256=sPbi2teuzCfRECnCyj6LrNNu0drSqbBHpH-o1xoJYfs,4392
43
- agno/db/firestore/utils.py,sha256=ddmij9sdKDPbAnpUIyA74G1L55md9JWrrwGAssjy1Es,13808
43
+ agno/db/firestore/utils.py,sha256=hQudu539CDkEKG1GvtDPOJbzdhIpSTE7Y-Uu8IdooDU,13812
44
44
  agno/db/gcs_json/__init__.py,sha256=aTR4o3aFrzfANHtRw7nX9uc5_GsY52ch0rmoo7uXuc4,76
45
45
  agno/db/gcs_json/gcs_json_db.py,sha256=vtLrWlwEALSDAkHu3k8YEthkBLGENuYyO1yH493NOc8,54561
46
- agno/db/gcs_json/utils.py,sha256=4qBkY9F3i-PG55k99hEqzs15RNHgrkZ_jtfaRe0xQrA,8004
46
+ agno/db/gcs_json/utils.py,sha256=mleGhIY2J7s5rPUteQbIBosJQgRsRDPNJEwGBzh7Hws,8008
47
47
  agno/db/in_memory/__init__.py,sha256=OvR_FONhOh9PmcRfUA_6gvplZT5UGIBAgVKqVg6SWTA,80
48
48
  agno/db/in_memory/in_memory_db.py,sha256=IapPmv178SXv5Gy9t395PjvvcjpyIDNt_mpwL-2QGB8,45991
49
- agno/db/in_memory/utils.py,sha256=c50_QSw2DHeujjl5iHlJlgWxlmNHXwKl3ZwyLvVgED4,8057
49
+ agno/db/in_memory/utils.py,sha256=KM-FlcN8IszNU4dtP82oSAg5ImpYil3ygH0mOxWV2Ns,8061
50
50
  agno/db/json/__init__.py,sha256=zyPTmVF9S-OwXCL7FSkrDmunZ_Q14YZO3NYUv1Pa14Y,62
51
51
  agno/db/json/json_db.py,sha256=JgBintmR0gGaXsPLTprgvawpivXbEXhhW_2h5da5HB8,52632
52
- agno/db/json/utils.py,sha256=Hygm1SZ1qSLUH7h55MeULvoSGFIPMVnes-kp0kbrJSg,8052
52
+ agno/db/json/utils.py,sha256=a4dOAKLIP8vHh64gZ3ebBTrf69EzSM4vd2_80_WwRa8,8056
53
53
  agno/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  agno/db/migrations/v1_to_v2.py,sha256=gj8deaEWUxOr0qJyMfjOpV3LxEh-otOSOxDckeUq0qU,24938
55
55
  agno/db/mongo/__init__.py,sha256=NG2WC2jE5PX1kMXTYCVHjhomf5DAJgvzSj45QHdvl2E,466
56
- agno/db/mongo/async_mongo.py,sha256=edoerEZCPxWiFZFKdT73xRNY2-i9fTLqRsQWi37CbvA,80358
56
+ agno/db/mongo/async_mongo.py,sha256=7U7wTcqWewtR4a_aJi108GjD9uTw4oGmuNOXfMIrZf8,80357
57
57
  agno/db/mongo/mongo.py,sha256=0Mqr_U_ViK8S7clJR6nre-bAMaaGvfhEdSQtgKP9gfw,77034
58
58
  agno/db/mongo/schemas.py,sha256=d2ZxqqzKYwz0Iexgrv1HWArGnmk3KUKJ37PCzFykodI,2314
59
- agno/db/mongo/utils.py,sha256=UO-mI3w2-EUzgFQ3gzfT7-SeXlofau_eUzWknOhPvjY,9248
59
+ agno/db/mongo/utils.py,sha256=9xdra4QRe01f441VrSpBMMy9gv7SYeKrJJchlOdwfsE,9252
60
60
  agno/db/mysql/__init__.py,sha256=ohBMZ1E6ctioEF0XX5PjC4LtUQrc6lFkjsE4ojyXA8g,63
61
61
  agno/db/mysql/mysql.py,sha256=rkfUFwOcJ2lxyPq1QE0SItJ0ZhP2oY1Zj556jSJ77xk,95134
62
62
  agno/db/mysql/schemas.py,sha256=OpdAWhh-ElwQ5JOg1MKJqGJ16qzVTuyS56iH9Zw3oHs,6171
63
- agno/db/mysql/utils.py,sha256=jF06bYYASQYdpmR6lwjD4iAp3-fq7moezjOnEYpju8g,12356
63
+ agno/db/mysql/utils.py,sha256=XHuvgI-xAe0Y0sBZWSXW9B0xM0KKgI-JDssG7Tyqlbs,12360
64
64
  agno/db/postgres/__init__.py,sha256=Ojk00nTCzQFiH2ViD7KIBjgpkTKLRNPCwWnuXMKtNXY,154
65
- agno/db/postgres/async_postgres.py,sha256=2j6qJ3vXnh4YjdQ64uQFV2HgH_LnKgxVUrN31Smlm8k,78354
65
+ agno/db/postgres/async_postgres.py,sha256=y3l3R6gw4xb9Wlhh5YYrnEJ-n-Rmqzne2MC9FYKzxtA,78604
66
66
  agno/db/postgres/postgres.py,sha256=HnxdgdIFik3fPnFQLtAmz4y5y0EDNMcKzfh-Wlh8SoM,91345
67
67
  agno/db/postgres/schemas.py,sha256=O049oyPU07tHwnyuOzYyiKcK1NYvh6cQmmsFOvA7LTs,5971
68
- agno/db/postgres/utils.py,sha256=lHU20wxpFT20Lqqk8Pippbxs9I9h_MH7gku7DCemkfI,15461
68
+ agno/db/postgres/utils.py,sha256=ZHWmVlx96pqI07h-hoiMm6TZTsudpf2zxID4MJtiY9s,15465
69
69
  agno/db/redis/__init__.py,sha256=rZWeZ4CpVeKP-enVQ-SRoJ777i0rdGNgoNDRS9gsfAc,63
70
70
  agno/db/redis/redis.py,sha256=QoM8J8uXCv5x5w0RZsFs9mpNzctXkCSBaZo46rrHvxs,62821
71
71
  agno/db/redis/schemas.py,sha256=3WilZq3NqZqRONyu_mAjjmQpClgYDYoWjfkvlOh0Tfw,4038
72
- agno/db/redis/utils.py,sha256=b6FthFWSgrkMtjHSclPAyjW-ZwYLFn_3r-WFiCkuntI,11232
72
+ agno/db/redis/utils.py,sha256=4iql9MavWM3okOhuOFKK7r0TP1AAT5qAAbiL5jTE84k,11236
73
73
  agno/db/schemas/__init__.py,sha256=g72Zr5_nm00yXHStv4pf9PG9bGLKXEK7Av6YQtrDbCQ,147
74
74
  agno/db/schemas/culture.py,sha256=w4azKAVLf5X4xyRUFXMIEq0CA0pnyeN03W3eMpqScxo,4342
75
75
  agno/db/schemas/evals.py,sha256=T1zIiwrN5fxZVD2em85wQ9CV-HSVZvNF4D4v9_w30VA,786
@@ -79,12 +79,12 @@ agno/db/schemas/metrics.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
79
  agno/db/singlestore/__init__.py,sha256=dufbaod8ZZIeZIVi0hYJQ8Eu2DfIfWdIy00cpqAsx9U,87
80
80
  agno/db/singlestore/schemas.py,sha256=Eb9wipCjWr48dlF3CMDa53WDvFsr7QhLOSaTgbUkMKg,6178
81
81
  agno/db/singlestore/singlestore.py,sha256=B_RG3f67j7JLOQ_xs4bnGw8ZjTLqopzd5GGg2GjTPUc,93042
82
- agno/db/singlestore/utils.py,sha256=ZYkpaSwFE_EiJ06vOd_bpr22RvdercFObTTlw3hfq2M,13667
82
+ agno/db/singlestore/utils.py,sha256=NnA6YJAk1Oj-5w7Y-juxuQ7eiFnpjVAiGCV5U7QcjVE,13671
83
83
  agno/db/sqlite/__init__.py,sha256=09V3i4y0-tBjt60--57ivZ__SaaS67GCsDT4Apzv-5Y,138
84
84
  agno/db/sqlite/async_sqlite.py,sha256=EGHkhETD-UPxzm0wvOHJo99BlOOddW1NRtahNnpFTFw,95604
85
85
  agno/db/sqlite/schemas.py,sha256=NyEvAFG-hi3Inm5femgJdorxJ5l2-bXLWBhxJ4r7jW0,5832
86
86
  agno/db/sqlite/sqlite.py,sha256=NQfh56217Xki1KnDCM_kAfPjn4RHz_0wYbXJBaUOi3Q,93789
87
- agno/db/sqlite/utils.py,sha256=XHQoSmvOTCrMdLPMIBj0Zwj7WY_X8U8wRHkI8hq5S30,15547
87
+ agno/db/sqlite/utils.py,sha256=21Z1PjQNjz1QaeY0BQY-abg0sv0nIJJ3oHuFUTV-raU,15551
88
88
  agno/db/surrealdb/__init__.py,sha256=C8qp5-Nx9YnSmgKEtGua-sqG_ntCXONBw1qqnNyKPqI,75
89
89
  agno/db/surrealdb/metrics.py,sha256=oKDRyjRQ6KR3HaO8zDHQLVMG7-0NDkOFOKX5I7mD5FA,10336
90
90
  agno/db/surrealdb/models.py,sha256=2KBxSxiEI4yQ2OTOr1HVeL8Fd52tQfWkM53kwzqUmyw,11512
@@ -133,7 +133,7 @@ agno/knowledge/embedder/jina.py,sha256=M2M2ki0XyylyitJs_ZL2JoepC1y70IJzYntPsCVUx
133
133
  agno/knowledge/embedder/langdb.py,sha256=_vbE1Jbj16WGP4aEkh54D7ESTu0LlI1_lp5WiXPIABA,731
134
134
  agno/knowledge/embedder/mistral.py,sha256=AMc3VBpQCKFxetx2gRd9c6iRvR4-bSEWJ1Q4JPwQg28,8608
135
135
  agno/knowledge/embedder/nebius.py,sha256=4I2irehvR6Di00Al4jbG4vAa6KZnbOJ-7QqVjB7Mn64,363
136
- agno/knowledge/embedder/ollama.py,sha256=fzbC2IMkYOs0QJn3rtMZiLxxpPRPIw7uTefGtjmxW1I,6005
136
+ agno/knowledge/embedder/ollama.py,sha256=faLkOvPt2dWs8h87anAgeeG3LJpMH4jVMWP7_3f7JHs,6313
137
137
  agno/knowledge/embedder/openai.py,sha256=oUEyqIyREIPYRCtQBjAn-aIjxI7DQkMZQmXOt0OkLbo,7331
138
138
  agno/knowledge/embedder/sentence_transformer.py,sha256=khJJbJlBFDeVJm7yd4ub3e7n7rM-l5z00f594jGtIaU,2203
139
139
  agno/knowledge/embedder/together.py,sha256=Pt524Lh6YRDKfD8rfmLu0Qlw4dDh4vLz7KEMIvIULBk,387
@@ -165,7 +165,7 @@ agno/knowledge/reranker/cohere.py,sha256=2Be5blVyeZ3vYlnFa2NYvJuytjaCB8G2OWJ11pQ
165
165
  agno/knowledge/reranker/infinity.py,sha256=N9geg9xZqRdJZksfQcvbGJgMymXrQVJl_K5KICWqH8o,7193
166
166
  agno/knowledge/reranker/sentence_transformer.py,sha256=ZN4SqnMZsUhg5G7AzlONM1_UjezfNrjFYXpNVHD4U-U,1912
167
167
  agno/memory/__init__.py,sha256=XWKJU5SJObYZqEKMZ2XYwgH8-YeuWUoSRfT4dEI5HnY,101
168
- agno/memory/manager.py,sha256=Hvs0JYLy8QM7KZhR5mNEET1rZqEb7N6uCoMYf9YRyzA,51834
168
+ agno/memory/manager.py,sha256=p7ZHhzrfYYEj_7ALCdvU72qWa_qtxkQc-A9taqVfLAw,51829
169
169
  agno/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
170
170
  agno/models/base.py,sha256=6ucSAOgG95n6uT2VaWp8QtZctVnH67FS4JwYt4P4_Rw,95015
171
171
  agno/models/defaults.py,sha256=1_fe4-ZbNriE8BgqxVRVi4KGzEYxYKYsz4hn6CZNEEM,40
@@ -257,7 +257,7 @@ agno/models/vllm/vllm.py,sha256=UtiiSvUR4pG_1CzuhY5MWduRgzM2hGVTakKJ6ZBdQmo,2730
257
257
  agno/models/xai/__init__.py,sha256=ukcCxnCHxTtkJNA2bAMTX4MhCv1wJcbiq8ZIfYczIxs,55
258
258
  agno/models/xai/xai.py,sha256=jA6_39tfapkjkHKdzbKaNq1t9qIvO1IaZY1hQqEmFVs,4181
259
259
  agno/os/__init__.py,sha256=h8oQu7vhD5RZf09jkyM_Kt1Kdq_d5kFB9gJju8QPwcY,55
260
- agno/os/app.py,sha256=F_5XGuZMVc2Y4X9-9WrF8JGvE9Ae74s1AVLo01LU_Lk,27835
260
+ agno/os/app.py,sha256=SDvchR-fqrDROT2vRF03Pj-inXj1JZLmOSLIblPJMOw,31218
261
261
  agno/os/auth.py,sha256=FyBtAKWtg-qSunCas5m5pK1dVEmikOSZvcCp5r25tTA,1844
262
262
  agno/os/config.py,sha256=u4R9yazQXIcKjR3QzEIZw_XAe_OHp3xn0ff7SVkj2jA,2893
263
263
  agno/os/mcp.py,sha256=vJhjjSm1KC61HLoxPj24lSrjkjo7plkoFfcQX2BmTp0,10253
@@ -316,19 +316,19 @@ agno/reasoning/openai.py,sha256=JYk-mR9cMf1ibprX3MdL8oeCEDyQ3XaJw9PAIYvWeGk,3234
316
316
  agno/reasoning/step.py,sha256=6DaOb_0DJRz9Yh1w_mxcRaOSVzIQDrj3lQ6rzHLdIwA,1220
317
317
  agno/reasoning/vertexai.py,sha256=O9ntvalkIY2jLmWviEH1DnecMskqTL-mRZQBZohoHiU,2974
318
318
  agno/run/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
319
- agno/run/agent.py,sha256=7HXieysLfmAURwy-wdAju01nTbdkat9eIOSjbuOWyfk,25432
319
+ agno/run/agent.py,sha256=uTtruA2DCrt5qPuAH6QuDQZ-s4E7TEP8NkIGBE7n-OA,26887
320
320
  agno/run/base.py,sha256=2KEu0TLfCM-0Dd3JQ6aSQf_dqtKHtDIUt0oCPdk7rIk,7756
321
321
  agno/run/cancel.py,sha256=yoSj3fnx8D7Gf-fSngVIgd3GOp3tRaDhHH_4QeHDoAk,2667
322
322
  agno/run/messages.py,sha256=rAC4CLW-xBA6qFS1BOvcjJ9j_qYf0a7sX1mcdY04zMU,1126
323
- agno/run/team.py,sha256=_ykwaf4i-7MFvgDr3pdwxWe8SRmubA0ll7igWrih09w,25888
323
+ agno/run/team.py,sha256=hR61LilAVVvVzVTbyJ600youEP29poX2CosmKa0f4kU,27343
324
324
  agno/run/workflow.py,sha256=dxnrvG7icRt7oOiFYyJvqI_XpSj4A0dCAMRCmsSo1XQ,23377
325
325
  agno/session/__init__.py,sha256=p6eqzWcLSHiMex2yZvkwv2yrFUNdGs21TGMS49xrEC4,376
326
- agno/session/agent.py,sha256=S2bdsxVBIYHMCZlXVtkXnbm4p_kVvX1j7v4u3V7Jups,9943
326
+ agno/session/agent.py,sha256=UGgDQB5nTxFwJcqWpWAmRGjXMLhwSCqRXDyoEi5a-jg,11763
327
327
  agno/session/summary.py,sha256=JEvSnvOgYf6pxmExXsQu7kQGx5p4OLVuQtgsypz2jhY,10130
328
- agno/session/team.py,sha256=fRmFn_51O6uRUlLYgt3HKcAoEjpDScMRd0NW5WTWQWQ,13442
328
+ agno/session/team.py,sha256=M9QEmGYyQM64ZsvPWRdp1xZV6EQGuun6pjJL05AzU-k,15260
329
329
  agno/session/workflow.py,sha256=tluE_3ERMBYJtffpwlrhdETWlzJk6Xw2x06FZ1Y3fXg,7397
330
330
  agno/team/__init__.py,sha256=toHidBOo5M3n_TIVtIKHgcDbLL9HR-_U-YQYuIt_XtE,847
331
- agno/team/team.py,sha256=OaUOkVy3JaxlzbiXvGoriaZDRgDPdIvz7p-v8mFaSes,399490
331
+ agno/team/team.py,sha256=s1Xd-1S50HJR7iDhJM1lw-gYTRKhEs_fsUT8aZpS56Y,400633
332
332
  agno/tools/__init__.py,sha256=jNll2sELhPPbqm5nPeT4_uyzRO2_KRTW-8Or60kioS0,210
333
333
  agno/tools/agentql.py,sha256=S82Z9aTNr-E5wnA4fbFs76COljJtiQIjf2grjz3CkHU,4104
334
334
  agno/tools/airflow.py,sha256=uf2rOzZpSU64l_qRJ5Raku-R3Gky-uewmYkh6W0-oxg,2610
@@ -561,8 +561,8 @@ agno/workflow/step.py,sha256=3t83LwEajM-jHjcXzJR74iEO36P4ZVqenocmiWLtQOg,60532
561
561
  agno/workflow/steps.py,sha256=O3lbKw56ziSnuJndAGm8hjlEwdTh2jQXf1s0587Va3M,25671
562
562
  agno/workflow/types.py,sha256=J474F5MWHCHHVjrzTUPJihlcrRLUnQ3hVW2-9TWdxWw,18519
563
563
  agno/workflow/workflow.py,sha256=LBy_jVjvglRE4sOLAITZGaOJctJYbP59oV0HvuiHopA,147346
564
- agno-2.2.3.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
565
- agno-2.2.3.dist-info/METADATA,sha256=gwqIrVwG8PZSns55HIQJrJM_bJhR7BpYb9WTOFpIzZE,28193
566
- agno-2.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
567
- agno-2.2.3.dist-info/top_level.txt,sha256=MKyeuVesTyOKIXUhc-d_tPa2Hrh0oTA4LM0izowpx70,5
568
- agno-2.2.3.dist-info/RECORD,,
564
+ agno-2.2.5.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
565
+ agno-2.2.5.dist-info/METADATA,sha256=A7a12CJlQD0pcz6w19KkD2mMOQHzc36pYZ5eW5WCr5g,28193
566
+ agno-2.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
567
+ agno-2.2.5.dist-info/top_level.txt,sha256=MKyeuVesTyOKIXUhc-d_tPa2Hrh0oTA4LM0izowpx70,5
568
+ agno-2.2.5.dist-info/RECORD,,
File without changes