agno 2.2.6__py3-none-any.whl → 2.2.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
agno/agent/agent.py CHANGED
@@ -49,13 +49,13 @@ from agno.models.metrics import Metrics
49
49
  from agno.models.response import ModelResponse, ModelResponseEvent, ToolExecution
50
50
  from agno.models.utils import get_model
51
51
  from agno.reasoning.step import NextAction, ReasoningStep, ReasoningSteps
52
+ from agno.run import RunContext, RunStatus
52
53
  from agno.run.agent import (
53
54
  RunEvent,
54
55
  RunInput,
55
56
  RunOutput,
56
57
  RunOutputEvent,
57
58
  )
58
- from agno.run.base import RunStatus
59
59
  from agno.run.cancel import (
60
60
  cancel_run as cancel_run_global,
61
61
  )
@@ -95,7 +95,9 @@ from agno.utils.agent import (
95
95
  scrub_media_from_run_output,
96
96
  scrub_tool_results_from_run_output,
97
97
  set_session_name_util,
98
+ store_media_util,
98
99
  update_session_state_util,
100
+ validate_media_object_id,
99
101
  wait_for_background_tasks,
100
102
  wait_for_background_tasks_stream,
101
103
  )
@@ -263,9 +265,9 @@ class Agent:
263
265
 
264
266
  # --- Agent Hooks ---
265
267
  # Functions called right after agent-session is loaded, before processing starts
266
- pre_hooks: Optional[Union[List[Callable[..., Any]], List[BaseGuardrail]]] = None
268
+ pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
267
269
  # Functions called after output is generated but before the response is returned
268
- post_hooks: Optional[Union[List[Callable[..., Any]], List[BaseGuardrail]]] = None
270
+ post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
269
271
 
270
272
  # --- Agent Reasoning ---
271
273
  # Enable reasoning by working through the problem step by step.
@@ -458,8 +460,8 @@ class Agent:
458
460
  tool_call_limit: Optional[int] = None,
459
461
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
460
462
  tool_hooks: Optional[List[Callable]] = None,
461
- pre_hooks: Optional[Union[List[Callable[..., Any]], List[BaseGuardrail]]] = None,
462
- post_hooks: Optional[Union[List[Callable[..., Any]], List[BaseGuardrail]]] = None,
463
+ pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None,
464
+ post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None,
463
465
  reasoning: bool = False,
464
466
  reasoning_model: Optional[Union[Model, str]] = None,
465
467
  reasoning_agent: Optional[Agent] = None,
@@ -913,16 +915,13 @@ class Agent:
913
915
  def _run(
914
916
  self,
915
917
  run_response: RunOutput,
918
+ run_context: RunContext,
916
919
  session: AgentSession,
917
- session_state: Optional[Dict[str, Any]] = None,
918
920
  user_id: Optional[str] = None,
919
- knowledge_filters: Optional[Dict[str, Any]] = None,
920
921
  add_history_to_context: Optional[bool] = None,
921
922
  add_dependencies_to_context: Optional[bool] = None,
922
923
  add_session_state_to_context: Optional[bool] = None,
923
- metadata: Optional[Dict[str, Any]] = None,
924
924
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
925
- dependencies: Optional[Dict[str, Any]] = None,
926
925
  debug_mode: Optional[bool] = None,
927
926
  **kwargs: Any,
928
927
  ) -> RunOutput:
@@ -956,9 +955,7 @@ class Agent:
956
955
  hooks=self.pre_hooks, # type: ignore
957
956
  run_response=run_response,
958
957
  run_input=run_input,
959
- session_state=session_state,
960
- dependencies=dependencies,
961
- metadata=metadata,
958
+ run_context=run_context,
962
959
  session=session,
963
960
  user_id=user_id,
964
961
  debug_mode=debug_mode,
@@ -970,36 +967,32 @@ class Agent:
970
967
  # 2. Determine tools for model
971
968
  processed_tools = self.get_tools(
972
969
  run_response=run_response,
970
+ run_context=run_context,
973
971
  session=session,
974
972
  user_id=user_id,
975
- knowledge_filters=knowledge_filters,
976
973
  )
977
974
  _tools = self._determine_tools_for_model(
978
975
  model=self.model,
979
976
  processed_tools=processed_tools,
980
977
  run_response=run_response,
981
978
  session=session,
982
- session_state=session_state,
983
- dependencies=dependencies,
979
+ run_context=run_context,
984
980
  )
985
981
 
986
982
  # 3. Prepare run messages
987
983
  run_messages: RunMessages = self._get_run_messages(
988
984
  run_response=run_response,
985
+ run_context=run_context,
989
986
  input=run_input.input_content,
990
987
  session=session,
991
- session_state=session_state,
992
988
  user_id=user_id,
993
989
  audio=run_input.audios,
994
990
  images=run_input.images,
995
991
  videos=run_input.videos,
996
992
  files=run_input.files,
997
- knowledge_filters=knowledge_filters,
998
993
  add_history_to_context=add_history_to_context,
999
- dependencies=dependencies,
1000
994
  add_dependencies_to_context=add_dependencies_to_context,
1001
995
  add_session_state_to_context=add_session_state_to_context,
1002
- metadata=metadata,
1003
996
  tools=_tools,
1004
997
  **kwargs,
1005
998
  )
@@ -1074,7 +1067,7 @@ class Agent:
1074
1067
 
1075
1068
  # 8. Store media if enabled
1076
1069
  if self.store_media:
1077
- self._store_media(run_response, model_response)
1070
+ store_media_util(run_response, model_response)
1078
1071
 
1079
1072
  # 9. Convert the response to the structured format if needed
1080
1073
  self._convert_response_to_structured_format(run_response)
@@ -1084,11 +1077,9 @@ class Agent:
1084
1077
  post_hook_iterator = self._execute_post_hooks(
1085
1078
  hooks=self.post_hooks, # type: ignore
1086
1079
  run_output=run_response,
1080
+ run_context=run_context,
1087
1081
  session=session,
1088
1082
  user_id=user_id,
1089
- session_state=session_state,
1090
- dependencies=dependencies,
1091
- metadata=metadata,
1092
1083
  debug_mode=debug_mode,
1093
1084
  **kwargs,
1094
1085
  )
@@ -1112,7 +1103,9 @@ class Agent:
1112
1103
  run_response.status = RunStatus.completed
1113
1104
 
1114
1105
  # 13. Cleanup and store the run response and session
1115
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
1106
+ self._cleanup_and_store(
1107
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
1108
+ )
1116
1109
 
1117
1110
  # Log Agent Telemetry
1118
1111
  self._log_agent_telemetry(session_id=session.session_id, run_id=run_response.run_id)
@@ -1127,7 +1120,9 @@ class Agent:
1127
1120
  run_response.status = RunStatus.cancelled
1128
1121
 
1129
1122
  # Cleanup and store the run response and session
1130
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
1123
+ self._cleanup_and_store(
1124
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
1125
+ )
1131
1126
 
1132
1127
  return run_response
1133
1128
  finally:
@@ -1137,15 +1132,12 @@ class Agent:
1137
1132
  def _run_stream(
1138
1133
  self,
1139
1134
  run_response: RunOutput,
1135
+ run_context: RunContext,
1140
1136
  session: AgentSession,
1141
- session_state: Optional[Dict[str, Any]] = None,
1142
1137
  user_id: Optional[str] = None,
1143
- knowledge_filters: Optional[Dict[str, Any]] = None,
1144
1138
  add_history_to_context: Optional[bool] = None,
1145
1139
  add_dependencies_to_context: Optional[bool] = None,
1146
1140
  add_session_state_to_context: Optional[bool] = None,
1147
- metadata: Optional[Dict[str, Any]] = None,
1148
- dependencies: Optional[Dict[str, Any]] = None,
1149
1141
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
1150
1142
  stream_events: bool = False,
1151
1143
  yield_run_response: bool = False,
@@ -1179,9 +1171,7 @@ class Agent:
1179
1171
  hooks=self.pre_hooks, # type: ignore
1180
1172
  run_response=run_response,
1181
1173
  run_input=run_input,
1182
- session_state=session_state,
1183
- dependencies=dependencies,
1184
- metadata=metadata,
1174
+ run_context=run_context,
1185
1175
  session=session,
1186
1176
  user_id=user_id,
1187
1177
  debug_mode=debug_mode,
@@ -1193,17 +1183,16 @@ class Agent:
1193
1183
  # 2. Determine tools for model
1194
1184
  processed_tools = self.get_tools(
1195
1185
  run_response=run_response,
1186
+ run_context=run_context,
1196
1187
  session=session,
1197
1188
  user_id=user_id,
1198
- knowledge_filters=knowledge_filters,
1199
1189
  )
1200
1190
  _tools = self._determine_tools_for_model(
1201
1191
  model=self.model,
1202
1192
  processed_tools=processed_tools,
1203
1193
  run_response=run_response,
1204
1194
  session=session,
1205
- session_state=session_state,
1206
- dependencies=dependencies,
1195
+ run_context=run_context,
1207
1196
  )
1208
1197
 
1209
1198
  # 3. Prepare run messages
@@ -1211,18 +1200,15 @@ class Agent:
1211
1200
  run_response=run_response,
1212
1201
  input=run_input.input_content,
1213
1202
  session=session,
1214
- session_state=session_state,
1203
+ run_context=run_context,
1215
1204
  user_id=user_id,
1216
1205
  audio=run_input.audios,
1217
1206
  images=run_input.images,
1218
1207
  videos=run_input.videos,
1219
1208
  files=run_input.files,
1220
- knowledge_filters=knowledge_filters,
1221
1209
  add_history_to_context=add_history_to_context,
1222
- dependencies=dependencies,
1223
1210
  add_dependencies_to_context=add_dependencies_to_context,
1224
1211
  add_session_state_to_context=add_session_state_to_context,
1225
- metadata=metadata,
1226
1212
  tools=_tools,
1227
1213
  **kwargs,
1228
1214
  )
@@ -1281,7 +1267,7 @@ class Agent:
1281
1267
  tools=_tools,
1282
1268
  response_format=response_format,
1283
1269
  stream_events=stream_events,
1284
- session_state=session_state,
1270
+ session_state=run_context.session_state,
1285
1271
  ):
1286
1272
  raise_if_cancelled(run_response.run_id) # type: ignore
1287
1273
  yield event
@@ -1298,7 +1284,7 @@ class Agent:
1298
1284
  tools=_tools,
1299
1285
  response_format=response_format,
1300
1286
  stream_events=stream_events,
1301
- session_state=session_state,
1287
+ session_state=run_context.session_state,
1302
1288
  ):
1303
1289
  raise_if_cancelled(run_response.run_id) # type: ignore
1304
1290
  if isinstance(event, RunContentEvent):
@@ -1318,7 +1304,7 @@ class Agent:
1318
1304
  stream_events=stream_events,
1319
1305
  ):
1320
1306
  raise_if_cancelled(run_response.run_id) # type: ignore
1321
- yield event
1307
+ yield event # type: ignore
1322
1308
 
1323
1309
  # Check for cancellation after model processing
1324
1310
  raise_if_cancelled(run_response.run_id) # type: ignore
@@ -1359,9 +1345,7 @@ class Agent:
1359
1345
  yield from self._execute_post_hooks(
1360
1346
  hooks=self.post_hooks, # type: ignore
1361
1347
  run_output=run_response,
1362
- session_state=session_state,
1363
- dependencies=dependencies,
1364
- metadata=metadata,
1348
+ run_context=run_context,
1365
1349
  session=session,
1366
1350
  user_id=user_id,
1367
1351
  debug_mode=debug_mode,
@@ -1419,7 +1403,9 @@ class Agent:
1419
1403
  run_response.status = RunStatus.completed
1420
1404
 
1421
1405
  # 10. Cleanup and store the run response and session
1422
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
1406
+ self._cleanup_and_store(
1407
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
1408
+ )
1423
1409
 
1424
1410
  if stream_events:
1425
1411
  yield completed_event # type: ignore
@@ -1450,7 +1436,9 @@ class Agent:
1450
1436
  )
1451
1437
 
1452
1438
  # Cleanup and store the run response and session
1453
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
1439
+ self._cleanup_and_store(
1440
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
1441
+ )
1454
1442
  finally:
1455
1443
  # Always clean up the run tracking
1456
1444
  cleanup_run(run_response.run_id) # type: ignore
@@ -1553,9 +1541,9 @@ class Agent:
1553
1541
  # Normalise hook & guardails
1554
1542
  if not self._hooks_normalised:
1555
1543
  if self.pre_hooks:
1556
- self.pre_hooks = normalize_hooks(self.pre_hooks)
1544
+ self.pre_hooks = normalize_hooks(self.pre_hooks) # type: ignore
1557
1545
  if self.post_hooks:
1558
- self.post_hooks = normalize_hooks(self.post_hooks)
1546
+ self.post_hooks = normalize_hooks(self.post_hooks) # type: ignore
1559
1547
  self._hooks_normalised = True
1560
1548
 
1561
1549
  session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
@@ -1563,7 +1551,7 @@ class Agent:
1563
1551
  # Initialize the Agent
1564
1552
  self.initialize_agent(debug_mode=debug_mode)
1565
1553
 
1566
- image_artifacts, video_artifacts, audio_artifacts, file_artifacts = self._validate_media_object_id(
1554
+ image_artifacts, video_artifacts, audio_artifacts, file_artifacts = validate_media_object_id(
1567
1555
  images=images, videos=videos, audios=audio, files=files
1568
1556
  )
1569
1557
 
@@ -1586,12 +1574,22 @@ class Agent:
1586
1574
  )
1587
1575
  # Update session state from DB
1588
1576
  session_state = self._load_session_state(session=agent_session, session_state=session_state)
1577
+
1589
1578
  # Determine runtime dependencies
1590
- run_dependencies = dependencies if dependencies is not None else self.dependencies
1579
+ dependencies = dependencies if dependencies is not None else self.dependencies
1580
+
1581
+ # Initialize run context
1582
+ run_context = RunContext(
1583
+ run_id=run_id,
1584
+ session_id=session_id,
1585
+ user_id=user_id,
1586
+ session_state=session_state,
1587
+ dependencies=dependencies,
1588
+ )
1591
1589
 
1592
1590
  # Resolve dependencies
1593
- if run_dependencies is not None:
1594
- self._resolve_run_dependencies(dependencies=run_dependencies)
1591
+ if run_context.dependencies is not None:
1592
+ self._resolve_run_dependencies(run_context=run_context)
1595
1593
 
1596
1594
  add_dependencies = (
1597
1595
  add_dependencies_to_context if add_dependencies_to_context is not None else self.add_dependencies_to_context
@@ -1603,12 +1601,9 @@ class Agent:
1603
1601
  )
1604
1602
  add_history = add_history_to_context if add_history_to_context is not None else self.add_history_to_context
1605
1603
 
1606
- # Initialize Knowledge Filters
1607
- effective_filters = knowledge_filters
1608
-
1609
1604
  # When filters are passed manually
1610
1605
  if self.knowledge_filters or knowledge_filters:
1611
- effective_filters = self._get_effective_filters(knowledge_filters)
1606
+ run_context.knowledge_filters = self._get_effective_filters(knowledge_filters)
1612
1607
 
1613
1608
  # Use stream override value when necessary
1614
1609
  if stream is None:
@@ -1632,11 +1627,8 @@ class Agent:
1632
1627
  self.model = cast(Model, self.model)
1633
1628
 
1634
1629
  # Merge agent metadata with run metadata
1635
- if self.metadata is not None:
1636
- if metadata is None:
1637
- metadata = self.metadata
1638
- else:
1639
- merge_dictionaries(metadata, self.metadata)
1630
+ if self.metadata is not None and metadata is not None:
1631
+ merge_dictionaries(metadata, self.metadata)
1640
1632
 
1641
1633
  # Create a new run_response for this attempt
1642
1634
  run_response = RunOutput(
@@ -1645,8 +1637,8 @@ class Agent:
1645
1637
  agent_id=self.id,
1646
1638
  user_id=user_id,
1647
1639
  agent_name=self.name,
1648
- metadata=metadata,
1649
- session_state=session_state,
1640
+ metadata=run_context.metadata,
1641
+ session_state=run_context.session_state,
1650
1642
  input=run_input,
1651
1643
  )
1652
1644
 
@@ -1668,15 +1660,12 @@ class Agent:
1668
1660
  if stream:
1669
1661
  response_iterator = self._run_stream(
1670
1662
  run_response=run_response,
1663
+ run_context=run_context,
1671
1664
  session=agent_session,
1672
- session_state=session_state,
1673
1665
  user_id=user_id,
1674
- knowledge_filters=effective_filters,
1675
1666
  add_history_to_context=add_history,
1676
1667
  add_dependencies_to_context=add_dependencies,
1677
1668
  add_session_state_to_context=add_session_state,
1678
- metadata=metadata,
1679
- dependencies=run_dependencies,
1680
1669
  response_format=response_format,
1681
1670
  stream_events=stream_events,
1682
1671
  yield_run_response=yield_run_response,
@@ -1687,15 +1676,12 @@ class Agent:
1687
1676
  else:
1688
1677
  response = self._run(
1689
1678
  run_response=run_response,
1679
+ run_context=run_context,
1690
1680
  session=agent_session,
1691
- session_state=session_state,
1692
1681
  user_id=user_id,
1693
- knowledge_filters=effective_filters,
1694
1682
  add_history_to_context=add_history,
1695
1683
  add_dependencies_to_context=add_dependencies,
1696
1684
  add_session_state_to_context=add_session_state,
1697
- metadata=metadata,
1698
- dependencies=run_dependencies,
1699
1685
  response_format=response_format,
1700
1686
  debug_mode=debug_mode,
1701
1687
  **kwargs,
@@ -1748,16 +1734,13 @@ class Agent:
1748
1734
  async def _arun(
1749
1735
  self,
1750
1736
  run_response: RunOutput,
1737
+ run_context: RunContext,
1751
1738
  session_id: str,
1752
- session_state: Optional[Dict[str, Any]] = None,
1753
1739
  user_id: Optional[str] = None,
1754
- knowledge_filters: Optional[Dict[str, Any]] = None,
1755
1740
  add_history_to_context: Optional[bool] = None,
1756
1741
  add_dependencies_to_context: Optional[bool] = None,
1757
1742
  add_session_state_to_context: Optional[bool] = None,
1758
- metadata: Optional[Dict[str, Any]] = None,
1759
1743
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
1760
- dependencies: Optional[Dict[str, Any]] = None,
1761
1744
  debug_mode: Optional[bool] = None,
1762
1745
  **kwargs: Any,
1763
1746
  ) -> RunOutput:
@@ -1792,16 +1775,21 @@ class Agent:
1792
1775
  # 2. Update metadata and session state
1793
1776
  self._update_metadata(session=agent_session)
1794
1777
  # Initialize session state
1795
- session_state = self._initialize_session_state(
1796
- session_state=session_state or {}, user_id=user_id, session_id=session_id, run_id=run_response.run_id
1778
+ run_context.session_state = self._initialize_session_state(
1779
+ session_state=run_context.session_state or {},
1780
+ user_id=user_id,
1781
+ session_id=session_id,
1782
+ run_id=run_response.run_id,
1797
1783
  )
1798
1784
  # Update session state from DB
1799
- if session_state is not None:
1800
- session_state = self._load_session_state(session=agent_session, session_state=session_state)
1785
+ if run_context.session_state is not None:
1786
+ run_context.session_state = self._load_session_state(
1787
+ session=agent_session, session_state=run_context.session_state
1788
+ )
1801
1789
 
1802
1790
  # 3. Resolve dependencies
1803
- if dependencies is not None:
1804
- await self._aresolve_run_dependencies(dependencies=dependencies)
1791
+ if run_context.dependencies is not None:
1792
+ await self._aresolve_run_dependencies(run_context=run_context)
1805
1793
 
1806
1794
  # 4. Execute pre-hooks
1807
1795
  run_input = cast(RunInput, run_response.input)
@@ -1811,10 +1799,8 @@ class Agent:
1811
1799
  pre_hook_iterator = self._aexecute_pre_hooks(
1812
1800
  hooks=self.pre_hooks, # type: ignore
1813
1801
  run_response=run_response,
1802
+ run_context=run_context,
1814
1803
  run_input=run_input,
1815
- session_state=session_state,
1816
- dependencies=dependencies,
1817
- metadata=metadata,
1818
1804
  session=agent_session,
1819
1805
  user_id=user_id,
1820
1806
  debug_mode=debug_mode,
@@ -1828,36 +1814,33 @@ class Agent:
1828
1814
  self.model = cast(Model, self.model)
1829
1815
  processed_tools = await self.aget_tools(
1830
1816
  run_response=run_response,
1817
+ run_context=run_context,
1831
1818
  session=agent_session,
1832
1819
  user_id=user_id,
1833
- knowledge_filters=knowledge_filters,
1834
1820
  )
1821
+
1835
1822
  _tools = self._determine_tools_for_model(
1836
1823
  model=self.model,
1837
1824
  processed_tools=processed_tools,
1838
1825
  run_response=run_response,
1826
+ run_context=run_context,
1839
1827
  session=agent_session,
1840
- session_state=session_state,
1841
- dependencies=dependencies,
1842
1828
  )
1843
1829
 
1844
1830
  # 6. Prepare run messages
1845
1831
  run_messages: RunMessages = await self._aget_run_messages(
1846
1832
  run_response=run_response,
1833
+ run_context=run_context,
1847
1834
  input=run_input.input_content,
1848
1835
  session=agent_session,
1849
- session_state=session_state,
1850
1836
  user_id=user_id,
1851
1837
  audio=run_input.audios,
1852
1838
  images=run_input.images,
1853
1839
  videos=run_input.videos,
1854
1840
  files=run_input.files,
1855
- knowledge_filters=knowledge_filters,
1856
1841
  add_history_to_context=add_history_to_context,
1857
- dependencies=dependencies,
1858
1842
  add_dependencies_to_context=add_dependencies_to_context,
1859
1843
  add_session_state_to_context=add_session_state_to_context,
1860
- metadata=metadata,
1861
1844
  tools=_tools,
1862
1845
  **kwargs,
1863
1846
  )
@@ -1898,6 +1881,7 @@ class Agent:
1898
1881
  tool_call_limit=self.tool_call_limit,
1899
1882
  response_format=response_format,
1900
1883
  send_media_to_model=self.send_media_to_model,
1884
+ run_response=run_response,
1901
1885
  )
1902
1886
 
1903
1887
  # Check for cancellation after model call
@@ -1930,16 +1914,14 @@ class Agent:
1930
1914
 
1931
1915
  # 12. Store media if enabled
1932
1916
  if self.store_media:
1933
- self._store_media(run_response, model_response)
1917
+ store_media_util(run_response, model_response)
1934
1918
 
1935
1919
  # 13. Execute post-hooks (after output is generated but before response is returned)
1936
1920
  if self.post_hooks is not None:
1937
1921
  async for _ in self._aexecute_post_hooks(
1938
1922
  hooks=self.post_hooks, # type: ignore
1939
1923
  run_output=run_response,
1940
- session_state=session_state,
1941
- dependencies=dependencies,
1942
- metadata=metadata,
1924
+ run_context=run_context,
1943
1925
  session=agent_session,
1944
1926
  user_id=user_id,
1945
1927
  debug_mode=debug_mode,
@@ -1965,7 +1947,12 @@ class Agent:
1965
1947
  run_response.status = RunStatus.completed
1966
1948
 
1967
1949
  # 16. Cleanup and store the run response and session
1968
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
1950
+ await self._acleanup_and_store(
1951
+ run_response=run_response,
1952
+ session=agent_session,
1953
+ run_context=run_context,
1954
+ user_id=user_id,
1955
+ )
1969
1956
 
1970
1957
  # Log Agent Telemetry
1971
1958
  await self._alog_agent_telemetry(session_id=agent_session.session_id, run_id=run_response.run_id)
@@ -1981,7 +1968,12 @@ class Agent:
1981
1968
  run_response.status = RunStatus.cancelled
1982
1969
 
1983
1970
  # Cleanup and store the run response and session
1984
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
1971
+ await self._acleanup_and_store(
1972
+ run_response=run_response,
1973
+ session=agent_session,
1974
+ run_context=run_context,
1975
+ user_id=user_id,
1976
+ )
1985
1977
 
1986
1978
  return run_response
1987
1979
 
@@ -2009,15 +2001,12 @@ class Agent:
2009
2001
  async def _arun_stream(
2010
2002
  self,
2011
2003
  run_response: RunOutput,
2004
+ run_context: RunContext,
2012
2005
  session_id: str,
2013
- session_state: Optional[Dict[str, Any]] = None,
2014
2006
  user_id: Optional[str] = None,
2015
- knowledge_filters: Optional[Dict[str, Any]] = None,
2016
- dependencies: Optional[Dict[str, Any]] = None,
2017
2007
  add_history_to_context: Optional[bool] = None,
2018
2008
  add_dependencies_to_context: Optional[bool] = None,
2019
2009
  add_session_state_to_context: Optional[bool] = None,
2020
- metadata: Optional[Dict[str, Any]] = None,
2021
2010
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
2022
2011
  stream_events: bool = False,
2023
2012
  yield_run_response: Optional[bool] = None,
@@ -2058,16 +2047,21 @@ class Agent:
2058
2047
  # 2. Update metadata and session state
2059
2048
  self._update_metadata(session=agent_session)
2060
2049
  # Initialize session state
2061
- session_state = self._initialize_session_state(
2062
- session_state=session_state or {}, user_id=user_id, session_id=session_id, run_id=run_response.run_id
2050
+ run_context.session_state = self._initialize_session_state(
2051
+ session_state=run_context.session_state or {},
2052
+ user_id=user_id,
2053
+ session_id=session_id,
2054
+ run_id=run_response.run_id,
2063
2055
  )
2064
2056
  # Update session state from DB
2065
- if session_state is not None:
2066
- session_state = self._load_session_state(session=agent_session, session_state=session_state)
2057
+ if run_context.session_state is not None:
2058
+ run_context.session_state = self._load_session_state(
2059
+ session=agent_session, session_state=run_context.session_state
2060
+ )
2067
2061
 
2068
2062
  # 3. Resolve dependencies
2069
- if dependencies is not None:
2070
- await self._aresolve_run_dependencies(dependencies=dependencies)
2063
+ if run_context.dependencies is not None:
2064
+ await self._aresolve_run_dependencies(run_context=run_context)
2071
2065
 
2072
2066
  # 4. Execute pre-hooks
2073
2067
  run_input = cast(RunInput, run_response.input)
@@ -2077,11 +2071,9 @@ class Agent:
2077
2071
  pre_hook_iterator = self._aexecute_pre_hooks(
2078
2072
  hooks=self.pre_hooks, # type: ignore
2079
2073
  run_response=run_response,
2074
+ run_context=run_context,
2080
2075
  run_input=run_input,
2081
2076
  session=agent_session,
2082
- session_state=session_state,
2083
- dependencies=dependencies,
2084
- metadata=metadata,
2085
2077
  user_id=user_id,
2086
2078
  debug_mode=debug_mode,
2087
2079
  **kwargs,
@@ -2093,36 +2085,33 @@ class Agent:
2093
2085
  self.model = cast(Model, self.model)
2094
2086
  processed_tools = await self.aget_tools(
2095
2087
  run_response=run_response,
2088
+ run_context=run_context,
2096
2089
  session=agent_session,
2097
2090
  user_id=user_id,
2098
- knowledge_filters=knowledge_filters,
2099
2091
  )
2092
+
2100
2093
  _tools = self._determine_tools_for_model(
2101
2094
  model=self.model,
2102
2095
  processed_tools=processed_tools,
2103
2096
  run_response=run_response,
2097
+ run_context=run_context,
2104
2098
  session=agent_session,
2105
- session_state=session_state,
2106
- dependencies=dependencies,
2107
2099
  )
2108
2100
 
2109
2101
  # 6. Prepare run messages
2110
2102
  run_messages: RunMessages = await self._aget_run_messages(
2111
2103
  run_response=run_response,
2104
+ run_context=run_context,
2112
2105
  input=run_input.input_content,
2113
2106
  session=agent_session,
2114
- session_state=session_state,
2115
2107
  user_id=user_id,
2116
2108
  audio=run_input.audios,
2117
2109
  images=run_input.images,
2118
2110
  videos=run_input.videos,
2119
2111
  files=run_input.files,
2120
- knowledge_filters=knowledge_filters,
2121
2112
  add_history_to_context=add_history_to_context,
2122
- dependencies=dependencies,
2123
2113
  add_dependencies_to_context=add_dependencies_to_context,
2124
2114
  add_session_state_to_context=add_session_state_to_context,
2125
- metadata=metadata,
2126
2115
  tools=_tools,
2127
2116
  **kwargs,
2128
2117
  )
@@ -2169,7 +2158,7 @@ class Agent:
2169
2158
  tools=_tools,
2170
2159
  response_format=response_format,
2171
2160
  stream_events=stream_events,
2172
- session_state=session_state,
2161
+ session_state=run_context.session_state,
2173
2162
  ):
2174
2163
  raise_if_cancelled(run_response.run_id) # type: ignore
2175
2164
  yield event
@@ -2186,7 +2175,7 @@ class Agent:
2186
2175
  tools=_tools,
2187
2176
  response_format=response_format,
2188
2177
  stream_events=stream_events,
2189
- session_state=session_state,
2178
+ session_state=run_context.session_state,
2190
2179
  ):
2191
2180
  raise_if_cancelled(run_response.run_id) # type: ignore
2192
2181
  if isinstance(event, RunContentEvent):
@@ -2246,9 +2235,7 @@ class Agent:
2246
2235
  async for event in self._aexecute_post_hooks(
2247
2236
  hooks=self.post_hooks, # type: ignore
2248
2237
  run_output=run_response,
2249
- session_state=session_state,
2250
- dependencies=dependencies,
2251
- metadata=metadata,
2238
+ run_context=run_context,
2252
2239
  session=agent_session,
2253
2240
  user_id=user_id,
2254
2241
  debug_mode=debug_mode,
@@ -2310,7 +2297,12 @@ class Agent:
2310
2297
  run_response.status = RunStatus.completed
2311
2298
 
2312
2299
  # 13. Cleanup and store the run response and session
2313
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
2300
+ await self._acleanup_and_store(
2301
+ run_response=run_response,
2302
+ session=agent_session,
2303
+ run_context=run_context,
2304
+ user_id=user_id,
2305
+ )
2314
2306
 
2315
2307
  if stream_events:
2316
2308
  yield completed_event # type: ignore
@@ -2341,7 +2333,12 @@ class Agent:
2341
2333
  )
2342
2334
 
2343
2335
  # Cleanup and store the run response and session
2344
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
2336
+ await self._acleanup_and_store(
2337
+ run_response=run_response,
2338
+ session=agent_session,
2339
+ run_context=run_context,
2340
+ user_id=user_id,
2341
+ )
2345
2342
  finally:
2346
2343
  # Always disconnect MCP tools
2347
2344
  await self._disconnect_mcp_tools()
@@ -2454,12 +2451,12 @@ class Agent:
2454
2451
  # 2. Validate input against input_schema if provided
2455
2452
  validated_input = self._validate_input(input)
2456
2453
 
2457
- # Normalise hook & guardails
2454
+ # Normalise hooks & guardails
2458
2455
  if not self._hooks_normalised:
2459
2456
  if self.pre_hooks:
2460
- self.pre_hooks = normalize_hooks(self.pre_hooks, async_mode=True)
2457
+ self.pre_hooks = normalize_hooks(self.pre_hooks, async_mode=True) # type: ignore
2461
2458
  if self.post_hooks:
2462
- self.post_hooks = normalize_hooks(self.post_hooks, async_mode=True)
2459
+ self.post_hooks = normalize_hooks(self.post_hooks, async_mode=True) # type: ignore
2463
2460
  self._hooks_normalised = True
2464
2461
 
2465
2462
  # Initialize session
@@ -2468,12 +2465,12 @@ class Agent:
2468
2465
  # Initialize the Agent
2469
2466
  self.initialize_agent(debug_mode=debug_mode)
2470
2467
 
2471
- image_artifacts, video_artifacts, audio_artifacts, file_artifacts = self._validate_media_object_id(
2468
+ image_artifacts, video_artifacts, audio_artifacts, file_artifacts = validate_media_object_id(
2472
2469
  images=images, videos=videos, audios=audio, files=files
2473
2470
  )
2474
2471
 
2475
2472
  # Resolve variables
2476
- run_dependencies = dependencies if dependencies is not None else self.dependencies
2473
+ dependencies = dependencies if dependencies is not None else self.dependencies
2477
2474
  add_dependencies = (
2478
2475
  add_dependencies_to_context if add_dependencies_to_context is not None else self.add_dependencies_to_context
2479
2476
  )
@@ -2515,9 +2512,9 @@ class Agent:
2515
2512
  self.model = cast(Model, self.model)
2516
2513
 
2517
2514
  # Get knowledge filters
2518
- effective_filters = knowledge_filters
2515
+ knowledge_filters = knowledge_filters
2519
2516
  if self.knowledge_filters or knowledge_filters:
2520
- effective_filters = self._get_effective_filters(knowledge_filters)
2517
+ knowledge_filters = self._get_effective_filters(knowledge_filters)
2521
2518
 
2522
2519
  # Merge agent metadata with run metadata
2523
2520
  if self.metadata is not None:
@@ -2526,6 +2523,17 @@ class Agent:
2526
2523
  else:
2527
2524
  merge_dictionaries(metadata, self.metadata)
2528
2525
 
2526
+ # Initialize run context
2527
+ run_context = RunContext(
2528
+ run_id=run_id,
2529
+ session_id=session_id,
2530
+ user_id=user_id,
2531
+ session_state=session_state,
2532
+ dependencies=dependencies,
2533
+ knowledge_filters=knowledge_filters,
2534
+ metadata=metadata,
2535
+ )
2536
+
2529
2537
  # If no retries are set, use the agent's default retries
2530
2538
  retries = retries if retries is not None else self.retries
2531
2539
 
@@ -2536,8 +2544,8 @@ class Agent:
2536
2544
  agent_id=self.id,
2537
2545
  user_id=user_id,
2538
2546
  agent_name=self.name,
2539
- metadata=metadata,
2540
- session_state=session_state,
2547
+ metadata=run_context.metadata,
2548
+ session_state=run_context.session_state,
2541
2549
  input=run_input,
2542
2550
  )
2543
2551
 
@@ -2557,34 +2565,28 @@ class Agent:
2557
2565
  if stream:
2558
2566
  return self._arun_stream( # type: ignore
2559
2567
  run_response=run_response,
2568
+ run_context=run_context,
2560
2569
  user_id=user_id,
2561
2570
  response_format=response_format,
2562
2571
  stream_events=stream_events,
2563
2572
  yield_run_response=yield_run_response,
2564
- dependencies=run_dependencies,
2565
2573
  session_id=session_id,
2566
- session_state=session_state,
2567
- knowledge_filters=effective_filters,
2568
2574
  add_history_to_context=add_history,
2569
2575
  add_dependencies_to_context=add_dependencies,
2570
2576
  add_session_state_to_context=add_session_state,
2571
- metadata=metadata,
2572
2577
  debug_mode=debug_mode,
2573
2578
  **kwargs,
2574
2579
  ) # type: ignore[assignment]
2575
2580
  else:
2576
2581
  return self._arun( # type: ignore
2577
2582
  run_response=run_response,
2583
+ run_context=run_context,
2578
2584
  user_id=user_id,
2579
2585
  response_format=response_format,
2580
- dependencies=run_dependencies,
2581
2586
  session_id=session_id,
2582
- session_state=session_state,
2583
- knowledge_filters=effective_filters,
2584
2587
  add_history_to_context=add_history,
2585
2588
  add_dependencies_to_context=add_dependencies,
2586
2589
  add_session_state_to_context=add_session_state,
2587
- metadata=metadata,
2588
2590
  debug_mode=debug_mode,
2589
2591
  **kwargs,
2590
2592
  )
@@ -2675,7 +2677,7 @@ class Agent:
2675
2677
  self,
2676
2678
  run_response: Optional[RunOutput] = None,
2677
2679
  *,
2678
- run_id: Optional[str] = None,
2680
+ run_id: Optional[str] = None, # type: ignore
2679
2681
  updated_tools: Optional[List[ToolExecution]] = None,
2680
2682
  stream: Optional[bool] = None,
2681
2683
  stream_events: Optional[bool] = False,
@@ -2716,6 +2718,7 @@ class Agent:
2716
2718
  raise Exception("continue_run() is not supported with an async DB. Please use acontinue_arun() instead.")
2717
2719
 
2718
2720
  session_id = run_response.session_id if run_response else session_id
2721
+ run_id: str = run_response.run_id if run_response else run_id # type: ignore
2719
2722
 
2720
2723
  session_id, user_id = self._initialize_session(
2721
2724
  session_id=session_id,
@@ -2735,24 +2738,32 @@ class Agent:
2735
2738
  # Update session state from DB
2736
2739
  session_state = self._load_session_state(session=agent_session, session_state=session_state)
2737
2740
 
2738
- run_dependencies = dependencies if dependencies is not None else self.dependencies
2741
+ dependencies = dependencies if dependencies is not None else self.dependencies
2739
2742
 
2740
- # Resolve dependencies
2741
- if run_dependencies is not None:
2742
- self._resolve_run_dependencies(dependencies=run_dependencies)
2743
+ # Initialize run context
2744
+ run_context = RunContext(
2745
+ run_id=run_id, # type: ignore
2746
+ session_id=session_id,
2747
+ user_id=user_id,
2748
+ session_state=session_state,
2749
+ dependencies=dependencies,
2750
+ )
2743
2751
 
2744
- effective_filters = knowledge_filters
2752
+ # Resolve dependencies
2753
+ if run_context.dependencies is not None:
2754
+ self._resolve_run_dependencies(run_context=run_context)
2745
2755
 
2746
2756
  # When filters are passed manually
2747
- if self.knowledge_filters or knowledge_filters:
2748
- effective_filters = self._get_effective_filters(knowledge_filters)
2757
+ if self.knowledge_filters or run_context.knowledge_filters or knowledge_filters:
2758
+ run_context.knowledge_filters = self._get_effective_filters(knowledge_filters)
2749
2759
 
2750
2760
  # Merge agent metadata with run metadata
2761
+ run_context.metadata = metadata
2751
2762
  if self.metadata is not None:
2752
- if metadata is None:
2753
- metadata = self.metadata
2763
+ if run_context.metadata is None:
2764
+ run_context.metadata = self.metadata
2754
2765
  else:
2755
- merge_dictionaries(metadata, self.metadata)
2766
+ merge_dictionaries(run_context.metadata, self.metadata)
2756
2767
 
2757
2768
  # If no retries are set, use the agent's default retries
2758
2769
  retries = retries if retries is not None else self.retries
@@ -2803,17 +2814,17 @@ class Agent:
2803
2814
 
2804
2815
  processed_tools = self.get_tools(
2805
2816
  run_response=run_response,
2817
+ run_context=run_context,
2806
2818
  session=agent_session,
2807
2819
  user_id=user_id,
2808
- knowledge_filters=effective_filters,
2809
2820
  )
2821
+
2810
2822
  _tools = self._determine_tools_for_model(
2811
2823
  model=self.model,
2812
2824
  processed_tools=processed_tools,
2813
2825
  run_response=run_response,
2826
+ run_context=run_context,
2814
2827
  session=agent_session,
2815
- session_state=session_state,
2816
- dependencies=run_dependencies,
2817
2828
  )
2818
2829
 
2819
2830
  last_exception = None
@@ -2836,12 +2847,10 @@ class Agent:
2836
2847
  response_iterator = self._continue_run_stream(
2837
2848
  run_response=run_response,
2838
2849
  run_messages=run_messages,
2850
+ run_context=run_context,
2839
2851
  tools=_tools,
2840
2852
  user_id=user_id,
2841
2853
  session=agent_session,
2842
- session_state=session_state,
2843
- dependencies=run_dependencies,
2844
- metadata=metadata,
2845
2854
  response_format=response_format,
2846
2855
  stream_events=stream_events,
2847
2856
  debug_mode=debug_mode,
@@ -2852,12 +2861,10 @@ class Agent:
2852
2861
  response = self._continue_run(
2853
2862
  run_response=run_response,
2854
2863
  run_messages=run_messages,
2864
+ run_context=run_context,
2855
2865
  tools=_tools,
2856
2866
  user_id=user_id,
2857
2867
  session=agent_session,
2858
- session_state=session_state,
2859
- dependencies=run_dependencies,
2860
- metadata=metadata,
2861
2868
  response_format=response_format,
2862
2869
  debug_mode=debug_mode,
2863
2870
  **kwargs,
@@ -2904,11 +2911,9 @@ class Agent:
2904
2911
  self,
2905
2912
  run_response: RunOutput,
2906
2913
  run_messages: RunMessages,
2914
+ run_context: RunContext,
2907
2915
  session: AgentSession,
2908
2916
  tools: List[Union[Function, dict]],
2909
- session_state: Optional[Dict[str, Any]] = None,
2910
- dependencies: Optional[Dict[str, Any]] = None,
2911
- metadata: Optional[Dict[str, Any]] = None,
2912
2917
  user_id: Optional[str] = None,
2913
2918
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
2914
2919
  debug_mode: Optional[bool] = None,
@@ -2965,18 +2970,16 @@ class Agent:
2965
2970
 
2966
2971
  # 5. Store media if enabled
2967
2972
  if self.store_media:
2968
- self._store_media(run_response, model_response)
2973
+ store_media_util(run_response, model_response)
2969
2974
 
2970
2975
  # 6. Execute post-hooks
2971
2976
  if self.post_hooks is not None:
2972
2977
  post_hook_iterator = self._execute_post_hooks(
2973
2978
  hooks=self.post_hooks, # type: ignore
2974
2979
  run_output=run_response,
2980
+ run_context=run_context,
2975
2981
  session=session,
2976
2982
  user_id=user_id,
2977
- session_state=session_state,
2978
- dependencies=dependencies,
2979
- metadata=metadata,
2980
2983
  debug_mode=debug_mode,
2981
2984
  **kwargs,
2982
2985
  )
@@ -2998,7 +3001,9 @@ class Agent:
2998
3001
  run_response.status = RunStatus.completed
2999
3002
 
3000
3003
  # 8. Cleanup and store the run response and session
3001
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
3004
+ self._cleanup_and_store(
3005
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
3006
+ )
3002
3007
 
3003
3008
  # Log Agent Telemetry
3004
3009
  self._log_agent_telemetry(session_id=session.session_id, run_id=run_response.run_id)
@@ -3011,7 +3016,9 @@ class Agent:
3011
3016
  run_response.content = str(e)
3012
3017
 
3013
3018
  # Cleanup and store the run response and session
3014
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
3019
+ self._cleanup_and_store(
3020
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
3021
+ )
3015
3022
 
3016
3023
  return run_response
3017
3024
  finally:
@@ -3022,14 +3029,12 @@ class Agent:
3022
3029
  self,
3023
3030
  run_response: RunOutput,
3024
3031
  run_messages: RunMessages,
3032
+ run_context: RunContext,
3025
3033
  session: AgentSession,
3026
3034
  tools: List[Union[Function, dict]],
3027
- session_state: Optional[Dict[str, Any]] = None,
3028
- metadata: Optional[Dict[str, Any]] = None,
3029
3035
  user_id: Optional[str] = None,
3030
3036
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
3031
3037
  stream_events: bool = False,
3032
- dependencies: Optional[Dict[str, Any]] = None,
3033
3038
  debug_mode: Optional[bool] = None,
3034
3039
  **kwargs,
3035
3040
  ) -> Iterator[RunOutputEvent]:
@@ -3045,8 +3050,8 @@ class Agent:
3045
3050
  """
3046
3051
 
3047
3052
  # 1. Resolve dependencies
3048
- if dependencies is not None:
3049
- self._resolve_run_dependencies(dependencies=dependencies)
3053
+ if run_context.dependencies is not None:
3054
+ self._resolve_run_dependencies(run_context=run_context)
3050
3055
 
3051
3056
  # Start the Run by yielding a RunContinued event
3052
3057
  if stream_events:
@@ -3071,7 +3076,7 @@ class Agent:
3071
3076
  tools=tools,
3072
3077
  response_format=response_format,
3073
3078
  stream_events=stream_events,
3074
- session_state=session_state,
3079
+ session_state=run_context.session_state,
3075
3080
  ):
3076
3081
  yield event
3077
3082
 
@@ -3102,9 +3107,7 @@ class Agent:
3102
3107
  hooks=self.post_hooks, # type: ignore
3103
3108
  run_output=run_response,
3104
3109
  session=session,
3105
- session_state=session_state,
3106
- dependencies=dependencies,
3107
- metadata=metadata,
3110
+ run_context=run_context,
3108
3111
  user_id=user_id,
3109
3112
  debug_mode=debug_mode,
3110
3113
  **kwargs,
@@ -3157,7 +3160,9 @@ class Agent:
3157
3160
  run_response.status = RunStatus.completed
3158
3161
 
3159
3162
  # 5. Cleanup and store the run response and session
3160
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
3163
+ self._cleanup_and_store(
3164
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
3165
+ )
3161
3166
 
3162
3167
  if stream_events:
3163
3168
  yield completed_event # type: ignore
@@ -3182,7 +3187,9 @@ class Agent:
3182
3187
  )
3183
3188
 
3184
3189
  # Cleanup and store the run response and session
3185
- self._cleanup_and_store(run_response=run_response, session=session, user_id=user_id)
3190
+ self._cleanup_and_store(
3191
+ run_response=run_response, session=session, run_context=run_context, user_id=user_id
3192
+ )
3186
3193
  finally:
3187
3194
  # Always clean up the run tracking
3188
3195
  cleanup_run(run_response.run_id) # type: ignore
@@ -3229,7 +3236,7 @@ class Agent:
3229
3236
  self,
3230
3237
  run_response: Optional[RunOutput] = None,
3231
3238
  *,
3232
- run_id: Optional[str] = None,
3239
+ run_id: Optional[str] = None, # type: ignore
3233
3240
  updated_tools: Optional[List[ToolExecution]] = None,
3234
3241
  stream: Optional[bool] = None,
3235
3242
  stream_events: Optional[bool] = None,
@@ -3272,11 +3279,12 @@ class Agent:
3272
3279
  session_id=session_id,
3273
3280
  user_id=user_id,
3274
3281
  )
3282
+ run_id: str = run_id or run_response.run_id if run_response else run_id # type: ignore
3275
3283
 
3276
3284
  # Initialize the Agent
3277
3285
  self.initialize_agent(debug_mode=debug_mode)
3278
3286
 
3279
- run_dependencies = dependencies if dependencies is not None else self.dependencies
3287
+ dependencies = dependencies if dependencies is not None else self.dependencies
3280
3288
 
3281
3289
  # If no retries are set, use the agent's default retries
3282
3290
  retries = retries if retries is not None else self.retries
@@ -3303,9 +3311,9 @@ class Agent:
3303
3311
  self.stream_events = self.stream_events or stream_events
3304
3312
 
3305
3313
  # Get knowledge filters
3306
- effective_filters = knowledge_filters
3314
+ knowledge_filters = knowledge_filters
3307
3315
  if self.knowledge_filters or knowledge_filters:
3308
- effective_filters = self._get_effective_filters(knowledge_filters)
3316
+ knowledge_filters = self._get_effective_filters(knowledge_filters)
3309
3317
 
3310
3318
  # Merge agent metadata with run metadata
3311
3319
  if self.metadata is not None:
@@ -3318,6 +3326,17 @@ class Agent:
3318
3326
  response_format = self._get_response_format()
3319
3327
  self.model = cast(Model, self.model)
3320
3328
 
3329
+ # Initialize run context
3330
+ run_context = RunContext(
3331
+ run_id=run_id, # type: ignore
3332
+ session_id=session_id,
3333
+ user_id=user_id,
3334
+ session_state={},
3335
+ dependencies=dependencies,
3336
+ knowledge_filters=knowledge_filters,
3337
+ metadata=metadata,
3338
+ )
3339
+
3321
3340
  last_exception = None
3322
3341
  num_attempts = retries + 1
3323
3342
  for attempt in range(num_attempts):
@@ -3325,15 +3344,13 @@ class Agent:
3325
3344
  if stream:
3326
3345
  return self._acontinue_run_stream(
3327
3346
  run_response=run_response,
3347
+ run_context=run_context,
3328
3348
  updated_tools=updated_tools,
3329
- knowledge_filters=effective_filters,
3330
3349
  run_id=run_id,
3331
3350
  user_id=user_id,
3332
3351
  session_id=session_id,
3333
3352
  response_format=response_format,
3334
- dependencies=run_dependencies,
3335
3353
  stream_events=stream_events,
3336
- metadata=metadata,
3337
3354
  yield_run_response=yield_run_response,
3338
3355
  debug_mode=debug_mode,
3339
3356
  **kwargs,
@@ -3342,13 +3359,11 @@ class Agent:
3342
3359
  return self._acontinue_run( # type: ignore
3343
3360
  session_id=session_id,
3344
3361
  run_response=run_response,
3362
+ run_context=run_context,
3345
3363
  updated_tools=updated_tools,
3346
- knowledge_filters=effective_filters,
3347
3364
  run_id=run_id,
3348
3365
  user_id=user_id,
3349
3366
  response_format=response_format,
3350
- dependencies=run_dependencies,
3351
- metadata=metadata,
3352
3367
  debug_mode=debug_mode,
3353
3368
  **kwargs,
3354
3369
  )
@@ -3392,14 +3407,12 @@ class Agent:
3392
3407
  async def _acontinue_run(
3393
3408
  self,
3394
3409
  session_id: str,
3410
+ run_context: RunContext,
3395
3411
  run_response: Optional[RunOutput] = None,
3396
3412
  updated_tools: Optional[List[ToolExecution]] = None,
3397
- knowledge_filters: Optional[Dict[str, Any]] = None,
3398
3413
  run_id: Optional[str] = None,
3399
3414
  user_id: Optional[str] = None,
3400
3415
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
3401
- dependencies: Optional[Dict[str, Any]] = None,
3402
- metadata: Optional[Dict[str, Any]] = None,
3403
3416
  debug_mode: Optional[bool] = None,
3404
3417
  **kwargs,
3405
3418
  ) -> RunOutput:
@@ -3427,18 +3440,20 @@ class Agent:
3427
3440
  agent_session = await self._aread_or_create_session(session_id=session_id, user_id=user_id)
3428
3441
 
3429
3442
  # 2. Resolve dependencies
3430
- if dependencies is not None:
3431
- await self._aresolve_run_dependencies(dependencies=dependencies)
3443
+ if run_context.dependencies is not None:
3444
+ await self._aresolve_run_dependencies(run_context=run_context)
3432
3445
 
3433
3446
  # 3. Update metadata and session state
3434
3447
  self._update_metadata(session=agent_session)
3435
3448
  # Initialize session state
3436
- session_state = self._initialize_session_state(
3449
+ run_context.session_state = self._initialize_session_state(
3437
3450
  session_state={}, user_id=user_id, session_id=session_id, run_id=run_id
3438
3451
  )
3439
3452
  # Update session state from DB
3440
- if session_state is not None:
3441
- session_state = self._load_session_state(session=agent_session, session_state=session_state)
3453
+ if run_context.session_state is not None:
3454
+ run_context.session_state = self._load_session_state(
3455
+ session=agent_session, session_state=run_context.session_state
3456
+ )
3442
3457
 
3443
3458
  # 4. Prepare run response
3444
3459
  if run_response is not None:
@@ -3465,17 +3480,17 @@ class Agent:
3465
3480
  self.model = cast(Model, self.model)
3466
3481
  processed_tools = await self.aget_tools(
3467
3482
  run_response=run_response,
3483
+ run_context=run_context,
3468
3484
  session=agent_session,
3469
3485
  user_id=user_id,
3470
- knowledge_filters=knowledge_filters,
3471
3486
  )
3487
+
3472
3488
  _tools = self._determine_tools_for_model(
3473
3489
  model=self.model,
3474
3490
  processed_tools=processed_tools,
3475
3491
  run_response=run_response,
3492
+ run_context=run_context,
3476
3493
  session=agent_session,
3477
- session_state=session_state,
3478
- dependencies=dependencies,
3479
3494
  )
3480
3495
 
3481
3496
  # 6. Prepare run messages
@@ -3525,7 +3540,7 @@ class Agent:
3525
3540
 
3526
3541
  # 11. Store media if enabled
3527
3542
  if self.store_media:
3528
- self._store_media(run_response, model_response)
3543
+ store_media_util(run_response, model_response)
3529
3544
 
3530
3545
  raise_if_cancelled(run_response.run_id) # type: ignore
3531
3546
 
@@ -3534,12 +3549,10 @@ class Agent:
3534
3549
  async for _ in self._aexecute_post_hooks(
3535
3550
  hooks=self.post_hooks, # type: ignore
3536
3551
  run_output=run_response,
3552
+ run_context=run_context,
3537
3553
  session=agent_session,
3538
3554
  user_id=user_id,
3539
3555
  debug_mode=debug_mode,
3540
- session_state=session_state,
3541
- dependencies=dependencies,
3542
- metadata=metadata,
3543
3556
  **kwargs,
3544
3557
  ):
3545
3558
  pass
@@ -3561,7 +3574,12 @@ class Agent:
3561
3574
  run_response.status = RunStatus.completed
3562
3575
 
3563
3576
  # 14. Cleanup and store the run response and session
3564
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
3577
+ await self._acleanup_and_store(
3578
+ run_response=run_response,
3579
+ session=agent_session,
3580
+ run_context=run_context,
3581
+ user_id=user_id,
3582
+ )
3565
3583
 
3566
3584
  # Log Agent Telemetry
3567
3585
  await self._alog_agent_telemetry(session_id=agent_session.session_id, run_id=run_response.run_id)
@@ -3577,7 +3595,12 @@ class Agent:
3577
3595
  run_response.status = RunStatus.cancelled
3578
3596
 
3579
3597
  # Cleanup and store the run response and session
3580
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
3598
+ await self._acleanup_and_store(
3599
+ run_response=run_response,
3600
+ session=agent_session,
3601
+ run_context=run_context,
3602
+ user_id=user_id,
3603
+ )
3581
3604
 
3582
3605
  return run_response
3583
3606
  finally:
@@ -3590,16 +3613,14 @@ class Agent:
3590
3613
  async def _acontinue_run_stream(
3591
3614
  self,
3592
3615
  session_id: str,
3616
+ run_context: RunContext,
3593
3617
  run_response: Optional[RunOutput] = None,
3594
3618
  updated_tools: Optional[List[ToolExecution]] = None,
3595
- knowledge_filters: Optional[Dict[str, Any]] = None,
3596
3619
  run_id: Optional[str] = None,
3597
3620
  user_id: Optional[str] = None,
3598
3621
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
3599
3622
  stream_events: bool = False,
3600
3623
  yield_run_response: Optional[bool] = None,
3601
- dependencies: Optional[Dict[str, Any]] = None,
3602
- metadata: Optional[Dict[str, Any]] = None,
3603
3624
  debug_mode: Optional[bool] = None,
3604
3625
  **kwargs,
3605
3626
  ) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]:
@@ -3621,8 +3642,8 @@ class Agent:
3621
3642
  log_debug(f"Agent Run Continue: {run_response.run_id if run_response else run_id}", center=True) # type: ignore
3622
3643
 
3623
3644
  # 1. Resolve dependencies
3624
- if dependencies is not None:
3625
- await self._aresolve_run_dependencies(dependencies=dependencies)
3645
+ if run_context.dependencies is not None:
3646
+ await self._aresolve_run_dependencies(run_context=run_context)
3626
3647
 
3627
3648
  # 2. Read existing session from db
3628
3649
  agent_session = await self._aread_or_create_session(session_id=session_id, user_id=user_id)
@@ -3630,12 +3651,14 @@ class Agent:
3630
3651
  # 3. Update session state and metadata
3631
3652
  self._update_metadata(session=agent_session)
3632
3653
  # Initialize session state
3633
- session_state = self._initialize_session_state(
3654
+ run_context.session_state = self._initialize_session_state(
3634
3655
  session_state={}, user_id=user_id, session_id=session_id, run_id=run_id
3635
3656
  )
3636
3657
  # Update session state from DB
3637
- if session_state is not None:
3638
- session_state = self._load_session_state(session=agent_session, session_state=session_state)
3658
+ if run_context.session_state is not None:
3659
+ run_context.session_state = self._load_session_state(
3660
+ session=agent_session, session_state=run_context.session_state
3661
+ )
3639
3662
 
3640
3663
  # 4. Prepare run response
3641
3664
  if run_response is not None:
@@ -3662,17 +3685,17 @@ class Agent:
3662
3685
  self.model = cast(Model, self.model)
3663
3686
  processed_tools = await self.aget_tools(
3664
3687
  run_response=run_response,
3688
+ run_context=run_context,
3665
3689
  session=agent_session,
3666
3690
  user_id=user_id,
3667
- knowledge_filters=knowledge_filters,
3668
3691
  )
3692
+
3669
3693
  _tools = self._determine_tools_for_model(
3670
3694
  model=self.model,
3671
3695
  processed_tools=processed_tools,
3672
3696
  run_response=run_response,
3697
+ run_context=run_context,
3673
3698
  session=agent_session,
3674
- session_state=session_state,
3675
- dependencies=dependencies,
3676
3699
  )
3677
3700
 
3678
3701
  # 6. Prepare run messages
@@ -3777,11 +3800,9 @@ class Agent:
3777
3800
  async for event in self._aexecute_post_hooks(
3778
3801
  hooks=self.post_hooks, # type: ignore
3779
3802
  run_output=run_response,
3803
+ run_context=run_context,
3780
3804
  session=agent_session,
3781
3805
  user_id=user_id,
3782
- session_state=session_state,
3783
- dependencies=dependencies,
3784
- metadata=metadata,
3785
3806
  debug_mode=debug_mode,
3786
3807
  **kwargs,
3787
3808
  ):
@@ -3832,7 +3853,9 @@ class Agent:
3832
3853
  run_response.status = RunStatus.completed
3833
3854
 
3834
3855
  # 10. Cleanup and store the run response and session
3835
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
3856
+ await self._acleanup_and_store(
3857
+ run_response=run_response, session=agent_session, run_context=run_context, user_id=user_id
3858
+ )
3836
3859
 
3837
3860
  if stream_events:
3838
3861
  yield completed_event # type: ignore
@@ -3859,7 +3882,12 @@ class Agent:
3859
3882
  )
3860
3883
 
3861
3884
  # Cleanup and store the run response and session
3862
- await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
3885
+ await self._acleanup_and_store(
3886
+ run_response=run_response,
3887
+ session=agent_session,
3888
+ run_context=run_context,
3889
+ user_id=user_id,
3890
+ )
3863
3891
  finally:
3864
3892
  # Always disconnect MCP tools
3865
3893
  await self._disconnect_mcp_tools()
@@ -3873,9 +3901,7 @@ class Agent:
3873
3901
  run_response: RunOutput,
3874
3902
  run_input: RunInput,
3875
3903
  session: AgentSession,
3876
- session_state: Optional[Dict[str, Any]] = None,
3877
- dependencies: Optional[Dict[str, Any]] = None,
3878
- metadata: Optional[Dict[str, Any]] = None,
3904
+ run_context: RunContext,
3879
3905
  user_id: Optional[str] = None,
3880
3906
  debug_mode: Optional[bool] = None,
3881
3907
  **kwargs: Any,
@@ -3887,11 +3913,12 @@ class Agent:
3887
3913
  # Prepare all possible arguments once
3888
3914
  all_args = {
3889
3915
  "run_input": run_input,
3916
+ "run_context": run_context,
3890
3917
  "agent": self,
3891
3918
  "session": session,
3892
- "session_state": session_state,
3893
- "dependencies": dependencies,
3894
- "metadata": metadata,
3919
+ "session_state": run_context.session_state,
3920
+ "dependencies": run_context.dependencies,
3921
+ "metadata": run_context.metadata,
3895
3922
  "user_id": user_id,
3896
3923
  "debug_mode": debug_mode or self.debug_mode,
3897
3924
  }
@@ -3942,10 +3969,8 @@ class Agent:
3942
3969
  hooks: Optional[List[Callable[..., Any]]],
3943
3970
  run_response: RunOutput,
3944
3971
  run_input: RunInput,
3972
+ run_context: RunContext,
3945
3973
  session: AgentSession,
3946
- session_state: Optional[Dict[str, Any]] = None,
3947
- dependencies: Optional[Dict[str, Any]] = None,
3948
- metadata: Optional[Dict[str, Any]] = None,
3949
3974
  user_id: Optional[str] = None,
3950
3975
  debug_mode: Optional[bool] = None,
3951
3976
  **kwargs: Any,
@@ -3959,9 +3984,10 @@ class Agent:
3959
3984
  "run_input": run_input,
3960
3985
  "agent": self,
3961
3986
  "session": session,
3962
- "session_state": session_state,
3963
- "dependencies": dependencies,
3964
- "metadata": metadata,
3987
+ "run_context": run_context,
3988
+ "session_state": run_context.session_state,
3989
+ "dependencies": run_context.dependencies,
3990
+ "metadata": run_context.metadata,
3965
3991
  "user_id": user_id,
3966
3992
  "debug_mode": debug_mode or self.debug_mode,
3967
3993
  }
@@ -4016,9 +4042,7 @@ class Agent:
4016
4042
  hooks: Optional[List[Callable[..., Any]]],
4017
4043
  run_output: RunOutput,
4018
4044
  session: AgentSession,
4019
- session_state: Optional[Dict[str, Any]] = None,
4020
- dependencies: Optional[Dict[str, Any]] = None,
4021
- metadata: Optional[Dict[str, Any]] = None,
4045
+ run_context: RunContext,
4022
4046
  user_id: Optional[str] = None,
4023
4047
  debug_mode: Optional[bool] = None,
4024
4048
  **kwargs: Any,
@@ -4032,10 +4056,11 @@ class Agent:
4032
4056
  "run_output": run_output,
4033
4057
  "agent": self,
4034
4058
  "session": session,
4059
+ "session_state": run_context.session_state,
4060
+ "dependencies": run_context.dependencies,
4061
+ "metadata": run_context.metadata,
4035
4062
  "user_id": user_id,
4036
- "session_state": session_state,
4037
- "dependencies": dependencies,
4038
- "metadata": metadata,
4063
+ "run_context": run_context,
4039
4064
  "debug_mode": debug_mode or self.debug_mode,
4040
4065
  }
4041
4066
  all_args.update(kwargs)
@@ -4078,10 +4103,8 @@ class Agent:
4078
4103
  self,
4079
4104
  hooks: Optional[List[Callable[..., Any]]],
4080
4105
  run_output: RunOutput,
4106
+ run_context: RunContext,
4081
4107
  session: AgentSession,
4082
- session_state: Optional[Dict[str, Any]] = None,
4083
- dependencies: Optional[Dict[str, Any]] = None,
4084
- metadata: Optional[Dict[str, Any]] = None,
4085
4108
  user_id: Optional[str] = None,
4086
4109
  debug_mode: Optional[bool] = None,
4087
4110
  **kwargs: Any,
@@ -4095,10 +4118,11 @@ class Agent:
4095
4118
  "run_output": run_output,
4096
4119
  "agent": self,
4097
4120
  "session": session,
4121
+ "run_context": run_context,
4122
+ "session_state": run_context.session_state,
4123
+ "dependencies": run_context.dependencies,
4124
+ "metadata": run_context.metadata,
4098
4125
  "user_id": user_id,
4099
- "session_state": session_state,
4100
- "dependencies": dependencies,
4101
- "metadata": metadata,
4102
4126
  "debug_mode": debug_mode or self.debug_mode,
4103
4127
  }
4104
4128
  all_args.update(kwargs)
@@ -4587,25 +4611,6 @@ class Agent:
4587
4611
  _t.requires_user_input = False
4588
4612
  _t.answered = True
4589
4613
 
4590
- def _store_media(self, run_response: RunOutput, model_response: ModelResponse):
4591
- """Store media from model response in run_response for persistence"""
4592
- # Handle generated media fields from ModelResponse (generated media)
4593
- if model_response.images is not None:
4594
- for image in model_response.images:
4595
- self._add_image(image, run_response) # Generated images go to run_response.images
4596
-
4597
- if model_response.videos is not None:
4598
- for video in model_response.videos:
4599
- self._add_video(video, run_response) # Generated videos go to run_response.videos
4600
-
4601
- if model_response.audios is not None:
4602
- for audio in model_response.audios:
4603
- self._add_audio(audio, run_response) # Generated audio go to run_response.audio
4604
-
4605
- if model_response.files is not None:
4606
- for file in model_response.files:
4607
- self._add_file(file, run_response) # Generated files go to run_response.files
4608
-
4609
4614
  def _update_run_response(
4610
4615
  self,
4611
4616
  model_response: ModelResponse,
@@ -5030,7 +5035,9 @@ class Agent:
5030
5035
  # Store media in run_response if store_media is enabled
5031
5036
  if self.store_media:
5032
5037
  for image in model_response_event.images:
5033
- self._add_image(image, run_response)
5038
+ if run_response.images is None:
5039
+ run_response.images = []
5040
+ run_response.images.append(image)
5034
5041
 
5035
5042
  # Handle tool interruption events
5036
5043
  elif model_response_event.event == ModelResponseEvent.tool_call_paused.value:
@@ -5079,15 +5086,27 @@ class Agent:
5079
5086
 
5080
5087
  if model_response_event.images is not None:
5081
5088
  for image in model_response_event.images:
5082
- self._add_image(image, run_response)
5089
+ if run_response.images is None:
5090
+ run_response.images = []
5091
+ run_response.images.append(image)
5083
5092
 
5084
5093
  if model_response_event.videos is not None:
5085
5094
  for video in model_response_event.videos:
5086
- self._add_video(video, run_response)
5095
+ if run_response.videos is None:
5096
+ run_response.videos = []
5097
+ run_response.videos.append(video)
5087
5098
 
5088
5099
  if model_response_event.audios is not None:
5089
5100
  for audio in model_response_event.audios:
5090
- self._add_audio(audio, run_response)
5101
+ if run_response.audio is None:
5102
+ run_response.audio = []
5103
+ run_response.audio.append(audio)
5104
+
5105
+ if model_response_event.files is not None:
5106
+ for file_obj in model_response_event.files:
5107
+ if run_response.files is None:
5108
+ run_response.files = []
5109
+ run_response.files.append(file_obj)
5091
5110
 
5092
5111
  reasoning_step: Optional[ReasoningStep] = None
5093
5112
 
@@ -5304,12 +5323,16 @@ class Agent:
5304
5323
  def get_tools(
5305
5324
  self,
5306
5325
  run_response: RunOutput,
5326
+ run_context: RunContext,
5307
5327
  session: AgentSession,
5308
5328
  user_id: Optional[str] = None,
5309
5329
  knowledge_filters: Optional[Dict[str, Any]] = None,
5310
5330
  ) -> List[Union[Toolkit, Callable, Function, Dict]]:
5311
5331
  agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
5312
5332
 
5333
+ # Consider both run_context.knowledge_filters and knowledge_filters (deprecated)
5334
+ run_context.knowledge_filters = run_context.knowledge_filters or knowledge_filters
5335
+
5313
5336
  # Add provided tools
5314
5337
  if self.tools is not None:
5315
5338
  # If not running in async mode, raise if any tool is async
@@ -5355,7 +5378,7 @@ class Agent:
5355
5378
  self._search_knowledge_base_with_agentic_filters_function(
5356
5379
  run_response=run_response,
5357
5380
  async_mode=False,
5358
- knowledge_filters=knowledge_filters,
5381
+ knowledge_filters=run_context.knowledge_filters,
5359
5382
  )
5360
5383
  )
5361
5384
  else:
@@ -5363,7 +5386,7 @@ class Agent:
5363
5386
  self._get_search_knowledge_base_function(
5364
5387
  run_response=run_response,
5365
5388
  async_mode=False,
5366
- knowledge_filters=knowledge_filters,
5389
+ knowledge_filters=run_context.knowledge_filters,
5367
5390
  )
5368
5391
  )
5369
5392
 
@@ -5375,6 +5398,7 @@ class Agent:
5375
5398
  async def aget_tools(
5376
5399
  self,
5377
5400
  run_response: RunOutput,
5401
+ run_context: RunContext,
5378
5402
  session: AgentSession,
5379
5403
  user_id: Optional[str] = None,
5380
5404
  knowledge_filters: Optional[Dict[str, Any]] = None,
@@ -5382,6 +5406,9 @@ class Agent:
5382
5406
  ) -> List[Union[Toolkit, Callable, Function, Dict]]:
5383
5407
  agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
5384
5408
 
5409
+ # Consider both run_context.knowledge_filters and knowledge_filters (deprecated)
5410
+ run_context.knowledge_filters = run_context.knowledge_filters or knowledge_filters
5411
+
5385
5412
  # Connect MCP tools
5386
5413
  await self._connect_mcp_tools()
5387
5414
 
@@ -5439,7 +5466,7 @@ class Agent:
5439
5466
  self._search_knowledge_base_with_agentic_filters_function(
5440
5467
  run_response=run_response,
5441
5468
  async_mode=True,
5442
- knowledge_filters=knowledge_filters,
5469
+ knowledge_filters=run_context.knowledge_filters,
5443
5470
  )
5444
5471
  )
5445
5472
  else:
@@ -5447,7 +5474,7 @@ class Agent:
5447
5474
  self._get_search_knowledge_base_function(
5448
5475
  run_response=run_response,
5449
5476
  async_mode=True,
5450
- knowledge_filters=knowledge_filters,
5477
+ knowledge_filters=run_context.knowledge_filters,
5451
5478
  )
5452
5479
  )
5453
5480
 
@@ -5461,9 +5488,8 @@ class Agent:
5461
5488
  model: Model,
5462
5489
  processed_tools: List[Union[Toolkit, Callable, Function, Dict]],
5463
5490
  run_response: RunOutput,
5491
+ run_context: RunContext,
5464
5492
  session: AgentSession,
5465
- session_state: Optional[Dict[str, Any]] = None,
5466
- dependencies: Optional[Dict[str, Any]] = None,
5467
5493
  ) -> List[Union[Function, dict]]:
5468
5494
  _function_names = []
5469
5495
  _functions: List[Union[Function, dict]] = []
@@ -5568,8 +5594,9 @@ class Agent:
5568
5594
 
5569
5595
  for func in _functions: # type: ignore
5570
5596
  if isinstance(func, Function):
5571
- func._session_state = session_state
5572
- func._dependencies = dependencies
5597
+ func._run_context = run_context
5598
+ func._session_state = run_context.session_state
5599
+ func._dependencies = run_context.dependencies
5573
5600
  func._images = joint_images
5574
5601
  func._files = joint_files
5575
5602
  func._audios = joint_audios
@@ -5619,49 +5646,70 @@ class Agent:
5619
5646
  log_debug("Model does not support structured or JSON schema outputs.")
5620
5647
  return json_response_format
5621
5648
 
5622
- def _resolve_run_dependencies(self, dependencies: Dict[str, Any]) -> None:
5649
+ def _resolve_run_dependencies(self, run_context: RunContext) -> None:
5623
5650
  from inspect import iscoroutine, iscoroutinefunction, signature
5624
5651
 
5625
5652
  # Dependencies should already be resolved in run() method
5626
5653
  log_debug("Resolving dependencies")
5627
- if not isinstance(dependencies, dict):
5628
- log_warning("Dependencies is not a dict")
5654
+ if not isinstance(run_context.dependencies, dict):
5655
+ log_warning("Run dependencies are not a dict")
5629
5656
  return
5630
5657
 
5631
- for key, value in dependencies.items():
5658
+ for key, value in run_context.dependencies.items():
5632
5659
  if iscoroutine(value) or iscoroutinefunction(value):
5633
5660
  log_warning(f"Dependency {key} is a coroutine. Use agent.arun() or agent.aprint_response() instead.")
5634
5661
  continue
5635
5662
  elif callable(value):
5636
5663
  try:
5637
5664
  sig = signature(value)
5638
- result = value(agent=self) if "agent" in sig.parameters else value()
5665
+
5666
+ # Build kwargs for the function
5667
+ kwargs: Dict[str, Any] = {}
5668
+ if "agent" in sig.parameters:
5669
+ kwargs["agent"] = self
5670
+ if "run_context" in sig.parameters:
5671
+ kwargs["run_context"] = run_context
5672
+
5673
+ # Run the function
5674
+ result = value(**kwargs)
5675
+
5676
+ # Carry the result in the run context
5639
5677
  if result is not None:
5640
- dependencies[key] = result
5678
+ run_context.dependencies[key] = result
5679
+
5641
5680
  except Exception as e:
5642
5681
  log_warning(f"Failed to resolve dependencies for '{key}': {e}")
5643
5682
  else:
5644
- dependencies[key] = value
5683
+ run_context.dependencies[key] = value
5645
5684
 
5646
- async def _aresolve_run_dependencies(self, dependencies: Dict[str, Any]) -> None:
5685
+ async def _aresolve_run_dependencies(self, run_context: RunContext) -> None:
5647
5686
  from inspect import iscoroutine, iscoroutinefunction, signature
5648
5687
 
5649
5688
  log_debug("Resolving context (async)")
5650
- if not isinstance(dependencies, dict):
5651
- log_warning("Context is not a dict")
5689
+ if not isinstance(run_context.dependencies, dict):
5690
+ log_warning("Run dependencies are not a dict")
5652
5691
  return
5653
5692
 
5654
- for key, value in dependencies.items():
5693
+ for key, value in run_context.dependencies.items():
5655
5694
  if not callable(value):
5656
- dependencies[key] = value
5695
+ run_context.dependencies[key] = value
5657
5696
  continue
5658
5697
  try:
5659
5698
  sig = signature(value)
5660
- result = value(agent=self) if "agent" in sig.parameters else value()
5661
5699
 
5700
+ # Build kwargs for the function
5701
+ kwargs: Dict[str, Any] = {}
5702
+ if "agent" in sig.parameters:
5703
+ kwargs["agent"] = self
5704
+ if "run_context" in sig.parameters:
5705
+ kwargs["run_context"] = run_context
5706
+
5707
+ # Run the function
5708
+ result = value(**kwargs)
5662
5709
  if iscoroutine(result) or iscoroutinefunction(result):
5663
- result = await result
5664
- dependencies[key] = result
5710
+ result = await result # type: ignore
5711
+
5712
+ run_context.dependencies[key] = result
5665
5713
  except Exception as e:
5666
5714
  log_warning(f"Failed to resolve context for '{key}': {e}")
5667
5715
 
@@ -6530,10 +6578,10 @@ class Agent:
6530
6578
  def _format_message_with_state_variables(
6531
6579
  self,
6532
6580
  message: Any,
6533
- user_id: Optional[str] = None,
6534
6581
  session_state: Optional[Dict[str, Any]] = None,
6535
6582
  dependencies: Optional[Dict[str, Any]] = None,
6536
6583
  metadata: Optional[Dict[str, Any]] = None,
6584
+ user_id: Optional[str] = None,
6537
6585
  ) -> Any:
6538
6586
  """Format a message with the session state variables."""
6539
6587
  import re
@@ -6550,6 +6598,7 @@ class Agent:
6550
6598
  metadata or {},
6551
6599
  {"user_id": user_id} if user_id is not None else {},
6552
6600
  )
6601
+
6553
6602
  converted_msg = deepcopy(message)
6554
6603
  for var_name in format_variables.keys():
6555
6604
  # Only convert standalone {var_name} patterns, not nested ones
@@ -6569,12 +6618,13 @@ class Agent:
6569
6618
  def get_system_message(
6570
6619
  self,
6571
6620
  session: AgentSession,
6572
- session_state: Optional[Dict[str, Any]] = None,
6621
+ run_context: Optional[RunContext] = None,
6573
6622
  user_id: Optional[str] = None,
6574
6623
  tools: Optional[List[Union[Function, dict]]] = None,
6575
- dependencies: Optional[Dict[str, Any]] = None,
6576
- metadata: Optional[Dict[str, Any]] = None,
6577
6624
  add_session_state_to_context: Optional[bool] = None,
6625
+ session_state: Optional[Dict[str, Any]] = None, # Deprecated
6626
+ dependencies: Optional[Dict[str, Any]] = None, # Deprecated
6627
+ metadata: Optional[Dict[str, Any]] = None, # Deprecated
6578
6628
  ) -> Optional[Message]:
6579
6629
  """Return the system message for the Agent.
6580
6630
 
@@ -6583,6 +6633,12 @@ class Agent:
6583
6633
  3. Build and return the default system message for the Agent.
6584
6634
  """
6585
6635
 
6636
+ # Consider both run_context and session_state, dependencies, metadata (deprecated fields)
6637
+ if run_context is not None:
6638
+ session_state = run_context.session_state or session_state
6639
+ dependencies = run_context.dependencies or dependencies
6640
+ metadata = run_context.metadata or metadata
6641
+
6586
6642
  # 1. If the system_message is provided, use that.
6587
6643
  if self.system_message is not None:
6588
6644
  if isinstance(self.system_message, Message):
@@ -6596,14 +6652,13 @@ class Agent:
6596
6652
  if not isinstance(sys_message_content, str):
6597
6653
  raise Exception("system_message must return a string")
6598
6654
 
6599
- # Format the system message with the session state variables
6600
6655
  if self.resolve_in_context:
6601
6656
  sys_message_content = self._format_message_with_state_variables(
6602
6657
  sys_message_content,
6603
6658
  user_id=user_id,
6659
+ session_state=session_state,
6604
6660
  dependencies=dependencies,
6605
6661
  metadata=metadata,
6606
- session_state=session_state,
6607
6662
  )
6608
6663
 
6609
6664
  # type: ignore
@@ -6635,6 +6690,11 @@ class Agent:
6635
6690
  if "session_state" in signature.parameters:
6636
6691
  instruction_args["session_state"] = session_state or {}
6637
6692
 
6693
+ # Check for run_context parameter
6694
+ if "run_context" in signature.parameters:
6695
+ instruction_args["run_context"] = run_context or None
6696
+
6697
+ # Run the instructions function
6638
6698
  _instructions = self.instructions(**instruction_args)
6639
6699
 
6640
6700
  if isinstance(_instructions, str):
@@ -6912,11 +6972,13 @@ class Agent:
6912
6972
  async def aget_system_message(
6913
6973
  self,
6914
6974
  session: AgentSession,
6915
- session_state: Optional[Dict[str, Any]] = None,
6975
+ run_context: Optional[RunContext] = None,
6916
6976
  user_id: Optional[str] = None,
6917
6977
  tools: Optional[List[Union[Function, dict]]] = None,
6918
- dependencies: Optional[Dict[str, Any]] = None,
6919
- metadata: Optional[Dict[str, Any]] = None,
6978
+ add_session_state_to_context: Optional[bool] = None,
6979
+ session_state: Optional[Dict[str, Any]] = None, # Deprecated
6980
+ dependencies: Optional[Dict[str, Any]] = None, # Deprecated
6981
+ metadata: Optional[Dict[str, Any]] = None, # Deprecated
6920
6982
  ) -> Optional[Message]:
6921
6983
  """Return the system message for the Agent.
6922
6984
 
@@ -6925,6 +6987,12 @@ class Agent:
6925
6987
  3. Build and return the default system message for the Agent.
6926
6988
  """
6927
6989
 
6990
+ # Consider both run_context and session_state, dependencies, metadata (deprecated fields)
6991
+ if run_context is not None:
6992
+ session_state = run_context.session_state or session_state
6993
+ dependencies = run_context.dependencies or dependencies
6994
+ metadata = run_context.metadata or metadata
6995
+
6928
6996
  # 1. If the system_message is provided, use that.
6929
6997
  if self.system_message is not None:
6930
6998
  if isinstance(self.system_message, Message):
@@ -7037,7 +7105,7 @@ class Agent:
7037
7105
 
7038
7106
  # 3.2.5 Add information about agentic filters if enabled
7039
7107
  if self.knowledge is not None and self.enable_agentic_knowledge_filters:
7040
- valid_filters = getattr(self.knowledge, "valid_metadata_filters", None)
7108
+ valid_filters = await self.knowledge.aget_valid_filters()
7041
7109
  if valid_filters:
7042
7110
  valid_filters_str = ", ".join(valid_filters)
7043
7111
  additional_information.append(
@@ -7244,7 +7312,7 @@ class Agent:
7244
7312
  system_message_content += f"{get_response_model_format_prompt(self.output_schema)}"
7245
7313
 
7246
7314
  # 3.3.15 Add the session state to the system message
7247
- if self.add_session_state_to_context and session_state is not None:
7315
+ if add_session_state_to_context and session_state is not None:
7248
7316
  system_message_content += self._get_formatted_session_state_for_system_message(session_state)
7249
7317
 
7250
7318
  # Return the system message
@@ -7261,17 +7329,18 @@ class Agent:
7261
7329
  self,
7262
7330
  *,
7263
7331
  run_response: RunOutput,
7332
+ run_context: Optional[RunContext] = None,
7264
7333
  session_state: Optional[Dict[str, Any]] = None,
7334
+ dependencies: Optional[Dict[str, Any]] = None,
7335
+ metadata: Optional[Dict[str, Any]] = None,
7265
7336
  user_id: Optional[str] = None,
7266
7337
  input: Optional[Union[str, List, Dict, Message, BaseModel, List[Message]]] = None,
7267
7338
  audio: Optional[Sequence[Audio]] = None,
7268
7339
  images: Optional[Sequence[Image]] = None,
7269
7340
  videos: Optional[Sequence[Video]] = None,
7270
7341
  files: Optional[Sequence[File]] = None,
7271
- knowledge_filters: Optional[Dict[str, Any]] = None,
7272
- dependencies: Optional[Dict[str, Any]] = None,
7273
7342
  add_dependencies_to_context: Optional[bool] = None,
7274
- metadata: Optional[Dict[str, Any]] = None,
7343
+ knowledge_filters: Optional[Dict[str, Any]] = None,
7275
7344
  **kwargs: Any,
7276
7345
  ) -> Optional[Message]:
7277
7346
  """Return the user message for the Agent.
@@ -7280,6 +7349,13 @@ class Agent:
7280
7349
  2. If build_user_context is False or if the message is a list, return the message as is.
7281
7350
  3. Build the default user message for the Agent
7282
7351
  """
7352
+ # Consider both run_context and session_state, dependencies, metadata, knowledge_filters (deprecated fields)
7353
+ if run_context is not None:
7354
+ session_state = run_context.session_state or session_state
7355
+ dependencies = run_context.dependencies or dependencies
7356
+ metadata = run_context.metadata or metadata
7357
+ knowledge_filters = run_context.knowledge_filters or knowledge_filters
7358
+
7283
7359
  # Get references from the knowledge base to use in the user message
7284
7360
  references = None
7285
7361
 
@@ -7287,7 +7363,7 @@ class Agent:
7287
7363
  if not self.build_user_context:
7288
7364
  return Message(
7289
7365
  role=self.user_message_role or "user",
7290
- content=input,
7366
+ content=input, # type: ignore
7291
7367
  images=None if not self.send_media_to_model else images,
7292
7368
  audio=None if not self.send_media_to_model else audio,
7293
7369
  videos=None if not self.send_media_to_model else videos,
@@ -7428,20 +7504,17 @@ class Agent:
7428
7504
  self,
7429
7505
  *,
7430
7506
  run_response: RunOutput,
7507
+ run_context: RunContext,
7431
7508
  input: Union[str, List, Dict, Message, BaseModel, List[Message]],
7432
7509
  session: AgentSession,
7433
- session_state: Optional[Dict[str, Any]] = None,
7434
7510
  user_id: Optional[str] = None,
7435
7511
  audio: Optional[Sequence[Audio]] = None,
7436
7512
  images: Optional[Sequence[Image]] = None,
7437
7513
  videos: Optional[Sequence[Video]] = None,
7438
7514
  files: Optional[Sequence[File]] = None,
7439
- knowledge_filters: Optional[Dict[str, Any]] = None,
7440
7515
  add_history_to_context: Optional[bool] = None,
7441
- dependencies: Optional[Dict[str, Any]] = None,
7442
7516
  add_dependencies_to_context: Optional[bool] = None,
7443
7517
  add_session_state_to_context: Optional[bool] = None,
7444
- metadata: Optional[Dict[str, Any]] = None,
7445
7518
  tools: Optional[List[Union[Function, dict]]] = None,
7446
7519
  **kwargs: Any,
7447
7520
  ) -> RunMessages:
@@ -7475,11 +7548,12 @@ class Agent:
7475
7548
  # 1. Add system message to run_messages
7476
7549
  system_message = self.get_system_message(
7477
7550
  session=session,
7478
- session_state=session_state,
7551
+ run_context=run_context,
7552
+ session_state=run_context.session_state,
7553
+ dependencies=run_context.dependencies,
7554
+ metadata=run_context.metadata,
7479
7555
  user_id=user_id,
7480
7556
  tools=tools,
7481
- dependencies=dependencies,
7482
- metadata=metadata,
7483
7557
  add_session_state_to_context=add_session_state_to_context,
7484
7558
  )
7485
7559
  if system_message is not None:
@@ -7564,16 +7638,13 @@ class Agent:
7564
7638
  ):
7565
7639
  user_message = self._get_user_message(
7566
7640
  run_response=run_response,
7567
- session_state=session_state,
7641
+ run_context=run_context,
7568
7642
  input=input,
7569
7643
  audio=audio,
7570
7644
  images=images,
7571
7645
  videos=videos,
7572
7646
  files=files,
7573
- knowledge_filters=knowledge_filters,
7574
- dependencies=dependencies,
7575
7647
  add_dependencies_to_context=add_dependencies_to_context,
7576
- metadata=metadata,
7577
7648
  **kwargs,
7578
7649
  )
7579
7650
 
@@ -7638,6 +7709,7 @@ class Agent:
7638
7709
  run_response: RunOutput,
7639
7710
  input: Union[str, List, Dict, Message, BaseModel, List[Message]],
7640
7711
  session: AgentSession,
7712
+ run_context: Optional[RunContext] = None,
7641
7713
  session_state: Optional[Dict[str, Any]] = None,
7642
7714
  user_id: Optional[str] = None,
7643
7715
  audio: Optional[Sequence[Audio]] = None,
@@ -7677,17 +7749,25 @@ class Agent:
7677
7749
  )
7678
7750
  """
7679
7751
 
7752
+ # Consider both run_context and session_state, dependencies, metadata (deprecated fields)
7753
+ if run_context is not None:
7754
+ session_state = run_context.session_state or session_state
7755
+ dependencies = run_context.dependencies or dependencies
7756
+ metadata = run_context.metadata or metadata
7757
+
7680
7758
  # Initialize the RunMessages object (no media here - that's in RunInput now)
7681
7759
  run_messages = RunMessages()
7682
7760
 
7683
7761
  # 1. Add system message to run_messages
7684
7762
  system_message = await self.aget_system_message(
7685
7763
  session=session,
7764
+ run_context=run_context,
7686
7765
  session_state=session_state,
7687
7766
  user_id=user_id,
7688
7767
  tools=tools,
7689
7768
  dependencies=dependencies,
7690
7769
  metadata=metadata,
7770
+ add_session_state_to_context=add_session_state_to_context,
7691
7771
  )
7692
7772
  if system_message is not None:
7693
7773
  run_messages.system_message = system_message
@@ -7771,16 +7851,17 @@ class Agent:
7771
7851
  ):
7772
7852
  user_message = self._get_user_message(
7773
7853
  run_response=run_response,
7854
+ run_context=run_context,
7774
7855
  session_state=session_state,
7856
+ dependencies=dependencies,
7857
+ metadata=metadata,
7775
7858
  input=input,
7776
7859
  audio=audio,
7777
7860
  images=images,
7778
7861
  videos=videos,
7779
7862
  files=files,
7780
7863
  knowledge_filters=knowledge_filters,
7781
- dependencies=dependencies,
7782
7864
  add_dependencies_to_context=add_dependencies_to_context,
7783
- metadata=metadata,
7784
7865
  **kwargs,
7785
7866
  )
7786
7867
 
@@ -8020,7 +8101,7 @@ class Agent:
8020
8101
 
8021
8102
  # Validate the filters against known valid filter keys
8022
8103
  if self.knowledge is not None:
8023
- valid_filters, invalid_keys = self.knowledge.validate_filters(filters) # type: ignore
8104
+ valid_filters, invalid_keys = await self.knowledge.async_validate_filters(filters) # type: ignore
8024
8105
 
8025
8106
  # Warn about invalid filter keys
8026
8107
  if invalid_keys: # type: ignore
@@ -8256,38 +8337,6 @@ class Agent:
8256
8337
 
8257
8338
  return metrics
8258
8339
 
8259
- ###########################################################################
8260
- # Handle images, videos and audio
8261
- ###########################################################################
8262
-
8263
- def _add_image(self, image: Image, run_response: RunOutput) -> None:
8264
- """Add an image to both the agent's stateful storage and the current run response"""
8265
- # Add to run response
8266
- if run_response.images is None:
8267
- run_response.images = []
8268
- run_response.images.append(image)
8269
-
8270
- def _add_video(self, video: Video, run_response: RunOutput) -> None:
8271
- """Add a video to both the agent's stateful storage and the current run response"""
8272
- # Add to run response
8273
- if run_response.videos is None:
8274
- run_response.videos = []
8275
- run_response.videos.append(video)
8276
-
8277
- def _add_audio(self, audio: Audio, run_response: RunOutput) -> None:
8278
- """Add audio to both the agent's stateful storage and the current run response"""
8279
- # Add to run response
8280
- if run_response.audio is None:
8281
- run_response.audio = []
8282
- run_response.audio.append(audio)
8283
-
8284
- def _add_file(self, file: File, run_response: RunOutput) -> None:
8285
- """Add file to both the agent's stateful storage and the current run response"""
8286
- # Add to run response
8287
- if run_response.files is None:
8288
- run_response.files = []
8289
- run_response.files.append(file)
8290
-
8291
8340
  ###########################################################################
8292
8341
  # Reasoning
8293
8342
  ###########################################################################
@@ -10055,7 +10104,13 @@ class Agent:
10055
10104
 
10056
10105
  return effective_filters
10057
10106
 
10058
- def _cleanup_and_store(self, run_response: RunOutput, session: AgentSession, user_id: Optional[str] = None) -> None:
10107
+ def _cleanup_and_store(
10108
+ self,
10109
+ run_response: RunOutput,
10110
+ session: AgentSession,
10111
+ run_context: Optional[RunContext] = None,
10112
+ user_id: Optional[str] = None,
10113
+ ) -> None:
10059
10114
  # Scrub the stored run based on storage flags
10060
10115
  self._scrub_run_output_for_storage(run_response)
10061
10116
 
@@ -10063,10 +10118,10 @@ class Agent:
10063
10118
  if run_response.metrics:
10064
10119
  run_response.metrics.stop_timer()
10065
10120
 
10066
- # Update run_response.session_state from session before saving
10121
+ # Update run_response.session_state before saving
10067
10122
  # This ensures RunOutput reflects all tool modifications
10068
- if session.session_data is not None and "session_state" in session.session_data:
10069
- run_response.session_state = session.session_data["session_state"]
10123
+ if session.session_data is not None and run_context is not None and run_context.session_state is not None:
10124
+ run_response.session_state = run_context.session_state
10070
10125
 
10071
10126
  # Optional: Save output to file if save_response_to_file is set
10072
10127
  self.save_run_response_to_file(
@@ -10086,7 +10141,11 @@ class Agent:
10086
10141
  self.save_session(session=session)
10087
10142
 
10088
10143
  async def _acleanup_and_store(
10089
- self, run_response: RunOutput, session: AgentSession, user_id: Optional[str] = None
10144
+ self,
10145
+ run_response: RunOutput,
10146
+ session: AgentSession,
10147
+ run_context: Optional[RunContext] = None,
10148
+ user_id: Optional[str] = None,
10090
10149
  ) -> None:
10091
10150
  # Scrub the stored run based on storage flags
10092
10151
  self._scrub_run_output_for_storage(run_response)
@@ -10097,8 +10156,8 @@ class Agent:
10097
10156
 
10098
10157
  # Update run_response.session_state from session before saving
10099
10158
  # This ensures RunOutput reflects all tool modifications
10100
- if session.session_data is not None and "session_state" in session.session_data:
10101
- run_response.session_state = session.session_data["session_state"]
10159
+ if session.session_data is not None and run_context is not None and run_context.session_state is not None:
10160
+ run_response.session_state = run_context.session_state
10102
10161
 
10103
10162
  # Optional: Save output to file if save_response_to_file is set
10104
10163
  self.save_run_response_to_file(
@@ -10114,7 +10173,14 @@ class Agent:
10114
10173
  # Calculate session metrics
10115
10174
  self._update_session_metrics(session=session, run_response=run_response)
10116
10175
 
10117
- # Save session to storage
10176
+ # Update session state before saving the session
10177
+ if run_context is not None and run_context.session_state is not None:
10178
+ if session.session_data is not None:
10179
+ session.session_data["session_state"] = run_context.session_state
10180
+ else:
10181
+ session.session_data = {"session_state": run_context.session_state}
10182
+
10183
+ # Save session to memory
10118
10184
  await self.asave_session(session=session)
10119
10185
 
10120
10186
  def _scrub_run_output_for_storage(self, run_response: RunOutput) -> None:
@@ -10130,58 +10196,6 @@ class Agent:
10130
10196
  if not self.store_history_messages:
10131
10197
  scrub_history_messages_from_run_output(run_response)
10132
10198
 
10133
- def _validate_media_object_id(
10134
- self,
10135
- images: Optional[Sequence[Image]] = None,
10136
- videos: Optional[Sequence[Video]] = None,
10137
- audios: Optional[Sequence[Audio]] = None,
10138
- files: Optional[Sequence[File]] = None,
10139
- ) -> tuple:
10140
- """Convert raw Image/Video/Audio objects - now unified, so just return as-is."""
10141
- # With unified classes, no conversion needed - just ensure IDs are set
10142
- image_list = None
10143
- if images:
10144
- image_list = []
10145
- for img in images:
10146
- # Ensure ID is set (validation should handle this, but double-check)
10147
- if not img.id:
10148
- from uuid import uuid4
10149
-
10150
- img.id = str(uuid4())
10151
- image_list.append(img)
10152
-
10153
- video_list = None
10154
- if videos:
10155
- video_list = []
10156
- for vid in videos:
10157
- if not vid.id:
10158
- from uuid import uuid4
10159
-
10160
- vid.id = str(uuid4())
10161
- video_list.append(vid)
10162
-
10163
- audio_list = None
10164
- if audios:
10165
- audio_list = []
10166
- for aud in audios:
10167
- if not aud.id:
10168
- from uuid import uuid4
10169
-
10170
- aud.id = str(uuid4())
10171
- audio_list.append(aud)
10172
-
10173
- file_list = None
10174
- if files:
10175
- file_list = []
10176
- for file in files:
10177
- if not file.id:
10178
- from uuid import uuid4
10179
-
10180
- file.id = str(uuid4())
10181
- file_list.append(file)
10182
-
10183
- return image_list, video_list, audio_list, file_list
10184
-
10185
10199
  def cli_app(
10186
10200
  self,
10187
10201
  input: Optional[str] = None,