agno 2.1.9__py3-none-any.whl → 2.1.10__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 (54) hide show
  1. agno/agent/agent.py +646 -133
  2. agno/culture/__init__.py +3 -0
  3. agno/culture/manager.py +954 -0
  4. agno/db/async_postgres/async_postgres.py +232 -0
  5. agno/db/async_postgres/schemas.py +15 -0
  6. agno/db/async_postgres/utils.py +58 -0
  7. agno/db/base.py +83 -6
  8. agno/db/dynamo/dynamo.py +162 -0
  9. agno/db/dynamo/schemas.py +44 -0
  10. agno/db/dynamo/utils.py +59 -0
  11. agno/db/firestore/firestore.py +231 -0
  12. agno/db/firestore/schemas.py +10 -0
  13. agno/db/firestore/utils.py +96 -0
  14. agno/db/gcs_json/gcs_json_db.py +190 -0
  15. agno/db/gcs_json/utils.py +58 -0
  16. agno/db/in_memory/in_memory_db.py +118 -0
  17. agno/db/in_memory/utils.py +58 -0
  18. agno/db/json/json_db.py +129 -0
  19. agno/db/json/utils.py +58 -0
  20. agno/db/mongo/mongo.py +222 -0
  21. agno/db/mongo/schemas.py +10 -0
  22. agno/db/mongo/utils.py +59 -0
  23. agno/db/mysql/mysql.py +232 -1
  24. agno/db/mysql/schemas.py +14 -0
  25. agno/db/mysql/utils.py +58 -0
  26. agno/db/postgres/postgres.py +242 -0
  27. agno/db/postgres/schemas.py +15 -0
  28. agno/db/postgres/utils.py +58 -0
  29. agno/db/redis/redis.py +181 -0
  30. agno/db/redis/schemas.py +14 -0
  31. agno/db/redis/utils.py +58 -0
  32. agno/db/schemas/__init__.py +2 -1
  33. agno/db/schemas/culture.py +120 -0
  34. agno/db/singlestore/schemas.py +14 -0
  35. agno/db/singlestore/singlestore.py +231 -0
  36. agno/db/singlestore/utils.py +58 -0
  37. agno/db/sqlite/schemas.py +14 -0
  38. agno/db/sqlite/sqlite.py +274 -7
  39. agno/db/sqlite/utils.py +62 -0
  40. agno/db/surrealdb/models.py +51 -1
  41. agno/db/surrealdb/surrealdb.py +154 -0
  42. agno/db/surrealdb/utils.py +61 -1
  43. agno/knowledge/reader/field_labeled_csv_reader.py +0 -2
  44. agno/memory/manager.py +28 -11
  45. agno/models/message.py +0 -1
  46. agno/os/app.py +28 -6
  47. agno/team/team.py +1 -1
  48. agno/tools/gmail.py +59 -14
  49. agno/workflow/router.py +1 -1
  50. {agno-2.1.9.dist-info → agno-2.1.10.dist-info}/METADATA +1 -1
  51. {agno-2.1.9.dist-info → agno-2.1.10.dist-info}/RECORD +54 -51
  52. {agno-2.1.9.dist-info → agno-2.1.10.dist-info}/WHEEL +0 -0
  53. {agno-2.1.9.dist-info → agno-2.1.10.dist-info}/licenses/LICENSE +0 -0
  54. {agno-2.1.9.dist-info → agno-2.1.10.dist-info}/top_level.txt +0 -0
agno/agent/agent.py CHANGED
@@ -27,7 +27,9 @@ from uuid import uuid4
27
27
 
28
28
  from pydantic import BaseModel
29
29
 
30
+ from agno.culture.manager import CultureManager
30
31
  from agno.db.base import AsyncBaseDb, BaseDb, SessionType, UserMemory
32
+ from agno.db.schemas.culture import CulturalKnowledge
31
33
  from agno.exceptions import (
32
34
  InputCheckError,
33
35
  ModelProviderError,
@@ -349,6 +351,17 @@ class Agent:
349
351
  # Metadata stored with this agent
350
352
  metadata: Optional[Dict[str, Any]] = None
351
353
 
354
+ # --- Experimental Features ---
355
+ # --- Agent Culture ---
356
+ # Culture manager to use for this agent
357
+ culture_manager: Optional[CultureManager] = None
358
+ # Enable the agent to manage cultural knowledge
359
+ enable_agentic_culture: bool = False
360
+ # Update cultural knowledge after every run
361
+ update_cultural_knowledge: bool = False
362
+ # If True, the agent adds cultural knowledge in the response
363
+ add_culture_to_context: Optional[bool] = None
364
+
352
365
  # --- Debug ---
353
366
  # Enable debug logs
354
367
  debug_mode: bool = False
@@ -447,6 +460,10 @@ class Agent:
447
460
  store_events: bool = False,
448
461
  events_to_skip: Optional[List[RunEvent]] = None,
449
462
  role: Optional[str] = None,
463
+ culture_manager: Optional[CultureManager] = None,
464
+ enable_agentic_culture: bool = False,
465
+ update_cultural_knowledge: bool = False,
466
+ add_culture_to_context: Optional[bool] = None,
450
467
  debug_mode: bool = False,
451
468
  debug_level: Literal[1, 2] = 1,
452
469
  telemetry: bool = True,
@@ -566,6 +583,11 @@ class Agent:
566
583
  if self.events_to_skip is None:
567
584
  self.events_to_skip = [RunEvent.run_content]
568
585
 
586
+ self.culture_manager = culture_manager
587
+ self.enable_agentic_culture = enable_agentic_culture
588
+ self.update_cultural_knowledge = update_cultural_knowledge
589
+ self.add_culture_to_context = add_culture_to_context
590
+
569
591
  self.debug_mode = debug_mode
570
592
  if debug_level not in [1, 2]:
571
593
  log_warning(f"Invalid debug level: {debug_level}. Setting to 1.")
@@ -669,6 +691,23 @@ class Agent:
669
691
  f"Cannot validate {type(input)} against input_schema. Expected dict or {self.input_schema.__name__} instance."
670
692
  )
671
693
 
694
+ def _set_culture_manager(self) -> None:
695
+ if self.db is None:
696
+ log_warning("Database not provided. Cultural knowledge will not be stored.")
697
+
698
+ if self.culture_manager is None:
699
+ self.culture_manager = CultureManager(model=self.model, db=self.db)
700
+ else:
701
+ if self.culture_manager.model is None:
702
+ self.culture_manager.model = self.model
703
+ if self.culture_manager.db is None:
704
+ self.culture_manager.db = self.db
705
+
706
+ if self.add_culture_to_context is None:
707
+ self.add_culture_to_context = (
708
+ self.enable_agentic_culture or self.update_cultural_knowledge or self.culture_manager is not None
709
+ )
710
+
672
711
  def _set_memory_manager(self) -> None:
673
712
  if self.db is None:
674
713
  log_warning("Database not provided. Memories will not be stored.")
@@ -709,6 +748,13 @@ class Agent:
709
748
  self.set_id()
710
749
  if self.enable_user_memories or self.enable_agentic_memory or self.memory_manager is not None:
711
750
  self._set_memory_manager()
751
+ if (
752
+ self.add_culture_to_context
753
+ or self.update_cultural_knowledge
754
+ or self.enable_agentic_culture
755
+ or self.culture_manager is not None
756
+ ):
757
+ self._set_culture_manager()
712
758
  if self.enable_session_summaries or self.session_summary_manager is not None:
713
759
  self._set_session_summary_manager()
714
760
 
@@ -791,8 +837,8 @@ class Agent:
791
837
  debug_mode: Optional[bool] = None,
792
838
  **kwargs: Any,
793
839
  ) -> RunOutput:
794
- """
795
- Run the Agent and return the RunOutput.
840
+ """Run the Agent and return the RunOutput.
841
+
796
842
  Steps:
797
843
  1. Execute pre-hooks
798
844
  2. Prepare run messages
@@ -803,7 +849,7 @@ class Agent:
803
849
  7. Calculate session metrics
804
850
  8. Optional: Save output to file if save_response_to_file is set
805
851
  9. Add RunOutput to Agent Session
806
- 10. Update Agent Memory
852
+ 10. Update Agent Memory, Cultural Knowledge and Summaries
807
853
  11. Save session to storage
808
854
  """
809
855
 
@@ -865,7 +911,7 @@ class Agent:
865
911
 
866
912
  log_debug(f"Agent Run Start: {run_response.run_id}", center=True)
867
913
 
868
- # 3. Reason about the task
914
+ # 3. Reason about the task if reasoning is enabled
869
915
  self._handle_reasoning(run_response=run_response, run_messages=run_messages)
870
916
 
871
917
  # Check for cancellation before model call
@@ -894,7 +940,11 @@ class Agent:
894
940
  self._parse_response_with_parser_model(model_response, run_messages)
895
941
 
896
942
  # 5. Update the RunOutput with the model response
897
- self._update_run_response(model_response=model_response, run_response=run_response, run_messages=run_messages)
943
+ self._update_run_response(
944
+ model_response=model_response,
945
+ run_response=run_response,
946
+ run_messages=run_messages,
947
+ )
898
948
 
899
949
  if self.store_media:
900
950
  self._store_media(run_response, model_response)
@@ -902,7 +952,10 @@ class Agent:
902
952
  # We should break out of the run function
903
953
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
904
954
  return self._handle_agent_run_paused(
905
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
955
+ run_response=run_response,
956
+ run_messages=run_messages,
957
+ session=session,
958
+ user_id=user_id,
906
959
  )
907
960
 
908
961
  # Convert the response to the structured format if needed
@@ -931,15 +984,21 @@ class Agent:
931
984
 
932
985
  # 8. Optional: Save output to file if save_response_to_file is set
933
986
  self.save_run_response_to_file(
934
- run_response=run_response, input=run_messages.user_message, session_id=session.session_id, user_id=user_id
987
+ run_response=run_response,
988
+ input=run_messages.user_message,
989
+ session_id=session.session_id,
990
+ user_id=user_id,
935
991
  )
936
992
 
937
993
  # 9. Add the RunOutput to Agent Session
938
994
  session.upsert_run(run=run_response)
939
995
 
940
- # 10. Update Agent Memory
941
- response_iterator = self._make_memories_and_summaries(
942
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
996
+ # 10. Update Agent Memory, Cultural Knowledge and Summaries
997
+ response_iterator = self._make_memories_cultural_knowledge_and_summaries(
998
+ run_response=run_response,
999
+ run_messages=run_messages,
1000
+ session=session,
1001
+ user_id=user_id,
943
1002
  )
944
1003
  # Consume the response iterator to ensure the memory is updated before the run is completed
945
1004
  deque(response_iterator, maxlen=0)
@@ -989,7 +1048,7 @@ class Agent:
989
1048
  5. Calculate session metrics
990
1049
  6. Optional: Save output to file if save_response_to_file is set
991
1050
  7. Add the RunOutput to the Agent Session
992
- 8. Update Agent Memory
1051
+ 8. Update Agent Memory, Cultural Knowledge and Summaries
993
1052
  9. Create the run completed event
994
1053
  10. Save session to storage
995
1054
  """
