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.
- agno/agent/agent.py +193 -26
- agno/db/postgres/async_postgres.py +23 -7
- agno/db/utils.py +2 -0
- agno/models/base.py +34 -4
- agno/models/response.py +1 -1
- agno/os/routers/evals/utils.py +13 -3
- agno/run/agent.py +17 -0
- agno/run/requirement.py +98 -0
- agno/run/team.py +10 -0
- agno/team/team.py +91 -10
- agno/tools/postgres.py +76 -36
- agno/tools/redshift.py +406 -0
- agno/tools/toolkit.py +25 -0
- agno/utils/events.py +5 -1
- {agno-2.3.6.dist-info → agno-2.3.7.dist-info}/METADATA +4 -1
- {agno-2.3.6.dist-info → agno-2.3.7.dist-info}/RECORD +19 -17
- {agno-2.3.6.dist-info → agno-2.3.7.dist-info}/WHEEL +0 -0
- {agno-2.3.6.dist-info → agno-2.3.7.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.6.dist-info → agno-2.3.7.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -68,6 +68,7 @@ from agno.run.cancel import (
|
|
|
68
68
|
register_run,
|
|
69
69
|
)
|
|
70
70
|
from agno.run.messages import RunMessages
|
|
71
|
+
from agno.run.requirement import RunRequirement
|
|
71
72
|
from agno.run.team import TeamRunOutputEvent
|
|
72
73
|
from agno.session import AgentSession, SessionSummaryManager, TeamSession, WorkflowSession
|
|
73
74
|
from agno.session.summary import SessionSummary
|
|
@@ -683,6 +684,7 @@ class Agent:
|
|
|
683
684
|
self._hooks_normalised = False
|
|
684
685
|
|
|
685
686
|
self._mcp_tools_initialized_on_run: List[Any] = []
|
|
687
|
+
self._connectable_tools_initialized_on_run: List[Any] = []
|
|
686
688
|
|
|
687
689
|
# Lazy-initialized shared thread pool executor for background tasks (memory, cultural knowledge, etc.)
|
|
688
690
|
self._background_executor: Optional[Any] = None
|
|
@@ -912,16 +914,48 @@ class Agent:
|
|
|
912
914
|
and any(c.__name__ in ["MCPTools", "MultiMCPTools"] for c in type(tool).__mro__)
|
|
913
915
|
and not tool.initialized # type: ignore
|
|
914
916
|
):
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
917
|
+
try:
|
|
918
|
+
# Connect the MCP server
|
|
919
|
+
await tool.connect() # type: ignore
|
|
920
|
+
self._mcp_tools_initialized_on_run.append(tool) # type: ignore
|
|
921
|
+
except Exception as e:
|
|
922
|
+
log_warning(f"Error connecting tool: {str(e)}")
|
|
918
923
|
|
|
919
924
|
async def _disconnect_mcp_tools(self) -> None:
|
|
920
925
|
"""Disconnect the MCP tools from the agent."""
|
|
921
926
|
for tool in self._mcp_tools_initialized_on_run:
|
|
922
|
-
|
|
927
|
+
try:
|
|
928
|
+
await tool.close()
|
|
929
|
+
except Exception as e:
|
|
930
|
+
log_warning(f"Error disconnecting tool: {str(e)}")
|
|
923
931
|
self._mcp_tools_initialized_on_run = []
|
|
924
932
|
|
|
933
|
+
def _connect_connectable_tools(self) -> None:
|
|
934
|
+
"""Connect tools that require connection management (e.g., database connections)."""
|
|
935
|
+
if self.tools:
|
|
936
|
+
for tool in self.tools:
|
|
937
|
+
if (
|
|
938
|
+
hasattr(tool, "requires_connect")
|
|
939
|
+
and tool.requires_connect
|
|
940
|
+
and hasattr(tool, "connect")
|
|
941
|
+
and tool not in self._connectable_tools_initialized_on_run
|
|
942
|
+
):
|
|
943
|
+
try:
|
|
944
|
+
tool.connect() # type: ignore
|
|
945
|
+
self._connectable_tools_initialized_on_run.append(tool)
|
|
946
|
+
except Exception as e:
|
|
947
|
+
log_warning(f"Error connecting tool: {str(e)}")
|
|
948
|
+
|
|
949
|
+
def _disconnect_connectable_tools(self) -> None:
|
|
950
|
+
"""Disconnect tools that require connection management."""
|
|
951
|
+
for tool in self._connectable_tools_initialized_on_run:
|
|
952
|
+
if hasattr(tool, "close"):
|
|
953
|
+
try:
|
|
954
|
+
tool.close() # type: ignore
|
|
955
|
+
except Exception as e:
|
|
956
|
+
log_warning(f"Error disconnecting tool: {str(e)}")
|
|
957
|
+
self._connectable_tools_initialized_on_run = []
|
|
958
|
+
|
|
925
959
|
def _initialize_session(
|
|
926
960
|
self,
|
|
927
961
|
session_id: Optional[str] = None,
|
|
@@ -1175,6 +1209,8 @@ class Agent:
|
|
|
1175
1209
|
|
|
1176
1210
|
return run_response
|
|
1177
1211
|
finally:
|
|
1212
|
+
# Always disconnect connectable tools
|
|
1213
|
+
self._disconnect_connectable_tools()
|
|
1178
1214
|
# Always clean up the run tracking
|
|
1179
1215
|
cleanup_run(run_response.run_id) # type: ignore
|
|
1180
1216
|
|
|
@@ -1493,6 +1529,8 @@ class Agent:
|
|
|
1493
1529
|
run_response=run_response, session=session, run_context=run_context, user_id=user_id
|
|
1494
1530
|
)
|
|
1495
1531
|
finally:
|
|
1532
|
+
# Always disconnect connectable tools
|
|
1533
|
+
self._disconnect_connectable_tools()
|
|
1496
1534
|
# Always clean up the run tracking
|
|
1497
1535
|
cleanup_run(run_response.run_id) # type: ignore
|
|
1498
1536
|
|
|
@@ -2075,6 +2113,8 @@ class Agent:
|
|
|
2075
2113
|
return run_response
|
|
2076
2114
|
|
|
2077
2115
|
finally:
|
|
2116
|
+
# Always disconnect connectable tools
|
|
2117
|
+
self._disconnect_connectable_tools()
|
|
2078
2118
|
# Always disconnect MCP tools
|
|
2079
2119
|
await self._disconnect_mcp_tools()
|
|
2080
2120
|
|
|
@@ -2442,6 +2482,8 @@ class Agent:
|
|
|
2442
2482
|
user_id=user_id,
|
|
2443
2483
|
)
|
|
2444
2484
|
finally:
|
|
2485
|
+
# Always disconnect connectable tools
|
|
2486
|
+
self._disconnect_connectable_tools()
|
|
2445
2487
|
# Always disconnect MCP tools
|
|
2446
2488
|
await self._disconnect_mcp_tools()
|
|
2447
2489
|
|
|
@@ -2784,6 +2826,7 @@ class Agent:
|
|
|
2784
2826
|
*,
|
|
2785
2827
|
run_id: Optional[str] = None,
|
|
2786
2828
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
2829
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
2787
2830
|
stream: Literal[False] = False,
|
|
2788
2831
|
stream_events: Optional[bool] = None,
|
|
2789
2832
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -2794,6 +2837,7 @@ class Agent:
|
|
|
2794
2837
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2795
2838
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2796
2839
|
debug_mode: Optional[bool] = None,
|
|
2840
|
+
yield_run_output: bool = False,
|
|
2797
2841
|
) -> RunOutput: ...
|
|
2798
2842
|
|
|
2799
2843
|
@overload
|
|
@@ -2803,6 +2847,7 @@ class Agent:
|
|
|
2803
2847
|
*,
|
|
2804
2848
|
run_id: Optional[str] = None,
|
|
2805
2849
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
2850
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
2806
2851
|
stream: Literal[True] = True,
|
|
2807
2852
|
stream_events: Optional[bool] = False,
|
|
2808
2853
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -2813,6 +2858,7 @@ class Agent:
|
|
|
2813
2858
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2814
2859
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2815
2860
|
debug_mode: Optional[bool] = None,
|
|
2861
|
+
yield_run_output: bool = False,
|
|
2816
2862
|
) -> Iterator[RunOutputEvent]: ...
|
|
2817
2863
|
|
|
2818
2864
|
def continue_run(
|
|
@@ -2821,6 +2867,7 @@ class Agent:
|
|
|
2821
2867
|
*,
|
|
2822
2868
|
run_id: Optional[str] = None, # type: ignore
|
|
2823
2869
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
2870
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
2824
2871
|
stream: Optional[bool] = None,
|
|
2825
2872
|
stream_events: Optional[bool] = False,
|
|
2826
2873
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -2832,14 +2879,15 @@ class Agent:
|
|
|
2832
2879
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2833
2880
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2834
2881
|
debug_mode: Optional[bool] = None,
|
|
2882
|
+
yield_run_output: bool = False,
|
|
2835
2883
|
**kwargs,
|
|
2836
|
-
) -> Union[RunOutput, Iterator[RunOutputEvent]]:
|
|
2884
|
+
) -> Union[RunOutput, Iterator[Union[RunOutputEvent, RunOutput]]]:
|
|
2837
2885
|
"""Continue a previous run.
|
|
2838
2886
|
|
|
2839
2887
|
Args:
|
|
2840
2888
|
run_response: The run response to continue.
|
|
2841
2889
|
run_id: The run id to continue. Alternative to passing run_response.
|
|
2842
|
-
|
|
2890
|
+
requirements: The requirements to continue the run. This or updated_tools is required with `run_id`.
|
|
2843
2891
|
stream: Whether to stream the response.
|
|
2844
2892
|
stream_events: Whether to stream all events.
|
|
2845
2893
|
user_id: The user id to continue the run for.
|
|
@@ -2851,6 +2899,7 @@ class Agent:
|
|
|
2851
2899
|
metadata: The metadata to use for the run.
|
|
2852
2900
|
debug_mode: Whether to enable debug mode.
|
|
2853
2901
|
(deprecated) stream_intermediate_steps: Whether to stream all steps.
|
|
2902
|
+
(deprecated) updated_tools: Use 'requirements' instead.
|
|
2854
2903
|
"""
|
|
2855
2904
|
if run_response is None and run_id is None:
|
|
2856
2905
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
@@ -2950,16 +2999,35 @@ class Agent:
|
|
|
2950
2999
|
# The run is continued from a provided run_response. This contains the updated tools.
|
|
2951
3000
|
input = run_response.messages or []
|
|
2952
3001
|
elif run_id is not None:
|
|
2953
|
-
# The run is continued from a run_id
|
|
2954
|
-
if updated_tools is None:
|
|
2955
|
-
raise ValueError("
|
|
3002
|
+
# The run is continued from a run_id, one of requirements or updated_tool (deprecated) is required.
|
|
3003
|
+
if updated_tools is None and requirements is None:
|
|
3004
|
+
raise ValueError("To continue a run from a given run_id, the requirements parameter must be provided.")
|
|
2956
3005
|
|
|
2957
3006
|
runs = agent_session.runs
|
|
2958
3007
|
run_response = next((r for r in runs if r.run_id == run_id), None) # type: ignore
|
|
2959
3008
|
if run_response is None:
|
|
2960
3009
|
raise RuntimeError(f"No runs found for run ID {run_id}")
|
|
2961
|
-
|
|
3010
|
+
|
|
2962
3011
|
input = run_response.messages or []
|
|
3012
|
+
|
|
3013
|
+
# If we have updated_tools, set them in the run_response
|
|
3014
|
+
if updated_tools is not None:
|
|
3015
|
+
warnings.warn(
|
|
3016
|
+
"The 'updated_tools' parameter is deprecated and will be removed in future versions. Use 'requirements' instead.",
|
|
3017
|
+
DeprecationWarning,
|
|
3018
|
+
stacklevel=2,
|
|
3019
|
+
)
|
|
3020
|
+
run_response.tools = updated_tools
|
|
3021
|
+
|
|
3022
|
+
# If we have requirements, get the updated tools and set them in the run_response
|
|
3023
|
+
elif requirements is not None:
|
|
3024
|
+
run_response.requirements = requirements
|
|
3025
|
+
updated_tools = [req.tool_execution for req in requirements if req.tool_execution is not None]
|
|
3026
|
+
if updated_tools and run_response.tools:
|
|
3027
|
+
updated_tools_map = {tool.tool_call_id: tool for tool in updated_tools}
|
|
3028
|
+
run_response.tools = [updated_tools_map.get(tool.tool_call_id, tool) for tool in run_response.tools]
|
|
3029
|
+
else:
|
|
3030
|
+
run_response.tools = updated_tools
|
|
2963
3031
|
else:
|
|
2964
3032
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
2965
3033
|
|
|
@@ -3009,6 +3077,7 @@ class Agent:
|
|
|
3009
3077
|
session=agent_session,
|
|
3010
3078
|
response_format=response_format,
|
|
3011
3079
|
stream_events=stream_events,
|
|
3080
|
+
yield_run_output=yield_run_output,
|
|
3012
3081
|
debug_mode=debug_mode,
|
|
3013
3082
|
background_tasks=background_tasks,
|
|
3014
3083
|
**kwargs,
|
|
@@ -3182,6 +3251,8 @@ class Agent:
|
|
|
3182
3251
|
|
|
3183
3252
|
return run_response
|
|
3184
3253
|
finally:
|
|
3254
|
+
# Always disconnect connectable tools
|
|
3255
|
+
self._disconnect_connectable_tools()
|
|
3185
3256
|
# Always clean up the run tracking
|
|
3186
3257
|
cleanup_run(run_response.run_id) # type: ignore
|
|
3187
3258
|
|
|
@@ -3196,9 +3267,10 @@ class Agent:
|
|
|
3196
3267
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
3197
3268
|
stream_events: bool = False,
|
|
3198
3269
|
debug_mode: Optional[bool] = None,
|
|
3270
|
+
yield_run_output: bool = False,
|
|
3199
3271
|
background_tasks: Optional[Any] = None,
|
|
3200
3272
|
**kwargs,
|
|
3201
|
-
) -> Iterator[RunOutputEvent]:
|
|
3273
|
+
) -> Iterator[Union[RunOutputEvent, RunOutput]]:
|
|
3202
3274
|
"""Continue a previous run.
|
|
3203
3275
|
|
|
3204
3276
|
Steps:
|
|
@@ -3331,6 +3403,9 @@ class Agent:
|
|
|
3331
3403
|
if stream_events:
|
|
3332
3404
|
yield completed_event # type: ignore
|
|
3333
3405
|
|
|
3406
|
+
if yield_run_output:
|
|
3407
|
+
yield run_response
|
|
3408
|
+
|
|
3334
3409
|
# Log Agent Telemetry
|
|
3335
3410
|
self._log_agent_telemetry(session_id=session.session_id, run_id=run_response.run_id)
|
|
3336
3411
|
|
|
@@ -3355,6 +3430,8 @@ class Agent:
|
|
|
3355
3430
|
run_response=run_response, session=session, run_context=run_context, user_id=user_id
|
|
3356
3431
|
)
|
|
3357
3432
|
finally:
|
|
3433
|
+
# Always disconnect connectable tools
|
|
3434
|
+
self._disconnect_connectable_tools()
|
|
3358
3435
|
# Always clean up the run tracking
|
|
3359
3436
|
cleanup_run(run_response.run_id) # type: ignore
|
|
3360
3437
|
|
|
@@ -3368,6 +3445,7 @@ class Agent:
|
|
|
3368
3445
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3369
3446
|
run_id: Optional[str] = None,
|
|
3370
3447
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3448
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3371
3449
|
user_id: Optional[str] = None,
|
|
3372
3450
|
session_id: Optional[str] = None,
|
|
3373
3451
|
retries: Optional[int] = None,
|
|
@@ -3388,6 +3466,7 @@ class Agent:
|
|
|
3388
3466
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3389
3467
|
run_id: Optional[str] = None,
|
|
3390
3468
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3469
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3391
3470
|
user_id: Optional[str] = None,
|
|
3392
3471
|
session_id: Optional[str] = None,
|
|
3393
3472
|
retries: Optional[int] = None,
|
|
@@ -3404,6 +3483,7 @@ class Agent:
|
|
|
3404
3483
|
*,
|
|
3405
3484
|
run_id: Optional[str] = None, # type: ignore
|
|
3406
3485
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3486
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3407
3487
|
stream: Optional[bool] = None,
|
|
3408
3488
|
stream_events: Optional[bool] = None,
|
|
3409
3489
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -3423,7 +3503,8 @@ class Agent:
|
|
|
3423
3503
|
Args:
|
|
3424
3504
|
run_response: The run response to continue.
|
|
3425
3505
|
run_id: The run id to continue. Alternative to passing run_response.
|
|
3426
|
-
|
|
3506
|
+
|
|
3507
|
+
requirements: The requirements to continue the run. This or updated_tools is required with `run_id`.
|
|
3427
3508
|
stream: Whether to stream the response.
|
|
3428
3509
|
stream_events: Whether to stream all events.
|
|
3429
3510
|
user_id: The user id to continue the run for.
|
|
@@ -3436,6 +3517,7 @@ class Agent:
|
|
|
3436
3517
|
debug_mode: Whether to enable debug mode.
|
|
3437
3518
|
yield_run_output: Whether to yield the run response.
|
|
3438
3519
|
(deprecated) stream_intermediate_steps: Whether to stream all steps.
|
|
3520
|
+
(deprecated) updated_tools: Use 'requirements' instead.
|
|
3439
3521
|
"""
|
|
3440
3522
|
if run_response is None and run_id is None:
|
|
3441
3523
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
@@ -3443,6 +3525,12 @@ class Agent:
|
|
|
3443
3525
|
if run_response is None and (run_id is not None and (session_id is None and self.session_id is None)):
|
|
3444
3526
|
raise ValueError("Session ID is required to continue a run from a run_id.")
|
|
3445
3527
|
|
|
3528
|
+
if updated_tools is not None:
|
|
3529
|
+
warnings.warn(
|
|
3530
|
+
"The 'updated_tools' parameter is deprecated and will be removed in future versions. Use 'requirements' instead.",
|
|
3531
|
+
DeprecationWarning,
|
|
3532
|
+
stacklevel=2,
|
|
3533
|
+
)
|
|
3446
3534
|
background_tasks = kwargs.pop("background_tasks", None)
|
|
3447
3535
|
if background_tasks is not None:
|
|
3448
3536
|
from fastapi import BackgroundTasks
|
|
@@ -3526,6 +3614,7 @@ class Agent:
|
|
|
3526
3614
|
run_response=run_response,
|
|
3527
3615
|
run_context=run_context,
|
|
3528
3616
|
updated_tools=updated_tools,
|
|
3617
|
+
requirements=requirements,
|
|
3529
3618
|
run_id=run_id,
|
|
3530
3619
|
user_id=user_id,
|
|
3531
3620
|
session_id=session_id,
|
|
@@ -3542,6 +3631,7 @@ class Agent:
|
|
|
3542
3631
|
run_response=run_response,
|
|
3543
3632
|
run_context=run_context,
|
|
3544
3633
|
updated_tools=updated_tools,
|
|
3634
|
+
requirements=requirements,
|
|
3545
3635
|
run_id=run_id,
|
|
3546
3636
|
user_id=user_id,
|
|
3547
3637
|
response_format=response_format,
|
|
@@ -3592,6 +3682,7 @@ class Agent:
|
|
|
3592
3682
|
run_context: RunContext,
|
|
3593
3683
|
run_response: Optional[RunOutput] = None,
|
|
3594
3684
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3685
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3595
3686
|
run_id: Optional[str] = None,
|
|
3596
3687
|
user_id: Optional[str] = None,
|
|
3597
3688
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
@@ -3644,15 +3735,29 @@ class Agent:
|
|
|
3644
3735
|
input = run_response.messages or []
|
|
3645
3736
|
elif run_id is not None:
|
|
3646
3737
|
# The run is continued from a run_id. This requires the updated tools to be passed.
|
|
3647
|
-
if updated_tools is None:
|
|
3648
|
-
raise ValueError("
|
|
3738
|
+
if updated_tools is None and requirements is None:
|
|
3739
|
+
raise ValueError("Either updated tools or requirements are required to continue a run from a run_id.")
|
|
3649
3740
|
|
|
3650
3741
|
runs = agent_session.runs
|
|
3651
3742
|
run_response = next((r for r in runs if r.run_id == run_id), None) # type: ignore
|
|
3652
3743
|
if run_response is None:
|
|
3653
3744
|
raise RuntimeError(f"No runs found for run ID {run_id}")
|
|
3654
|
-
|
|
3745
|
+
|
|
3655
3746
|
input = run_response.messages or []
|
|
3747
|
+
|
|
3748
|
+
# If we have updated_tools, set them in the run_response
|
|
3749
|
+
if updated_tools is not None:
|
|
3750
|
+
run_response.tools = updated_tools
|
|
3751
|
+
|
|
3752
|
+
# If we have requirements, get the updated tools and set them in the run_response
|
|
3753
|
+
elif requirements is not None:
|
|
3754
|
+
run_response.requirements = requirements
|
|
3755
|
+
updated_tools = [req.tool_execution for req in requirements if req.tool_execution is not None]
|
|
3756
|
+
if updated_tools and run_response.tools:
|
|
3757
|
+
updated_tools_map = {tool.tool_call_id: tool for tool in updated_tools}
|
|
3758
|
+
run_response.tools = [updated_tools_map.get(tool.tool_call_id, tool) for tool in run_response.tools]
|
|
3759
|
+
else:
|
|
3760
|
+
run_response.tools = updated_tools
|
|
3656
3761
|
else:
|
|
3657
3762
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
3658
3763
|
|
|
@@ -3791,6 +3896,8 @@ class Agent:
|
|
|
3791
3896
|
|
|
3792
3897
|
return run_response
|
|
3793
3898
|
finally:
|
|
3899
|
+
# Always disconnect connectable tools
|
|
3900
|
+
self._disconnect_connectable_tools()
|
|
3794
3901
|
# Always disconnect MCP tools
|
|
3795
3902
|
await self._disconnect_mcp_tools()
|
|
3796
3903
|
|
|
@@ -3803,6 +3910,7 @@ class Agent:
|
|
|
3803
3910
|
run_context: RunContext,
|
|
3804
3911
|
run_response: Optional[RunOutput] = None,
|
|
3805
3912
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3913
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3806
3914
|
run_id: Optional[str] = None,
|
|
3807
3915
|
user_id: Optional[str] = None,
|
|
3808
3916
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
@@ -3852,17 +3960,32 @@ class Agent:
|
|
|
3852
3960
|
if run_response is not None:
|
|
3853
3961
|
# The run is continued from a provided run_response. This contains the updated tools.
|
|
3854
3962
|
input = run_response.messages or []
|
|
3963
|
+
|
|
3855
3964
|
elif run_id is not None:
|
|
3856
|
-
# The run is continued from a run_id. This requires the updated tools to be passed.
|
|
3857
|
-
if updated_tools is None:
|
|
3858
|
-
raise ValueError("
|
|
3965
|
+
# The run is continued from a run_id. This requires the updated tools or requirements to be passed.
|
|
3966
|
+
if updated_tools is None and requirements is None:
|
|
3967
|
+
raise ValueError("Either updated tools or requirements are required to continue a run from a run_id.")
|
|
3859
3968
|
|
|
3860
3969
|
runs = agent_session.runs
|
|
3861
3970
|
run_response = next((r for r in runs if r.run_id == run_id), None) # type: ignore
|
|
3862
3971
|
if run_response is None:
|
|
3863
3972
|
raise RuntimeError(f"No runs found for run ID {run_id}")
|
|
3864
|
-
|
|
3973
|
+
|
|
3865
3974
|
input = run_response.messages or []
|
|
3975
|
+
|
|
3976
|
+
# If we have updated_tools, set them in the run_response
|
|
3977
|
+
if updated_tools is not None:
|
|
3978
|
+
run_response.tools = updated_tools
|
|
3979
|
+
|
|
3980
|
+
# If we have requirements, get the updated tools and set them in the run_response
|
|
3981
|
+
elif requirements is not None:
|
|
3982
|
+
run_response.requirements = requirements
|
|
3983
|
+
updated_tools = [req.tool_execution for req in requirements if req.tool_execution is not None]
|
|
3984
|
+
if updated_tools and run_response.tools:
|
|
3985
|
+
updated_tools_map = {tool.tool_call_id: tool for tool in updated_tools}
|
|
3986
|
+
run_response.tools = [updated_tools_map.get(tool.tool_call_id, tool) for tool in run_response.tools]
|
|
3987
|
+
else:
|
|
3988
|
+
run_response.tools = updated_tools
|
|
3866
3989
|
else:
|
|
3867
3990
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
3868
3991
|
|
|
@@ -4081,6 +4204,8 @@ class Agent:
|
|
|
4081
4204
|
user_id=user_id,
|
|
4082
4205
|
)
|
|
4083
4206
|
finally:
|
|
4207
|
+
# Always disconnect connectable tools
|
|
4208
|
+
self._disconnect_connectable_tools()
|
|
4084
4209
|
# Always disconnect MCP tools
|
|
4085
4210
|
await self._disconnect_mcp_tools()
|
|
4086
4211
|
|
|
@@ -4496,6 +4621,7 @@ class Agent:
|
|
|
4496
4621
|
create_run_paused_event(
|
|
4497
4622
|
from_run_response=run_response,
|
|
4498
4623
|
tools=run_response.tools,
|
|
4624
|
+
requirements=run_response.requirements,
|
|
4499
4625
|
),
|
|
4500
4626
|
run_response,
|
|
4501
4627
|
events_to_skip=self.events_to_skip, # type: ignore
|
|
@@ -4544,6 +4670,7 @@ class Agent:
|
|
|
4544
4670
|
create_run_paused_event(
|
|
4545
4671
|
from_run_response=run_response,
|
|
4546
4672
|
tools=run_response.tools,
|
|
4673
|
+
requirements=run_response.requirements,
|
|
4547
4674
|
),
|
|
4548
4675
|
run_response,
|
|
4549
4676
|
events_to_skip=self.events_to_skip, # type: ignore
|
|
@@ -5359,7 +5486,7 @@ class Agent:
|
|
|
5359
5486
|
run_response.images = []
|
|
5360
5487
|
run_response.images.append(image)
|
|
5361
5488
|
|
|
5362
|
-
# Handle tool interruption events
|
|
5489
|
+
# Handle tool interruption events (HITL flow)
|
|
5363
5490
|
elif model_response_event.event == ModelResponseEvent.tool_call_paused.value:
|
|
5364
5491
|
# Add tool calls to the run_response
|
|
5365
5492
|
tool_executions_list = model_response_event.tool_executions
|
|
@@ -5369,6 +5496,10 @@ class Agent:
|
|
|
5369
5496
|
run_response.tools = tool_executions_list
|
|
5370
5497
|
else:
|
|
5371
5498
|
run_response.tools.extend(tool_executions_list)
|
|
5499
|
+
# Add requirement to the run_response
|
|
5500
|
+
if run_response.requirements is None:
|
|
5501
|
+
run_response.requirements = []
|
|
5502
|
+
run_response.requirements.append(RunRequirement(tool_execution=tool_executions_list[-1]))
|
|
5372
5503
|
|
|
5373
5504
|
# If the model response is a tool_call_started, add the tool call to the run_response
|
|
5374
5505
|
elif (
|
|
@@ -5649,6 +5780,9 @@ class Agent:
|
|
|
5649
5780
|
) -> List[Union[Toolkit, Callable, Function, Dict]]:
|
|
5650
5781
|
agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
5651
5782
|
|
|
5783
|
+
# Connect tools that require connection management
|
|
5784
|
+
self._connect_connectable_tools()
|
|
5785
|
+
|
|
5652
5786
|
# Add provided tools
|
|
5653
5787
|
if self.tools is not None:
|
|
5654
5788
|
# If not running in async mode, raise if any tool is async
|
|
@@ -5695,6 +5829,7 @@ class Agent:
|
|
|
5695
5829
|
run_response=run_response,
|
|
5696
5830
|
async_mode=False,
|
|
5697
5831
|
knowledge_filters=run_context.knowledge_filters,
|
|
5832
|
+
run_context=run_context,
|
|
5698
5833
|
)
|
|
5699
5834
|
)
|
|
5700
5835
|
else:
|
|
@@ -5703,6 +5838,7 @@ class Agent:
|
|
|
5703
5838
|
run_response=run_response,
|
|
5704
5839
|
async_mode=False,
|
|
5705
5840
|
knowledge_filters=run_context.knowledge_filters,
|
|
5841
|
+
run_context=run_context,
|
|
5706
5842
|
)
|
|
5707
5843
|
)
|
|
5708
5844
|
|
|
@@ -5721,6 +5857,9 @@ class Agent:
|
|
|
5721
5857
|
) -> List[Union[Toolkit, Callable, Function, Dict]]:
|
|
5722
5858
|
agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
5723
5859
|
|
|
5860
|
+
# Connect tools that require connection management
|
|
5861
|
+
self._connect_connectable_tools()
|
|
5862
|
+
|
|
5724
5863
|
# Connect MCP tools
|
|
5725
5864
|
await self._connect_mcp_tools()
|
|
5726
5865
|
|
|
@@ -5783,6 +5922,7 @@ class Agent:
|
|
|
5783
5922
|
run_response=run_response,
|
|
5784
5923
|
async_mode=True,
|
|
5785
5924
|
knowledge_filters=run_context.knowledge_filters,
|
|
5925
|
+
run_context=run_context,
|
|
5786
5926
|
)
|
|
5787
5927
|
)
|
|
5788
5928
|
else:
|
|
@@ -5791,6 +5931,7 @@ class Agent:
|
|
|
5791
5931
|
run_response=run_response,
|
|
5792
5932
|
async_mode=True,
|
|
5793
5933
|
knowledge_filters=run_context.knowledge_filters,
|
|
5934
|
+
run_context=run_context,
|
|
5794
5935
|
)
|
|
5795
5936
|
)
|
|
5796
5937
|
|
|
@@ -7820,7 +7961,7 @@ class Agent:
|
|
|
7820
7961
|
retrieval_timer = Timer()
|
|
7821
7962
|
retrieval_timer.start()
|
|
7822
7963
|
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
7823
|
-
query=user_msg_content, filters=knowledge_filters, **kwargs
|
|
7964
|
+
query=user_msg_content, filters=knowledge_filters, run_context=run_context, **kwargs
|
|
7824
7965
|
)
|
|
7825
7966
|
if docs_from_knowledge is not None:
|
|
7826
7967
|
references = MessageReferences(
|
|
@@ -7994,7 +8135,7 @@ class Agent:
|
|
|
7994
8135
|
retrieval_timer = Timer()
|
|
7995
8136
|
retrieval_timer.start()
|
|
7996
8137
|
docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
|
|
7997
|
-
query=user_msg_content, filters=knowledge_filters, **kwargs
|
|
8138
|
+
query=user_msg_content, filters=knowledge_filters, run_context=run_context, **kwargs
|
|
7998
8139
|
)
|
|
7999
8140
|
if docs_from_knowledge is not None:
|
|
8000
8141
|
references = MessageReferences(
|
|
@@ -8575,6 +8716,7 @@ class Agent:
|
|
|
8575
8716
|
num_documents: Optional[int] = None,
|
|
8576
8717
|
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8577
8718
|
validate_filters: bool = False,
|
|
8719
|
+
run_context: Optional[RunContext] = None,
|
|
8578
8720
|
**kwargs,
|
|
8579
8721
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8580
8722
|
"""Get relevant docs from the knowledge base to answer a query.
|
|
@@ -8584,6 +8726,7 @@ class Agent:
|
|
|
8584
8726
|
num_documents (Optional[int]): Number of documents to return.
|
|
8585
8727
|
filters (Optional[Dict[str, Any]]): Filters to apply to the search.
|
|
8586
8728
|
validate_filters (bool): Whether to validate the filters against known valid filter keys.
|
|
8729
|
+
run_context (Optional[RunContext]): Runtime context containing dependencies and other context.
|
|
8587
8730
|
**kwargs: Additional keyword arguments.
|
|
8588
8731
|
|
|
8589
8732
|
Returns:
|
|
@@ -8591,6 +8734,9 @@ class Agent:
|
|
|
8591
8734
|
"""
|
|
8592
8735
|
from agno.knowledge.document import Document
|
|
8593
8736
|
|
|
8737
|
+
# Extract dependencies from run_context if available
|
|
8738
|
+
dependencies = run_context.dependencies if run_context else None
|
|
8739
|
+
|
|
8594
8740
|
if num_documents is None and self.knowledge is not None:
|
|
8595
8741
|
num_documents = self.knowledge.max_results
|
|
8596
8742
|
# Validate the filters against known valid filter keys
|
|
@@ -8622,6 +8768,11 @@ class Agent:
|
|
|
8622
8768
|
knowledge_retriever_kwargs = {"agent": self}
|
|
8623
8769
|
if "filters" in sig.parameters:
|
|
8624
8770
|
knowledge_retriever_kwargs["filters"] = filters
|
|
8771
|
+
if "run_context" in sig.parameters:
|
|
8772
|
+
knowledge_retriever_kwargs["run_context"] = run_context
|
|
8773
|
+
elif "dependencies" in sig.parameters:
|
|
8774
|
+
# Backward compatibility: support dependencies parameter
|
|
8775
|
+
knowledge_retriever_kwargs["dependencies"] = dependencies
|
|
8625
8776
|
knowledge_retriever_kwargs.update({"query": query, "num_documents": num_documents, **kwargs})
|
|
8626
8777
|
return self.knowledge_retriever(**knowledge_retriever_kwargs)
|
|
8627
8778
|
except Exception as e:
|
|
@@ -8660,11 +8811,15 @@ class Agent:
|
|
|
8660
8811
|
num_documents: Optional[int] = None,
|
|
8661
8812
|
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8662
8813
|
validate_filters: bool = False,
|
|
8814
|
+
run_context: Optional[RunContext] = None,
|
|
8663
8815
|
**kwargs,
|
|
8664
8816
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8665
8817
|
"""Get relevant documents from knowledge base asynchronously."""
|
|
8666
8818
|
from agno.knowledge.document import Document
|
|
8667
8819
|
|
|
8820
|
+
# Extract dependencies from run_context if available
|
|
8821
|
+
dependencies = run_context.dependencies if run_context else None
|
|
8822
|
+
|
|
8668
8823
|
if num_documents is None and self.knowledge is not None:
|
|
8669
8824
|
num_documents = self.knowledge.max_results
|
|
8670
8825
|
|
|
@@ -8696,6 +8851,11 @@ class Agent:
|
|
|
8696
8851
|
knowledge_retriever_kwargs = {"agent": self}
|
|
8697
8852
|
if "filters" in sig.parameters:
|
|
8698
8853
|
knowledge_retriever_kwargs["filters"] = filters
|
|
8854
|
+
if "run_context" in sig.parameters:
|
|
8855
|
+
knowledge_retriever_kwargs["run_context"] = run_context
|
|
8856
|
+
elif "dependencies" in sig.parameters:
|
|
8857
|
+
# Backward compatibility: support dependencies parameter
|
|
8858
|
+
knowledge_retriever_kwargs["dependencies"] = dependencies
|
|
8699
8859
|
knowledge_retriever_kwargs.update({"query": query, "num_documents": num_documents, **kwargs})
|
|
8700
8860
|
result = self.knowledge_retriever(**knowledge_retriever_kwargs)
|
|
8701
8861
|
|
|
@@ -10038,6 +10198,7 @@ class Agent:
|
|
|
10038
10198
|
run_response: RunOutput,
|
|
10039
10199
|
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
10040
10200
|
async_mode: bool = False,
|
|
10201
|
+
run_context: Optional[RunContext] = None,
|
|
10041
10202
|
) -> Function:
|
|
10042
10203
|
"""Factory function to create a search_knowledge_base function with filters."""
|
|
10043
10204
|
|
|
@@ -10054,7 +10215,9 @@ class Agent:
|
|
|
10054
10215
|
# Get the relevant documents from the knowledge base, passing filters
|
|
10055
10216
|
retrieval_timer = Timer()
|
|
10056
10217
|
retrieval_timer.start()
|
|
10057
|
-
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
10218
|
+
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
10219
|
+
query=query, filters=knowledge_filters, run_context=run_context
|
|
10220
|
+
)
|
|
10058
10221
|
if docs_from_knowledge is not None:
|
|
10059
10222
|
references = MessageReferences(
|
|
10060
10223
|
query=query,
|
|
@@ -10085,7 +10248,10 @@ class Agent:
|
|
|
10085
10248
|
"""
|
|
10086
10249
|
retrieval_timer = Timer()
|
|
10087
10250
|
retrieval_timer.start()
|
|
10088
|
-
|
|
10251
|
+
dependencies = run_context.dependencies if run_context else None
|
|
10252
|
+
docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
|
|
10253
|
+
query=query, filters=knowledge_filters, dependencies=dependencies
|
|
10254
|
+
)
|
|
10089
10255
|
if docs_from_knowledge is not None:
|
|
10090
10256
|
references = MessageReferences(
|
|
10091
10257
|
query=query,
|
|
@@ -10114,6 +10280,7 @@ class Agent:
|
|
|
10114
10280
|
run_response: RunOutput,
|
|
10115
10281
|
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
10116
10282
|
async_mode: bool = False,
|
|
10283
|
+
run_context: Optional[RunContext] = None,
|
|
10117
10284
|
) -> Function:
|
|
10118
10285
|
"""Factory function to create a search_knowledge_base function with filters."""
|
|
10119
10286
|
|
|
@@ -10134,7 +10301,7 @@ class Agent:
|
|
|
10134
10301
|
retrieval_timer = Timer()
|
|
10135
10302
|
retrieval_timer.start()
|
|
10136
10303
|
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
10137
|
-
query=query, filters=search_filters, validate_filters=True
|
|
10304
|
+
query=query, filters=search_filters, validate_filters=True, run_context=run_context
|
|
10138
10305
|
)
|
|
10139
10306
|
if docs_from_knowledge is not None:
|
|
10140
10307
|
references = MessageReferences(
|
|
@@ -10171,7 +10338,7 @@ class Agent:
|
|
|
10171
10338
|
retrieval_timer = Timer()
|
|
10172
10339
|
retrieval_timer.start()
|
|
10173
10340
|
docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
|
|
10174
|
-
query=query, filters=search_filters, validate_filters=True
|
|
10341
|
+
query=query, filters=search_filters, validate_filters=True, run_context=run_context
|
|
10175
10342
|
)
|
|
10176
10343
|
if docs_from_knowledge is not None:
|
|
10177
10344
|
references = MessageReferences(
|