agno 2.3.3__py3-none-any.whl → 2.3.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.
Files changed (108) hide show
  1. agno/agent/agent.py +177 -41
  2. agno/culture/manager.py +2 -2
  3. agno/db/base.py +330 -8
  4. agno/db/dynamo/dynamo.py +722 -2
  5. agno/db/dynamo/schemas.py +127 -0
  6. agno/db/firestore/firestore.py +573 -1
  7. agno/db/firestore/schemas.py +40 -0
  8. agno/db/gcs_json/gcs_json_db.py +446 -1
  9. agno/db/in_memory/in_memory_db.py +143 -1
  10. agno/db/json/json_db.py +438 -1
  11. agno/db/mongo/async_mongo.py +522 -0
  12. agno/db/mongo/mongo.py +523 -1
  13. agno/db/mongo/schemas.py +29 -0
  14. agno/db/mysql/mysql.py +536 -3
  15. agno/db/mysql/schemas.py +38 -0
  16. agno/db/postgres/async_postgres.py +546 -14
  17. agno/db/postgres/postgres.py +535 -2
  18. agno/db/postgres/schemas.py +38 -0
  19. agno/db/redis/redis.py +468 -1
  20. agno/db/redis/schemas.py +32 -0
  21. agno/db/singlestore/schemas.py +38 -0
  22. agno/db/singlestore/singlestore.py +523 -1
  23. agno/db/sqlite/async_sqlite.py +548 -9
  24. agno/db/sqlite/schemas.py +38 -0
  25. agno/db/sqlite/sqlite.py +537 -5
  26. agno/db/sqlite/utils.py +6 -8
  27. agno/db/surrealdb/models.py +25 -0
  28. agno/db/surrealdb/surrealdb.py +548 -1
  29. agno/eval/accuracy.py +10 -4
  30. agno/eval/performance.py +10 -4
  31. agno/eval/reliability.py +22 -13
  32. agno/exceptions.py +11 -0
  33. agno/hooks/__init__.py +3 -0
  34. agno/hooks/decorator.py +164 -0
  35. agno/knowledge/chunking/semantic.py +2 -2
  36. agno/models/aimlapi/aimlapi.py +17 -0
  37. agno/models/anthropic/claude.py +19 -12
  38. agno/models/aws/bedrock.py +3 -4
  39. agno/models/aws/claude.py +5 -1
  40. agno/models/azure/ai_foundry.py +2 -2
  41. agno/models/azure/openai_chat.py +8 -0
  42. agno/models/cerebras/cerebras.py +61 -4
  43. agno/models/cerebras/cerebras_openai.py +17 -0
  44. agno/models/cohere/chat.py +5 -1
  45. agno/models/cometapi/cometapi.py +18 -1
  46. agno/models/dashscope/dashscope.py +2 -3
  47. agno/models/deepinfra/deepinfra.py +18 -1
  48. agno/models/deepseek/deepseek.py +2 -3
  49. agno/models/fireworks/fireworks.py +18 -1
  50. agno/models/google/gemini.py +8 -2
  51. agno/models/groq/groq.py +5 -2
  52. agno/models/internlm/internlm.py +18 -1
  53. agno/models/langdb/langdb.py +13 -1
  54. agno/models/litellm/chat.py +2 -2
  55. agno/models/litellm/litellm_openai.py +18 -1
  56. agno/models/meta/llama_openai.py +19 -2
  57. agno/models/nebius/nebius.py +2 -3
  58. agno/models/nvidia/nvidia.py +20 -3
  59. agno/models/openai/chat.py +17 -2
  60. agno/models/openai/responses.py +17 -2
  61. agno/models/openrouter/openrouter.py +21 -2
  62. agno/models/perplexity/perplexity.py +17 -1
  63. agno/models/portkey/portkey.py +7 -6
  64. agno/models/requesty/requesty.py +19 -2
  65. agno/models/response.py +2 -1
  66. agno/models/sambanova/sambanova.py +20 -3
  67. agno/models/siliconflow/siliconflow.py +19 -2
  68. agno/models/together/together.py +20 -3
  69. agno/models/vercel/v0.py +20 -3
  70. agno/models/vllm/vllm.py +19 -14
  71. agno/models/xai/xai.py +19 -2
  72. agno/os/app.py +104 -0
  73. agno/os/config.py +13 -0
  74. agno/os/interfaces/whatsapp/router.py +0 -1
  75. agno/os/mcp.py +1 -0
  76. agno/os/router.py +31 -0
  77. agno/os/routers/traces/__init__.py +3 -0
  78. agno/os/routers/traces/schemas.py +414 -0
  79. agno/os/routers/traces/traces.py +499 -0
  80. agno/os/schema.py +22 -1
  81. agno/os/utils.py +57 -0
  82. agno/run/agent.py +1 -0
  83. agno/run/base.py +17 -0
  84. agno/run/team.py +4 -0
  85. agno/session/team.py +1 -0
  86. agno/table.py +10 -0
  87. agno/team/team.py +215 -65
  88. agno/tools/function.py +10 -8
  89. agno/tools/nano_banana.py +1 -1
  90. agno/tracing/__init__.py +12 -0
  91. agno/tracing/exporter.py +157 -0
  92. agno/tracing/schemas.py +276 -0
  93. agno/tracing/setup.py +111 -0
  94. agno/utils/agent.py +4 -4
  95. agno/utils/hooks.py +56 -1
  96. agno/vectordb/qdrant/qdrant.py +22 -22
  97. agno/workflow/condition.py +8 -0
  98. agno/workflow/loop.py +8 -0
  99. agno/workflow/parallel.py +8 -0
  100. agno/workflow/router.py +8 -0
  101. agno/workflow/step.py +20 -0
  102. agno/workflow/steps.py +8 -0
  103. agno/workflow/workflow.py +83 -17
  104. {agno-2.3.3.dist-info → agno-2.3.5.dist-info}/METADATA +2 -2
  105. {agno-2.3.3.dist-info → agno-2.3.5.dist-info}/RECORD +108 -98
  106. {agno-2.3.3.dist-info → agno-2.3.5.dist-info}/WHEEL +0 -0
  107. {agno-2.3.3.dist-info → agno-2.3.5.dist-info}/licenses/LICENSE +0 -0
  108. {agno-2.3.3.dist-info → agno-2.3.5.dist-info}/top_level.txt +0 -0
agno/agent/agent.py CHANGED
@@ -83,8 +83,8 @@ from agno.utils.agent import (
83
83
  aget_session_state_util,
84
84
  aset_session_name_util,
85
85
  aupdate_session_state_util,
86
- await_for_background_tasks,
87
- await_for_background_tasks_stream,
86
+ await_for_open_threads,
87
+ await_for_thread_tasks_stream,
88
88
  collect_joint_audios,
89
89
  collect_joint_files,
90
90
  collect_joint_images,
@@ -103,8 +103,8 @@ from agno.utils.agent import (
103
103
  store_media_util,
104
104
  update_session_state_util,
105
105
  validate_media_object_id,
106
- wait_for_background_tasks,
107
- wait_for_background_tasks_stream,
106
+ wait_for_open_threads,
107
+ wait_for_thread_tasks_stream,
108
108
  )
109
109
  from agno.utils.common import is_typed_dict, validate_typed_dict
110
110
  from agno.utils.events import (
@@ -131,7 +131,7 @@ from agno.utils.events import (
131
131
  create_tool_call_started_event,
132
132
  handle_event,
133
133
  )
134
- from agno.utils.hooks import filter_hook_args, normalize_hooks
134
+ from agno.utils.hooks import copy_args_for_background, filter_hook_args, normalize_hooks, should_run_hook_in_background
135
135
  from agno.utils.knowledge import get_agentic_or_user_search_filters
136
136
  from agno.utils.log import (
137
137
  log_debug,
@@ -273,6 +273,8 @@ class Agent:
273
273
  pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
274
274
  # Functions called after output is generated but before the response is returned
275
275
  post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
276
+ # If True, run hooks as FastAPI background tasks (non-blocking). Set by AgentOS.
277
+ _run_hooks_in_background: Optional[bool] = None
276
278
 
277
279
  # --- Agent Reasoning ---
278
280
  # Enable reasoning by working through the problem step by step.
@@ -594,7 +596,6 @@ class Agent:
594
596
  self.tool_choice = tool_choice
595
597
  self.tool_hooks = tool_hooks
596
598
 
597
- # Initialize hooks with backward compatibility
598
599
  self.pre_hooks = pre_hooks
599
600
  self.post_hooks = post_hooks
600
601
 
@@ -710,9 +711,13 @@ class Agent:
710
711
  self.id = generate_id_from_name(self.name)
711
712
 
712
713
  def _set_debug(self, debug_mode: Optional[bool] = None) -> None:
714
+ # Get the debug level from the environment variable or the default debug level
715
+ debug_level: Literal[1, 2] = (
716
+ cast(Literal[1, 2], int(env)) if (env := getenv("AGNO_DEBUG_LEVEL")) in ("1", "2") else self.debug_level
717
+ )
713
718
  # If the default debug mode is set, or passed on run, or via environment variable, set the debug mode to True
714
719
  if self.debug_mode or debug_mode or getenv("AGNO_DEBUG", "false").lower() == "true":
715
- set_log_level_to_debug(level=self.debug_level)
720
+ set_log_level_to_debug(level=debug_level)
716
721
  else:
717
722
  set_log_level_to_info()
718
723
 
@@ -967,6 +972,7 @@ class Agent:
967
972
  add_session_state_to_context: Optional[bool] = None,
968
973
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
969
974
  debug_mode: Optional[bool] = None,
975
+ background_tasks: Optional[Any] = None,
970
976
  **kwargs: Any,
971
977
  ) -> RunOutput:
972
978
  """Run the Agent and return the RunOutput.
@@ -987,9 +993,6 @@ class Agent:
987
993
  13. Cleanup and store the run response and session
988
994
  """
989
995
 
990
- # Register run for cancellation tracking
991
- register_run(run_response.run_id) # type: ignore
992
-
993
996
  # 1. Execute pre-hooks
994
997
  run_input = cast(RunInput, run_response.input)
995
998
  self.model = cast(Model, self.model)
@@ -1003,6 +1006,7 @@ class Agent:
1003
1006
  session=session,
1004
1007
  user_id=user_id,
1005
1008
  debug_mode=debug_mode,
1009
+ background_tasks=background_tasks,
1006
1010
  **kwargs,
1007
1011
  )
1008
1012
  # Consume the generator without yielding
@@ -1105,9 +1109,7 @@ class Agent:
1105
1109
 
1106
1110
  # We should break out of the run function
1107
1111
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
1108
- wait_for_background_tasks(
1109
- memory_future=memory_future, cultural_knowledge_future=cultural_knowledge_future
1110
- )
1112
+ wait_for_open_threads(memory_future=memory_future, cultural_knowledge_future=cultural_knowledge_future)
1111
1113
 
1112
1114
  return self._handle_agent_run_paused(run_response=run_response, session=session, user_id=user_id)
1113
1115
 
@@ -1127,6 +1129,7 @@ class Agent:
1127
1129
  session=session,
1128
1130
  user_id=user_id,
1129
1131
  debug_mode=debug_mode,
1132
+ background_tasks=background_tasks,
1130
1133
  **kwargs,
1131
1134
  )
1132
1135
  deque(post_hook_iterator, maxlen=0)
@@ -1135,7 +1138,7 @@ class Agent:
1135
1138
  raise_if_cancelled(run_response.run_id) # type: ignore
1136
1139
 
1137
1140
  # 11. Wait for background memory creation and cultural knowledge creation
1138
- wait_for_background_tasks(memory_future=memory_future, cultural_knowledge_future=cultural_knowledge_future)
1141
+ wait_for_open_threads(memory_future=memory_future, cultural_knowledge_future=cultural_knowledge_future)
1139
1142
 
1140
1143
  # 12. Create session summary
1141
1144
  if self.session_summary_manager is not None:
@@ -1188,6 +1191,7 @@ class Agent:
1188
1191
  stream_events: bool = False,
1189
1192
  yield_run_output: Optional[bool] = None,
1190
1193
  debug_mode: Optional[bool] = None,
1194
+ background_tasks: Optional[Any] = None,
1191
1195
  **kwargs: Any,
1192
1196
  ) -> Iterator[Union[RunOutputEvent, RunOutput]]:
1193
1197
  """Run the Agent and yield the RunOutput.
@@ -1205,9 +1209,6 @@ class Agent:
1205
1209
  10. Cleanup and store the run response and session
1206
1210
  """
1207
1211
 
1208
- # Register run for cancellation tracking
1209
- register_run(run_response.run_id) # type: ignore
1210
-
1211
1212
  # 1. Execute pre-hooks
1212
1213
  run_input = cast(RunInput, run_response.input)
1213
1214
  self.model = cast(Model, self.model)
@@ -1222,6 +1223,7 @@ class Agent:
1222
1223
  user_id=user_id,
1223
1224
  debug_mode=debug_mode,
1224
1225
  stream_events=stream_events,
1226
+ background_tasks=background_tasks,
1225
1227
  **kwargs,
1226
1228
  )
1227
1229
  for event in pre_hook_iterator:
@@ -1365,7 +1367,7 @@ class Agent:
1365
1367
 
1366
1368
  # We should break out of the run function
1367
1369
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
1368
- yield from wait_for_background_tasks_stream(
1370
+ yield from wait_for_thread_tasks_stream(
1369
1371
  memory_future=memory_future,
1370
1372
  cultural_knowledge_future=cultural_knowledge_future,
1371
1373
  stream_events=stream_events,
@@ -1399,11 +1401,12 @@ class Agent:
1399
1401
  user_id=user_id,
1400
1402
  debug_mode=debug_mode,
1401
1403
  stream_events=stream_events,
1404
+ background_tasks=background_tasks,
1402
1405
  **kwargs,
1403
1406
  )
1404
1407
 
1405
1408
  # 8. Wait for background memory creation and cultural knowledge creation
1406
- yield from wait_for_background_tasks_stream(
1409
+ yield from wait_for_thread_tasks_stream(
1407
1410
  memory_future=memory_future,
1408
1411
  cultural_knowledge_future=cultural_knowledge_future,
1409
1412
  stream_events=stream_events,
@@ -1585,6 +1588,10 @@ class Agent:
1585
1588
  "`run` method is not supported with an async database. Please use `arun` method instead."
1586
1589
  )
1587
1590
 
1591
+ # Create a run_id for this specific run and register immediately for cancellation tracking
1592
+ run_id = str(uuid4())
1593
+ register_run(run_id)
1594
+
1588
1595
  if (add_history_to_context or self.add_history_to_context) and not self.db and not self.team_id:
1589
1596
  log_warning(
1590
1597
  "add_history_to_context is True, but no database has been assigned to the agent. History will not be added to the context."
@@ -1597,8 +1604,11 @@ class Agent:
1597
1604
  stacklevel=2,
1598
1605
  )
1599
1606
 
1600
- # Create a run_id for this specific run
1601
- run_id = str(uuid4())
1607
+ background_tasks = kwargs.pop("background_tasks", None)
1608
+ if background_tasks is not None:
1609
+ from fastapi import BackgroundTasks
1610
+
1611
+ background_tasks: BackgroundTasks = background_tasks # type: ignore
1602
1612
 
1603
1613
  # Validate input against input_schema if provided
1604
1614
  validated_input = self._validate_input(input)
@@ -1750,6 +1760,7 @@ class Agent:
1750
1760
  stream_events=stream_events,
1751
1761
  yield_run_output=yield_run_output,
1752
1762
  debug_mode=debug_mode,
1763
+ background_tasks=background_tasks,
1753
1764
  **kwargs,
1754
1765
  )
1755
1766
  return response_iterator
@@ -1764,6 +1775,7 @@ class Agent:
1764
1775
  add_session_state_to_context=add_session_state,
1765
1776
  response_format=response_format,
1766
1777
  debug_mode=debug_mode,
1778
+ background_tasks=background_tasks,
1767
1779
  **kwargs,
1768
1780
  )
1769
1781
  return response
@@ -1822,6 +1834,7 @@ class Agent:
1822
1834
  add_session_state_to_context: Optional[bool] = None,
1823
1835
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
1824
1836
  debug_mode: Optional[bool] = None,
1837
+ background_tasks: Optional[Any] = None,
1825
1838
  **kwargs: Any,
1826
1839
  ) -> RunOutput:
1827
1840
  """Run the Agent and return the RunOutput.
@@ -1846,9 +1859,6 @@ class Agent:
1846
1859
  """
1847
1860
  log_debug(f"Agent Run Start: {run_response.run_id}", center=True)
1848
1861
 
1849
- # Register run for cancellation tracking
1850
- register_run(run_response.run_id) # type: ignore
1851
-
1852
1862
  # 1. Read or create session. Reads from the database if provided.
1853
1863
  agent_session = await self._aread_or_create_session(session_id=session_id, user_id=user_id)
1854
1864
 
@@ -1884,6 +1894,7 @@ class Agent:
1884
1894
  session=agent_session,
1885
1895
  user_id=user_id,
1886
1896
  debug_mode=debug_mode,
1897
+ background_tasks=background_tasks,
1887
1898
  **kwargs,
1888
1899
  )
1889
1900
  # Consume the async iterator without yielding
@@ -1986,9 +1997,7 @@ class Agent:
1986
1997
 
1987
1998
  # We should break out of the run function
1988
1999
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
1989
- await await_for_background_tasks(
1990
- memory_task=memory_task, cultural_knowledge_task=cultural_knowledge_task
1991
- )
2000
+ await await_for_open_threads(memory_task=memory_task, cultural_knowledge_task=cultural_knowledge_task)
1992
2001
  return await self._ahandle_agent_run_paused(
1993
2002
  run_response=run_response, session=agent_session, user_id=user_id
1994
2003
  )
@@ -2009,6 +2018,7 @@ class Agent:
2009
2018
  session=agent_session,
2010
2019
  user_id=user_id,
2011
2020
  debug_mode=debug_mode,
2021
+ background_tasks=background_tasks,
2012
2022
  **kwargs,
2013
2023
  ):
2014
2024
  pass
@@ -2017,7 +2027,7 @@ class Agent:
2017
2027
  raise_if_cancelled(run_response.run_id) # type: ignore
2018
2028
 
2019
2029
  # 14. Wait for background memory creation
2020
- await await_for_background_tasks(memory_task=memory_task, cultural_knowledge_task=cultural_knowledge_task)
2030
+ await await_for_open_threads(memory_task=memory_task, cultural_knowledge_task=cultural_knowledge_task)
2021
2031
 
2022
2032
  # 15. Create session summary
2023
2033
  if self.session_summary_manager is not None:
@@ -2096,6 +2106,7 @@ class Agent:
2096
2106
  stream_events: bool = False,
2097
2107
  yield_run_output: Optional[bool] = None,
2098
2108
  debug_mode: Optional[bool] = None,
2109
+ background_tasks: Optional[Any] = None,
2099
2110
  **kwargs: Any,
2100
2111
  ) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]:
2101
2112
  """Run the Agent and yield the RunOutput.
@@ -2162,6 +2173,7 @@ class Agent:
2162
2173
  user_id=user_id,
2163
2174
  debug_mode=debug_mode,
2164
2175
  stream_events=stream_events,
2176
+ background_tasks=background_tasks,
2165
2177
  **kwargs,
2166
2178
  )
2167
2179
  async for event in pre_hook_iterator:
@@ -2220,9 +2232,6 @@ class Agent:
2220
2232
  log_debug("Starting cultural knowledge creation in background task.")
2221
2233
  cultural_knowledge_task = create_task(self._acreate_cultural_knowledge(run_messages=run_messages))
2222
2234
 
2223
- # Register run for cancellation tracking
2224
- register_run(run_response.run_id) # type: ignore
2225
-
2226
2235
  try:
2227
2236
  # 8. Reason about the task if reasoning is enabled
2228
2237
  async for item in self._ahandle_reasoning_stream(
@@ -2304,7 +2313,7 @@ class Agent:
2304
2313
 
2305
2314
  # Break out of the run function if a tool call is paused
2306
2315
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
2307
- async for item in await_for_background_tasks_stream(
2316
+ async for item in await_for_thread_tasks_stream(
2308
2317
  memory_task=memory_task,
2309
2318
  cultural_knowledge_task=cultural_knowledge_task,
2310
2319
  stream_events=stream_events,
@@ -2328,12 +2337,13 @@ class Agent:
2328
2337
  user_id=user_id,
2329
2338
  debug_mode=debug_mode,
2330
2339
  stream_events=stream_events,
2340
+ background_tasks=background_tasks,
2331
2341
  **kwargs,
2332
2342
  ):
2333
2343
  yield event
2334
2344
 
2335
2345
  # 11. Wait for background memory creation
2336
- async for item in await_for_background_tasks_stream(
2346
+ async for item in await_for_thread_tasks_stream(
2337
2347
  memory_task=memory_task,
2338
2348
  cultural_knowledge_task=cultural_knowledge_task,
2339
2349
  stream_events=stream_events,
@@ -2537,6 +2547,10 @@ class Agent:
2537
2547
  ) -> Union[RunOutput, AsyncIterator[RunOutputEvent]]:
2538
2548
  """Async Run the Agent and return the response."""
2539
2549
 
2550
+ # Create a run_id for this specific run and register immediately for cancellation tracking
2551
+ run_id = str(uuid4())
2552
+ register_run(run_id)
2553
+
2540
2554
  if (add_history_to_context or self.add_history_to_context) and not self.db and not self.team_id:
2541
2555
  log_warning(
2542
2556
  "add_history_to_context is True, but no database has been assigned to the agent. History will not be added to the context."
@@ -2549,8 +2563,11 @@ class Agent:
2549
2563
  stacklevel=2,
2550
2564
  )
2551
2565
 
2552
- # Create a run_id for this specific run
2553
- run_id = str(uuid4())
2566
+ background_tasks = kwargs.pop("background_tasks", None)
2567
+ if background_tasks is not None:
2568
+ from fastapi import BackgroundTasks
2569
+
2570
+ background_tasks: BackgroundTasks = background_tasks # type: ignore
2554
2571
 
2555
2572
  # 2. Validate input against input_schema if provided
2556
2573
  validated_input = self._validate_input(input)
@@ -2695,6 +2712,7 @@ class Agent:
2695
2712
  add_dependencies_to_context=add_dependencies,
2696
2713
  add_session_state_to_context=add_session_state,
2697
2714
  debug_mode=debug_mode,
2715
+ background_tasks=background_tasks,
2698
2716
  **kwargs,
2699
2717
  ) # type: ignore[assignment]
2700
2718
  else:
@@ -2708,6 +2726,7 @@ class Agent:
2708
2726
  add_dependencies_to_context=add_dependencies,
2709
2727
  add_session_state_to_context=add_session_state,
2710
2728
  debug_mode=debug_mode,
2729
+ background_tasks=background_tasks,
2711
2730
  **kwargs,
2712
2731
  )
2713
2732
 
@@ -2839,6 +2858,12 @@ class Agent:
2839
2858
  if self._has_async_db():
2840
2859
  raise Exception("continue_run() is not supported with an async DB. Please use acontinue_arun() instead.")
2841
2860
 
2861
+ background_tasks = kwargs.pop("background_tasks", None)
2862
+ if background_tasks is not None:
2863
+ from fastapi import BackgroundTasks
2864
+
2865
+ background_tasks: BackgroundTasks = background_tasks # type: ignore
2866
+
2842
2867
  session_id = run_response.session_id if run_response else session_id
2843
2868
  run_id: str = run_response.run_id if run_response else run_id # type: ignore
2844
2869
 
@@ -2982,6 +3007,7 @@ class Agent:
2982
3007
  response_format=response_format,
2983
3008
  stream_events=stream_events,
2984
3009
  debug_mode=debug_mode,
3010
+ background_tasks=background_tasks,
2985
3011
  **kwargs,
2986
3012
  )
2987
3013
  return response_iterator
@@ -2995,6 +3021,7 @@ class Agent:
2995
3021
  session=agent_session,
2996
3022
  response_format=response_format,
2997
3023
  debug_mode=debug_mode,
3024
+ background_tasks=background_tasks,
2998
3025
  **kwargs,
2999
3026
  )
3000
3027
  return response
@@ -3045,6 +3072,7 @@ class Agent:
3045
3072
  user_id: Optional[str] = None,
3046
3073
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
3047
3074
  debug_mode: Optional[bool] = None,
3075
+ background_tasks: Optional[Any] = None,
3048
3076
  **kwargs,
3049
3077
  ) -> RunOutput:
3050
3078
  """Continue a previous run.