@@ -1063,7 +1122,7 @@ class Agent:
1063
1122
  # Check for cancellation before model processing
1064
1123
  raise_if_cancelled(run_response.run_id) # type: ignore
1065
1124
 
1066
- # 4. Process model response
1125
+ # 4. Generate a response from the Model (includes running function calls)
1067
1126
  if self.output_model is None:
1068
1127
  for event in self._handle_model_response_stream(
1069
1128
  session=session,
@@ -1112,13 +1171,18 @@ class Agent:
1112
1171
 
1113
1172
  # If a parser model is provided, structure the response separately
1114
1173
  yield from self._parse_response_with_parser_model_stream(
1115
- session=session, run_response=run_response, stream_intermediate_steps=stream_intermediate_steps
1174
+ session=session,
1175
+ run_response=run_response,
1176
+ stream_intermediate_steps=stream_intermediate_steps,
1116
1177
  )
1117
1178
 
1118
1179
  # We should break out of the run function
1119
1180
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
1120
1181
  yield from self._handle_agent_run_paused_stream(
1121
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
1182
+ run_response=run_response,
1183
+ run_messages=run_messages,
1184
+ session=session,
1185
+ user_id=user_id,
1122
1186
  )
1123
1187
  return
1124
1188
 
@@ -1156,9 +1220,12 @@ class Agent:
1156
1220
  # 7. Add RunOutput to Agent Session
1157
1221
  session.upsert_run(run=run_response)
1158
1222
 
1159
- # 8. Update Agent Memory
1160
- yield from self._make_memories_and_summaries(
1161
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
1223
+ # 8. Update Agent Memory, Cultural Knowledge and Summaries
1224
+ yield from self._make_memories_cultural_knowledge_and_summaries(
1225
+ run_response=run_response,
1226
+ run_messages=run_messages,
1227
+ session=session,
1228
+ user_id=user_id,
1162
1229
  )
1163
1230
 
1164
1231
  # 9. Create the run completed event
@@ -1299,7 +1366,10 @@ class Agent:
1299
1366
  self._hooks_normalised = True
1300
1367
 
1301
1368
  session_id, user_id, session_state = self._initialize_session(
1302
- run_id=run_id, session_id=session_id, user_id=user_id, session_state=session_state
1369
+ run_id=run_id,
1370
+ session_id=session_id,
1371
+ user_id=user_id,
1372
+ session_state=session_state,
1303
1373
  )
1304
1374
 
1305
1375
  # Initialize the Agent
@@ -1470,7 +1540,10 @@ class Agent:
1470
1540
 
1471
1541
  if stream:
1472
1542
  return generator_wrapper( # type: ignore
1473
- create_run_cancelled_event(from_run_response=run_response, reason="Operation cancelled by user")
1543
+ create_run_cancelled_event(
1544
+ from_run_response=run_response,
1545
+ reason="Operation cancelled by user",
1546
+ )
1474
1547
  )
1475
1548
  else:
1476
1549
  return run_response
@@ -1623,7 +1696,9 @@ class Agent:
1623
1696
 
1624
1697
  # 9. Update the RunOutput with the model response
1625
1698
  self._update_run_response(
1626
- model_response=model_response, run_response=run_response, run_messages=run_messages
1699
+ model_response=model_response,
1700
+ run_response=run_response,
1701
+ run_messages=run_messages,
1627
1702
  )
1628
1703
 
1629
1704
  # Optional: Store media
@@ -1633,7 +1708,10 @@ class Agent:
1633
1708
  # Break out of the run function if a tool call is paused
1634
1709
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
1635
1710
  return self._handle_agent_run_paused(
1636
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
1711
+ run_response=run_response,
1712
+ run_messages=run_messages,
1713
+ session=agent_session,
1714
+ user_id=user_id,
1637
1715
  )
1638
1716
  raise_if_cancelled(run_response.run_id) # type: ignore
1639
1717
 
@@ -1675,9 +1753,12 @@ class Agent:
1675
1753
  # 11. Add RunOutput to Agent Session
1676
1754
  agent_session.upsert_run(run=run_response)
1677
1755
 
1678
- # 12. Update Agent Memory
1679
- async for _ in self._amake_memories_and_summaries(
1680
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
1756
+ # 12. Update Agent Memory, Cultural Knowledge and Summaries
1757
+ async for _ in self._amake_memories_cultural_knowledge_and_summaries(
1758
+ run_response=run_response,
1759
+ run_messages=run_messages,
1760
+ session=agent_session,
1761
+ user_id=user_id,
1681
1762
  ):
1682
1763
  pass
1683
1764
 
@@ -1884,14 +1965,19 @@ class Agent:
1884
1965
 
1885
1966
  # If a parser model is provided, structure the response separately
1886
1967
  async for event in self._aparse_response_with_parser_model_stream(
1887
- session=agent_session, run_response=run_response, stream_intermediate_steps=stream_intermediate_steps
1968
+ session=agent_session,
1969
+ run_response=run_response,
1970
+ stream_intermediate_steps=stream_intermediate_steps,
1888
1971
  ):
1889
1972
  yield event
1890
1973
 
1891
1974
  # Break out of the run function if a tool call is paused
1892
1975
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
1893
1976
  for item in self._handle_agent_run_paused_stream(
1894
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
1977
+ run_response=run_response,
1978
+ run_messages=run_messages,
1979
+ session=agent_session,
1980
+ user_id=user_id,
1895
1981
  ):
1896
1982
  yield item
1897
1983
  return
@@ -1932,8 +2018,11 @@ class Agent:
1932
2018
  agent_session.upsert_run(run=run_response)
1933
2019
 
1934
2020
  # 11. Update Agent Memory
1935
- async for event in self._amake_memories_and_summaries(
1936
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
2021
+ async for event in self._amake_memories_cultural_knowledge_and_summaries(
2022
+ run_response=run_response,
2023
+ run_messages=run_messages,
2024
+ session=agent_session,
2025
+ user_id=user_id,
1937
2026
  ):
1938
2027
  yield event
1939
2028
 
@@ -2077,7 +2166,10 @@ class Agent:
2077
2166
 
2078
2167
  # Initialize session
2079
2168
  session_id, user_id, session_state = self._initialize_session(
2080
- run_id=run_id, session_id=session_id, user_id=user_id, session_state=session_state
2169
+ run_id=run_id,
2170
+ session_id=session_id,
2171
+ user_id=user_id,
2172
+ session_state=session_state,
2081
2173
  )
2082
2174
 
2083
2175
  # Initialize the Agent
@@ -2224,7 +2316,10 @@ class Agent:
2224
2316
 
2225
2317
  if stream:
2226
2318
  return async_generator_wrapper( # type: ignore
2227
- create_run_cancelled_event(from_run_response=run_response, reason="Operation cancelled by user")
2319
+ create_run_cancelled_event(
2320
+ from_run_response=run_response,
2321
+ reason="Operation cancelled by user",
2322
+ )
2228
2323
  )
2229
2324
  else:
2230
2325
  return run_response
@@ -2531,12 +2626,19 @@ class Agent:
2531
2626
  tool_call_limit=self.tool_call_limit,
2532
2627
  )
2533
2628
 
2534
- self._update_run_response(model_response=model_response, run_response=run_response, run_messages=run_messages)
2629
+ self._update_run_response(
2630
+ model_response=model_response,
2631
+ run_response=run_response,
2632
+ run_messages=run_messages,
2633
+ )
2535
2634
 
2536
2635
  # We should break out of the run function
2537
2636
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
2538
2637
  return self._handle_agent_run_paused(
2539
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
2638
+ run_response=run_response,
2639
+ run_messages=run_messages,
2640
+ session=session,
2641
+ user_id=user_id,
2540
2642
  )
2541
2643
 
2542
2644
  # 3. Calculate session metrics
@@ -2565,15 +2667,21 @@ class Agent:
2565
2667
 
2566
2668
  # 4. Save output to file if save_response_to_file is set
2567
2669
  self.save_run_response_to_file(
2568
- run_response=run_response, input=run_messages.user_message, session_id=session.session_id, user_id=user_id
2670
+ run_response=run_response,
2671
+ input=run_messages.user_message,
2672
+ session_id=session.session_id,
2673
+ user_id=user_id,
2569
2674
  )
2570
2675
 
2571
2676
  # 5. Add the run to memory
2572
2677
  session.upsert_run(run=run_response)
2573
2678
 
2574
- # 6. Update Agent Memory
2575
- response_iterator = self._make_memories_and_summaries(
2576
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
2679
+ # 6. Update Agent Memory, Cultural Knowledge and Summaries
2680
+ response_iterator = self._make_memories_cultural_knowledge_and_summaries(
2681
+ run_response=run_response,
2682
+ run_messages=run_messages,
2683
+ session=session,
2684
+ user_id=user_id,
2577
2685
  )
2578
2686
  # Consume the response iterator to ensure the memory is updated before the run is completed
2579
2687
  deque(response_iterator, maxlen=0)
@@ -2636,7 +2744,10 @@ class Agent:
2636
2744
  # We should break out of the run function
2637
2745
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
2638
2746
  yield from self._handle_agent_run_paused_stream(
2639
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
2747
+ run_response=run_response,
2748
+ run_messages=run_messages,
2749
+ session=session,
2750
+ user_id=user_id,
2640
2751
  )
2641
2752
  return
2642
2753
 
@@ -2664,15 +2775,21 @@ class Agent:
2664
2775
 
2665
2776
  # 4. Save output to file if save_response_to_file is set
2666
2777
  self.save_run_response_to_file(
2667
- run_response=run_response, input=run_messages.user_message, session_id=session.session_id, user_id=user_id
2778
+ run_response=run_response,
2779
+ input=run_messages.user_message,
2780
+ session_id=session.session_id,
2781
+ user_id=user_id,
2668
2782
  )
2669
2783
 
2670
2784
  # 5. Add the run to memory
2671
2785
  session.upsert_run(run=run_response)
2672
2786
 
2673
2787
  # 6. Update Agent Memory
2674
- yield from self._make_memories_and_summaries(
2675
- run_response=run_response, run_messages=run_messages, session=session, user_id=user_id
2788
+ yield from self._make_memories_cultural_knowledge_and_summaries(
2789
+ run_response=run_response,
2790
+ run_messages=run_messages,
2791
+ session=session,
2792
+ user_id=user_id,
2676
2793
  )
2677
2794
 
2678
2795
  # 7. Create the run completed event
@@ -2998,7 +3115,9 @@ class Agent:
2998
3115
 
2999
3116
  # 9. Update the RunOutput with the model response
3000
3117
  self._update_run_response(
3001
- model_response=model_response, run_response=run_response, run_messages=run_messages
3118
+ model_response=model_response,
3119
+ run_response=run_response,
3120
+ run_messages=run_messages,
3002
3121
  )
3003
3122
 
3004
3123
  if self.store_media:
@@ -3009,7 +3128,10 @@ class Agent:
3009
3128
  # Break out of the run function if a tool call is paused
3010
3129
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
3011
3130
  return self._handle_agent_run_paused(
3012
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
3131
+ run_response=run_response,
3132
+ run_messages=run_messages,
3133
+ session=agent_session,
3134
+ user_id=user_id,
3013
3135
  )
3014
3136
  raise_if_cancelled(run_response.run_id) # type: ignore
3015
3137
 
@@ -3039,8 +3161,11 @@ class Agent:
3039
3161
  run_response.metrics.stop_timer()
3040
3162
 
3041
3163
  # 12. Update Agent Memory
3042
- async for _ in self._amake_memories_and_summaries(
3043
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
3164
+ async for _ in self._amake_memories_cultural_knowledge_and_summaries(
3165
+ run_response=run_response,
3166
+ run_messages=run_messages,
3167
+ session=agent_session,
3168
+ user_id=user_id,
3044
3169
  ):
3045
3170
  pass
3046
3171
 
@@ -3238,7 +3363,10 @@ class Agent:
3238
3363
  # Break out of the run function if a tool call is paused
3239
3364
  if any(tool_call.is_paused for tool_call in run_response.tools or []):
3240
3365
  for item in self._handle_agent_run_paused_stream(
3241
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
3366
+ run_response=run_response,
3367
+ run_messages=run_messages,
3368
+ session=agent_session,
3369
+ user_id=user_id,
3242
3370
  ):
3243
3371
  yield item
3244
3372
  return
@@ -3281,8 +3409,11 @@ class Agent:
3281
3409
  self._update_session_metrics(session=agent_session, run_response=run_response)
3282
3410
 
3283
3411
  # 12. Update Agent Memory
3284
- async for event in self._amake_memories_and_summaries(
3285
- run_response=run_response, run_messages=run_messages, session=agent_session, user_id=user_id
3412
+ async for event in self._amake_memories_cultural_knowledge_and_summaries(
3413
+ run_response=run_response,
3414
+ run_messages=run_messages,
3415
+ session=agent_session,
3416
+ user_id=user_id,
3286
3417
  ):
3287
3418
  yield event
3288
3419
 
@@ -3358,7 +3489,9 @@ class Agent:
3358
3489
  yield self._handle_event(
3359
3490
  run_response=run_response,
3360
3491
  event=create_pre_hook_started_event(
3361
- from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
3492
+ from_run_response=run_response,
3493
+ run_input=run_input,
3494
+ pre_hook_name=hook.__name__,
3362
3495
  ),
3363
3496
  )
3364
3497
  try:
@@ -3370,7 +3503,9 @@ class Agent:
3370
3503
  yield self._handle_event(
3371
3504
  run_response=run_response,
3372
3505
  event=create_pre_hook_completed_event(
3373
- from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
3506
+ from_run_response=run_response,
3507
+ run_input=run_input,
3508
+ pre_hook_name=hook.__name__,
3374
3509
  ),
3375
3510
  )
3376
3511
 
@@ -3420,7 +3555,9 @@ class Agent:
3420
3555
  yield self._handle_event(
3421
3556
  run_response=run_response,
3422
3557
  event=create_pre_hook_started_event(
3423
- from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
3558
+ from_run_response=run_response,
3559
+ run_input=run_input,
3560
+ pre_hook_name=hook.__name__,
3424
3561
  ),
3425
3562
  )
3426
3563
  try:
@@ -3436,7 +3573,9 @@ class Agent:
3436
3573
  yield self._handle_event(
3437
3574
  run_response=run_response,
3438
3575
  event=create_pre_hook_completed_event(
3439
- from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
3576
+ from_run_response=run_response,
3577
+ run_input=run_input,
3578
+ pre_hook_name=hook.__name__,
3440
3579
  ),
3441
3580
  )
3442
3581
 
@@ -3559,7 +3698,10 @@ class Agent:
3559
3698
 
3560
3699
  # Save output to file if save_response_to_file is set
3561
3700
  self.save_run_response_to_file(
3562
- run_response=run_response, input=run_messages.user_message, session_id=session.session_id, user_id=user_id
3701
+ run_response=run_response,
3702
+ input=run_messages.user_message,
3703
+ session_id=session.session_id,
3704
+ user_id=user_id,
3563
3705
  )
3564
3706
 
3565
3707
  session.upsert_run(run=run_response)
@@ -3596,7 +3738,10 @@ class Agent:
3596
3738
 
3597
3739
  # Save output to file if save_response_to_file is set
3598
3740
  self.save_run_response_to_file(
3599
- run_response=run_response, input=run_messages.user_message, session_id=session.session_id, user_id=user_id
3741
+ run_response=run_response,
3742
+ input=run_messages.user_message,
3743
+ session_id=session.session_id,
3744
+ user_id=user_id,
3600
3745
  )
3601
3746
  session.upsert_run(run=run_response)
3602
3747
  # Save session to storage
@@ -3703,7 +3848,9 @@ class Agent:
3703
3848
  tool.tool_call_error = tool_execution.tool_call_error
3704
3849
  yield self._handle_event(
3705
3850
  create_tool_call_completed_event(
3706
- from_run_response=run_response, tool=tool, content=call_result.content
3851
+ from_run_response=run_response,
3852
+ tool=tool,
3853
+ content=call_result.content,
3707
3854
  ),
3708
3855
  run_response,
3709
3856
  )
@@ -3750,7 +3897,9 @@ class Agent:
3750
3897
  tool.tool_call_error = tool_execution.tool_call_error
3751
3898
  yield self._handle_event(
3752
3899
  create_tool_call_completed_event(
3753
- from_run_response=run_response, tool=tool, content=call_result.content
3900
+ from_run_response=run_response,
3901
+ tool=tool,
3902
+ content=call_result.content,
3754
3903
  ),
3755
3904
  run_response,
3756
3905
  )
@@ -3925,7 +4074,12 @@ class Agent:
3925
4074
  for file in model_response.files:
3926
4075
  self._add_file(file, run_response) # Generated files go to run_response.files
3927
4076
 
3928
- def _update_run_response(self, model_response: ModelResponse, run_response: RunOutput, run_messages: RunMessages):
4077
+ def _update_run_response(
4078
+ self,
4079
+ model_response: ModelResponse,
4080
+ run_response: RunOutput,
4081
+ run_messages: RunMessages,
4082
+ ):
3929
4083
  # Handle structured outputs
3930
4084
  if self.output_schema is not None and model_response.parsed is not None:
3931
4085
  # We get native structured outputs from the model
@@ -3966,7 +4120,9 @@ class Agent:
3966
4120
  if tool_name.lower() in ["think", "analyze"]:
3967
4121
  tool_args = tool_call.tool_args or {}
3968
4122
  self._update_reasoning_content_from_tool_call(
3969
- run_response=run_response, tool_name=tool_name, tool_args=tool_args
4123
+ run_response=run_response,
4124
+ tool_name=tool_name,
4125
+ tool_args=tool_args,
3970
4126
  )
3971
4127
 
3972
4128
  # Update the run_response audio with the model response audio
@@ -4045,7 +4201,8 @@ class Agent:
4045
4201
 
4046
4202
  if all_reasoning_steps:
4047
4203
  add_reasoning_metrics_to_metadata(
4048
- run_response=run_response, reasoning_time_taken=reasoning_state["reasoning_time_taken"]
4204
+ run_response=run_response,
4205
+ reasoning_time_taken=reasoning_state["reasoning_time_taken"],
4049
4206
  )
4050
4207
  yield self._handle_event(
4051
4208
  create_reasoning_completed_event(
@@ -4122,7 +4279,8 @@ class Agent:
4122
4279
 
4123
4280
  if all_reasoning_steps:
4124
4281
  add_reasoning_metrics_to_metadata(
4125
- run_response=run_response, reasoning_time_taken=reasoning_state["reasoning_time_taken"]
4282
+ run_response=run_response,
4283
+ reasoning_time_taken=reasoning_state["reasoning_time_taken"],
4126
4284
  )
4127
4285
  yield self._handle_event(
4128
4286
  create_reasoning_completed_event(
@@ -4342,14 +4500,16 @@ class Agent:
4342
4500
  # Yield each tool call started event
4343
4501
  for tool in tool_executions_list:
4344
4502
  yield self._handle_event(
4345
- create_tool_call_started_event(from_run_response=run_response, tool=tool), run_response
4503
+ create_tool_call_started_event(from_run_response=run_response, tool=tool),
4504
+ run_response,
4346
4505
  )
4347
4506
 
4348
4507
  # If the model response is a tool_call_completed, update the existing tool call in the run_response
4349
4508
  elif model_response_event.event == ModelResponseEvent.tool_call_completed.value:
4350
4509
  if model_response_event.updated_session_state is not None and session.session_data is not None:
4351
4510
  merge_dictionaries(
4352
- session.session_data["session_state"], model_response_event.updated_session_state
4511
+ session.session_data["session_state"],
4512
+ model_response_event.updated_session_state,
4353
4513
  )
4354
4514
 
4355
4515
  if model_response_event.images is not None:
@@ -4390,7 +4550,9 @@ class Agent:
4390
4550
  tool_args = tool_call.tool_args or {}
4391
4551
 
4392
4552
  reasoning_step = self._update_reasoning_content_from_tool_call(
4393
- run_response=run_response, tool_name=tool_name, tool_args=tool_args
4553
+ run_response=run_response,
4554
+ tool_name=tool_name,
4555
+ tool_args=tool_args,
4394
4556
  )
4395
4557
 
4396
4558
  tool_call_metrics = tool_call.metrics
@@ -4406,7 +4568,9 @@ class Agent:
4406
4568
 
4407
4569
  yield self._handle_event(
4408
4570
  create_tool_call_completed_event(
4409
- from_run_response=run_response, tool=tool_call, content=model_response_event.content
4571
+ from_run_response=run_response,
4572
+ tool=tool_call,
4573
+ content=model_response_event.content,
4410
4574
  ),
4411
4575
  run_response,
4412
4576
  )
@@ -4415,7 +4579,8 @@ class Agent:
4415
4579
  if reasoning_step is not None:
4416
4580
  if reasoning_state and not reasoning_state["reasoning_started"]:
4417
4581
  yield self._handle_event(
4418
- create_reasoning_started_event(from_run_response=run_response), run_response
4582
+ create_reasoning_started_event(from_run_response=run_response),
4583
+ run_response,
4419
4584
  )
4420
4585
  reasoning_state["reasoning_started"] = True
4421
4586
 
@@ -4428,7 +4593,7 @@ class Agent:
4428
4593
  run_response,
4429
4594
  )
4430
4595
 
4431
- def _make_memories_and_summaries(
4596
+ def _make_memories_cultural_knowledge_and_summaries(
4432
4597
  self,
4433
4598
  run_response: RunOutput,
4434
4599
  run_messages: RunMessages,
@@ -4440,10 +4605,11 @@ class Agent:
4440
4605
  with ThreadPoolExecutor(max_workers=3) as executor:
4441
4606
  futures = []
4442
4607
 
4443
- # Create user memories
4444
4608
  user_message_str = (
4445
4609
  run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
4446
4610
  )
4611
+
4612
+ # Create user memories
4447
4613
  if user_message_str is not None and self.memory_manager is not None and not self.enable_agentic_memory:
4448
4614
  log_debug("Creating user memories.")
4449
4615
  futures.append(
@@ -4486,6 +4652,16 @@ class Agent:
4486
4652
  else:
4487
4653
  log_warning("Unable to add messages to memory")
4488
4654
 
4655
+ # Create cultural knowledge
4656
+ if user_message_str is not None and self.culture_manager is not None and self.update_cultural_knowledge:
4657
+ log_debug("Creating cultural knowledge.")
4658
+ futures.append(
4659
+ executor.submit(
4660
+ self.culture_manager.create_cultural_knowledge,
4661
+ message=user_message_str,
4662
+ )
4663
+ )
4664
+
4489
4665
  # Create session summary
4490
4666
  if self.session_summary_manager is not None:
4491
4667
  log_debug("Creating session summary.")
@@ -4499,7 +4675,8 @@ class Agent:
4499
4675
  if futures:
4500
4676
  if self.stream_intermediate_steps:
4501
4677
  yield self._handle_event(
4502
- create_memory_update_started_event(from_run_response=run_response), run_response
4678
+ create_memory_update_started_event(from_run_response=run_response),
4679
+ run_response,
4503
4680
  )
4504
4681
 
4505
4682
  # Wait for all operations to complete and handle any errors
@@ -4511,10 +4688,11 @@ class Agent:
4511
4688
 
4512
4689
  if self.stream_intermediate_steps:
4513
4690
  yield self._handle_event(
4514
- create_memory_update_completed_event(from_run_response=run_response), run_response
4691
+ create_memory_update_completed_event(from_run_response=run_response),
4692
+ run_response,
4515
4693
  )
4516
4694
 
4517
- async def _amake_memories_and_summaries(
4695
+ async def _amake_memories_cultural_knowledge_and_summaries(
4518
4696
  self,
4519
4697
  run_response: RunOutput,
4520
4698
  run_messages: RunMessages,
@@ -4529,7 +4707,9 @@ class Agent:
4529
4707
 
4530
4708
  tasks.append(
4531
4709
  self.memory_manager.acreate_user_memories(
4532
- message=run_messages.user_message.get_content_string(), user_id=user_id, agent_id=self.id
4710
+ message=run_messages.user_message.get_content_string(),
4711
+ user_id=user_id,
4712
+ agent_id=self.id,
4533
4713
  )
4534
4714
  )
4535
4715
 
@@ -4561,6 +4741,18 @@ class Agent:
4561
4741
  else:
4562
4742
  log_warning("Unable to add messages to memory")
4563
4743
 
4744
+ # Create cultural knowledge
4745
+ if (
4746
+ run_messages.user_message is not None
4747
+ and self.culture_manager is not None
4748
+ and self.update_cultural_knowledge
4749
+ ):
4750
+ log_debug("Creating cultural knowledge.")
4751
+
4752
+ tasks.append(
4753
+ self.culture_manager.acreate_cultural_knowledge(message=run_messages.user_message.get_content_string())
4754
+ )
4755
+
4564
4756
  # Create session summary
4565
4757
  if self.session_summary_manager is not None:
4566
4758
  log_debug("Creating session summary.")
@@ -4573,7 +4765,8 @@ class Agent:
4573
4765
  if tasks:
4574
4766
  if self.stream_intermediate_steps:
4575
4767
  yield self._handle_event(
4576
- create_memory_update_started_event(from_run_response=run_response), run_response
4768
+ create_memory_update_started_event(from_run_response=run_response),
4769
+ run_response,
4577
4770
  )
4578
4771
 
4579
4772
  # Execute all tasks concurrently and handle any errors
@@ -4584,7 +4777,8 @@ class Agent:
4584
4777
 
4585
4778
  if self.stream_intermediate_steps:
4586
4779
  yield self._handle_event(
4587
- create_memory_update_completed_event(from_run_response=run_response), run_response
4780
+ create_memory_update_completed_event(from_run_response=run_response),
4781
+ run_response,
4588
4782
  )
4589
4783
 
4590
4784
  def _raise_if_async_tools(self) -> None:
@@ -4634,7 +4828,15 @@ class Agent:
4634
4828
 
4635
4829
  # If any of the tools has "agent" as parameter, set _rebuild_tools to True
4636
4830
  for tool in agent_tools:
4637
- param_names = {"agent", "session_state", "team", "images", "videos", "audios", "files"}
4831
+ param_names = {
4832
+ "agent",
4833
+ "session_state",
4834
+ "team",
4835
+ "images",
4836
+ "videos",
4837
+ "audios",
4838
+ "files",
4839
+ }
4638
4840
 
4639
4841
  if isinstance(tool, Function):
4640
4842
  if param_names & set(tool.parameters):
@@ -4671,6 +4873,10 @@ class Agent:
4671
4873
  agent_tools.append(self._get_update_user_memory_function(user_id=user_id, async_mode=async_mode))
4672
4874
  self._rebuild_tools = True
4673
4875
 
4876
+ if self.enable_agentic_culture:
4877
+ agent_tools.append(self._get_update_cultural_knowledge_function(async_mode=async_mode))
4878
+ self._rebuild_tools = True
4879
+
4674
4880
  if self.enable_agentic_state:
4675
4881
  agent_tools.append(self.update_session_state)
4676
4882
 
@@ -4690,13 +4896,17 @@ class Agent:
4690
4896
  if self.enable_agentic_knowledge_filters:
4691
4897
  agent_tools.append(
4692
4898
  self._search_knowledge_base_with_agentic_filters_function(
4693
- run_response=run_response, async_mode=async_mode, knowledge_filters=knowledge_filters
4899
+ run_response=run_response,
4900
+ async_mode=async_mode,
4901
+ knowledge_filters=knowledge_filters,
4694
4902
  )
4695
4903
  )
4696
4904
  else:
4697
4905
  agent_tools.append(
4698
4906
  self._get_search_knowledge_base_function(
4699
- run_response=run_response, async_mode=async_mode, knowledge_filters=knowledge_filters
4907
+ run_response=run_response,
4908
+ async_mode=async_mode,
4909
+ knowledge_filters=knowledge_filters,
4700
4910
  )
4701
4911
  )
4702
4912
  self._rebuild_tools = True
@@ -4784,13 +4994,17 @@ class Agent:
4784
4994
  if self.enable_agentic_knowledge_filters:
4785
4995
  agent_tools.append(
4786
4996
  self._search_knowledge_base_with_agentic_filters_function(
4787
- run_response=run_response, async_mode=async_mode, knowledge_filters=knowledge_filters
4997
+ run_response=run_response,
4998
+ async_mode=async_mode,
4999
+ knowledge_filters=knowledge_filters,
4788
5000
  )
4789
5001
  )
4790
5002
  else:
4791
5003
  agent_tools.append(
4792
5004
  self._get_search_knowledge_base_function(
4793
- run_response=run_response, async_mode=async_mode, knowledge_filters=knowledge_filters
5005
+ run_response=run_response,
5006
+ async_mode=async_mode,
5007
+ knowledge_filters=knowledge_filters,
4794
5008
  )
4795
5009
  )
4796
5010
  self._rebuild_tools = True
@@ -5614,7 +5828,10 @@ class Agent:
5614
5828
  self.save_session(session=session) # type: ignore
5615
5829
 
5616
5830
  def set_session_name(
5617
- self, session_id: Optional[str] = None, autogenerate: bool = False, session_name: Optional[str] = None
5831
+ self,
5832
+ session_id: Optional[str] = None,
5833
+ autogenerate: bool = False,
5834
+ session_name: Optional[str] = None,
5618
5835
  ) -> AgentSession:
5619
5836
  """Set the session name and save to storage"""
5620
5837
  session_id = session_id or self.session_id
@@ -5775,6 +5992,20 @@ class Agent:
5775
5992
 
5776
5993
  return await self.memory_manager.aget_user_memories(user_id=user_id)
5777
5994
 
5995
+ def get_culture_knowledge(self) -> Optional[List[CulturalKnowledge]]:
5996
+ """Get the cultural knowledge the agent has access to"""
5997
+ if self.culture_manager is None:
5998
+ return None
5999
+
6000
+ return self.culture_manager.get_all_knowledge()
6001
+
6002
+ async def aget_culture_knowledge(self) -> Optional[List[CulturalKnowledge]]:
6003
+ """Get the cultural knowledge the agent has access to"""
6004
+ if self.culture_manager is None:
6005
+ return None
6006
+
6007
+ return await self.culture_manager.aget_all_knowledge()
6008
+
5778
6009
  def _format_message_with_state_variables(
5779
6010
  self,
5780
6011
  message: Any,
@@ -5924,7 +6155,14 @@ class Agent:
5924
6155
  location = get_location()
5925
6156
  if location:
5926
6157
  location_str = ", ".join(
5927
- filter(None, [location.get("city"), location.get("region"), location.get("country")])
6158
+ filter(
6159
+ None,
6160
+ [
6161
+ location.get("city"),
6162
+ location.get("region"),
6163
+ location.get("country"),
6164
+ ],
6165
+ )
5928
6166
  )
5929
6167
  if location_str:
5930
6168
  additional_information.append(f"Your approximate location is: {location_str}.")
@@ -5939,7 +6177,8 @@ class Agent:
5939
6177
  if valid_filters:
5940
6178
  valid_filters_str = ", ".join(valid_filters)
5941
6179
  additional_information.append(
5942
- dedent(f"""
6180
+ dedent(
6181
+ f"""
5943
6182
  The knowledge base contains documents with these metadata filters: {valid_filters_str}.
5944
6183
  Always use filters when the user query indicates specific metadata.
5945
6184
 
@@ -5955,7 +6194,8 @@ class Agent:
5955
6194
  - Ensure the filter keys match the valid metadata filters: {valid_filters_str}.
5956
6195
 
5957
6196
  You can use the search_knowledge_base tool to search the knowledge base and get the most relevant documents. Make sure to pass the filters as [Dict[str: Any]] to the tool. FOLLOW THIS STRUCTURE STRICTLY.
5958
- """)
6197
+ """
6198
+ )
5959
6199
  )
5960
6200
 
5961
6201
  # 3.3 Build the default system message for the Agent.
@@ -6043,6 +6283,67 @@ class Agent:
6043
6283
  "</updating_user_memories>\n\n"
6044
6284
  )
6045
6285
 
6286
+ # 3.3.10 Then add cultural knowledge to the system prompt
6287
+ if self.add_culture_to_context:
6288
+ _culture_manager_not_set = None
6289
+ if not self.culture_manager:
6290
+ self._set_culture_manager()
6291
+ _culture_manager_not_set = True
6292
+
6293
+ cultural_knowledge = self.culture_manager.get_all_knowledge() # type: ignore
6294
+
6295
+ if cultural_knowledge and len(cultural_knowledge) > 0:
6296
+ system_message_content += (
6297
+ "You have access to shared **Cultural Knowledge**, which provides context, norms, rules and guidance "
6298
+ "for your reasoning, communication, and decision-making. "
6299
+ "Cultural Knowledge represents the collective understanding, values, rules and practices that have "
6300
+ "emerged across agents and teams. It encodes collective experience — including preferred "
6301
+ "approaches, common patterns, lessons learned, and ethical guardrails.\n\n"
6302
+ "When performing any task:\n"
6303
+ "- **Reference Cultural Knowledge** to align with shared norms and best practices.\n"
6304
+ "- **Apply it contextually**, not mechanically — adapt principles to the current situation.\n"
6305
+ "- **Preserve consistency** with cultural values (tone, reasoning, and style) unless explicitly told otherwise.\n"
6306
+ "- **Extend it** when you discover new insights — your outputs may become future Cultural Knowledge.\n"
6307
+ "- **Clarify conflicts** if Cultural Knowledge appears to contradict explicit user instructions.\n\n"
6308
+ "Your goal is to act not only intelligently but also *culturally coherently* — reflecting the "
6309
+ "collective intelligence of the system.\n\n"
6310
+ "Below is the currently available Cultural Knowledge for this context:\n\n"
6311
+ )
6312
+ system_message_content += "<cultural_knowledge>"
6313
+ for _knowledge in cultural_knowledge: # type: ignore
6314
+ system_message_content += "\n---"
6315
+ system_message_content += f"\nName: {_knowledge.name}"
6316
+ system_message_content += f"\nSummary: {_knowledge.summary}"
6317
+ system_message_content += f"\nContent: {_knowledge.content}"
6318
+ system_message_content += "\n</cultural_knowledge>\n"
6319
+ else:
6320
+ system_message_content += (
6321
+ "You have the capability to access shared **Cultural Knowledge**, which normally provides "
6322
+ "context, norms, and guidance for your behavior and reasoning. However, no cultural knowledge "
6323
+ "is currently available in this session.\n"
6324
+ "Proceed thoughtfully and document any useful insights you create — they may become future "
6325
+ "Cultural Knowledge for others.\n\n"
6326
+ )
6327
+
6328
+ if _culture_manager_not_set:
6329
+ self.culture_manager = None
6330
+
6331
+ if self.enable_agentic_culture:
6332
+ system_message_content += (
6333
+ "\n<contributing_to_culture>\n"
6334
+ "When you discover an insight, pattern, rule, or best practice that will help future agents, use the `create_or_update_cultural_knowledge` tool to add or update entries in the shared cultural knowledge.\n"
6335
+ "\n"
6336
+ "When to contribute:\n"
6337
+ "- You discover a reusable insight, pattern, rule, or best practice that will help future agents.\n"
6338
+ "- You correct or clarify an existing cultural entry.\n"
6339
+ "- You capture a guardrail, decision rationale, postmortem lesson, or example template.\n"
6340
+ "- You identify missing context that should persist across sessions or teams.\n"
6341
+ "\n"
6342
+ "Cultural knowledge should capture reusable insights, best practices, or contextual knowledge that transcends individual conversations.\n"
6343
+ "Mention your contribution to the user only if it is relevant to their request or they asked to be notified.\n"
6344
+ "</contributing_to_culture>\n\n"
6345
+ )
6346
+
6046
6347
  # 3.3.11 Then add a summary of the interaction to the system prompt
6047
6348
  if self.add_session_summary_to_context and session.summary is not None:
6048
6349
  system_message_content += "Here is a brief summary of your previous interactions:\n\n"
@@ -6195,7 +6496,14 @@ class Agent:
6195
6496
  location = get_location()
6196
6497
  if location:
6197
6498
  location_str = ", ".join(
6198
- filter(None, [location.get("city"), location.get("region"), location.get("country")])
6499
+ filter(
6500
+ None,
6501
+ [
6502
+ location.get("city"),
6503
+ location.get("region"),
6504
+ location.get("country"),
6505
+ ],
6506
+ )
6199
6507
  )
6200
6508
  if location_str:
6201
6509
  additional_information.append(f"Your approximate location is: {location_str}.")
@@ -6210,7 +6518,8 @@ class Agent:
6210
6518
  if valid_filters:
6211
6519
  valid_filters_str = ", ".join(valid_filters)
6212
6520
  additional_information.append(
6213
- dedent(f"""
6521
+ dedent(
6522
+ f"""
6214
6523
  The knowledge base contains documents with these metadata filters: {valid_filters_str}.
6215
6524
  Always use filters when the user query indicates specific metadata.
6216
6525
 
@@ -6226,7 +6535,8 @@ class Agent:
6226
6535
  - Ensure the filter keys match the valid metadata filters: {valid_filters_str}.
6227
6536
 
6228
6537
  You can use the search_knowledge_base tool to search the knowledge base and get the most relevant documents. Make sure to pass the filters as [Dict[str: Any]] to the tool. FOLLOW THIS STRUCTURE STRICTLY.
6229
- """)
6538
+ """
6539
+ )
6230
6540
  )
6231
6541
 
6232
6542
  # 3.3 Build the default system message for the Agent.
@@ -6317,6 +6627,67 @@ class Agent:
6317
6627
  "</updating_user_memories>\n\n"
6318
6628
  )
6319
6629
 
6630
+ # 3.3.10 Then add cultural knowledge to the system prompt
6631
+ if self.add_culture_to_context:
6632
+ _culture_manager_not_set = None
6633
+ if not self.culture_manager:
6634
+ self._set_culture_manager()
6635
+ _culture_manager_not_set = True
6636
+
6637
+ cultural_knowledge = await self.culture_manager.aget_all_knowledge() # type: ignore
6638
+
6639
+ if cultural_knowledge and len(cultural_knowledge) > 0:
6640
+ system_message_content += (
6641
+ "You have access to shared **Cultural Knowledge**, which provides context, norms, rules and guidance "
6642
+ "for your reasoning, communication, and decision-making.\n\n"
6643
+ "Cultural Knowledge represents the collective understanding, values, rules and practices that have "
6644
+ "emerged across agents and teams. It encodes collective experience — including preferred "
6645
+ "approaches, common patterns, lessons learned, and ethical guardrails.\n\n"
6646
+ "When performing any task:\n"
6647
+ "- **Reference Cultural Knowledge** to align with shared norms and best practices.\n"
6648
+ "- **Apply it contextually**, not mechanically — adapt principles to the current situation.\n"
6649
+ "- **Preserve consistency** with cultural values (tone, reasoning, and style) unless explicitly told otherwise.\n"
6650
+ "- **Extend it** when you discover new insights — your outputs may become future Cultural Knowledge.\n"
6651
+ "- **Clarify conflicts** if Cultural Knowledge appears to contradict explicit user instructions.\n\n"
6652
+ "Your goal is to act not only intelligently but also *culturally coherently* — reflecting the "
6653
+ "collective intelligence of the system.\n\n"
6654
+ "Below is the currently available Cultural Knowledge for this context:\n\n"
6655
+ )
6656
+ system_message_content += "<cultural_knowledge>"
6657
+ for _knowledge in cultural_knowledge: # type: ignore
6658
+ system_message_content += "\n---"
6659
+ system_message_content += f"\nName: {_knowledge.name}"
6660
+ system_message_content += f"\nSummary: {_knowledge.summary}"
6661
+ system_message_content += f"\nContent: {_knowledge.content}"
6662
+ system_message_content += "\n</cultural_knowledge>\n"
6663
+ else:
6664
+ system_message_content += (
6665
+ "You have the capability to access shared **Cultural Knowledge**, which normally provides "
6666
+ "context, norms, and guidance for your behavior and reasoning. However, no cultural knowledge "
6667
+ "is currently available in this session.\n"
6668
+ "Proceed thoughtfully and document any useful insights you create — they may become future "
6669
+ "Cultural Knowledge for others.\n\n"
6670
+ )
6671
+
6672
+ if _culture_manager_not_set:
6673
+ self.culture_manager = None
6674
+
6675
+ if self.enable_agentic_culture:
6676
+ system_message_content += (
6677
+ "\n<contributing_to_culture>\n"
6678
+ "When you discover an insight, pattern, rule, or best practice that will help future agents, use the `create_or_update_cultural_knowledge` tool to add or update entries in the shared cultural knowledge.\n"
6679
+ "\n"
6680
+ "When to contribute:\n"
6681
+ "- You discover a reusable insight, pattern, rule, or best practice that will help future agents.\n"
6682
+ "- You correct or clarify an existing cultural entry.\n"
6683
+ "- You capture a guardrail, decision rationale, postmortem lesson, or example template.\n"
6684
+ "- You identify missing context that should persist across sessions or teams.\n"
6685
+ "\n"
6686
+ "Cultural knowledge should capture reusable insights, best practices, or contextual knowledge that transcends individual conversations.\n"
6687
+ "Mention your contribution to the user only if it is relevant to their request or they asked to be notified.\n"
6688
+ "</contributing_to_culture>\n\n"
6689
+ )
6690
+
6320
6691
  # 3.3.11 Then add a summary of the interaction to the system prompt
6321
6692
  if self.add_session_summary_to_context and session.summary is not None:
6322
6693
  system_message_content += "Here is a brief summary of your previous interactions:\n\n"
@@ -6954,7 +7325,9 @@ class Agent:
6954
7325
  return run_messages
6955
7326
 
6956
7327
  def _get_messages_for_parser_model(
6957
- self, model_response: ModelResponse, response_format: Optional[Union[Dict, Type[BaseModel]]]
7328
+ self,
7329
+ model_response: ModelResponse,
7330
+ response_format: Optional[Union[Dict, Type[BaseModel]]],
6958
7331
  ) -> List[Message]:
6959
7332
  """Get the messages for the parser model."""
6960
7333
  system_content = (
@@ -6972,7 +7345,9 @@ class Agent:
6972
7345
  ]
6973
7346
 
6974
7347
  def _get_messages_for_parser_model_stream(
6975
- self, run_response: RunOutput, response_format: Optional[Union[Dict, Type[BaseModel]]]
7348
+ self,
7349
+ run_response: RunOutput,
7350
+ response_format: Optional[Union[Dict, Type[BaseModel]]],
6976
7351
  ) -> List[Message]:
6977
7352
  """Get the messages for the parser model."""
6978
7353
  system_content = (
@@ -7008,7 +7383,11 @@ class Agent:
7008
7383
  return messages
7009
7384
 
7010
7385
  def get_relevant_docs_from_knowledge(
7011
- self, query: str, num_documents: Optional[int] = None, filters: Optional[Dict[str, Any]] = None, **kwargs
7386
+ self,
7387
+ query: str,
7388
+ num_documents: Optional[int] = None,
7389
+ filters: Optional[Dict[str, Any]] = None,
7390
+ **kwargs,
7012
7391
  ) -> Optional[List[Union[Dict[str, Any], str]]]:
7013
7392
  """Get relevant docs from the knowledge base to answer a query.
7014
7393
 
@@ -7083,7 +7462,11 @@ class Agent:
7083
7462
  raise e
7084
7463
 
7085
7464
  async def aget_relevant_docs_from_knowledge(
7086
- self, query: str, num_documents: Optional[int] = None, filters: Optional[Dict[str, Any]] = None, **kwargs
7465
+ self,
7466
+ query: str,
7467
+ num_documents: Optional[int] = None,
7468
+ filters: Optional[Dict[str, Any]] = None,
7469
+ **kwargs,
7087
7470
  ) -> Optional[List[Union[Dict[str, Any], str]]]:
7088
7471
  """Get relevant documents from knowledge base asynchronously."""
7089
7472
  from agno.knowledge.document import Document
@@ -7418,7 +7801,10 @@ class Agent:
7418
7801
  def _reason(self, run_response: RunOutput, run_messages: RunMessages) -> Iterator[RunOutputEvent]:
7419
7802
  # Yield a reasoning started event
7420
7803
  if self.stream_intermediate_steps:
7421
- yield self._handle_event(create_reasoning_started_event(from_run_response=run_response), run_response)
7804
+ yield self._handle_event(
7805
+ create_reasoning_started_event(from_run_response=run_response),
7806
+ run_response,
7807
+ )
7422
7808
 
7423
7809
  use_default_reasoning = False
7424
7810
 
@@ -7479,56 +7865,64 @@ class Agent:
7479
7865
 
7480
7866
  log_debug("Starting DeepSeek Reasoning", center=True, symbol="=")
7481
7867
  reasoning_message = get_deepseek_reasoning(
7482
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7868
+ reasoning_agent=reasoning_agent,
7869
+ messages=run_messages.get_input_messages(),
7483
7870
  )
7484
7871
  elif is_groq:
7485
7872
  from agno.reasoning.groq import get_groq_reasoning
7486
7873
 
7487
7874
  log_debug("Starting Groq Reasoning", center=True, symbol="=")
7488
7875
  reasoning_message = get_groq_reasoning(
7489
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7876
+ reasoning_agent=reasoning_agent,
7877
+ messages=run_messages.get_input_messages(),
7490
7878
  )
7491
7879
  elif is_openai:
7492
7880
  from agno.reasoning.openai import get_openai_reasoning
7493
7881
 
7494
7882
  log_debug("Starting OpenAI Reasoning", center=True, symbol="=")
7495
7883
  reasoning_message = get_openai_reasoning(
7496
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7884
+ reasoning_agent=reasoning_agent,
7885
+ messages=run_messages.get_input_messages(),
7497
7886
  )
7498
7887
  elif is_ollama:
7499
7888
  from agno.reasoning.ollama import get_ollama_reasoning
7500
7889
 
7501
7890
  log_debug("Starting Ollama Reasoning", center=True, symbol="=")
7502
7891
  reasoning_message = get_ollama_reasoning(
7503
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7892
+ reasoning_agent=reasoning_agent,
7893
+ messages=run_messages.get_input_messages(),
7504
7894
  )
7505
7895
  elif is_ai_foundry:
7506
7896
  from agno.reasoning.azure_ai_foundry import get_ai_foundry_reasoning
7507
7897
 
7508
7898
  log_debug("Starting Azure AI Foundry Reasoning", center=True, symbol="=")
7509
7899
  reasoning_message = get_ai_foundry_reasoning(
7510
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7900
+ reasoning_agent=reasoning_agent,
7901
+ messages=run_messages.get_input_messages(),
7511
7902
  )
7512
7903
  elif is_gemini:
7513
7904
  from agno.reasoning.gemini import get_gemini_reasoning
7514
7905
 
7515
7906
  log_debug("Starting Gemini Reasoning", center=True, symbol="=")
7516
7907
  reasoning_message = get_gemini_reasoning(
7517
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7908
+ reasoning_agent=reasoning_agent,
7909
+ messages=run_messages.get_input_messages(),
7518
7910
  )
7519
7911
  elif is_anthropic:
7520
7912
  from agno.reasoning.anthropic import get_anthropic_reasoning
7521
7913
 
7522
7914
  log_debug("Starting Anthropic Claude Reasoning", center=True, symbol="=")
7523
7915
  reasoning_message = get_anthropic_reasoning(
7524
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7916
+ reasoning_agent=reasoning_agent,
7917
+ messages=run_messages.get_input_messages(),
7525
7918
  )
7526
7919
  elif is_vertexai:
7527
7920
  from agno.reasoning.vertexai import get_vertexai_reasoning
7528
7921
 
7529
7922
  log_debug("Starting VertexAI Reasoning", center=True, symbol="=")
7530
7923
  reasoning_message = get_vertexai_reasoning(
7531
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
7924
+ reasoning_agent=reasoning_agent,
7925
+ messages=run_messages.get_input_messages(),
7532
7926
  )
7533
7927
 
7534
7928
  if reasoning_message is None:
@@ -7561,7 +7955,10 @@ class Agent:
7561
7955
 
7562
7956
  if use_default_reasoning:
7563
7957
  from agno.reasoning.default import get_default_reasoning_agent
7564
- from agno.reasoning.helpers import get_next_action, update_messages_with_reasoning
7958
+ from agno.reasoning.helpers import (
7959
+ get_next_action,
7960
+ update_messages_with_reasoning,
7961
+ )
7565
7962
 
7566
7963
  # Get default reasoning agent
7567
7964
  reasoning_agent: Optional[Agent] = self.reasoning_agent # type: ignore
@@ -7627,7 +8024,8 @@ class Agent:
7627
8024
  if self.stream_intermediate_steps:
7628
8025
  for reasoning_step in reasoning_steps:
7629
8026
  updated_reasoning_content = self._format_reasoning_step_content(
7630
- run_response=run_response, reasoning_step=reasoning_step
8027
+ run_response=run_response,
8028
+ reasoning_step=reasoning_step,
7631
8029
  )
7632
8030
 
7633
8031
  yield self._handle_event(
@@ -7686,7 +8084,10 @@ class Agent:
7686
8084
  async def _areason(self, run_response: RunOutput, run_messages: RunMessages) -> Any:
7687
8085
  # Yield a reasoning started event
7688
8086
  if self.stream_intermediate_steps:
7689
- yield self._handle_event(create_reasoning_started_event(from_run_response=run_response), run_response)
8087
+ yield self._handle_event(
8088
+ create_reasoning_started_event(from_run_response=run_response),
8089
+ run_response,
8090
+ )
7690
8091
 
7691
8092
  use_default_reasoning = False
7692
8093
 
@@ -7747,56 +8148,64 @@ class Agent:
7747
8148
 
7748
8149
  log_debug("Starting DeepSeek Reasoning", center=True, symbol="=")
7749
8150
  reasoning_message = await aget_deepseek_reasoning(
7750
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8151
+ reasoning_agent=reasoning_agent,
8152
+ messages=run_messages.get_input_messages(),
7751
8153
  )
7752
8154
  elif is_groq:
7753
8155
  from agno.reasoning.groq import aget_groq_reasoning
7754
8156
 
7755
8157
  log_debug("Starting Groq Reasoning", center=True, symbol="=")
7756
8158
  reasoning_message = await aget_groq_reasoning(
7757
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8159
+ reasoning_agent=reasoning_agent,
8160
+ messages=run_messages.get_input_messages(),
7758
8161
  )
7759
8162
  elif is_openai:
7760
8163
  from agno.reasoning.openai import aget_openai_reasoning
7761
8164
 
7762
8165
  log_debug("Starting OpenAI Reasoning", center=True, symbol="=")
7763
8166
  reasoning_message = await aget_openai_reasoning(
7764
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8167
+ reasoning_agent=reasoning_agent,
8168
+ messages=run_messages.get_input_messages(),
7765
8169
  )
7766
8170
  elif is_ollama:
7767
8171
  from agno.reasoning.ollama import get_ollama_reasoning
7768
8172
 
7769
8173
  log_debug("Starting Ollama Reasoning", center=True, symbol="=")
7770
8174
  reasoning_message = get_ollama_reasoning(
7771
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8175
+ reasoning_agent=reasoning_agent,
8176
+ messages=run_messages.get_input_messages(),
7772
8177
  )
7773
8178
  elif is_ai_foundry:
7774
8179
  from agno.reasoning.azure_ai_foundry import get_ai_foundry_reasoning
7775
8180
 
7776
8181
  log_debug("Starting Azure AI Foundry Reasoning", center=True, symbol="=")
7777
8182
  reasoning_message = get_ai_foundry_reasoning(
7778
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8183
+ reasoning_agent=reasoning_agent,
8184
+ messages=run_messages.get_input_messages(),
7779
8185
  )
7780
8186
  elif is_gemini:
7781
8187
  from agno.reasoning.gemini import aget_gemini_reasoning
7782
8188
 
7783
8189
  log_debug("Starting Gemini Reasoning", center=True, symbol="=")
7784
8190
  reasoning_message = await aget_gemini_reasoning(
7785
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8191
+ reasoning_agent=reasoning_agent,
8192
+ messages=run_messages.get_input_messages(),
7786
8193
  )
7787
8194
  elif is_anthropic:
7788
8195
  from agno.reasoning.anthropic import aget_anthropic_reasoning
7789
8196
 
7790
8197
  log_debug("Starting Anthropic Claude Reasoning", center=True, symbol="=")
7791
8198
  reasoning_message = await aget_anthropic_reasoning(
7792
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8199
+ reasoning_agent=reasoning_agent,
8200
+ messages=run_messages.get_input_messages(),
7793
8201
  )
7794
8202
  elif is_vertexai:
7795
8203
  from agno.reasoning.vertexai import aget_vertexai_reasoning
7796
8204
 
7797
8205
  log_debug("Starting VertexAI Reasoning", center=True, symbol="=")
7798
8206
  reasoning_message = await aget_vertexai_reasoning(
7799
- reasoning_agent=reasoning_agent, messages=run_messages.get_input_messages()
8207
+ reasoning_agent=reasoning_agent,
8208
+ messages=run_messages.get_input_messages(),
7800
8209
  )
7801
8210
 
7802
8211
  if reasoning_message is None:
@@ -7829,7 +8238,10 @@ class Agent:
7829
8238
 
7830
8239
  if use_default_reasoning:
7831
8240
  from agno.reasoning.default import get_default_reasoning_agent
7832
- from agno.reasoning.helpers import get_next_action, update_messages_with_reasoning
8241
+ from agno.reasoning.helpers import (
8242
+ get_next_action,
8243
+ update_messages_with_reasoning,
8244
+ )
7833
8245
 
7834
8246
  # Get default reasoning agent
7835
8247
  reasoning_agent: Optional[Agent] = self.reasoning_agent # type: ignore
@@ -7895,7 +8307,8 @@ class Agent:
7895
8307
  if self.stream_intermediate_steps:
7896
8308
  for reasoning_step in reasoning_steps:
7897
8309
  updated_reasoning_content = self._format_reasoning_step_content(
7898
- run_response=run_response, reasoning_step=reasoning_step
8310
+ run_response=run_response,
8311
+ reasoning_step=reasoning_step,
7899
8312
  )
7900
8313
 
7901
8314
  # Yield the response with the updated reasoning_content
@@ -7985,7 +8398,10 @@ class Agent:
7985
8398
  response_format=parser_response_format,
7986
8399
  )
7987
8400
  self._process_parser_response(
7988
- model_response, run_messages, parser_model_response, messages_for_parser_model
8401
+ model_response,
8402
+ run_messages,
8403
+ parser_model_response,
8404
+ messages_for_parser_model,
7989
8405
  )
7990
8406
  else:
7991
8407
  log_warning("A response model is required to parse the response with a parser model")
@@ -8005,19 +8421,28 @@ class Agent:
8005
8421
  response_format=parser_response_format,
8006
8422
  )
8007
8423
  self._process_parser_response(
8008
- model_response, run_messages, parser_model_response, messages_for_parser_model
8424
+ model_response,
8425
+ run_messages,
8426
+ parser_model_response,
8427
+ messages_for_parser_model,
8009
8428
  )
8010
8429
  else:
8011
8430
  log_warning("A response model is required to parse the response with a parser model")
8012
8431
 
8013
8432
  def _parse_response_with_parser_model_stream(
8014
- self, session: AgentSession, run_response: RunOutput, stream_intermediate_steps: bool = True
8433
+ self,
8434
+ session: AgentSession,
8435
+ run_response: RunOutput,
8436
+ stream_intermediate_steps: bool = True,
8015
8437
  ):
8016
8438
  """Parse the model response using the parser model"""
8017
8439
  if self.parser_model is not None:
8018
8440
  if self.output_schema is not None:
8019
8441
  if stream_intermediate_steps:
8020
- yield self._handle_event(create_parser_model_response_started_event(run_response), run_response)
8442
+ yield self._handle_event(
8443
+ create_parser_model_response_started_event(run_response),
8444
+ run_response,
8445
+ )
8021
8446
 
8022
8447
  parser_model_response = ModelResponse(content="")
8023
8448
  parser_response_format = self._get_response_format(self.parser_model)
@@ -8050,19 +8475,28 @@ class Agent:
8050
8475
  log_warning("Unable to parse response with parser model")
8051
8476
 
8052
8477
  if stream_intermediate_steps:
8053
- yield self._handle_event(create_parser_model_response_completed_event(run_response), run_response)
8478
+ yield self._handle_event(
8479
+ create_parser_model_response_completed_event(run_response),
8480
+ run_response,
8481
+ )
8054
8482
 
8055
8483
  else:
8056
8484
  log_warning("A response model is required to parse the response with a parser model")
8057
8485
 
8058
8486
  async def _aparse_response_with_parser_model_stream(
8059
- self, session: AgentSession, run_response: RunOutput, stream_intermediate_steps: bool = True
8487
+ self,
8488
+ session: AgentSession,
8489
+ run_response: RunOutput,
8490
+ stream_intermediate_steps: bool = True,
8060
8491
  ):
8061
8492
  """Parse the model response using the parser model stream."""
8062
8493
  if self.parser_model is not None:
8063
8494
  if self.output_schema is not None:
8064
8495
  if stream_intermediate_steps:
8065
- yield self._handle_event(create_parser_model_response_started_event(run_response), run_response)
8496
+ yield self._handle_event(
8497
+ create_parser_model_response_started_event(run_response),
8498
+ run_response,
8499
+ )
8066
8500
 
8067
8501
  parser_model_response = ModelResponse(content="")
8068
8502
  parser_response_format = self._get_response_format(self.parser_model)
@@ -8097,7 +8531,10 @@ class Agent:
8097
8531
  log_warning("Unable to parse response with parser model")
8098
8532
 
8099
8533
  if stream_intermediate_steps:
8100
- yield self._handle_event(create_parser_model_response_completed_event(run_response), run_response)
8534
+ yield self._handle_event(
8535
+ create_parser_model_response_completed_event(run_response),
8536
+ run_response,
8537
+ )
8101
8538
  else:
8102
8539
  log_warning("A response model is required to parse the response with a parser model")
8103
8540
 
@@ -8258,6 +8695,30 @@ class Agent:
8258
8695
 
8259
8696
  return Function.from_callable(update_user_memory_function, name="update_user_memory")
8260
8697
 
8698
+ def _get_update_cultural_knowledge_function(self, async_mode: bool = False) -> Function:
8699
+ def update_cultural_knowledge(task: str) -> str:
8700
+ """Use this function to update a cultural knowledge."""
8701
+ self.culture_manager = cast(CultureManager, self.culture_manager)
8702
+ response = self.culture_manager.update_culture_task(task=task)
8703
+
8704
+ return response
8705
+
8706
+ async def aupdate_cultural_knowledge(task: str) -> str:
8707
+ """Use this function to update a cultural knowledge asynchronously."""
8708
+ self.culture_manager = cast(CultureManager, self.culture_manager)
8709
+ response = await self.culture_manager.aupdate_culture_task(task=task)
8710
+ return response
8711
+
8712
+ if async_mode:
8713
+ update_cultural_knowledge_function = aupdate_cultural_knowledge
8714
+ else:
8715
+ update_cultural_knowledge_function = update_cultural_knowledge # type: ignore
8716
+
8717
+ return Function.from_callable(
8718
+ update_cultural_knowledge_function,
8719
+ name="create_or_update_cultural_knowledge",
8720
+ )
8721
+
8261
8722
  def _get_chat_history_function(self, session: AgentSession) -> Callable:
8262
8723
  def get_chat_history(num_chats: Optional[int] = None) -> str:
8263
8724
  """Use this function to get the chat history between the user and agent.
@@ -8333,7 +8794,10 @@ class Agent:
8333
8794
  return f"Updated session state: {session_state}"
8334
8795
 
8335
8796
  def _get_search_knowledge_base_function(
8336
- self, run_response: RunOutput, knowledge_filters: Optional[Dict[str, Any]] = None, async_mode: bool = False
8797
+ self,
8798
+ run_response: RunOutput,
8799
+ knowledge_filters: Optional[Dict[str, Any]] = None,
8800
+ async_mode: bool = False,
8337
8801
  ) -> Function:
8338
8802
  """Factory function to create a search_knowledge_base function with filters."""
8339
8803
 
@@ -8353,7 +8817,9 @@ class Agent:
8353
8817
  docs_from_knowledge = self.get_relevant_docs_from_knowledge(query=query, filters=knowledge_filters)
8354
8818
  if docs_from_knowledge is not None:
8355
8819
  references = MessageReferences(
8356
- query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)
8820
+ query=query,
8821
+ references=docs_from_knowledge,
8822
+ time=round(retrieval_timer.elapsed, 4),
8357
8823
  )
8358
8824
  # Add the references to the run_response
8359
8825
  if run_response.references is None:
@@ -8382,7 +8848,9 @@ class Agent:
8382
8848
  docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(query=query, filters=knowledge_filters)
8383
8849
  if docs_from_knowledge is not None:
8384
8850
  references = MessageReferences(
8385
- query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)
8851
+ query=query,
8852
+ references=docs_from_knowledge,
8853
+ time=round(retrieval_timer.elapsed, 4),
8386
8854
  )
8387
8855
  if run_response.references is None:
8388
8856
  run_response.references = []
@@ -8402,7 +8870,10 @@ class Agent:
8402
8870
  return Function.from_callable(search_knowledge_base_function, name="search_knowledge_base")
8403
8871
 
8404
8872
  def _search_knowledge_base_with_agentic_filters_function(
8405
- self, run_response: RunOutput, knowledge_filters: Optional[Dict[str, Any]] = None, async_mode: bool = False
8873
+ self,
8874
+ run_response: RunOutput,
8875
+ knowledge_filters: Optional[Dict[str, Any]] = None,
8876
+ async_mode: bool = False,
8406
8877
  ) -> Function:
8407
8878
  """Factory function to create a search_knowledge_base function with filters."""
8408
8879
 
@@ -8425,7 +8896,9 @@ class Agent:
8425
8896
  docs_from_knowledge = self.get_relevant_docs_from_knowledge(query=query, filters=search_filters)
8426
8897
  if docs_from_knowledge is not None:
8427
8898
  references = MessageReferences(
8428
- query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)
8899
+ query=query,
8900
+ references=docs_from_knowledge,
8901
+ time=round(retrieval_timer.elapsed, 4),
8429
8902
  )
8430
8903
  # Add the references to the run_response
8431
8904
  if run_response.references is None:
@@ -8458,7 +8931,9 @@ class Agent:
8458
8931
  docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(query=query, filters=search_filters)
8459
8932
  if docs_from_knowledge is not None:
8460
8933
  references = MessageReferences(
8461
- query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)
8934
+ query=query,
8935
+ references=docs_from_knowledge,
8936
+ time=round(retrieval_timer.elapsed, 4),
8462
8937
  )
8463
8938
  if run_response.references is None:
8464
8939
  run_response.references = []
@@ -8475,7 +8950,10 @@ class Agent:
8475
8950
  else:
8476
8951
  search_knowledge_base_function = search_knowledge_base # type: ignore
8477
8952
 
8478
- return Function.from_callable(search_knowledge_base_function, name="search_knowledge_base_with_agentic_filters")
8953
+ return Function.from_callable(
8954
+ search_knowledge_base_function,
8955
+ name="search_knowledge_base_with_agentic_filters",
8956
+ )
8479
8957
 
8480
8958
  def add_to_knowledge(self, query: str, result: str) -> str:
8481
8959
  """Use this function to add information to the knowledge base for future use.
@@ -8530,7 +9008,9 @@ class Agent:
8530
9008
  self.db = cast(BaseDb, self.db)
8531
9009
 
8532
9010
  selected_sessions = self.db.get_sessions(
8533
- session_type=SessionType.AGENT, limit=num_history_sessions, user_id=user_id
9011
+ session_type=SessionType.AGENT,
9012
+ limit=num_history_sessions,
9013
+ user_id=user_id,
8534
9014
  )
8535
9015
 
8536
9016
  all_messages = []
@@ -9139,7 +9619,12 @@ class Agent:
9139
9619
 
9140
9620
  if input:
9141
9621
  self.print_response(
9142
- input=input, stream=stream, markdown=markdown, user_id=user_id, session_id=session_id, **kwargs
9622
+ input=input,
9623
+ stream=stream,
9624
+ markdown=markdown,
9625
+ user_id=user_id,
9626
+ session_id=session_id,
9627
+ **kwargs,
9143
9628
  )
9144
9629
 
9145
9630
  _exit_on = exit_on or ["exit", "quit", "bye"]
@@ -9149,7 +9634,12 @@ class Agent:
9149
9634
  break
9150
9635
 
9151
9636
  self.print_response(
9152
- input=message, stream=stream, markdown=markdown, user_id=user_id, session_id=session_id, **kwargs
9637
+ input=message,
9638
+ stream=stream,
9639
+ markdown=markdown,
9640
+ user_id=user_id,
9641
+ session_id=session_id,
9642
+ **kwargs,
9153
9643
  )
9154
9644
 
9155
9645
  async def acli_app(
@@ -9172,7 +9662,12 @@ class Agent:
9172
9662
 
9173
9663
  if input:
9174
9664
  await self.aprint_response(
9175
- input=input, stream=stream, markdown=markdown, user_id=user_id, session_id=session_id, **kwargs
9665
+ input=input,
9666
+ stream=stream,
9667
+ markdown=markdown,
9668
+ user_id=user_id,
9669
+ session_id=session_id,
9670
+ **kwargs,
9176
9671
  )
9177
9672
 
9178
9673
  _exit_on = exit_on or ["exit", "quit", "bye"]
@@ -9182,7 +9677,12 @@ class Agent:
9182
9677
  break
9183
9678
 
9184
9679
  await self.aprint_response(
9185
- input=message, stream=stream, markdown=markdown, user_id=user_id, session_id=session_id, **kwargs
9680
+ input=message,
9681
+ stream=stream,
9682
+ markdown=markdown,
9683
+ user_id=user_id,
9684
+ session_id=session_id,
9685
+ **kwargs,
9186
9686
  )
9187
9687
 
9188
9688
  ###########################################################################
@@ -9200,7 +9700,12 @@ class Agent:
9200
9700
  "parser_model": self.parser_model.to_dict() if self.parser_model else None,
9201
9701
  "output_model": self.output_model.to_dict() if self.output_model else None,
9202
9702
  "has_tools": self.tools is not None,
9203
- "has_memory": self.enable_user_memories is True,
9703
+ "has_memory": self.enable_user_memories is True
9704
+ or self.enable_agentic_memory is True
9705
+ or self.memory_manager is not None,
9706
+ "has_culture": self.enable_agentic_culture is True
9707
+ or self.update_cultural_knowledge is True
9708
+ or self.culture_manager is not None,
9204
9709
  "has_reasoning": self.reasoning is True,
9205
9710
  "has_knowledge": self.knowledge is not None,
9206
9711
  "has_input_schema": self.input_schema is not None,
@@ -9219,7 +9724,11 @@ class Agent:
9219
9724
 
9220
9725
  try:
9221
9726
  create_agent_run(
9222
- run=AgentRunCreate(session_id=session_id, run_id=run_id, data=self._get_telemetry_data()),
9727
+ run=AgentRunCreate(
9728
+ session_id=session_id,
9729
+ run_id=run_id,
9730
+ data=self._get_telemetry_data(),
9731
+ ),
9223
9732
  )
9224
9733
  except Exception as e:
9225
9734
  log_debug(f"Could not create Agent run telemetry event: {e}")
@@ -9235,7 +9744,11 @@ class Agent:
9235
9744
 
9236
9745
  try:
9237
9746
  await acreate_agent_run(
9238
- run=AgentRunCreate(session_id=session_id, run_id=run_id, data=self._get_telemetry_data())
9747
+ run=AgentRunCreate(
9748
+ session_id=session_id,
9749
+ run_id=run_id,
9750
+ data=self._get_telemetry_data(),
9751
+ )
9239
9752
  )
9240
9753
 
9241
9754
  except Exception as e: