agno 2.3.6__py3-none-any.whl → 2.3.7__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.
@@ -255,47 +255,63 @@ class AsyncPostgresDb(AsyncBaseDb):
255
255
  if table_type == "sessions":
256
256
  if not hasattr(self, "session_table"):
257
257
  self.session_table = await self._get_or_create_table(
258
- table_name=self.session_table_name, table_type="sessions"
258
+ table_name=self.session_table_name,
259
+ table_type="sessions",
260
+ create_table_if_not_found=create_table_if_not_found,
259
261
  )
260
262
  return self.session_table
261
263
 
262
264
  if table_type == "memories":
263
265
  if not hasattr(self, "memory_table"):
264
266
  self.memory_table = await self._get_or_create_table(
265
- table_name=self.memory_table_name, table_type="memories"
267
+ table_name=self.memory_table_name,
268
+ table_type="memories",
269
+ create_table_if_not_found=create_table_if_not_found,
266
270
  )
267
271
  return self.memory_table
268
272
 
269
273
  if table_type == "metrics":
270
274
  if not hasattr(self, "metrics_table"):
271
275
  self.metrics_table = await self._get_or_create_table(
272
- table_name=self.metrics_table_name, table_type="metrics"
276
+ table_name=self.metrics_table_name,
277
+ table_type="metrics",
278
+ create_table_if_not_found=create_table_if_not_found,
273
279
  )
274
280
  return self.metrics_table
275
281
 
276
282
  if table_type == "evals":
277
283
  if not hasattr(self, "eval_table"):
278
- self.eval_table = await self._get_or_create_table(table_name=self.eval_table_name, table_type="evals")
284
+ self.eval_table = await self._get_or_create_table(
285
+ table_name=self.eval_table_name,
286
+ table_type="evals",
287
+ create_table_if_not_found=create_table_if_not_found,
288
+ )
279
289
  return self.eval_table
280
290
 
281
291
  if table_type == "knowledge":
282
292
  if not hasattr(self, "knowledge_table"):
283
293
  self.knowledge_table = await self._get_or_create_table(
284
- table_name=self.knowledge_table_name, table_type="knowledge"
294
+ table_name=self.knowledge_table_name,
295
+ table_type="knowledge",
296
+ create_table_if_not_found=create_table_if_not_found,
285
297
  )
286
298
  return self.knowledge_table
287
299
 
288
300
  if table_type == "culture":
289
301
  if not hasattr(self, "culture_table"):
290
302
  self.culture_table = await self._get_or_create_table(
291
- table_name=self.culture_table_name, table_type="culture"
303
+ table_name=self.culture_table_name,
304
+ table_type="culture",
305
+ create_table_if_not_found=create_table_if_not_found,
292
306
  )
293
307
  return self.culture_table
294
308
 
295
309
  if table_type == "versions":
296
310
  if not hasattr(self, "versions_table"):
297
311
  self.versions_table = await self._get_or_create_table(
298
- table_name=self.versions_table_name, table_type="versions"
312
+ table_name=self.versions_table_name,
313
+ table_type="versions",
314
+ create_table_if_not_found=create_table_if_not_found,
299
315
  )
300
316
  return self.versions_table
301
317
 
agno/db/utils.py CHANGED
@@ -20,6 +20,8 @@ class CustomJSONEncoder(json.JSONEncoder):
20
20
  return obj.to_dict()
21
21
  elif isinstance(obj, Metrics):
22
22
  return obj.to_dict()
23
+ elif isinstance(obj, type):
24
+ return str(obj)
23
25
 
24
26
  return super().default(obj)
25
27
 
agno/models/base.py CHANGED
@@ -30,6 +30,7 @@ from agno.models.message import Citations, Message
30
30
  from agno.models.metrics import Metrics
31
31
  from agno.models.response import ModelResponse, ModelResponseEvent, ToolExecution
32
32
  from agno.run.agent import CustomEvent, RunContentEvent, RunOutput, RunOutputEvent
33
+ from agno.run.requirement import RunRequirement
33
34
  from agno.run.team import RunContentEvent as TeamRunContentEvent
34
35
  from agno.run.team import TeamRunOutput, TeamRunOutputEvent
35
36
  from agno.run.workflow import WorkflowRunOutputEvent
@@ -423,10 +424,23 @@ class Model(ABC):
423
424
  ]
424
425
  and function_call_response.tool_executions is not None
425
426
  ):
427
+ # Record the tool execution in the model response
426
428
  if model_response.tool_executions is None:
427
429
  model_response.tool_executions = []
428
430
  model_response.tool_executions.extend(function_call_response.tool_executions)
429
431
 
432
+ # If the tool is currently paused (HITL flow), add the requirement to the run response
433
+ if (
434
+ function_call_response.event == ModelResponseEvent.tool_call_paused.value
435
+ and run_response is not None
436
+ ):
437
+ current_tool_execution = function_call_response.tool_executions[-1]
438
+ if run_response.requirements is None:
439
+ run_response.requirements = []
440
+ run_response.requirements.append(
441
+ RunRequirement(tool_execution=current_tool_execution)
442
+ )
443
+
430
444
  elif function_call_response.event not in [
431
445
  ModelResponseEvent.tool_call_started.value,
432
446
  ModelResponseEvent.tool_call_completed.value,
@@ -615,6 +629,19 @@ class Model(ABC):
615
629
  if model_response.tool_executions is None:
616
630
  model_response.tool_executions = []
617
631
  model_response.tool_executions.extend(function_call_response.tool_executions)
632
+
633
+ # If the tool is currently paused (HITL flow), add the requirement to the run response
634
+ if (
635
+ function_call_response.event == ModelResponseEvent.tool_call_paused.value
636
+ and run_response is not None
637
+ ):
638
+ current_tool_execution = function_call_response.tool_executions[-1]
639
+ if run_response.requirements is None:
640
+ run_response.requirements = []
641
+ run_response.requirements.append(
642
+ RunRequirement(tool_execution=current_tool_execution)
643
+ )
644
+
618
645
  elif function_call_response.event not in [
619
646
  ModelResponseEvent.tool_call_started.value,
620
647
  ModelResponseEvent.tool_call_completed.value,
@@ -1706,7 +1733,7 @@ class Model(ABC):
1706
1733
 
1707
1734
  paused_tool_executions = []
1708
1735
 
1709
- # The function cannot be executed without user confirmation
1736
+ # The function requires user confirmation (HITL)
1710
1737
  if fc.function.requires_confirmation:
1711
1738
  paused_tool_executions.append(
1712
1739
  ToolExecution(
@@ -1716,7 +1743,8 @@ class Model(ABC):
1716
1743
  requires_confirmation=True,
1717
1744
  )
1718
1745
  )
1719
- # If the function requires user input, we yield a message to the user
1746
+
1747
+ # The function requires user input (HITL)
1720
1748
  if fc.function.requires_user_input:
1721
1749
  user_input_schema = fc.function.user_input_schema
1722
1750
  if fc.arguments and user_input_schema:
@@ -1734,7 +1762,8 @@ class Model(ABC):
1734
1762
  user_input_schema=user_input_schema,
1735
1763
  )
1736
1764
  )
1737
- # If the function is from the user control flow tools, we handle it here
1765
+
1766
+ # If the function is from the user control flow (HITL) tools, we handle it here
1738
1767
  if fc.function.name == "get_user_input" and fc.arguments and fc.arguments.get("user_input_fields"):
1739
1768
  user_input_schema = []
1740
1769
  for input_field in fc.arguments.get("user_input_fields", []):
@@ -1760,7 +1789,8 @@ class Model(ABC):
1760
1789
  user_input_schema=user_input_schema,
1761
1790
  )
1762
1791
  )
1763
- # If the function requires external execution, we yield a message to the user
1792
+
1793
+ # The function requires external execution (HITL)
1764
1794
  if fc.function.external_execution:
1765
1795
  paused_tool_executions.append(
1766
1796
  ToolExecution(
agno/models/response.py CHANGED
@@ -37,7 +37,7 @@ class ToolExecution:
37
37
 
38
38
  created_at: int = field(default_factory=lambda: int(time()))
39
39
 
40
- # User control flow requirements
40
+ # User control flow (HITL) fields
41
41
  requires_confirmation: Optional[bool] = None
42
42
  confirmed: Optional[bool] = None
43
43
  confirmation_note: Optional[str] = None
@@ -36,7 +36,10 @@ async def run_accuracy_eval(
36
36
  model=default_model,
37
37
  )
38
38
 
39
- result = accuracy_eval.run(print_results=False, print_summary=False)
39
+ if isinstance(db, AsyncBaseDb):
40
+ result = await accuracy_eval.arun(print_results=False, print_summary=False)
41
+ else:
42
+ result = accuracy_eval.run(print_results=False, print_summary=False)
40
43
  if not result:
41
44
  raise HTTPException(status_code=500, detail="Failed to run accuracy evaluation")
42
45
 
@@ -86,7 +89,11 @@ async def run_performance_eval(
86
89
  model_id=model_id,
87
90
  model_provider=model_provider,
88
91
  )
89
- result = performance_eval.run(print_results=False, print_summary=False)
92
+
93
+ if isinstance(db, AsyncBaseDb):
94
+ result = await performance_eval.arun(print_results=False, print_summary=False)
95
+ else:
96
+ result = performance_eval.run(print_results=False, print_summary=False)
90
97
  if not result:
91
98
  raise HTTPException(status_code=500, detail="Failed to run performance evaluation")
92
99
 
@@ -141,7 +148,10 @@ async def run_reliability_eval(
141
148
  model_id = team.model.id if team and team.model else None
142
149
  model_provider = team.model.provider if team and team.model else None
143
150
 
144
- result = reliability_eval.run(print_results=False)
151
+ if isinstance(db, AsyncBaseDb):
152
+ result = await reliability_eval.arun(print_results=False)
153
+ else:
154
+ result = reliability_eval.run(print_results=False)
145
155
  if not result:
146
156
  raise HTTPException(status_code=500, detail="Failed to run reliability evaluation")
147
157
 
agno/run/agent.py CHANGED
@@ -11,6 +11,7 @@ from agno.models.metrics import Metrics
11
11
  from agno.models.response import ToolExecution
12
12
  from agno.reasoning.step import ReasoningStep
13
13
  from agno.run.base import BaseRunOutputEvent, MessageReferences, RunStatus
14
+ from agno.run.requirement import RunRequirement
14
15
  from agno.utils.log import logger
15
16
  from agno.utils.media import (
16
17
  reconstruct_audio_list,
@@ -273,11 +274,18 @@ class RunCompletedEvent(BaseAgentRunEvent):
273
274
  class RunPausedEvent(BaseAgentRunEvent):
274
275
  event: str = RunEvent.run_paused.value
275
276
  tools: Optional[List[ToolExecution]] = None
277
+ requirements: Optional[List[RunRequirement]] = None
276
278
 
277
279
  @property
278
280
  def is_paused(self):
279
281
  return True
280
282
 
283
+ @property
284
+ def active_requirements(self) -> List[RunRequirement]:
285
+ if not self.requirements:
286
+ return []
287
+ return [requirement for requirement in self.requirements if not requirement.is_resolved()]
288
+
281
289
 
282
290
  @dataclass
283
291
  class RunContinuedEvent(BaseAgentRunEvent):
@@ -539,11 +547,20 @@ class RunOutput:
539
547
 
540
548
  status: RunStatus = RunStatus.running
541
549
 
550
+ # User control flow (HITL) requirements to continue a run when paused, in order of arrival
551
+ requirements: Optional[list[RunRequirement]] = None
552
+
542
553
  # === FOREIGN KEY RELATIONSHIPS ===
543
554
  # These fields establish relationships to parent workflow/step structures
544
555
  # and should be treated as foreign keys for data integrity
545
556
  workflow_step_id: Optional[str] = None # FK: Points to StepOutput.step_id
546
557
 
558
+ @property
559
+ def active_requirements(self) -> list[RunRequirement]:
560
+ if not self.requirements:
561
+ return []
562
+ return [requirement for requirement in self.requirements if not requirement.is_resolved()]
563
+
547
564
  @property
548
565
  def is_paused(self):
549
566
  return self.status == RunStatus.paused
@@ -0,0 +1,98 @@
1
+ from dataclasses import dataclass
2
+ from datetime import datetime, timezone
3
+ from typing import TYPE_CHECKING, List, Optional
4
+ from uuid import uuid4
5
+
6
+ from agno.models.response import ToolExecution, UserInputField
7
+
8
+ if TYPE_CHECKING:
9
+ pass
10
+
11
+
12
+ @dataclass
13
+ class RunRequirement:
14
+ """Requirement to complete a paused run (used in HITL flows)"""
15
+
16
+ tool_execution: Optional[ToolExecution] = None
17
+ created_at: datetime = datetime.now(timezone.utc)
18
+
19
+ # User confirmation
20
+ confirmation: Optional[bool] = None
21
+ confirmation_note: Optional[str] = None
22
+
23
+ # User input
24
+ user_input_schema: Optional[List[UserInputField]] = None
25
+
26
+ # External execution
27
+ external_execution_result: Optional[str] = None
28
+
29
+ def __init__(self, tool_execution: ToolExecution):
30
+ self.id = str(uuid4())
31
+ self.tool_execution = tool_execution
32
+ self.user_input_schema = tool_execution.user_input_schema
33
+
34
+ @property
35
+ def needs_confirmation(self) -> bool:
36
+ if self.confirmation is not None:
37
+ return False
38
+ if not self.tool_execution:
39
+ return False
40
+ if self.tool_execution.confirmed is True:
41
+ return True
42
+
43
+ return self.tool_execution.requires_confirmation or False
44
+
45
+ @property
46
+ def needs_user_input(self) -> bool:
47
+ if not self.tool_execution:
48
+ return False
49
+ if self.tool_execution.answered is True:
50
+ return False
51
+ if self.user_input_schema and not all(field.value is not None for field in self.user_input_schema):
52
+ return True
53
+
54
+ return self.tool_execution.requires_user_input or False
55
+
56
+ @property
57
+ def needs_external_execution(self) -> bool:
58
+ if not self.tool_execution:
59
+ return False
60
+ if self.external_execution_result is not None:
61
+ return True
62
+
63
+ return self.tool_execution.external_execution_required or False
64
+
65
+ def confirm(self):
66
+ if not self.needs_confirmation:
67
+ raise ValueError("This requirement does not require confirmation")
68
+ self.confirmation = True
69
+ if self.tool_execution:
70
+ self.tool_execution.confirmed = True
71
+
72
+ def reject(self):
73
+ if not self.needs_confirmation:
74
+ raise ValueError("This requirement does not require confirmation")
75
+ self.confirmation = False
76
+ if self.tool_execution:
77
+ self.tool_execution.confirmed = False
78
+
79
+ def set_external_execution_result(self, result: str):
80
+ if not self.needs_external_execution:
81
+ raise ValueError("This requirement does not require external execution")
82
+ self.external_execution_result = result
83
+ if self.tool_execution:
84
+ self.tool_execution.result = result
85
+
86
+ def update_tool(self):
87
+ if not self.tool_execution:
88
+ return
89
+ if self.confirmation is True:
90
+ self.tool_execution.confirmed = True
91
+ elif self.confirmation is False:
92
+ self.tool_execution.confirmed = False
93
+ else:
94
+ raise ValueError("This requirement does not require confirmation or user input")
95
+
96
+ def is_resolved(self) -> bool:
97
+ """Return True if the requirement has been resolved"""
98
+ return not self.needs_confirmation and not self.needs_user_input and not self.needs_external_execution
agno/run/team.py CHANGED
@@ -12,6 +12,7 @@ from agno.models.response import ToolExecution
12
12
  from agno.reasoning.step import ReasoningStep
13
13
  from agno.run.agent import RunEvent, RunOutput, RunOutputEvent, run_output_event_from_dict
14
14
  from agno.run.base import BaseRunOutputEvent, MessageReferences, RunStatus
15
+ from agno.run.requirement import RunRequirement
15
16
  from agno.utils.log import log_error
16
17
  from agno.utils.media import (
17
18
  reconstruct_audio_list,
@@ -515,11 +516,20 @@ class TeamRunOutput:
515
516
 
516
517
  status: RunStatus = RunStatus.running
517
518
 
519
+ # User control flow (HITL) requirements to continue a run when paused, in order of arrival
520
+ requirements: Optional[list[RunRequirement]] = None
521
+
518
522
  # === FOREIGN KEY RELATIONSHIPS ===
519
523
  # These fields establish relationships to parent workflow/step structures
520
524
  # and should be treated as foreign keys for data integrity
521
525
  workflow_step_id: Optional[str] = None # FK: Points to StepOutput.step_id
522
526
 
527
+ @property
528
+ def active_requirements(self) -> list[RunRequirement]:
529
+ if not self.requirements:
530
+ return []
531
+ return [requirement for requirement in self.requirements if not requirement.is_resolved()]
532
+
523
533
  @property
524
534
  def is_paused(self):
525
535
  return self.status == RunStatus.paused
agno/team/team.py CHANGED
@@ -723,6 +723,8 @@ class Team:
723
723
 
724
724
  # List of MCP tools that were initialized on the last run
725
725
  self._mcp_tools_initialized_on_run: List[Any] = []
726
+ # List of connectable tools that were initialized on the last run
727
+ self._connectable_tools_initialized_on_run: List[Any] = []
726
728
 
727
729
  # Lazy-initialized shared thread pool executor for background tasks (memory, cultural knowledge, etc.)
728
730
  self._background_executor: Optional[Any] = None
@@ -1046,16 +1048,48 @@ class Team:
1046
1048
  and any(c.__name__ in ["MCPTools", "MultiMCPTools"] for c in type(tool).__mro__)
1047
1049
  and not tool.initialized # type: ignore
1048
1050
  ):
1049
- # Connect the MCP server
1050
- await tool.connect() # type: ignore
1051
- self._mcp_tools_initialized_on_run.append(tool)
1051
+ try:
1052
+ # Connect the MCP server
1053
+ await tool.connect() # type: ignore
1054
+ self._mcp_tools_initialized_on_run.append(tool)
1055
+ except Exception as e:
1056
+ log_warning(f"Error connecting tool: {str(e)}")
1052
1057
 
1053
1058
  async def _disconnect_mcp_tools(self) -> None:
1054
1059
  """Disconnect the MCP tools from the agent."""
1055
1060
  for tool in self._mcp_tools_initialized_on_run:
1056
- await tool.close()
1061
+ try:
1062
+ await tool.close()
1063
+ except Exception as e:
1064
+ log_warning(f"Error disconnecting tool: {str(e)}")
1057
1065
  self._mcp_tools_initialized_on_run = []
1058
1066
 
1067
+ def _connect_connectable_tools(self) -> None:
1068
+ """Connect tools that require connection management (e.g., database connections)."""
1069
+ if self.tools:
1070
+ for tool in self.tools:
1071
+ if (
1072
+ hasattr(tool, "requires_connect")
1073
+ and tool.requires_connect
1074
+ and hasattr(tool, "connect")
1075
+ and tool not in self._connectable_tools_initialized_on_run
1076
+ ):
1077
+ try:
1078
+ tool.connect() # type: ignore
1079
+ self._connectable_tools_initialized_on_run.append(tool)
1080
+ except Exception as e:
1081
+ log_warning(f"Error connecting tool: {str(e)}")
1082
+
1083
+ def _disconnect_connectable_tools(self) -> None:
1084
+ """Disconnect tools that require connection management."""
1085
+ for tool in self._connectable_tools_initialized_on_run:
1086
+ if hasattr(tool, "close"):
1087
+ try:
1088
+ tool.close() # type: ignore
1089
+ except Exception as e:
1090
+ log_warning(f"Error disconnecting tool: {str(e)}")
1091
+ self._connectable_tools_initialized_on_run = []
1092
+
1059
1093
  def _execute_pre_hooks(
1060
1094
  self,
1061
1095
  hooks: Optional[List[Callable[..., Any]]],
@@ -1625,6 +1659,8 @@ class Team:
1625
1659
  self._cleanup_and_store(run_response=run_response, session=session)
1626
1660
  return run_response
1627
1661
  finally:
1662
+ # Always disconnect connectable tools
1663
+ self._disconnect_connectable_tools()
1628
1664
  cleanup_run(run_response.run_id) # type: ignore
1629
1665
 
1630
1666
  def _run_stream(
@@ -1911,6 +1947,8 @@ class Team:
1911
1947
  # Add the RunOutput to Team Session even when cancelled
1912
1948
  self._cleanup_and_store(run_response=run_response, session=session)
1913
1949
  finally:
1950
+ # Always disconnect connectable tools
1951
+ self._disconnect_connectable_tools()
1914
1952
  # Always clean up the run tracking
1915
1953
  cleanup_run(run_response.run_id) # type: ignore
1916
1954
 
@@ -2475,6 +2513,8 @@ class Team:
2475
2513
 
2476
2514
  return run_response
2477
2515
  finally:
2516
+ # Always disconnect connectable tools
2517
+ self._disconnect_connectable_tools()
2478
2518
  await self._disconnect_mcp_tools()
2479
2519
  # Cancel the memory task if it's still running
2480
2520
  if memory_task is not None and not memory_task.done():
@@ -2801,6 +2841,8 @@ class Team:
2801
2841
  await self._acleanup_and_store(run_response=run_response, session=team_session)
2802
2842
 
2803
2843
  finally:
2844
+ # Always disconnect connectable tools
2845
+ self._disconnect_connectable_tools()
2804
2846
  await self._disconnect_mcp_tools()
2805
2847
  # Cancel the memory task if it's still running
2806
2848
  if memory_task is not None and not memory_task.done():
@@ -5333,6 +5375,9 @@ class Team:
5333
5375
  add_session_state_to_context: Optional[bool] = None,
5334
5376
  check_mcp_tools: bool = True,
5335
5377
  ) -> List[Union[Function, dict]]:
5378
+ # Connect tools that require connection management
5379
+ self._connect_connectable_tools()
5380
+
5336
5381
  # Prepare tools
5337
5382
  _tools: List[Union[Toolkit, Callable, Function, Dict]] = []
5338
5383
 
@@ -5382,6 +5427,7 @@ class Team:
5382
5427
  run_response=run_response,
5383
5428
  knowledge_filters=run_context.knowledge_filters,
5384
5429
  async_mode=async_mode,
5430
+ run_context=run_context,
5385
5431
  )
5386
5432
  )
5387
5433
  else:
@@ -5390,6 +5436,7 @@ class Team:
5390
5436
  run_response=run_response,
5391
5437
  knowledge_filters=run_context.knowledge_filters,
5392
5438
  async_mode=async_mode,
5439
+ run_context=run_context,
5393
5440
  )
5394
5441
  )
5395
5442
 
@@ -6579,7 +6626,10 @@ class Team:
6579
6626
  retrieval_timer = Timer()
6580
6627
  retrieval_timer.start()
6581
6628
  docs_from_knowledge = self.get_relevant_docs_from_knowledge(
6582
- query=user_msg_content, filters=run_context.knowledge_filters, **kwargs
6629
+ query=user_msg_content,
6630
+ filters=run_context.knowledge_filters,
6631
+ run_context=run_context,
6632
+ **kwargs,
6583
6633
  )
6584
6634
  if docs_from_knowledge is not None:
6585
6635
  references = MessageReferences(
@@ -6734,7 +6784,10 @@ class Team:
6734
6784
  retrieval_timer = Timer()
6735
6785
  retrieval_timer.start()
6736
6786
  docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
6737
- query=user_msg_content, filters=run_context.knowledge_filters, **kwargs
6787
+ query=user_msg_content,
6788
+ filters=run_context.knowledge_filters,
6789
+ run_context=run_context,
6790
+ **kwargs,
6738
6791
  )
6739
6792
  if docs_from_knowledge is not None:
6740
6793
  references = MessageReferences(
@@ -9000,11 +9053,15 @@ class Team:
9000
9053
  query: str,
9001
9054
  num_documents: Optional[int] = None,
9002
9055
  filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
9056
+ run_context: Optional[RunContext] = None,
9003
9057
  **kwargs,
9004
9058
  ) -> Optional[List[Union[Dict[str, Any], str]]]:
9005
9059
  """Return a list of references from the knowledge base"""
9006
9060
  from agno.knowledge.document import Document
9007
9061
 
9062
+ # Extract dependencies from run_context if available
9063
+ dependencies = run_context.dependencies if run_context else None
9064
+
9008
9065
  if num_documents is None and self.knowledge is not None:
9009
9066
  num_documents = self.knowledge.max_results
9010
9067
 
@@ -9036,6 +9093,11 @@ class Team:
9036
9093
  knowledge_retriever_kwargs = {"team": self}
9037
9094
  if "filters" in sig.parameters:
9038
9095
  knowledge_retriever_kwargs["filters"] = filters
9096
+ if "run_context" in sig.parameters:
9097
+ knowledge_retriever_kwargs["run_context"] = run_context
9098
+ elif "dependencies" in sig.parameters:
9099
+ # Backward compatibility: support dependencies parameter
9100
+ knowledge_retriever_kwargs["dependencies"] = dependencies
9039
9101
  knowledge_retriever_kwargs.update({"query": query, "num_documents": num_documents, **kwargs})
9040
9102
  return self.knowledge_retriever(**knowledge_retriever_kwargs)
9041
9103
  except Exception as e:
@@ -9067,11 +9129,15 @@ class Team:
9067
9129
  query: str,
9068
9130
  num_documents: Optional[int] = None,
9069
9131
  filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
9132
+ run_context: Optional[RunContext] = None,
9070
9133
  **kwargs,
9071
9134
  ) -> Optional[List[Union[Dict[str, Any], str]]]:
9072
9135
  """Get relevant documents from knowledge base asynchronously."""
9073
9136
  from agno.knowledge.document import Document
9074
9137
 
9138
+ # Extract dependencies from run_context if available
9139
+ dependencies = run_context.dependencies if run_context else None
9140
+
9075
9141
  if num_documents is None and self.knowledge is not None:
9076
9142
  num_documents = self.knowledge.max_results
9077
9143
 
@@ -9103,6 +9169,11 @@ class Team:
9103
9169
  knowledge_retriever_kwargs = {"team": self}
9104
9170
  if "filters" in sig.parameters:
9105
9171
  knowledge_retriever_kwargs["filters"] = filters
9172
+ if "run_context" in sig.parameters:
9173
+ knowledge_retriever_kwargs["run_context"] = run_context
9174
+ elif "dependencies" in sig.parameters:
9175
+ # Backward compatibility: support dependencies parameter
9176
+ knowledge_retriever_kwargs["dependencies"] = dependencies
9106
9177
  knowledge_retriever_kwargs.update({"query": query, "num_documents": num_documents, **kwargs})
9107
9178
 
9108
9179
  result = self.knowledge_retriever(**knowledge_retriever_kwargs)
@@ -9187,6 +9258,7 @@ class Team:
9187
9258
  run_response: TeamRunOutput,