@@ -3109,6 +3137,7 @@ class Agent:
3109
3137
  session=session,
3110
3138
  user_id=user_id,
3111
3139
  debug_mode=debug_mode,
3140
+ background_tasks=background_tasks,
3112
3141
  **kwargs,
3113
3142
  )
3114
3143
  deque(post_hook_iterator, maxlen=0)
@@ -3164,6 +3193,7 @@ class Agent:
3164
3193
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
3165
3194
  stream_events: bool = False,
3166
3195
  debug_mode: Optional[bool] = None,
3196
+ background_tasks: Optional[Any] = None,
3167
3197
  **kwargs,
3168
3198
  ) -> Iterator[RunOutputEvent]:
3169
3199
  """Continue a previous run.
@@ -3240,6 +3270,7 @@ class Agent:
3240
3270
  user_id=user_id,
3241
3271
  debug_mode=debug_mode,
3242
3272
  stream_events=stream_events,
3273
+ background_tasks=background_tasks,
3243
3274
  **kwargs,
3244
3275
  )
3245
3276
 
@@ -3341,6 +3372,7 @@ class Agent:
3341
3372
  dependencies: Optional[Dict[str, Any]] = None,
3342
3373
  metadata: Optional[Dict[str, Any]] = None,
3343
3374
  debug_mode: Optional[bool] = None,
3375
+ **kwargs: Any,
3344
3376
  ) -> RunOutput: ...
3345
3377
 
3346
3378
  @overload
@@ -3360,6 +3392,7 @@ class Agent:
3360
3392
  dependencies: Optional[Dict[str, Any]] = None,
3361
3393
  metadata: Optional[Dict[str, Any]] = None,
3362
3394
  debug_mode: Optional[bool] = None,
3395
+ **kwargs: Any,
3363
3396
  ) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]: ...
3364
3397
 
3365
3398
  def acontinue_run( # type: ignore
@@ -3407,6 +3440,12 @@ class Agent:
3407
3440
  if run_response is None and (run_id is not None and (session_id is None and self.session_id is None)):
3408
3441
  raise ValueError("Session ID is required to continue a run from a run_id.")
3409
3442
 
3443
+ background_tasks = kwargs.pop("background_tasks", None)
3444
+ if background_tasks is not None:
3445
+ from fastapi import BackgroundTasks
3446
+
3447
+ background_tasks: BackgroundTasks = background_tasks # type: ignore
3448
+
3410
3449
  session_id, user_id = self._initialize_session(
3411
3450
  session_id=session_id,
3412
3451
  user_id=user_id,
@@ -3491,6 +3530,7 @@ class Agent:
3491
3530
  stream_events=stream_events,
3492
3531
  yield_run_output=yield_run_output,
3493
3532
  debug_mode=debug_mode,
3533
+ background_tasks=background_tasks,
3494
3534
  **kwargs,
3495
3535
  )
3496
3536
  else:
@@ -3503,6 +3543,7 @@ class Agent:
3503
3543
  user_id=user_id,
3504
3544
  response_format=response_format,
3505
3545
  debug_mode=debug_mode,
3546
+ background_tasks=background_tasks,
3506
3547
  **kwargs,
3507
3548
  )
3508
3549
  except ModelProviderError as e:
@@ -3552,6 +3593,7 @@ class Agent:
3552
3593
  user_id: Optional[str] = None,
3553
3594
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
3554
3595
  debug_mode: Optional[bool] = None,
3596
+ background_tasks: Optional[Any] = None,
3555
3597
  **kwargs,
3556
3598
  ) -> RunOutput:
3557
3599
  """Continue a previous run.
@@ -3694,6 +3736,7 @@ class Agent:
3694
3736
  session=agent_session,
3695
3737
  user_id=user_id,
3696
3738
  debug_mode=debug_mode,
3739
+ background_tasks=background_tasks,
3697
3740
  **kwargs,
3698
3741
  ):
3699
3742
  pass
@@ -3763,6 +3806,7 @@ class Agent:
3763
3806
  stream_events: bool = False,
3764
3807
  yield_run_output: bool = False,
3765
3808
  debug_mode: Optional[bool] = None,
3809
+ background_tasks: Optional[Any] = None,
3766
3810
  **kwargs,
3767
3811
  ) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]:
3768
3812
  """Continue a previous run.
@@ -3948,6 +3992,7 @@ class Agent:
3948
3992
  user_id=user_id,
3949
3993
  debug_mode=debug_mode,
3950
3994
  stream_events=stream_events,
3995
+ background_tasks=background_tasks,
3951
3996
  **kwargs,
3952
3997
  ):
3953
3998
  yield event
@@ -4049,13 +4094,13 @@ class Agent:
4049
4094
  user_id: Optional[str] = None,
4050
4095
  debug_mode: Optional[bool] = None,
4051
4096
  stream_events: bool = False,
4097
+ background_tasks: Optional[Any] = None,
4052
4098
  **kwargs: Any,
4053
4099
  ) -> Iterator[RunOutputEvent]:
4054
4100
  """Execute multiple pre-hook functions in succession."""
4055
4101
  if hooks is None:
4056
4102
  return
4057
-
4058
- # Prepare all possible arguments once
4103
+ # Prepare arguments for this hook
4059
4104
  all_args = {
4060
4105
  "run_input": run_input,
4061
4106
  "run_context": run_context,
@@ -4067,9 +4112,32 @@ class Agent:
4067
4112
  "user_id": user_id,
4068
4113
  "debug_mode": debug_mode or self.debug_mode,
4069
4114
  }
4115
+
4116
+ # Check if background_tasks is available and ALL hooks should run in background
4117
+ # Note: Pre-hooks running in background may not be able to modify run_input
4118
+ if self._run_hooks_in_background is True and background_tasks is not None:
4119
+ # Schedule ALL pre_hooks as background tasks
4120
+ # Copy args to prevent race conditions
4121
+ bg_args = copy_args_for_background(all_args)
4122
+ for hook in hooks:
4123
+ # Filter arguments to only include those that the hook accepts
4124
+ filtered_args = filter_hook_args(hook, bg_args)
4125
+
4126
+ # Add to background tasks
4127
+ background_tasks.add_task(hook, **filtered_args)
4128
+ return
4129
+
4070
4130
  all_args.update(kwargs)
4071
4131
 
4072
4132
  for i, hook in enumerate(hooks):
4133
+ # Check if this specific hook should run in background (via @hook decorator)
4134
+ if should_run_hook_in_background(hook) and background_tasks is not None:
4135
+ # Copy args to prevent race conditions
4136
+ bg_args = copy_args_for_background(all_args)
4137
+ filtered_args = filter_hook_args(hook, bg_args)
4138
+ background_tasks.add_task(hook, **filtered_args)
4139
+ continue
4140
+
4073
4141
  if stream_events:
4074
4142
  yield handle_event( # type: ignore
4075
4143
  run_response=run_response,
@@ -4121,13 +4189,13 @@ class Agent:
4121
4189
  user_id: Optional[str] = None,
4122
4190
  debug_mode: Optional[bool] = None,
4123
4191
  stream_events: bool = False,
4192
+ background_tasks: Optional[Any] = None,
4124
4193
  **kwargs: Any,
4125
4194
  ) -> AsyncIterator[RunOutputEvent]:
4126
4195
  """Execute multiple pre-hook functions in succession (async version)."""
4127
4196
  if hooks is None:
4128
4197
  return
4129
-
4130
- # Prepare all possible arguments once
4198
+ # Prepare arguments for this hook
4131
4199
  all_args = {
4132
4200
  "run_input": run_input,
4133
4201
  "agent": self,
@@ -4139,9 +4207,32 @@ class Agent:
4139
4207
  "user_id": user_id,
4140
4208
  "debug_mode": debug_mode or self.debug_mode,
4141
4209
  }
4210
+
4211
+ # Check if background_tasks is available and ALL hooks should run in background
4212
+ # Note: Pre-hooks running in background may not be able to modify run_input
4213
+ if self._run_hooks_in_background is True and background_tasks is not None:
4214
+ # Schedule ALL pre_hooks as background tasks
4215
+ # Copy args to prevent race conditions
4216
+ bg_args = copy_args_for_background(all_args)
4217
+ for hook in hooks:
4218
+ # Filter arguments to only include those that the hook accepts
4219
+ filtered_args = filter_hook_args(hook, bg_args)
4220
+
4221
+ # Add to background tasks (both sync and async hooks supported)
4222
+ background_tasks.add_task(hook, **filtered_args)
4223
+ return
4224
+
4142
4225
  all_args.update(kwargs)
4143
4226
 
4144
4227
  for i, hook in enumerate(hooks):
4228
+ # Check if this specific hook should run in background (via @hook decorator)
4229
+ if should_run_hook_in_background(hook) and background_tasks is not None:
4230
+ # Copy args to prevent race conditions
4231
+ bg_args = copy_args_for_background(all_args)
4232
+ filtered_args = filter_hook_args(hook, bg_args)
4233
+ background_tasks.add_task(hook, **filtered_args)
4234
+ continue
4235
+
4145
4236
  if stream_events:
4146
4237
  yield handle_event( # type: ignore
4147
4238
  run_response=run_response,
@@ -4196,13 +4287,14 @@ class Agent:
4196
4287
  user_id: Optional[str] = None,
4197
4288
  debug_mode: Optional[bool] = None,
4198
4289
  stream_events: bool = False,
4290
+ background_tasks: Optional[Any] = None,
4199
4291
  **kwargs: Any,
4200
4292
  ) -> Iterator[RunOutputEvent]:
4201
4293
  """Execute multiple post-hook functions in succession."""
4202
4294
  if hooks is None:
4203
4295
  return
4204
4296
 
4205
- # Prepare all possible arguments once
4297
+ # Prepare arguments for this hook
4206
4298
  all_args = {
4207
4299
  "run_output": run_output,
4208
4300
  "agent": self,
@@ -4214,9 +4306,31 @@ class Agent:
4214
4306
  "run_context": run_context,
4215
4307
  "debug_mode": debug_mode or self.debug_mode,
4216
4308
  }
4309
+
4310
+ # Check if background_tasks is available and ALL hooks should run in background
4311
+ if self._run_hooks_in_background is True and background_tasks is not None:
4312
+ # Schedule ALL post_hooks as background tasks
4313
+ # Copy args to prevent race conditions
4314
+ bg_args = copy_args_for_background(all_args)
4315
+ for hook in hooks:
4316
+ # Filter arguments to only include those that the hook accepts
4317
+ filtered_args = filter_hook_args(hook, bg_args)
4318
+
4319
+ # Add to background tasks
4320
+ background_tasks.add_task(hook, **filtered_args)
4321
+ return
4322
+
4217
4323
  all_args.update(kwargs)
4218
4324
 
4219
4325
  for i, hook in enumerate(hooks):
4326
+ # Check if this specific hook should run in background (via @hook decorator)
4327
+ if should_run_hook_in_background(hook) and background_tasks is not None:
4328
+ # Copy args to prevent race conditions
4329
+ bg_args = copy_args_for_background(all_args)
4330
+ filtered_args = filter_hook_args(hook, bg_args)
4331
+ background_tasks.add_task(hook, **filtered_args)
4332
+ continue
4333
+
4220
4334
  if stream_events:
4221
4335
  yield handle_event( # type: ignore
4222
4336
  run_response=run_output,
@@ -4261,13 +4375,14 @@ class Agent:
4261
4375
  user_id: Optional[str] = None,
4262
4376
  debug_mode: Optional[bool] = None,
4263
4377
  stream_events: bool = False,
4378
+ background_tasks: Optional[Any] = None,
4264
4379
  **kwargs: Any,
4265
4380
  ) -> AsyncIterator[RunOutputEvent]:
4266
4381
  """Execute multiple post-hook functions in succession (async version)."""
4267
4382
  if hooks is None:
4268
4383
  return
4269
4384
 
4270
- # Prepare all possible arguments once
4385
+ # Prepare arguments for this hook
4271
4386
  all_args = {
4272
4387
  "run_output": run_output,
4273
4388
  "agent": self,
@@ -4279,9 +4394,29 @@ class Agent:
4279
4394
  "user_id": user_id,
4280
4395
  "debug_mode": debug_mode or self.debug_mode,
4281
4396
  }
4397
+ # Check if background_tasks is available and ALL hooks should run in background
4398
+ if self._run_hooks_in_background is True and background_tasks is not None:
4399
+ # Copy args to prevent race conditions
4400
+ bg_args = copy_args_for_background(all_args)
4401
+ for hook in hooks:
4402
+ # Filter arguments to only include those that the hook accepts
4403
+ filtered_args = filter_hook_args(hook, bg_args)
4404
+
4405
+ # Add to background tasks (both sync and async hooks supported)
4406
+ background_tasks.add_task(hook, **filtered_args)
4407
+ return
4408
+
4282
4409
  all_args.update(kwargs)
4283
4410
 
4284
4411
  for i, hook in enumerate(hooks):
4412
+ # Check if this specific hook should run in background (via @hook decorator)
4413
+ if should_run_hook_in_background(hook) and background_tasks is not None:
4414
+ # Copy args to prevent race conditions
4415
+ bg_args = copy_args_for_background(all_args)
4416
+ filtered_args = filter_hook_args(hook, bg_args)
4417
+ background_tasks.add_task(hook, **filtered_args)
4418
+ continue
4419
+
4285
4420
  if stream_events:
4286
4421
  yield handle_event( # type: ignore
4287
4422
  run_response=run_output,
@@ -8664,6 +8799,7 @@ class Agent:
8664
8799
  # Update fields if provided
8665
8800
  if update:
8666
8801
  fields_for_new_agent.update(update)
8802
+
8667
8803
  # Create a new Agent
8668
8804
  new_agent = self.__class__(**fields_for_new_agent)
8669
8805
  log_debug(f"Created new {self.__class__.__name__}")
agno/culture/manager.py CHANGED
@@ -118,7 +118,7 @@ class CultureManager:
118
118
 
119
119
  self.db = cast(AsyncBaseDb, self.db)
120
120
 
121
- return await self.db.get_cultural_knowledge(id=id)
121
+ return await self.db.get_cultural_knowledge(id=id) # type: ignore
122
122
 
123
123
  def get_all_knowledge(self, name: Optional[str] = None) -> Optional[List[CulturalKnowledge]]:
124
124
  """Get all cultural knowledge in the database"""
@@ -135,7 +135,7 @@ class CultureManager:
135
135
  return None
136
136
 
137
137
  if isinstance(self.db, AsyncBaseDb):
138
- return await self.db.get_all_cultural_knowledge(name=name)
138
+ return await self.db.get_all_cultural_knowledge(name=name) # type: ignore
139
139
  else:
140
140
  return self.db.get_all_cultural_knowledge(name=name)
141
141