agno 2.3.5__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 +200 -30
- agno/db/postgres/async_postgres.py +37 -11
- agno/db/postgres/postgres.py +9 -3
- agno/db/sqlite/async_sqlite.py +1 -1
- agno/db/sqlite/sqlite.py +3 -4
- agno/db/utils.py +2 -0
- agno/eval/accuracy.py +8 -4
- agno/integrations/discord/client.py +1 -1
- agno/models/base.py +34 -4
- agno/models/cerebras/cerebras.py +11 -12
- agno/models/response.py +1 -1
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/routers/evals/utils.py +13 -3
- agno/os/schema.py +2 -1
- agno/run/agent.py +17 -0
- agno/run/requirement.py +98 -0
- agno/run/team.py +10 -0
- agno/session/team.py +0 -1
- agno/table.py +1 -1
- agno/team/team.py +98 -14
- agno/tools/google_drive.py +4 -3
- agno/tools/postgres.py +76 -36
- agno/tools/redshift.py +406 -0
- agno/tools/spotify.py +922 -0
- agno/tools/toolkit.py +25 -0
- agno/utils/agent.py +2 -2
- agno/utils/events.py +5 -1
- agno/utils/mcp.py +1 -1
- agno/workflow/workflow.py +5 -2
- {agno-2.3.5.dist-info → agno-2.3.7.dist-info}/METADATA +40 -32
- {agno-2.3.5.dist-info → agno-2.3.7.dist-info}/RECORD +34 -31
- {agno-2.3.5.dist-info → agno-2.3.7.dist-info}/WHEEL +0 -0
- {agno-2.3.5.dist-info → agno-2.3.7.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.5.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
|
|
|
@@ -1645,7 +1683,10 @@ class Agent:
|
|
|
1645
1683
|
|
|
1646
1684
|
# Initialize session state
|
|
1647
1685
|
session_state = self._initialize_session_state(
|
|
1648
|
-
session_state=session_state
|
|
1686
|
+
session_state=session_state if session_state is not None else {},
|
|
1687
|
+
user_id=user_id,
|
|
1688
|
+
session_id=session_id,
|
|
1689
|
+
run_id=run_id,
|
|
1649
1690
|
)
|
|
1650
1691
|
# Update session state from DB
|
|
1651
1692
|
session_state = self._load_session_state(session=agent_session, session_state=session_state)
|
|
@@ -1866,7 +1907,7 @@ class Agent:
|
|
|
1866
1907
|
self._update_metadata(session=agent_session)
|
|
1867
1908
|
# Initialize session state
|
|
1868
1909
|
run_context.session_state = self._initialize_session_state(
|
|
1869
|
-
session_state=run_context.session_state
|
|
1910
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
1870
1911
|
user_id=user_id,
|
|
1871
1912
|
session_id=session_id,
|
|
1872
1913
|
run_id=run_response.run_id,
|
|
@@ -2072,6 +2113,8 @@ class Agent:
|
|
|
2072
2113
|
return run_response
|
|
2073
2114
|
|
|
2074
2115
|
finally:
|
|
2116
|
+
# Always disconnect connectable tools
|
|
2117
|
+
self._disconnect_connectable_tools()
|
|
2075
2118
|
# Always disconnect MCP tools
|
|
2076
2119
|
await self._disconnect_mcp_tools()
|
|
2077
2120
|
|
|
@@ -2144,7 +2187,7 @@ class Agent:
|
|
|
2144
2187
|
self._update_metadata(session=agent_session)
|
|
2145
2188
|
# Initialize session state
|
|
2146
2189
|
run_context.session_state = self._initialize_session_state(
|
|
2147
|
-
session_state=run_context.session_state
|
|
2190
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
2148
2191
|
user_id=user_id,
|
|
2149
2192
|
session_id=session_id,
|
|
2150
2193
|
run_id=run_response.run_id,
|
|
@@ -2439,6 +2482,8 @@ class Agent:
|
|
|
2439
2482
|
user_id=user_id,
|
|
2440
2483
|
)
|
|
2441
2484
|
finally:
|
|
2485
|
+
# Always disconnect connectable tools
|
|
2486
|
+
self._disconnect_connectable_tools()
|
|
2442
2487
|
# Always disconnect MCP tools
|
|
2443
2488
|
await self._disconnect_mcp_tools()
|
|
2444
2489
|
|
|
@@ -2781,6 +2826,7 @@ class Agent:
|
|
|
2781
2826
|
*,
|
|
2782
2827
|
run_id: Optional[str] = None,
|
|
2783
2828
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
2829
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
2784
2830
|
stream: Literal[False] = False,
|
|
2785
2831
|
stream_events: Optional[bool] = None,
|
|
2786
2832
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -2791,6 +2837,7 @@ class Agent:
|
|
|
2791
2837
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2792
2838
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2793
2839
|
debug_mode: Optional[bool] = None,
|
|
2840
|
+
yield_run_output: bool = False,
|
|
2794
2841
|
) -> RunOutput: ...
|
|
2795
2842
|
|
|
2796
2843
|
@overload
|
|
@@ -2800,6 +2847,7 @@ class Agent:
|
|
|
2800
2847
|
*,
|
|
2801
2848
|
run_id: Optional[str] = None,
|
|
2802
2849
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
2850
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
2803
2851
|
stream: Literal[True] = True,
|
|
2804
2852
|
stream_events: Optional[bool] = False,
|
|
2805
2853
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -2810,6 +2858,7 @@ class Agent:
|
|
|
2810
2858
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2811
2859
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2812
2860
|
debug_mode: Optional[bool] = None,
|
|
2861
|
+
yield_run_output: bool = False,
|
|
2813
2862
|
) -> Iterator[RunOutputEvent]: ...
|
|
2814
2863
|
|
|
2815
2864
|
def continue_run(
|
|
@@ -2818,6 +2867,7 @@ class Agent:
|
|
|
2818
2867
|
*,
|
|
2819
2868
|
run_id: Optional[str] = None, # type: ignore
|
|
2820
2869
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
2870
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
2821
2871
|
stream: Optional[bool] = None,
|
|
2822
2872
|
stream_events: Optional[bool] = False,
|
|
2823
2873
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -2829,14 +2879,15 @@ class Agent:
|
|
|
2829
2879
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2830
2880
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2831
2881
|
debug_mode: Optional[bool] = None,
|
|
2882
|
+
yield_run_output: bool = False,
|
|
2832
2883
|
**kwargs,
|
|
2833
|
-
) -> Union[RunOutput, Iterator[RunOutputEvent]]:
|
|
2884
|
+
) -> Union[RunOutput, Iterator[Union[RunOutputEvent, RunOutput]]]:
|
|
2834
2885
|
"""Continue a previous run.
|
|
2835
2886
|
|
|
2836
2887
|
Args:
|
|
2837
2888
|
run_response: The run response to continue.
|
|
2838
2889
|
run_id: The run id to continue. Alternative to passing run_response.
|
|
2839
|
-
|
|
2890
|
+
requirements: The requirements to continue the run. This or updated_tools is required with `run_id`.
|
|
2840
2891
|
stream: Whether to stream the response.
|
|
2841
2892
|
stream_events: Whether to stream all events.
|
|
2842
2893
|
user_id: The user id to continue the run for.
|
|
@@ -2848,6 +2899,7 @@ class Agent:
|
|
|
2848
2899
|
metadata: The metadata to use for the run.
|
|
2849
2900
|
debug_mode: Whether to enable debug mode.
|
|
2850
2901
|
(deprecated) stream_intermediate_steps: Whether to stream all steps.
|
|
2902
|
+
(deprecated) updated_tools: Use 'requirements' instead.
|
|
2851
2903
|
"""
|
|
2852
2904
|
if run_response is None and run_id is None:
|
|
2853
2905
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
@@ -2947,16 +2999,35 @@ class Agent:
|
|
|
2947
2999
|
# The run is continued from a provided run_response. This contains the updated tools.
|
|
2948
3000
|
input = run_response.messages or []
|
|
2949
3001
|
elif run_id is not None:
|
|
2950
|
-
# The run is continued from a run_id
|
|
2951
|
-
if updated_tools is None:
|
|
2952
|
-
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.")
|
|
2953
3005
|
|
|
2954
3006
|
runs = agent_session.runs
|
|
2955
3007
|
run_response = next((r for r in runs if r.run_id == run_id), None) # type: ignore
|
|
2956
3008
|
if run_response is None:
|
|
2957
3009
|
raise RuntimeError(f"No runs found for run ID {run_id}")
|
|
2958
|
-
|
|
3010
|
+
|
|
2959
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
|
|
2960
3031
|
else:
|
|
2961
3032
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
2962
3033
|
|
|
@@ -3006,6 +3077,7 @@ class Agent:
|
|
|
3006
3077
|
session=agent_session,
|
|
3007
3078
|
response_format=response_format,
|
|
3008
3079
|
stream_events=stream_events,
|
|
3080
|
+
yield_run_output=yield_run_output,
|
|
3009
3081
|
debug_mode=debug_mode,
|
|
3010
3082
|
background_tasks=background_tasks,
|
|
3011
3083
|
**kwargs,
|
|
@@ -3179,6 +3251,8 @@ class Agent:
|
|
|
3179
3251
|
|
|
3180
3252
|
return run_response
|
|
3181
3253
|
finally:
|
|
3254
|
+
# Always disconnect connectable tools
|
|
3255
|
+
self._disconnect_connectable_tools()
|
|
3182
3256
|
# Always clean up the run tracking
|
|
3183
3257
|
cleanup_run(run_response.run_id) # type: ignore
|
|
3184
3258
|
|
|
@@ -3193,9 +3267,10 @@ class Agent:
|
|
|
3193
3267
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
3194
3268
|
stream_events: bool = False,
|
|
3195
3269
|
debug_mode: Optional[bool] = None,
|
|
3270
|
+
yield_run_output: bool = False,
|
|
3196
3271
|
background_tasks: Optional[Any] = None,
|
|
3197
3272
|
**kwargs,
|
|
3198
|
-
) -> Iterator[RunOutputEvent]:
|
|
3273
|
+
) -> Iterator[Union[RunOutputEvent, RunOutput]]:
|
|
3199
3274
|
"""Continue a previous run.
|
|
3200
3275
|
|
|
3201
3276
|
Steps:
|
|
@@ -3328,6 +3403,9 @@ class Agent:
|
|
|
3328
3403
|
if stream_events:
|
|
3329
3404
|
yield completed_event # type: ignore
|
|
3330
3405
|
|
|
3406
|
+
if yield_run_output:
|
|
3407
|
+
yield run_response
|
|
3408
|
+
|
|
3331
3409
|
# Log Agent Telemetry
|
|
3332
3410
|
self._log_agent_telemetry(session_id=session.session_id, run_id=run_response.run_id)
|
|
3333
3411
|
|
|
@@ -3352,6 +3430,8 @@ class Agent:
|
|
|
3352
3430
|
run_response=run_response, session=session, run_context=run_context, user_id=user_id
|
|
3353
3431
|
)
|
|
3354
3432
|
finally:
|
|
3433
|
+
# Always disconnect connectable tools
|
|
3434
|
+
self._disconnect_connectable_tools()
|
|
3355
3435
|
# Always clean up the run tracking
|
|
3356
3436
|
cleanup_run(run_response.run_id) # type: ignore
|
|
3357
3437
|
|
|
@@ -3365,6 +3445,7 @@ class Agent:
|
|
|
3365
3445
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3366
3446
|
run_id: Optional[str] = None,
|
|
3367
3447
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3448
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3368
3449
|
user_id: Optional[str] = None,
|
|
3369
3450
|
session_id: Optional[str] = None,
|
|
3370
3451
|
retries: Optional[int] = None,
|
|
@@ -3385,6 +3466,7 @@ class Agent:
|
|
|
3385
3466
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3386
3467
|
run_id: Optional[str] = None,
|
|
3387
3468
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3469
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3388
3470
|
user_id: Optional[str] = None,
|
|
3389
3471
|
session_id: Optional[str] = None,
|
|
3390
3472
|
retries: Optional[int] = None,
|
|
@@ -3401,6 +3483,7 @@ class Agent:
|
|
|
3401
3483
|
*,
|
|
3402
3484
|
run_id: Optional[str] = None, # type: ignore
|
|
3403
3485
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3486
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3404
3487
|
stream: Optional[bool] = None,
|
|
3405
3488
|
stream_events: Optional[bool] = None,
|
|
3406
3489
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -3420,7 +3503,8 @@ class Agent:
|
|
|
3420
3503
|
Args:
|
|
3421
3504
|
run_response: The run response to continue.
|
|
3422
3505
|
run_id: The run id to continue. Alternative to passing run_response.
|
|
3423
|
-
|
|
3506
|
+
|
|
3507
|
+
requirements: The requirements to continue the run. This or updated_tools is required with `run_id`.
|
|
3424
3508
|
stream: Whether to stream the response.
|
|
3425
3509
|
stream_events: Whether to stream all events.
|
|
3426
3510
|
user_id: The user id to continue the run for.
|
|
@@ -3433,6 +3517,7 @@ class Agent:
|
|
|
3433
3517
|
debug_mode: Whether to enable debug mode.
|
|
3434
3518
|
yield_run_output: Whether to yield the run response.
|
|
3435
3519
|
(deprecated) stream_intermediate_steps: Whether to stream all steps.
|
|
3520
|
+
(deprecated) updated_tools: Use 'requirements' instead.
|
|
3436
3521
|
"""
|
|
3437
3522
|
if run_response is None and run_id is None:
|
|
3438
3523
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
@@ -3440,6 +3525,12 @@ class Agent:
|
|
|
3440
3525
|
if run_response is None and (run_id is not None and (session_id is None and self.session_id is None)):
|
|
3441
3526
|
raise ValueError("Session ID is required to continue a run from a run_id.")
|
|
3442
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
|
+
)
|
|
3443
3534
|
background_tasks = kwargs.pop("background_tasks", None)
|
|
3444
3535
|
if background_tasks is not None:
|
|
3445
3536
|
from fastapi import BackgroundTasks
|
|
@@ -3523,6 +3614,7 @@ class Agent:
|
|
|
3523
3614
|
run_response=run_response,
|
|
3524
3615
|
run_context=run_context,
|
|
3525
3616
|
updated_tools=updated_tools,
|
|
3617
|
+
requirements=requirements,
|
|
3526
3618
|
run_id=run_id,
|
|
3527
3619
|
user_id=user_id,
|
|
3528
3620
|
session_id=session_id,
|
|
@@ -3539,6 +3631,7 @@ class Agent:
|
|
|
3539
3631
|
run_response=run_response,
|
|
3540
3632
|
run_context=run_context,
|
|
3541
3633
|
updated_tools=updated_tools,
|
|
3634
|
+
requirements=requirements,
|
|
3542
3635
|
run_id=run_id,
|
|
3543
3636
|
user_id=user_id,
|
|
3544
3637
|
response_format=response_format,
|
|
@@ -3589,6 +3682,7 @@ class Agent:
|
|
|
3589
3682
|
run_context: RunContext,
|
|
3590
3683
|
run_response: Optional[RunOutput] = None,
|
|
3591
3684
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3685
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3592
3686
|
run_id: Optional[str] = None,
|
|
3593
3687
|
user_id: Optional[str] = None,
|
|
3594
3688
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
@@ -3641,15 +3735,29 @@ class Agent:
|
|
|
3641
3735
|
input = run_response.messages or []
|
|
3642
3736
|
elif run_id is not None:
|
|
3643
3737
|
# The run is continued from a run_id. This requires the updated tools to be passed.
|
|
3644
|
-
if updated_tools is None:
|
|
3645
|
-
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.")
|
|
3646
3740
|
|
|
3647
3741
|
runs = agent_session.runs
|
|
3648
3742
|
run_response = next((r for r in runs if r.run_id == run_id), None) # type: ignore
|
|
3649
3743
|
if run_response is None:
|
|
3650
3744
|
raise RuntimeError(f"No runs found for run ID {run_id}")
|
|
3651
|
-
|
|
3745
|
+
|
|
3652
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
|
|
3653
3761
|
else:
|
|
3654
3762
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
3655
3763
|
|
|
@@ -3788,6 +3896,8 @@ class Agent:
|
|
|
3788
3896
|
|
|
3789
3897
|
return run_response
|
|
3790
3898
|
finally:
|
|
3899
|
+
# Always disconnect connectable tools
|
|
3900
|
+
self._disconnect_connectable_tools()
|
|
3791
3901
|
# Always disconnect MCP tools
|
|
3792
3902
|
await self._disconnect_mcp_tools()
|
|
3793
3903
|
|
|
@@ -3800,6 +3910,7 @@ class Agent:
|
|
|
3800
3910
|
run_context: RunContext,
|
|
3801
3911
|
run_response: Optional[RunOutput] = None,
|
|
3802
3912
|
updated_tools: Optional[List[ToolExecution]] = None,
|
|
3913
|
+
requirements: Optional[List[RunRequirement]] = None,
|
|
3803
3914
|
run_id: Optional[str] = None,
|
|
3804
3915
|
user_id: Optional[str] = None,
|
|
3805
3916
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
@@ -3849,17 +3960,32 @@ class Agent:
|
|
|
3849
3960
|
if run_response is not None:
|
|
3850
3961
|
# The run is continued from a provided run_response. This contains the updated tools.
|
|
3851
3962
|
input = run_response.messages or []
|
|
3963
|
+
|
|
3852
3964
|
elif run_id is not None:
|
|
3853
|
-
# The run is continued from a run_id. This requires the updated tools to be passed.
|
|
3854
|
-
if updated_tools is None:
|
|
3855
|
-
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.")
|
|
3856
3968
|
|
|
3857
3969
|
runs = agent_session.runs
|
|
3858
3970
|
run_response = next((r for r in runs if r.run_id == run_id), None) # type: ignore
|
|
3859
3971
|
if run_response is None:
|
|
3860
3972
|
raise RuntimeError(f"No runs found for run ID {run_id}")
|
|
3861
|
-
|
|
3973
|
+
|
|
3862
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
|
|
3863
3989
|
else:
|
|
3864
3990
|
raise ValueError("Either run_response or run_id must be provided.")
|
|
3865
3991
|
|
|
@@ -4078,6 +4204,8 @@ class Agent:
|
|
|
4078
4204
|
user_id=user_id,
|
|
4079
4205
|
)
|
|
4080
4206
|
finally:
|
|
4207
|
+
# Always disconnect connectable tools
|
|
4208
|
+
self._disconnect_connectable_tools()
|
|
4081
4209
|
# Always disconnect MCP tools
|
|
4082
4210
|
await self._disconnect_mcp_tools()
|
|
4083
4211
|
|
|
@@ -4493,6 +4621,7 @@ class Agent:
|
|
|
4493
4621
|
create_run_paused_event(
|
|
4494
4622
|
from_run_response=run_response,
|
|
4495
4623
|
tools=run_response.tools,
|
|
4624
|
+
requirements=run_response.requirements,
|
|
4496
4625
|
),
|
|
4497
4626
|
run_response,
|
|
4498
4627
|
events_to_skip=self.events_to_skip, # type: ignore
|
|
@@ -4541,6 +4670,7 @@ class Agent:
|
|
|
4541
4670
|
create_run_paused_event(
|
|
4542
4671
|
from_run_response=run_response,
|
|
4543
4672
|
tools=run_response.tools,
|
|
4673
|
+
requirements=run_response.requirements,
|
|
4544
4674
|
),
|
|
4545
4675
|
run_response,
|
|
4546
4676
|
events_to_skip=self.events_to_skip, # type: ignore
|
|
@@ -5356,7 +5486,7 @@ class Agent:
|
|
|
5356
5486
|
run_response.images = []
|
|
5357
5487
|
run_response.images.append(image)
|
|
5358
5488
|
|
|
5359
|
-
# Handle tool interruption events
|
|
5489
|
+
# Handle tool interruption events (HITL flow)
|
|
5360
5490
|
elif model_response_event.event == ModelResponseEvent.tool_call_paused.value:
|
|
5361
5491
|
# Add tool calls to the run_response
|
|
5362
5492
|
tool_executions_list = model_response_event.tool_executions
|
|
@@ -5366,6 +5496,10 @@ class Agent:
|
|
|
5366
5496
|
run_response.tools = tool_executions_list
|
|
5367
5497
|
else:
|
|
5368
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]))
|
|
5369
5503
|
|
|
5370
5504
|
# If the model response is a tool_call_started, add the tool call to the run_response
|
|
5371
5505
|
elif (
|
|
@@ -5646,6 +5780,9 @@ class Agent:
|
|
|
5646
5780
|
) -> List[Union[Toolkit, Callable, Function, Dict]]:
|
|
5647
5781
|
agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
5648
5782
|
|
|
5783
|
+
# Connect tools that require connection management
|
|
5784
|
+
self._connect_connectable_tools()
|
|
5785
|
+
|
|
5649
5786
|
# Add provided tools
|
|
5650
5787
|
if self.tools is not None:
|
|
5651
5788
|
# If not running in async mode, raise if any tool is async
|
|
@@ -5692,6 +5829,7 @@ class Agent:
|
|
|
5692
5829
|
run_response=run_response,
|
|
5693
5830
|
async_mode=False,
|
|
5694
5831
|
knowledge_filters=run_context.knowledge_filters,
|
|
5832
|
+
run_context=run_context,
|
|
5695
5833
|
)
|
|
5696
5834
|
)
|
|
5697
5835
|
else:
|
|
@@ -5700,6 +5838,7 @@ class Agent:
|
|
|
5700
5838
|
run_response=run_response,
|
|
5701
5839
|
async_mode=False,
|
|
5702
5840
|
knowledge_filters=run_context.knowledge_filters,
|
|
5841
|
+
run_context=run_context,
|
|
5703
5842
|
)
|
|
5704
5843
|
)
|
|
5705
5844
|
|
|
@@ -5718,6 +5857,9 @@ class Agent:
|
|
|
5718
5857
|
) -> List[Union[Toolkit, Callable, Function, Dict]]:
|
|
5719
5858
|
agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
5720
5859
|
|
|
5860
|
+
# Connect tools that require connection management
|
|
5861
|
+
self._connect_connectable_tools()
|
|
5862
|
+
|
|
5721
5863
|
# Connect MCP tools
|
|
5722
5864
|
await self._connect_mcp_tools()
|
|
5723
5865
|
|
|
@@ -5780,6 +5922,7 @@ class Agent:
|
|
|
5780
5922
|
run_response=run_response,
|
|
5781
5923
|
async_mode=True,
|
|
5782
5924
|
knowledge_filters=run_context.knowledge_filters,
|
|
5925
|
+
run_context=run_context,
|
|
5783
5926
|
)
|
|
5784
5927
|
)
|
|
5785
5928
|
else:
|
|
@@ -5788,6 +5931,7 @@ class Agent:
|
|
|
5788
5931
|
run_response=run_response,
|
|
5789
5932
|
async_mode=True,
|
|
5790
5933
|
knowledge_filters=run_context.knowledge_filters,
|
|
5934
|
+
run_context=run_context,
|
|
5791
5935
|
)
|
|
5792
5936
|
)
|
|
5793
5937
|
|
|
@@ -6988,7 +7132,7 @@ class Agent:
|
|
|
6988
7132
|
|
|
6989
7133
|
# Should already be resolved and passed from run() method
|
|
6990
7134
|
format_variables = ChainMap(
|
|
6991
|
-
session_state
|
|
7135
|
+
session_state if session_state is not None else {},
|
|
6992
7136
|
dependencies or {},
|
|
6993
7137
|
metadata or {},
|
|
6994
7138
|
{"user_id": user_id} if user_id is not None else {},
|
|
@@ -7817,7 +7961,7 @@ class Agent:
|
|
|
7817
7961
|
retrieval_timer = Timer()
|
|
7818
7962
|
retrieval_timer.start()
|
|
7819
7963
|
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
7820
|
-
query=user_msg_content, filters=knowledge_filters, **kwargs
|
|
7964
|
+
query=user_msg_content, filters=knowledge_filters, run_context=run_context, **kwargs
|
|
7821
7965
|
)
|
|
7822
7966
|
if docs_from_knowledge is not None:
|
|
7823
7967
|
references = MessageReferences(
|
|
@@ -7991,7 +8135,7 @@ class Agent:
|
|
|
7991
8135
|
retrieval_timer = Timer()
|
|
7992
8136
|
retrieval_timer.start()
|
|
7993
8137
|
docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
|
|
7994
|
-
query=user_msg_content, filters=knowledge_filters, **kwargs
|
|
8138
|
+
query=user_msg_content, filters=knowledge_filters, run_context=run_context, **kwargs
|
|
7995
8139
|
)
|
|
7996
8140
|
if docs_from_knowledge is not None:
|
|
7997
8141
|
references = MessageReferences(
|
|
@@ -8572,6 +8716,7 @@ class Agent:
|
|
|
8572
8716
|
num_documents: Optional[int] = None,
|
|
8573
8717
|
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8574
8718
|
validate_filters: bool = False,
|
|
8719
|
+
run_context: Optional[RunContext] = None,
|
|
8575
8720
|
**kwargs,
|
|
8576
8721
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8577
8722
|
"""Get relevant docs from the knowledge base to answer a query.
|
|
@@ -8581,6 +8726,7 @@ class Agent:
|
|
|
8581
8726
|
num_documents (Optional[int]): Number of documents to return.
|
|
8582
8727
|
filters (Optional[Dict[str, Any]]): Filters to apply to the search.
|
|
8583
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.
|
|
8584
8730
|
**kwargs: Additional keyword arguments.
|
|
8585
8731
|
|
|
8586
8732
|
Returns:
|
|
@@ -8588,6 +8734,9 @@ class Agent:
|
|
|
8588
8734
|
"""
|
|
8589
8735
|
from agno.knowledge.document import Document
|
|
8590
8736
|
|
|
8737
|
+
# Extract dependencies from run_context if available
|
|
8738
|
+
dependencies = run_context.dependencies if run_context else None
|
|
8739
|
+
|
|
8591
8740
|
if num_documents is None and self.knowledge is not None:
|
|
8592
8741
|
num_documents = self.knowledge.max_results
|
|
8593
8742
|
# Validate the filters against known valid filter keys
|
|
@@ -8619,6 +8768,11 @@ class Agent:
|
|
|
8619
8768
|
knowledge_retriever_kwargs = {"agent": self}
|
|
8620
8769
|
if "filters" in sig.parameters:
|
|
8621
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
|
|
8622
8776
|
knowledge_retriever_kwargs.update({"query": query, "num_documents": num_documents, **kwargs})
|
|
8623
8777
|
return self.knowledge_retriever(**knowledge_retriever_kwargs)
|
|
8624
8778
|
except Exception as e:
|
|
@@ -8657,11 +8811,15 @@ class Agent:
|
|
|
8657
8811
|
num_documents: Optional[int] = None,
|
|
8658
8812
|
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
8659
8813
|
validate_filters: bool = False,
|
|
8814
|
+
run_context: Optional[RunContext] = None,
|
|
8660
8815
|
**kwargs,
|
|
8661
8816
|
) -> Optional[List[Union[Dict[str, Any], str]]]:
|
|
8662
8817
|
"""Get relevant documents from knowledge base asynchronously."""
|
|
8663
8818
|
from agno.knowledge.document import Document
|
|
8664
8819
|
|
|
8820
|
+
# Extract dependencies from run_context if available
|
|
8821
|
+
dependencies = run_context.dependencies if run_context else None
|
|
8822
|
+
|
|
8665
8823
|
if num_documents is None and self.knowledge is not None:
|
|
8666
8824
|
num_documents = self.knowledge.max_results
|
|
8667
8825
|
|
|
@@ -8693,6 +8851,11 @@ class Agent:
|
|
|
8693
8851
|
knowledge_retriever_kwargs = {"agent": self}
|
|
8694
8852
|
if "filters" in sig.parameters:
|
|
8695
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
|
|
8696
8859
|
knowledge_retriever_kwargs.update({"query": query, "num_documents": num_documents, **kwargs})
|
|
8697
8860
|
result = self.knowledge_retriever(**knowledge_retriever_kwargs)
|
|
8698
8861
|
|
|
@@ -10035,6 +10198,7 @@ class Agent:
|
|
|
10035
10198
|
run_response: RunOutput,
|
|
10036
10199
|
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
10037
10200
|
async_mode: bool = False,
|
|
10201
|
+
run_context: Optional[RunContext] = None,
|
|
10038
10202
|
) -> Function:
|
|
10039
10203
|
"""Factory function to create a search_knowledge_base function with filters."""
|
|
10040
10204
|
|
|
@@ -10051,7 +10215,9 @@ class Agent:
|
|
|
10051
10215
|
# Get the relevant documents from the knowledge base, passing filters
|
|
10052
10216
|
retrieval_timer = Timer()
|
|
10053
10217
|
retrieval_timer.start()
|
|
10054
|
-
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
|
+
)
|
|
10055
10221
|
if docs_from_knowledge is not None:
|
|
10056
10222
|
references = MessageReferences(
|
|
10057
10223
|
query=query,
|
|
@@ -10082,7 +10248,10 @@ class Agent:
|
|
|
10082
10248
|
"""
|
|
10083
10249
|
retrieval_timer = Timer()
|
|
10084
10250
|
retrieval_timer.start()
|
|
10085
|
-
|
|
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
|
+
)
|
|
10086
10255
|
if docs_from_knowledge is not None:
|
|
10087
10256
|
references = MessageReferences(
|
|
10088
10257
|
query=query,
|
|
@@ -10111,6 +10280,7 @@ class Agent:
|
|
|
10111
10280
|
run_response: RunOutput,
|
|
10112
10281
|
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
10113
10282
|
async_mode: bool = False,
|
|
10283
|
+
run_context: Optional[RunContext] = None,
|
|
10114
10284
|
) -> Function:
|
|
10115
10285
|
"""Factory function to create a search_knowledge_base function with filters."""
|
|
10116
10286
|
|
|
@@ -10131,7 +10301,7 @@ class Agent:
|
|
|
10131
10301
|
retrieval_timer = Timer()
|
|
10132
10302
|
retrieval_timer.start()
|
|
10133
10303
|
docs_from_knowledge = self.get_relevant_docs_from_knowledge(
|
|
10134
|
-
query=query, filters=search_filters, validate_filters=True
|
|
10304
|
+
query=query, filters=search_filters, validate_filters=True, run_context=run_context
|
|
10135
10305
|
)
|
|
10136
10306
|
if docs_from_knowledge is not None:
|
|
10137
10307
|
references = MessageReferences(
|
|
@@ -10168,7 +10338,7 @@ class Agent:
|
|
|
10168
10338
|
retrieval_timer = Timer()
|
|
10169
10339
|
retrieval_timer.start()
|
|
10170
10340
|
docs_from_knowledge = await self.aget_relevant_docs_from_knowledge(
|
|
10171
|
-
query=query, filters=search_filters, validate_filters=True
|
|
10341
|
+
query=query, filters=search_filters, validate_filters=True, run_context=run_context
|
|
10172
10342
|
)
|
|
10173
10343
|
if docs_from_knowledge is not None:
|
|
10174
10344
|
references = MessageReferences(
|