9188
9259
  knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
9189
9260
  async_mode: bool = False,
9261
+ run_context: Optional[RunContext] = None,
9190
9262
  ) -> Function:
9191
9263
  """Factory function to create a search_knowledge_base function with filters."""
9192
9264
 
@@ -9202,7 +9274,9 @@ class Team:
9202
9274
  # Get the relevant documents from the knowledge base, passing filters
9203
9275
  retrieval_timer = Timer()
9204
9276
  retrieval_timer.start()
9205
- docs_from_knowledge = self.get_relevant_docs_from_knowledge(query=query, filters=knowledge_filters)
9277
+ docs_from_knowledge = self.get_relevant_docs_from_knowledge(
9278
+ query=query, filters=knowledge_filters, run_context=run_context
9279
+ )
9206
9280
  if docs_from_knowledge is not None:
9207
9281
  references = MessageReferences(
9208
9282
  query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)
@@ -9229,7 +9303,9 @@ class Team:
9229
9303
  """
9230
9304
  retrieval_timer = Timer()
9231
9305
  retrieval_timer.start()
9232
- docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(query=query, filters=knowledge_filters)
9306
+ docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
9307
+ query=query, filters=knowledge_filters, run_context=run_context
9308
+ )
9233
9309
  if docs_from_knowledge is not None:
9234
9310
  references = MessageReferences(
9235
9311
  query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)
@@ -9256,6 +9332,7 @@ class Team:
9256
9332
  run_response: TeamRunOutput,
9257
9333
  knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
9258
9334
  async_mode: bool = False,
9335
+ run_context: Optional[RunContext] = None,
9259
9336
  ) -> Function:
9260
9337
  """Factory function to create a search_knowledge_base function with filters."""
9261
9338
 
@@ -9275,7 +9352,9 @@ class Team:
9275
9352
  # Get the relevant documents from the knowledge base, passing filters
9276
9353
  retrieval_timer = Timer()
9277
9354
  retrieval_timer.start()
9278
- docs_from_knowledge = self.get_relevant_docs_from_knowledge(query=query, filters=search_filters)
9355
+ docs_from_knowledge = self.get_relevant_docs_from_knowledge(
9356
+ query=query, filters=search_filters, run_context=run_context
9357
+ )
9279
9358
  if docs_from_knowledge is not None:
9280
9359
  references = MessageReferences(
9281
9360
  query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)
@@ -9306,7 +9385,9 @@ class Team:
9306
9385
 
9307
9386
  retrieval_timer = Timer()
9308
9387
  retrieval_timer.start()
9309
- docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(query=query, filters=search_filters)
9388
+ docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
9389
+ query=query, filters=search_filters, run_context=run_context
9390
+ )
9310
9391
  if docs_from_knowledge is not None:
9311
9392
  references = MessageReferences(
9312
9393
  query=query, references=docs_from_knowledge, time=round(retrieval_timer.elapsed, 4)