agno 2.2.1__py3-none-any.whl → 2.2.3__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 +735 -574
- agno/culture/manager.py +22 -24
- agno/db/async_postgres/__init__.py +1 -1
- agno/db/dynamo/dynamo.py +0 -2
- agno/db/firestore/firestore.py +0 -2
- agno/db/gcs_json/gcs_json_db.py +0 -4
- agno/db/gcs_json/utils.py +0 -24
- agno/db/in_memory/in_memory_db.py +0 -3
- agno/db/json/json_db.py +4 -10
- agno/db/json/utils.py +0 -24
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +1999 -0
- agno/db/mongo/mongo.py +0 -2
- agno/db/mysql/mysql.py +0 -3
- agno/db/postgres/__init__.py +1 -1
- agno/db/{async_postgres → postgres}/async_postgres.py +19 -22
- agno/db/postgres/postgres.py +7 -10
- agno/db/postgres/utils.py +106 -2
- agno/db/redis/redis.py +0 -2
- agno/db/singlestore/singlestore.py +0 -3
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2269 -0
- agno/db/sqlite/sqlite.py +0 -2
- agno/db/sqlite/utils.py +96 -0
- agno/db/surrealdb/surrealdb.py +0 -6
- agno/knowledge/knowledge.py +3 -3
- agno/knowledge/reader/reader_factory.py +16 -0
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/memory/manager.py +28 -25
- agno/models/anthropic/claude.py +63 -6
- agno/models/base.py +251 -32
- agno/models/response.py +69 -0
- agno/os/router.py +7 -5
- agno/os/routers/memory/memory.py +2 -1
- agno/os/routers/memory/schemas.py +5 -2
- agno/os/schema.py +25 -20
- agno/os/utils.py +9 -2
- agno/run/agent.py +23 -30
- agno/run/base.py +17 -1
- agno/run/team.py +23 -29
- agno/run/workflow.py +17 -12
- agno/session/agent.py +3 -0
- agno/session/summary.py +4 -1
- agno/session/team.py +1 -1
- agno/team/team.py +599 -367
- agno/tools/dalle.py +2 -4
- agno/tools/eleven_labs.py +23 -25
- agno/tools/function.py +40 -0
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +324 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/slack.py +18 -3
- agno/tools/tavily.py +146 -0
- agno/utils/agent.py +366 -1
- agno/utils/mcp.py +92 -2
- agno/utils/media.py +166 -1
- agno/utils/print_response/workflow.py +17 -1
- agno/utils/team.py +89 -1
- agno/workflow/step.py +0 -1
- agno/workflow/types.py +10 -15
- {agno-2.2.1.dist-info → agno-2.2.3.dist-info}/METADATA +28 -25
- {agno-2.2.1.dist-info → agno-2.2.3.dist-info}/RECORD +66 -62
- agno/db/async_postgres/schemas.py +0 -139
- agno/db/async_postgres/utils.py +0 -347
- agno/tools/mcp.py +0 -679
- {agno-2.2.1.dist-info → agno-2.2.3.dist-info}/WHEEL +0 -0
- {agno-2.2.1.dist-info → agno-2.2.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.1.dist-info → agno-2.2.3.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from asyncio import CancelledError, create_task
|
|
4
4
|
from collections import ChainMap, deque
|
|
5
5
|
from dataclasses import dataclass
|
|
6
|
+
from inspect import iscoroutinefunction
|
|
6
7
|
from os import getenv
|
|
7
8
|
from textwrap import dedent
|
|
8
9
|
from typing import (
|
|
@@ -65,18 +66,35 @@ from agno.run.cancel import (
|
|
|
65
66
|
from agno.run.messages import RunMessages
|
|
66
67
|
from agno.run.team import TeamRunOutputEvent
|
|
67
68
|
from agno.session import AgentSession, SessionSummaryManager, TeamSession, WorkflowSession
|
|
69
|
+
from agno.session.summary import SessionSummary
|
|
68
70
|
from agno.tools import Toolkit
|
|
69
71
|
from agno.tools.function import Function
|
|
70
72
|
from agno.utils.agent import (
|
|
73
|
+
aget_chat_history_util,
|
|
74
|
+
aget_last_run_output_util,
|
|
75
|
+
aget_run_output_util,
|
|
76
|
+
aget_session_metrics_util,
|
|
77
|
+
aget_session_name_util,
|
|
78
|
+
aget_session_state_util,
|
|
79
|
+
aset_session_name_util,
|
|
80
|
+
aupdate_session_state_util,
|
|
71
81
|
await_for_background_tasks,
|
|
72
82
|
await_for_background_tasks_stream,
|
|
73
83
|
collect_joint_audios,
|
|
74
84
|
collect_joint_files,
|
|
75
85
|
collect_joint_images,
|
|
76
86
|
collect_joint_videos,
|
|
87
|
+
get_chat_history_util,
|
|
88
|
+
get_last_run_output_util,
|
|
89
|
+
get_run_output_util,
|
|
90
|
+
get_session_metrics_util,
|
|
91
|
+
get_session_name_util,
|
|
92
|
+
get_session_state_util,
|
|
77
93
|
scrub_history_messages_from_run_output,
|
|
78
94
|
scrub_media_from_run_output,
|
|
79
95
|
scrub_tool_results_from_run_output,
|
|
96
|
+
set_session_name_util,
|
|
97
|
+
update_session_state_util,
|
|
80
98
|
wait_for_background_tasks,
|
|
81
99
|
wait_for_background_tasks_stream,
|
|
82
100
|
)
|
|
@@ -615,17 +633,16 @@ class Agent:
|
|
|
615
633
|
self.telemetry = telemetry
|
|
616
634
|
|
|
617
635
|
# If we are caching the agent session
|
|
618
|
-
self.
|
|
636
|
+
self._cached_session: Optional[AgentSession] = None
|
|
619
637
|
|
|
620
638
|
self._tool_instructions: Optional[List[str]] = None
|
|
621
|
-
self._tools_for_model: Optional[List[Dict[str, Any]]] = None
|
|
622
|
-
self._functions_for_model: Optional[Dict[str, Function]] = None
|
|
623
|
-
self._rebuild_tools: bool = True
|
|
624
639
|
|
|
625
640
|
self._formatter: Optional[SafeFormatter] = None
|
|
626
641
|
|
|
627
642
|
self._hooks_normalised = False
|
|
628
643
|
|
|
644
|
+
self._mcp_tools_initialized_on_run: List[Any] = []
|
|
645
|
+
|
|
629
646
|
# Lazy-initialized shared thread pool executor for background tasks (memory, cultural knowledge, etc.)
|
|
630
647
|
self._background_executor: Optional[Any] = None
|
|
631
648
|
|
|
@@ -642,6 +659,14 @@ class Agent:
|
|
|
642
659
|
self._background_executor = ThreadPoolExecutor(max_workers=3, thread_name_prefix="agno-bg")
|
|
643
660
|
return self._background_executor
|
|
644
661
|
|
|
662
|
+
@property
|
|
663
|
+
def should_parse_structured_output(self) -> bool:
|
|
664
|
+
return self.output_schema is not None and self.parse_response and self.parser_model is None
|
|
665
|
+
|
|
666
|
+
@property
|
|
667
|
+
def cached_session(self) -> Optional[AgentSession]:
|
|
668
|
+
return self._cached_session
|
|
669
|
+
|
|
645
670
|
def set_id(self) -> None:
|
|
646
671
|
if self.id is None:
|
|
647
672
|
self.id = generate_id_from_name(self.name)
|
|
@@ -798,19 +823,28 @@ class Agent:
|
|
|
798
823
|
if self._formatter is None:
|
|
799
824
|
self._formatter = SafeFormatter()
|
|
800
825
|
|
|
801
|
-
@property
|
|
802
|
-
def should_parse_structured_output(self) -> bool:
|
|
803
|
-
return self.output_schema is not None and self.parse_response and self.parser_model is None
|
|
804
|
-
|
|
805
826
|
def add_tool(self, tool: Union[Toolkit, Callable, Function, Dict]):
|
|
806
827
|
if not self.tools:
|
|
807
828
|
self.tools = []
|
|
808
829
|
self.tools.append(tool)
|
|
809
|
-
self._rebuild_tools = True
|
|
810
830
|
|
|
811
831
|
def set_tools(self, tools: Sequence[Union[Toolkit, Callable, Function, Dict]]):
|
|
812
832
|
self.tools = list(tools) if tools else []
|
|
813
|
-
|
|
833
|
+
|
|
834
|
+
async def _connect_mcp_tools(self) -> None:
|
|
835
|
+
"""Connect the MCP tools to the agent."""
|
|
836
|
+
if self.tools:
|
|
837
|
+
for tool in self.tools:
|
|
838
|
+
if tool.__class__.__name__ in ["MCPTools", "MultiMCPTools"] and not tool.initialized: # type: ignore
|
|
839
|
+
# Connect the MCP server
|
|
840
|
+
await tool.connect() # type: ignore
|
|
841
|
+
self._mcp_tools_initialized_on_run.append(tool)
|
|
842
|
+
|
|
843
|
+
async def _disconnect_mcp_tools(self) -> None:
|
|
844
|
+
"""Disconnect the MCP tools from the agent."""
|
|
845
|
+
for tool in self._mcp_tools_initialized_on_run:
|
|
846
|
+
await tool.close()
|
|
847
|
+
self._mcp_tools_initialized_on_run = []
|
|
814
848
|
|
|
815
849
|
def _initialize_session(
|
|
816
850
|
self,
|
|
@@ -909,15 +943,19 @@ class Agent:
|
|
|
909
943
|
deque(pre_hook_iterator, maxlen=0)
|
|
910
944
|
|
|
911
945
|
# 2. Determine tools for model
|
|
912
|
-
self.
|
|
946
|
+
processed_tools = self.get_tools(
|
|
947
|
+
run_response=run_response,
|
|
948
|
+
session=session,
|
|
949
|
+
user_id=user_id,
|
|
950
|
+
knowledge_filters=knowledge_filters,
|
|
951
|
+
)
|
|
952
|
+
_tools = self._determine_tools_for_model(
|
|
913
953
|
model=self.model,
|
|
954
|
+
processed_tools=processed_tools,
|
|
914
955
|
run_response=run_response,
|
|
915
956
|
session=session,
|
|
916
957
|
session_state=session_state,
|
|
917
958
|
dependencies=dependencies,
|
|
918
|
-
user_id=user_id,
|
|
919
|
-
async_mode=False,
|
|
920
|
-
knowledge_filters=knowledge_filters,
|
|
921
959
|
)
|
|
922
960
|
|
|
923
961
|
# 3. Prepare run messages
|
|
@@ -937,6 +975,7 @@ class Agent:
|
|
|
937
975
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
938
976
|
add_session_state_to_context=add_session_state_to_context,
|
|
939
977
|
metadata=metadata,
|
|
978
|
+
tools=_tools,
|
|
940
979
|
**kwargs,
|
|
941
980
|
)
|
|
942
981
|
if len(run_messages.messages) == 0:
|
|
@@ -978,8 +1017,7 @@ class Agent:
|
|
|
978
1017
|
self.model = cast(Model, self.model)
|
|
979
1018
|
model_response: ModelResponse = self.model.response(
|
|
980
1019
|
messages=run_messages.messages,
|
|
981
|
-
tools=
|
|
982
|
-
functions=self._functions_for_model,
|
|
1020
|
+
tools=_tools,
|
|
983
1021
|
tool_choice=self.tool_choice,
|
|
984
1022
|
tool_call_limit=self.tool_call_limit,
|
|
985
1023
|
response_format=response_format,
|
|
@@ -1128,15 +1166,19 @@ class Agent:
|
|
|
1128
1166
|
yield event
|
|
1129
1167
|
|
|
1130
1168
|
# 2. Determine tools for model
|
|
1131
|
-
self.
|
|
1169
|
+
processed_tools = self.get_tools(
|
|
1170
|
+
run_response=run_response,
|
|
1171
|
+
session=session,
|
|
1172
|
+
user_id=user_id,
|
|
1173
|
+
knowledge_filters=knowledge_filters,
|
|
1174
|
+
)
|
|
1175
|
+
_tools = self._determine_tools_for_model(
|
|
1132
1176
|
model=self.model,
|
|
1177
|
+
processed_tools=processed_tools,
|
|
1133
1178
|
run_response=run_response,
|
|
1134
1179
|
session=session,
|
|
1135
1180
|
session_state=session_state,
|
|
1136
1181
|
dependencies=dependencies,
|
|
1137
|
-
user_id=user_id,
|
|
1138
|
-
async_mode=False,
|
|
1139
|
-
knowledge_filters=knowledge_filters,
|
|
1140
1182
|
)
|
|
1141
1183
|
|
|
1142
1184
|
# 3. Prepare run messages
|
|
@@ -1156,6 +1198,7 @@ class Agent:
|
|
|
1156
1198
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
1157
1199
|
add_session_state_to_context=add_session_state_to_context,
|
|
1158
1200
|
metadata=metadata,
|
|
1201
|
+
tools=_tools,
|
|
1159
1202
|
**kwargs,
|
|
1160
1203
|
)
|
|
1161
1204
|
if len(run_messages.messages) == 0:
|
|
@@ -1210,6 +1253,7 @@ class Agent:
|
|
|
1210
1253
|
session=session,
|
|
1211
1254
|
run_response=run_response,
|
|
1212
1255
|
run_messages=run_messages,
|
|
1256
|
+
tools=_tools,
|
|
1213
1257
|
response_format=response_format,
|
|
1214
1258
|
stream_events=stream_events,
|
|
1215
1259
|
):
|
|
@@ -1225,6 +1269,7 @@ class Agent:
|
|
|
1225
1269
|
session=session,
|
|
1226
1270
|
run_response=run_response,
|
|
1227
1271
|
run_messages=run_messages,
|
|
1272
|
+
tools=_tools,
|
|
1228
1273
|
response_format=response_format,
|
|
1229
1274
|
stream_events=stream_events,
|
|
1230
1275
|
):
|
|
@@ -1359,7 +1404,10 @@ class Agent:
|
|
|
1359
1404
|
# Handle run cancellation during streaming
|
|
1360
1405
|
log_info(f"Run {run_response.run_id} was cancelled during streaming")
|
|
1361
1406
|
run_response.status = RunStatus.cancelled
|
|
1362
|
-
|
|
1407
|
+
# Don't overwrite content - preserve any partial content that was streamed
|
|
1408
|
+
# Only set content if it's empty
|
|
1409
|
+
if not run_response.content:
|
|
1410
|
+
run_response.content = str(e)
|
|
1363
1411
|
|
|
1364
1412
|
# Yield the cancellation event
|
|
1365
1413
|
yield handle_event( # type: ignore
|
|
@@ -1745,15 +1793,19 @@ class Agent:
|
|
|
1745
1793
|
|
|
1746
1794
|
# 5. Determine tools for model
|
|
1747
1795
|
self.model = cast(Model, self.model)
|
|
1748
|
-
await self.
|
|
1796
|
+
processed_tools = await self.aget_tools(
|
|
1797
|
+
run_response=run_response,
|
|
1798
|
+
session=agent_session,
|
|
1799
|
+
user_id=user_id,
|
|
1800
|
+
knowledge_filters=knowledge_filters,
|
|
1801
|
+
)
|
|
1802
|
+
_tools = self._determine_tools_for_model(
|
|
1749
1803
|
model=self.model,
|
|
1804
|
+
processed_tools=processed_tools,
|
|
1750
1805
|
run_response=run_response,
|
|
1751
1806
|
session=agent_session,
|
|
1752
1807
|
session_state=session_state,
|
|
1753
1808
|
dependencies=dependencies,
|
|
1754
|
-
user_id=user_id,
|
|
1755
|
-
async_mode=True,
|
|
1756
|
-
knowledge_filters=knowledge_filters,
|
|
1757
1809
|
)
|
|
1758
1810
|
|
|
1759
1811
|
# 6. Prepare run messages
|
|
@@ -1773,6 +1825,7 @@ class Agent:
|
|
|
1773
1825
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
1774
1826
|
add_session_state_to_context=add_session_state_to_context,
|
|
1775
1827
|
metadata=metadata,
|
|
1828
|
+
tools=_tools,
|
|
1776
1829
|
**kwargs,
|
|
1777
1830
|
)
|
|
1778
1831
|
if len(run_messages.messages) == 0:
|
|
@@ -1781,10 +1834,8 @@ class Agent:
|
|
|
1781
1834
|
# 7. Start memory creation as a background task (runs concurrently with the main execution)
|
|
1782
1835
|
memory_task = None
|
|
1783
1836
|
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
1784
|
-
import asyncio
|
|
1785
|
-
|
|
1786
1837
|
log_debug("Starting memory creation in background task.")
|
|
1787
|
-
memory_task =
|
|
1838
|
+
memory_task = create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
1788
1839
|
|
|
1789
1840
|
# Start cultural knowledge creation on a separate thread (runs concurrently with the main execution loop)
|
|
1790
1841
|
cultural_knowledge_task = None
|
|
@@ -1793,10 +1844,8 @@ class Agent:
|
|
|
1793
1844
|
and self.culture_manager is not None
|
|
1794
1845
|
and self.update_cultural_knowledge
|
|
1795
1846
|
):
|
|
1796
|
-
import asyncio
|
|
1797
|
-
|
|
1798
1847
|
log_debug("Starting cultural knowledge creation in background thread.")
|
|
1799
|
-
cultural_knowledge_task =
|
|
1848
|
+
cultural_knowledge_task = create_task(self._acreate_cultural_knowledge(run_messages=run_messages))
|
|
1800
1849
|
|
|
1801
1850
|
try:
|
|
1802
1851
|
# Check for cancellation before model call
|
|
@@ -1811,8 +1860,7 @@ class Agent:
|
|
|
1811
1860
|
# 9. Generate a response from the Model (includes running function calls)
|
|
1812
1861
|
model_response: ModelResponse = await self.model.aresponse(
|
|
1813
1862
|
messages=run_messages.messages,
|
|
1814
|
-
tools=
|
|
1815
|
-
functions=self._functions_for_model,
|
|
1863
|
+
tools=_tools,
|
|
1816
1864
|
tool_choice=self.tool_choice,
|
|
1817
1865
|
tool_call_limit=self.tool_call_limit,
|
|
1818
1866
|
response_format=response_format,
|
|
@@ -1905,23 +1953,22 @@ class Agent:
|
|
|
1905
1953
|
return run_response
|
|
1906
1954
|
|
|
1907
1955
|
finally:
|
|
1956
|
+
# Always disconnect MCP tools
|
|
1957
|
+
await self._disconnect_mcp_tools()
|
|
1958
|
+
|
|
1908
1959
|
# Cancel the memory task if it's still running
|
|
1909
1960
|
if memory_task is not None and not memory_task.done():
|
|
1910
|
-
import asyncio
|
|
1911
|
-
|
|
1912
1961
|
memory_task.cancel()
|
|
1913
1962
|
try:
|
|
1914
1963
|
await memory_task
|
|
1915
|
-
except
|
|
1964
|
+
except CancelledError:
|
|
1916
1965
|
pass
|
|
1917
1966
|
# Cancel the cultural knowledge task if it's still running
|
|
1918
1967
|
if cultural_knowledge_task is not None and not cultural_knowledge_task.done():
|
|
1919
|
-
import asyncio
|
|
1920
|
-
|
|
1921
1968
|
cultural_knowledge_task.cancel()
|
|
1922
1969
|
try:
|
|
1923
1970
|
await cultural_knowledge_task
|
|
1924
|
-
except
|
|
1971
|
+
except CancelledError:
|
|
1925
1972
|
pass
|
|
1926
1973
|
# Always clean up the run tracking
|
|
1927
1974
|
cleanup_run(run_response.run_id) # type: ignore
|
|
@@ -2011,14 +2058,18 @@ class Agent:
|
|
|
2011
2058
|
|
|
2012
2059
|
# 5. Determine tools for model
|
|
2013
2060
|
self.model = cast(Model, self.model)
|
|
2014
|
-
self.
|
|
2015
|
-
model=self.model,
|
|
2061
|
+
processed_tools = await self.aget_tools(
|
|
2016
2062
|
run_response=run_response,
|
|
2017
2063
|
session=agent_session,
|
|
2018
|
-
session_state=session_state,
|
|
2019
2064
|
user_id=user_id,
|
|
2020
|
-
async_mode=True,
|
|
2021
2065
|
knowledge_filters=knowledge_filters,
|
|
2066
|
+
)
|
|
2067
|
+
_tools = self._determine_tools_for_model(
|
|
2068
|
+
model=self.model,
|
|
2069
|
+
processed_tools=processed_tools,
|
|
2070
|
+
run_response=run_response,
|
|
2071
|
+
session=agent_session,
|
|
2072
|
+
session_state=session_state,
|
|
2022
2073
|
dependencies=dependencies,
|
|
2023
2074
|
)
|
|
2024
2075
|
|
|
@@ -2039,6 +2090,7 @@ class Agent:
|
|
|
2039
2090
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
2040
2091
|
add_session_state_to_context=add_session_state_to_context,
|
|
2041
2092
|
metadata=metadata,
|
|
2093
|
+
tools=_tools,
|
|
2042
2094
|
**kwargs,
|
|
2043
2095
|
)
|
|
2044
2096
|
if len(run_messages.messages) == 0:
|
|
@@ -2047,10 +2099,8 @@ class Agent:
|
|
|
2047
2099
|
# 7. Start memory creation as a background task (runs concurrently with the main execution)
|
|
2048
2100
|
memory_task = None
|
|
2049
2101
|
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
2050
|
-
import asyncio
|
|
2051
|
-
|
|
2052
2102
|
log_debug("Starting memory creation in background task.")
|
|
2053
|
-
memory_task =
|
|
2103
|
+
memory_task = create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
2054
2104
|
|
|
2055
2105
|
# Start cultural knowledge creation on a separate thread (runs concurrently with the main execution loop)
|
|
2056
2106
|
cultural_knowledge_task = None
|
|
@@ -2059,10 +2109,8 @@ class Agent:
|
|
|
2059
2109
|
and self.culture_manager is not None
|
|
2060
2110
|
and self.update_cultural_knowledge
|
|
2061
2111
|
):
|
|
2062
|
-
import asyncio
|
|
2063
|
-
|
|
2064
2112
|
log_debug("Starting cultural knowledge creation in background task.")
|
|
2065
|
-
cultural_knowledge_task =
|
|
2113
|
+
cultural_knowledge_task = create_task(self._acreate_cultural_knowledge(run_messages=run_messages))
|
|
2066
2114
|
|
|
2067
2115
|
# Register run for cancellation tracking
|
|
2068
2116
|
register_run(run_response.run_id) # type: ignore
|
|
@@ -2085,6 +2133,7 @@ class Agent:
|
|
|
2085
2133
|
session=agent_session,
|
|
2086
2134
|
run_response=run_response,
|
|
2087
2135
|
run_messages=run_messages,
|
|
2136
|
+
tools=_tools,
|
|
2088
2137
|
response_format=response_format,
|
|
2089
2138
|
stream_events=stream_events,
|
|
2090
2139
|
):
|
|
@@ -2100,6 +2149,7 @@ class Agent:
|
|
|
2100
2149
|
session=agent_session,
|
|
2101
2150
|
run_response=run_response,
|
|
2102
2151
|
run_messages=run_messages,
|
|
2152
|
+
tools=_tools,
|
|
2103
2153
|
response_format=response_format,
|
|
2104
2154
|
stream_events=stream_events,
|
|
2105
2155
|
):
|
|
@@ -2237,7 +2287,10 @@ class Agent:
|
|
|
2237
2287
|
# Handle run cancellation during async streaming
|
|
2238
2288
|
log_info(f"Run {run_response.run_id} was cancelled during async streaming")
|
|
2239
2289
|
run_response.status = RunStatus.cancelled
|
|
2240
|
-
|
|
2290
|
+
# Don't overwrite content - preserve any partial content that was streamed
|
|
2291
|
+
# Only set content if it's empty
|
|
2292
|
+
if not run_response.content:
|
|
2293
|
+
run_response.content = str(e)
|
|
2241
2294
|
|
|
2242
2295
|
# Yield the cancellation event
|
|
2243
2296
|
yield handle_event( # type: ignore
|
|
@@ -2250,19 +2303,22 @@ class Agent:
|
|
|
2250
2303
|
# Cleanup and store the run response and session
|
|
2251
2304
|
await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
|
|
2252
2305
|
finally:
|
|
2306
|
+
# Always disconnect MCP tools
|
|
2307
|
+
await self._disconnect_mcp_tools()
|
|
2308
|
+
|
|
2253
2309
|
# Cancel the memory task if it's still running
|
|
2254
2310
|
if memory_task is not None and not memory_task.done():
|
|
2255
2311
|
memory_task.cancel()
|
|
2256
2312
|
try:
|
|
2257
2313
|
await memory_task
|
|
2258
|
-
except
|
|
2314
|
+
except CancelledError:
|
|
2259
2315
|
pass
|
|
2260
2316
|
|
|
2261
2317
|
if cultural_knowledge_task is not None and not cultural_knowledge_task.done():
|
|
2262
2318
|
cultural_knowledge_task.cancel()
|
|
2263
2319
|
try:
|
|
2264
2320
|
await cultural_knowledge_task
|
|
2265
|
-
except
|
|
2321
|
+
except CancelledError:
|
|
2266
2322
|
pass
|
|
2267
2323
|
|
|
2268
2324
|
# Always clean up the run tracking
|
|
@@ -2704,15 +2760,19 @@ class Agent:
|
|
|
2704
2760
|
response_format = self._get_response_format()
|
|
2705
2761
|
self.model = cast(Model, self.model)
|
|
2706
2762
|
|
|
2707
|
-
self.
|
|
2763
|
+
processed_tools = self.get_tools(
|
|
2764
|
+
run_response=run_response,
|
|
2765
|
+
session=agent_session,
|
|
2766
|
+
user_id=user_id,
|
|
2767
|
+
knowledge_filters=effective_filters,
|
|
2768
|
+
)
|
|
2769
|
+
_tools = self._determine_tools_for_model(
|
|
2708
2770
|
model=self.model,
|
|
2771
|
+
processed_tools=processed_tools,
|
|
2709
2772
|
run_response=run_response,
|
|
2710
2773
|
session=agent_session,
|
|
2711
2774
|
session_state=session_state,
|
|
2712
2775
|
dependencies=run_dependencies,
|
|
2713
|
-
user_id=user_id,
|
|
2714
|
-
async_mode=False,
|
|
2715
|
-
knowledge_filters=effective_filters,
|
|
2716
2776
|
)
|
|
2717
2777
|
|
|
2718
2778
|
last_exception = None
|
|
@@ -2735,6 +2795,7 @@ class Agent:
|
|
|
2735
2795
|
response_iterator = self._continue_run_stream(
|
|
2736
2796
|
run_response=run_response,
|
|
2737
2797
|
run_messages=run_messages,
|
|
2798
|
+
tools=_tools,
|
|
2738
2799
|
user_id=user_id,
|
|
2739
2800
|
session=agent_session,
|
|
2740
2801
|
session_state=session_state,
|
|
@@ -2750,6 +2811,7 @@ class Agent:
|
|
|
2750
2811
|
response = self._continue_run(
|
|
2751
2812
|
run_response=run_response,
|
|
2752
2813
|
run_messages=run_messages,
|
|
2814
|
+
tools=_tools,
|
|
2753
2815
|
user_id=user_id,
|
|
2754
2816
|
session=agent_session,
|
|
2755
2817
|
session_state=session_state,
|
|
@@ -2802,6 +2864,7 @@ class Agent:
|
|
|
2802
2864
|
run_response: RunOutput,
|
|
2803
2865
|
run_messages: RunMessages,
|
|
2804
2866
|
session: AgentSession,
|
|
2867
|
+
tools: List[Union[Function, dict]],
|
|
2805
2868
|
session_state: Optional[Dict[str, Any]] = None,
|
|
2806
2869
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2807
2870
|
metadata: Optional[Dict[str, Any]] = None,
|
|
@@ -2828,7 +2891,7 @@ class Agent:
|
|
|
2828
2891
|
self.model = cast(Model, self.model)
|
|
2829
2892
|
|
|
2830
2893
|
# 1. Handle the updated tools
|
|
2831
|
-
self._handle_tool_call_updates(run_response=run_response, run_messages=run_messages)
|
|
2894
|
+
self._handle_tool_call_updates(run_response=run_response, run_messages=run_messages, tools=tools)
|
|
2832
2895
|
|
|
2833
2896
|
try:
|
|
2834
2897
|
# Check for cancellation before model call
|
|
@@ -2839,8 +2902,7 @@ class Agent:
|
|
|
2839
2902
|
model_response: ModelResponse = self.model.response(
|
|
2840
2903
|
messages=run_messages.messages,
|
|
2841
2904
|
response_format=response_format,
|
|
2842
|
-
tools=
|
|
2843
|
-
functions=self._functions_for_model,
|
|
2905
|
+
tools=tools,
|
|
2844
2906
|
tool_choice=self.tool_choice,
|
|
2845
2907
|
tool_call_limit=self.tool_call_limit,
|
|
2846
2908
|
)
|
|
@@ -2920,6 +2982,7 @@ class Agent:
|
|
|
2920
2982
|
run_response: RunOutput,
|
|
2921
2983
|
run_messages: RunMessages,
|
|
2922
2984
|
session: AgentSession,
|
|
2985
|
+
tools: List[Union[Function, dict]],
|
|
2923
2986
|
session_state: Optional[Dict[str, Any]] = None,
|
|
2924
2987
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2925
2988
|
user_id: Optional[str] = None,
|
|
@@ -2955,7 +3018,7 @@ class Agent:
|
|
|
2955
3018
|
|
|
2956
3019
|
# 2. Handle the updated tools
|
|
2957
3020
|
yield from self._handle_tool_call_updates_stream(
|
|
2958
|
-
run_response=run_response, run_messages=run_messages, stream_events=stream_events
|
|
3021
|
+
run_response=run_response, run_messages=run_messages, tools=tools, stream_events=stream_events
|
|
2959
3022
|
)
|
|
2960
3023
|
|
|
2961
3024
|
try:
|
|
@@ -2964,6 +3027,7 @@ class Agent:
|
|
|
2964
3027
|
session=session,
|
|
2965
3028
|
run_response=run_response,
|
|
2966
3029
|
run_messages=run_messages,
|
|
3030
|
+
tools=tools,
|
|
2967
3031
|
response_format=response_format,
|
|
2968
3032
|
stream_events=stream_events,
|
|
2969
3033
|
):
|
|
@@ -3352,15 +3416,19 @@ class Agent:
|
|
|
3352
3416
|
|
|
3353
3417
|
# 5. Determine tools for model
|
|
3354
3418
|
self.model = cast(Model, self.model)
|
|
3355
|
-
await self.
|
|
3419
|
+
processed_tools = await self.aget_tools(
|
|
3420
|
+
run_response=run_response,
|
|
3421
|
+
session=agent_session,
|
|
3422
|
+
user_id=user_id,
|
|
3423
|
+
knowledge_filters=knowledge_filters,
|
|
3424
|
+
)
|
|
3425
|
+
_tools = self._determine_tools_for_model(
|
|
3356
3426
|
model=self.model,
|
|
3427
|
+
processed_tools=processed_tools,
|
|
3357
3428
|
run_response=run_response,
|
|
3358
3429
|
session=agent_session,
|
|
3359
3430
|
session_state=session_state,
|
|
3360
3431
|
dependencies=dependencies,
|
|
3361
|
-
user_id=user_id,
|
|
3362
|
-
async_mode=True,
|
|
3363
|
-
knowledge_filters=knowledge_filters,
|
|
3364
3432
|
)
|
|
3365
3433
|
|
|
3366
3434
|
# 6. Prepare run messages
|
|
@@ -3373,14 +3441,13 @@ class Agent:
|
|
|
3373
3441
|
|
|
3374
3442
|
try:
|
|
3375
3443
|
# 7. Handle the updated tools
|
|
3376
|
-
await self._ahandle_tool_call_updates(run_response=run_response, run_messages=run_messages)
|
|
3444
|
+
await self._ahandle_tool_call_updates(run_response=run_response, run_messages=run_messages, tools=_tools)
|
|
3377
3445
|
|
|
3378
3446
|
# 8. Get model response
|
|
3379
3447
|
model_response: ModelResponse = await self.model.aresponse(
|
|
3380
3448
|
messages=run_messages.messages,
|
|
3381
3449
|
response_format=response_format,
|
|
3382
|
-
tools=
|
|
3383
|
-
functions=self._functions_for_model,
|
|
3450
|
+
tools=_tools,
|
|
3384
3451
|
tool_choice=self.tool_choice,
|
|
3385
3452
|
tool_call_limit=self.tool_call_limit,
|
|
3386
3453
|
)
|
|
@@ -3467,6 +3534,9 @@ class Agent:
|
|
|
3467
3534
|
|
|
3468
3535
|
return run_response
|
|
3469
3536
|
finally:
|
|
3537
|
+
# Always disconnect MCP tools
|
|
3538
|
+
await self._disconnect_mcp_tools()
|
|
3539
|
+
|
|
3470
3540
|
# Always clean up the run tracking
|
|
3471
3541
|
cleanup_run(run_response.run_id) # type: ignore
|
|
3472
3542
|
|
|
@@ -3508,7 +3578,7 @@ class Agent:
|
|
|
3508
3578
|
await self._aresolve_run_dependencies(dependencies=dependencies)
|
|
3509
3579
|
|
|
3510
3580
|
# 2. Read existing session from db
|
|
3511
|
-
agent_session = self.
|
|
3581
|
+
agent_session = await self._aread_or_create_session(session_id=session_id, user_id=user_id)
|
|
3512
3582
|
|
|
3513
3583
|
# 3. Update session state and metadata
|
|
3514
3584
|
self._update_metadata(session=agent_session)
|
|
@@ -3543,15 +3613,19 @@ class Agent:
|
|
|
3543
3613
|
|
|
3544
3614
|
# 5. Determine tools for model
|
|
3545
3615
|
self.model = cast(Model, self.model)
|
|
3546
|
-
await self.
|
|
3616
|
+
processed_tools = await self.aget_tools(
|
|
3617
|
+
run_response=run_response,
|
|
3618
|
+
session=agent_session,
|
|
3619
|
+
user_id=user_id,
|
|
3620
|
+
knowledge_filters=knowledge_filters,
|
|
3621
|
+
)
|
|
3622
|
+
_tools = self._determine_tools_for_model(
|
|
3547
3623
|
model=self.model,
|
|
3624
|
+
processed_tools=processed_tools,
|
|
3548
3625
|
run_response=run_response,
|
|
3549
3626
|
session=agent_session,
|
|
3550
3627
|
session_state=session_state,
|
|
3551
3628
|
dependencies=dependencies,
|
|
3552
|
-
user_id=user_id,
|
|
3553
|
-
async_mode=True,
|
|
3554
|
-
knowledge_filters=knowledge_filters,
|
|
3555
3629
|
)
|
|
3556
3630
|
|
|
3557
3631
|
# 6. Prepare run messages
|
|
@@ -3574,7 +3648,7 @@ class Agent:
|
|
|
3574
3648
|
|
|
3575
3649
|
# 7. Handle the updated tools
|
|
3576
3650
|
async for event in self._ahandle_tool_call_updates_stream(
|
|
3577
|
-
run_response=run_response, run_messages=run_messages
|
|
3651
|
+
run_response=run_response, run_messages=run_messages, tools=_tools, stream_events=stream_events
|
|
3578
3652
|
):
|
|
3579
3653
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
3580
3654
|
yield event
|
|
@@ -3585,6 +3659,7 @@ class Agent:
|
|
|
3585
3659
|
session=agent_session,
|
|
3586
3660
|
run_response=run_response,
|
|
3587
3661
|
run_messages=run_messages,
|
|
3662
|
+
tools=_tools,
|
|
3588
3663
|
response_format=response_format,
|
|
3589
3664
|
stream_events=stream_events,
|
|
3590
3665
|
):
|
|
@@ -3600,6 +3675,7 @@ class Agent:
|
|
|
3600
3675
|
session=agent_session,
|
|
3601
3676
|
run_response=run_response,
|
|
3602
3677
|
run_messages=run_messages,
|
|
3678
|
+
tools=_tools,
|
|
3603
3679
|
response_format=response_format,
|
|
3604
3680
|
stream_events=stream_events,
|
|
3605
3681
|
):
|
|
@@ -3733,6 +3809,9 @@ class Agent:
|
|
|
3733
3809
|
# Cleanup and store the run response and session
|
|
3734
3810
|
await self._acleanup_and_store(run_response=run_response, session=agent_session, user_id=user_id)
|
|
3735
3811
|
finally:
|
|
3812
|
+
# Always disconnect MCP tools
|
|
3813
|
+
await self._disconnect_mcp_tools()
|
|
3814
|
+
|
|
3736
3815
|
# Always clean up the run tracking
|
|
3737
3816
|
cleanup_run(run_response.run_id) # type: ignore
|
|
3738
3817
|
|
|
@@ -3851,7 +3930,7 @@ class Agent:
|
|
|
3851
3930
|
# Filter arguments to only include those that the hook accepts
|
|
3852
3931
|
filtered_args = filter_hook_args(hook, all_args)
|
|
3853
3932
|
|
|
3854
|
-
if
|
|
3933
|
+
if iscoroutinefunction(hook):
|
|
3855
3934
|
await hook(**filtered_args)
|
|
3856
3935
|
else:
|
|
3857
3936
|
# Synchronous function
|
|
@@ -3985,8 +4064,9 @@ class Agent:
|
|
|
3985
4064
|
try:
|
|
3986
4065
|
# Filter arguments to only include those that the hook accepts
|
|
3987
4066
|
filtered_args = filter_hook_args(hook, all_args)
|
|
4067
|
+
from inspect import iscoroutinefunction
|
|
3988
4068
|
|
|
3989
|
-
if
|
|
4069
|
+
if iscoroutinefunction(hook):
|
|
3990
4070
|
await hook(**filtered_args)
|
|
3991
4071
|
else:
|
|
3992
4072
|
hook(**filtered_args)
|
|
@@ -4183,11 +4263,12 @@ class Agent:
|
|
|
4183
4263
|
run_response: RunOutput,
|
|
4184
4264
|
run_messages: RunMessages,
|
|
4185
4265
|
tool: ToolExecution,
|
|
4266
|
+
functions: Optional[Dict[str, Function]] = None,
|
|
4186
4267
|
stream_events: bool = False,
|
|
4187
4268
|
) -> Iterator[RunOutputEvent]:
|
|
4188
4269
|
self.model = cast(Model, self.model)
|
|
4189
4270
|
# Execute the tool
|
|
4190
|
-
function_call = self.model.get_function_call_to_run_from_tool_execution(tool,
|
|
4271
|
+
function_call = self.model.get_function_call_to_run_from_tool_execution(tool, functions)
|
|
4191
4272
|
function_call_results: List[Message] = []
|
|
4192
4273
|
|
|
4193
4274
|
for call_result in self.model.run_function_call(
|
|
@@ -4221,9 +4302,11 @@ class Agent:
|
|
|
4221
4302
|
if len(function_call_results) > 0:
|
|
4222
4303
|
run_messages.messages.extend(function_call_results)
|
|
4223
4304
|
|
|
4224
|
-
def _reject_tool_call(
|
|
4305
|
+
def _reject_tool_call(
|
|
4306
|
+
self, run_messages: RunMessages, tool: ToolExecution, functions: Optional[Dict[str, Function]] = None
|
|
4307
|
+
):
|
|
4225
4308
|
self.model = cast(Model, self.model)
|
|
4226
|
-
function_call = self.model.get_function_call_to_run_from_tool_execution(tool,
|
|
4309
|
+
function_call = self.model.get_function_call_to_run_from_tool_execution(tool, functions)
|
|
4227
4310
|
function_call.error = tool.confirmation_note or "Function call was rejected by the user"
|
|
4228
4311
|
function_call_result = self.model.create_function_call_result(
|
|
4229
4312
|
function_call=function_call,
|
|
@@ -4236,12 +4319,13 @@ class Agent:
|
|
|
4236
4319
|
run_response: RunOutput,
|
|
4237
4320
|
run_messages: RunMessages,
|
|
4238
4321
|
tool: ToolExecution,
|
|
4322
|
+
functions: Optional[Dict[str, Function]] = None,
|
|
4239
4323
|
stream_events: bool = False,
|
|
4240
4324
|
) -> AsyncIterator[RunOutputEvent]:
|
|
4241
4325
|
self.model = cast(Model, self.model)
|
|
4242
4326
|
|
|
4243
4327
|
# Execute the tool
|
|
4244
|
-
function_call = self.model.get_function_call_to_run_from_tool_execution(tool,
|
|
4328
|
+
function_call = self.model.get_function_call_to_run_from_tool_execution(tool, functions)
|
|
4245
4329
|
function_call_results: List[Message] = []
|
|
4246
4330
|
|
|
4247
4331
|
async for call_result in self.model.arun_function_calls(
|
|
@@ -4274,17 +4358,21 @@ class Agent:
|
|
|
4274
4358
|
if len(function_call_results) > 0:
|
|
4275
4359
|
run_messages.messages.extend(function_call_results)
|
|
4276
4360
|
|
|
4277
|
-
def _handle_tool_call_updates(
|
|
4361
|
+
def _handle_tool_call_updates(
|
|
4362
|
+
self, run_response: RunOutput, run_messages: RunMessages, tools: List[Union[Function, dict]]
|
|
4363
|
+
):
|
|
4278
4364
|
self.model = cast(Model, self.model)
|
|
4365
|
+
_functions = {tool.name: tool for tool in tools if isinstance(tool, Function)}
|
|
4366
|
+
|
|
4279
4367
|
for _t in run_response.tools or []:
|
|
4280
4368
|
# Case 1: Handle confirmed tools and execute them
|
|
4281
|
-
if _t.requires_confirmation is not None and _t.requires_confirmation is True and
|
|
4369
|
+
if _t.requires_confirmation is not None and _t.requires_confirmation is True and _functions:
|
|
4282
4370
|
# Tool is confirmed and hasn't been run before
|
|
4283
4371
|
if _t.confirmed is not None and _t.confirmed is True and _t.result is None:
|
|
4284
4372
|
# Consume the generator without yielding
|
|
4285
|
-
deque(self._run_tool(run_response, run_messages, _t), maxlen=0)
|
|
4373
|
+
deque(self._run_tool(run_response, run_messages, _t, functions=_functions), maxlen=0)
|
|
4286
4374
|
else:
|
|
4287
|
-
self._reject_tool_call(run_messages, _t)
|
|
4375
|
+
self._reject_tool_call(run_messages, _t, functions=_functions)
|
|
4288
4376
|
_t.confirmed = False
|
|
4289
4377
|
_t.confirmation_note = _t.confirmation_note or "Tool call was rejected"
|
|
4290
4378
|
_t.tool_call_error = True
|
|
@@ -4309,20 +4397,28 @@ class Agent:
|
|
|
4309
4397
|
_t.requires_user_input = False
|
|
4310
4398
|
_t.answered = True
|
|
4311
4399
|
# Consume the generator without yielding
|
|
4312
|
-
deque(self._run_tool(run_response, run_messages, _t), maxlen=0)
|
|
4400
|
+
deque(self._run_tool(run_response, run_messages, _t, functions=_functions), maxlen=0)
|
|
4313
4401
|
|
|
4314
4402
|
def _handle_tool_call_updates_stream(
|
|
4315
|
-
self,
|
|
4403
|
+
self,
|
|
4404
|
+
run_response: RunOutput,
|
|
4405
|
+
run_messages: RunMessages,
|
|
4406
|
+
tools: List[Union[Function, dict]],
|
|
4407
|
+
stream_events: bool = False,
|
|
4316
4408
|
) -> Iterator[RunOutputEvent]:
|
|
4317
4409
|
self.model = cast(Model, self.model)
|
|
4410
|
+
_functions = {tool.name: tool for tool in tools if isinstance(tool, Function)}
|
|
4411
|
+
|
|
4318
4412
|
for _t in run_response.tools or []:
|
|
4319
4413
|
# Case 1: Handle confirmed tools and execute them
|
|
4320
|
-
if _t.requires_confirmation is not None and _t.requires_confirmation is True and
|
|
4414
|
+
if _t.requires_confirmation is not None and _t.requires_confirmation is True and _functions:
|
|
4321
4415
|
# Tool is confirmed and hasn't been run before
|
|
4322
4416
|
if _t.confirmed is not None and _t.confirmed is True and _t.result is None:
|
|
4323
|
-
yield from self._run_tool(
|
|
4417
|
+
yield from self._run_tool(
|
|
4418
|
+
run_response, run_messages, _t, functions=_functions, stream_events=stream_events
|
|
4419
|
+
)
|
|
4324
4420
|
else:
|
|
4325
|
-
self._reject_tool_call(run_messages, _t)
|
|
4421
|
+
self._reject_tool_call(run_messages, _t, functions=_functions)
|
|
4326
4422
|
_t.confirmed = False
|
|
4327
4423
|
_t.confirmation_note = _t.confirmation_note or "Tool call was rejected"
|
|
4328
4424
|
_t.tool_call_error = True
|
|
@@ -4345,21 +4441,27 @@ class Agent:
|
|
|
4345
4441
|
# Case 4: Handle user input required tools
|
|
4346
4442
|
elif _t.requires_user_input is not None and _t.requires_user_input is True:
|
|
4347
4443
|
self._handle_user_input_update(tool=_t)
|
|
4348
|
-
yield from self._run_tool(
|
|
4444
|
+
yield from self._run_tool(
|
|
4445
|
+
run_response, run_messages, _t, functions=_functions, stream_events=stream_events
|
|
4446
|
+
)
|
|
4349
4447
|
_t.requires_user_input = False
|
|
4350
4448
|
_t.answered = True
|
|
4351
4449
|
|
|
4352
|
-
async def _ahandle_tool_call_updates(
|
|
4450
|
+
async def _ahandle_tool_call_updates(
|
|
4451
|
+
self, run_response: RunOutput, run_messages: RunMessages, tools: List[Union[Function, dict]]
|
|
4452
|
+
):
|
|
4353
4453
|
self.model = cast(Model, self.model)
|
|
4454
|
+
_functions = {tool.name: tool for tool in tools if isinstance(tool, Function)}
|
|
4455
|
+
|
|
4354
4456
|
for _t in run_response.tools or []:
|
|
4355
4457
|
# Case 1: Handle confirmed tools and execute them
|
|
4356
|
-
if _t.requires_confirmation is not None and _t.requires_confirmation is True and
|
|
4458
|
+
if _t.requires_confirmation is not None and _t.requires_confirmation is True and _functions:
|
|
4357
4459
|
# Tool is confirmed and hasn't been run before
|
|
4358
4460
|
if _t.confirmed is not None and _t.confirmed is True and _t.result is None:
|
|
4359
|
-
async for _ in self._arun_tool(run_response, run_messages, _t):
|
|
4461
|
+
async for _ in self._arun_tool(run_response, run_messages, _t, functions=_functions):
|
|
4360
4462
|
pass
|
|
4361
4463
|
else:
|
|
4362
|
-
self._reject_tool_call(run_messages, _t)
|
|
4464
|
+
self._reject_tool_call(run_messages, _t, functions=_functions)
|
|
4363
4465
|
_t.confirmed = False
|
|
4364
4466
|
_t.confirmation_note = _t.confirmation_note or "Tool call was rejected"
|
|
4365
4467
|
_t.tool_call_error = True
|
|
@@ -4380,24 +4482,32 @@ class Agent:
|
|
|
4380
4482
|
# Case 4: Handle user input required tools
|
|
4381
4483
|
elif _t.requires_user_input is not None and _t.requires_user_input is True:
|
|
4382
4484
|
self._handle_user_input_update(tool=_t)
|
|
4383
|
-
async for _ in self._arun_tool(run_response, run_messages, _t):
|
|
4485
|
+
async for _ in self._arun_tool(run_response, run_messages, _t, functions=_functions):
|
|
4384
4486
|
pass
|
|
4385
4487
|
_t.requires_user_input = False
|
|
4386
4488
|
_t.answered = True
|
|
4387
4489
|
|
|
4388
4490
|
async def _ahandle_tool_call_updates_stream(
|
|
4389
|
-
self,
|
|
4491
|
+
self,
|
|
4492
|
+
run_response: RunOutput,
|
|
4493
|
+
run_messages: RunMessages,
|
|
4494
|
+
tools: List[Union[Function, dict]],
|
|
4495
|
+
stream_events: bool = False,
|
|
4390
4496
|
) -> AsyncIterator[RunOutputEvent]:
|
|
4391
4497
|
self.model = cast(Model, self.model)
|
|
4498
|
+
_functions = {tool.name: tool for tool in tools if isinstance(tool, Function)}
|
|
4499
|
+
|
|
4392
4500
|
for _t in run_response.tools or []:
|
|
4393
4501
|
# Case 1: Handle confirmed tools and execute them
|
|
4394
|
-
if _t.requires_confirmation is not None and _t.requires_confirmation is True and
|
|
4502
|
+
if _t.requires_confirmation is not None and _t.requires_confirmation is True and _functions:
|
|
4395
4503
|
# Tool is confirmed and hasn't been run before
|
|
4396
4504
|
if _t.confirmed is not None and _t.confirmed is True and _t.result is None:
|
|
4397
|
-
async for event in self._arun_tool(
|
|
4505
|
+
async for event in self._arun_tool(
|
|
4506
|
+
run_response, run_messages, _t, functions=_functions, stream_events=stream_events
|
|
4507
|
+
):
|
|
4398
4508
|
yield event
|
|
4399
4509
|
else:
|
|
4400
|
-
self._reject_tool_call(run_messages, _t)
|
|
4510
|
+
self._reject_tool_call(run_messages, _t, functions=_functions)
|
|
4401
4511
|
_t.confirmed = False
|
|
4402
4512
|
_t.confirmation_note = _t.confirmation_note or "Tool call was rejected"
|
|
4403
4513
|
_t.tool_call_error = True
|
|
@@ -4418,7 +4528,9 @@ class Agent:
|
|
|
4418
4528
|
# # Case 4: Handle user input required tools
|
|
4419
4529
|
elif _t.requires_user_input is not None and _t.requires_user_input is True:
|
|
4420
4530
|
self._handle_user_input_update(tool=_t)
|
|
4421
|
-
async for event in self._arun_tool(
|
|
4531
|
+
async for event in self._arun_tool(
|
|
4532
|
+
run_response, run_messages, _t, functions=_functions, stream_events=stream_events
|
|
4533
|
+
):
|
|
4422
4534
|
yield event
|
|
4423
4535
|
_t.requires_user_input = False
|
|
4424
4536
|
_t.answered = True
|
|
@@ -4524,6 +4636,7 @@ class Agent:
|
|
|
4524
4636
|
session: AgentSession,
|
|
4525
4637
|
run_response: RunOutput,
|
|
4526
4638
|
run_messages: RunMessages,
|
|
4639
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
4527
4640
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
4528
4641
|
stream_events: bool = False,
|
|
4529
4642
|
) -> Iterator[RunOutputEvent]:
|
|
@@ -4543,8 +4656,7 @@ class Agent:
|
|
|
4543
4656
|
for model_response_event in self.model.response_stream(
|
|
4544
4657
|
messages=run_messages.messages,
|
|
4545
4658
|
response_format=response_format,
|
|
4546
|
-
tools=
|
|
4547
|
-
functions=self._functions_for_model,
|
|
4659
|
+
tools=tools,
|
|
4548
4660
|
tool_choice=self.tool_choice,
|
|
4549
4661
|
tool_call_limit=self.tool_call_limit,
|
|
4550
4662
|
stream_model_response=stream_model_response,
|
|
@@ -4602,6 +4714,7 @@ class Agent:
|
|
|
4602
4714
|
session: AgentSession,
|
|
4603
4715
|
run_response: RunOutput,
|
|
4604
4716
|
run_messages: RunMessages,
|
|
4717
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
4605
4718
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
4606
4719
|
stream_events: bool = False,
|
|
4607
4720
|
) -> AsyncIterator[RunOutputEvent]:
|
|
@@ -4621,8 +4734,7 @@ class Agent:
|
|
|
4621
4734
|
model_response_stream = self.model.aresponse_stream(
|
|
4622
4735
|
messages=run_messages.messages,
|
|
4623
4736
|
response_format=response_format,
|
|
4624
|
-
tools=
|
|
4625
|
-
functions=self._functions_for_model,
|
|
4737
|
+
tools=tools,
|
|
4626
4738
|
tool_choice=self.tool_choice,
|
|
4627
4739
|
tool_call_limit=self.tool_call_limit,
|
|
4628
4740
|
stream_model_response=stream_model_response,
|
|
@@ -5128,69 +5240,34 @@ class Agent:
|
|
|
5128
5240
|
self,
|
|
5129
5241
|
run_response: RunOutput,
|
|
5130
5242
|
session: AgentSession,
|
|
5131
|
-
async_mode: bool = False,
|
|
5132
5243
|
user_id: Optional[str] = None,
|
|
5133
5244
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
5134
|
-
) ->
|
|
5245
|
+
) -> List[Union[Toolkit, Callable, Function, Dict]]:
|
|
5135
5246
|
agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
5136
5247
|
|
|
5137
5248
|
# Add provided tools
|
|
5138
5249
|
if self.tools is not None:
|
|
5139
5250
|
# If not running in async mode, raise if any tool is async
|
|
5140
|
-
|
|
5141
|
-
self._raise_if_async_tools()
|
|
5251
|
+
self._raise_if_async_tools()
|
|
5142
5252
|
agent_tools.extend(self.tools)
|
|
5143
5253
|
|
|
5144
|
-
# If any of the tools has "agent" as parameter, set _rebuild_tools to True
|
|
5145
|
-
for tool in agent_tools:
|
|
5146
|
-
param_names = {
|
|
5147
|
-
"agent",
|
|
5148
|
-
"session_state",
|
|
5149
|
-
"team",
|
|
5150
|
-
"images",
|
|
5151
|
-
"videos",
|
|
5152
|
-
"audios",
|
|
5153
|
-
"files",
|
|
5154
|
-
}
|
|
5155
|
-
|
|
5156
|
-
if isinstance(tool, Function):
|
|
5157
|
-
if param_names & set(tool.parameters):
|
|
5158
|
-
self._rebuild_tools = True
|
|
5159
|
-
break
|
|
5160
|
-
elif isinstance(tool, Toolkit):
|
|
5161
|
-
for func in tool.functions.values():
|
|
5162
|
-
if param_names & set(func.parameters):
|
|
5163
|
-
self._rebuild_tools = True
|
|
5164
|
-
break
|
|
5165
|
-
elif callable(tool):
|
|
5166
|
-
from inspect import signature
|
|
5167
|
-
|
|
5168
|
-
if param_names & set(signature(tool).parameters):
|
|
5169
|
-
self._rebuild_tools = True
|
|
5170
|
-
break
|
|
5171
|
-
|
|
5172
5254
|
# Add tools for accessing memory
|
|
5173
5255
|
if self.read_chat_history:
|
|
5174
5256
|
agent_tools.append(self._get_chat_history_function(session=session))
|
|
5175
|
-
self._rebuild_tools = True
|
|
5176
5257
|
if self.read_tool_call_history:
|
|
5177
5258
|
agent_tools.append(self._get_tool_call_history_function(session=session))
|
|
5178
|
-
self._rebuild_tools = True
|
|
5179
5259
|
if self.search_session_history:
|
|
5180
5260
|
agent_tools.append(
|
|
5181
5261
|
self._get_previous_sessions_messages_function(
|
|
5182
5262
|
num_history_sessions=self.num_history_sessions, user_id=user_id
|
|
5183
5263
|
)
|
|
5184
5264
|
)
|
|
5185
|
-
self._rebuild_tools = True
|
|
5186
5265
|
|
|
5187
5266
|
if self.enable_agentic_memory:
|
|
5188
|
-
agent_tools.append(self._get_update_user_memory_function(user_id=user_id, async_mode=
|
|
5189
|
-
self._rebuild_tools = True
|
|
5267
|
+
agent_tools.append(self._get_update_user_memory_function(user_id=user_id, async_mode=False))
|
|
5190
5268
|
|
|
5191
5269
|
if self.enable_agentic_culture:
|
|
5192
|
-
agent_tools.append(self._get_update_cultural_knowledge_function(async_mode=
|
|
5193
|
-
self._rebuild_tools = True
|
|
5270
|
+
agent_tools.append(self._get_update_cultural_knowledge_function(async_mode=False))
|
|
5194
5271
|
|
|
5195
5272
|
if self.enable_agentic_state:
|
|
5196
5273
|
agent_tools.append(Function(name="update_session_state", entrypoint=self._update_session_state_tool))
|
|
@@ -5200,7 +5277,7 @@ class Agent:
|
|
|
5200
5277
|
# Check if knowledge retriever is an async function but used in sync mode
|
|
5201
5278
|
from inspect import iscoroutinefunction
|
|
5202
5279
|
|
|
5203
|
-
if
|
|
5280
|
+
if self.knowledge_retriever and iscoroutinefunction(self.knowledge_retriever):
|
|
5204
5281
|
log_warning(
|
|
5205
5282
|
"Async knowledge retriever function is being used with synchronous agent.run() or agent.print_response(). "
|
|
5206
5283
|
"It is recommended to use agent.arun() or agent.aprint_response() instead."
|
|
@@ -5212,7 +5289,7 @@ class Agent:
|
|
|
5212
5289
|
agent_tools.append(
|
|
5213
5290
|
self._search_knowledge_base_with_agentic_filters_function(
|
|
5214
5291
|
run_response=run_response,
|
|
5215
|
-
async_mode=
|
|
5292
|
+
async_mode=False,
|
|
5216
5293
|
knowledge_filters=knowledge_filters,
|
|
5217
5294
|
)
|
|
5218
5295
|
)
|
|
@@ -5220,11 +5297,10 @@ class Agent:
|
|
|
5220
5297
|
agent_tools.append(
|
|
5221
5298
|
self._get_search_knowledge_base_function(
|
|
5222
5299
|
run_response=run_response,
|
|
5223
|
-
async_mode=
|
|
5300
|
+
async_mode=False,
|
|
5224
5301
|
knowledge_filters=knowledge_filters,
|
|
5225
5302
|
)
|
|
5226
5303
|
)
|
|
5227
|
-
self._rebuild_tools = True
|
|
5228
5304
|
|
|
5229
5305
|
if self.update_knowledge:
|
|
5230
5306
|
agent_tools.append(self.add_to_knowledge)
|
|
@@ -5235,82 +5311,69 @@ class Agent:
|
|
|
5235
5311
|
self,
|
|
5236
5312
|
run_response: RunOutput,
|
|
5237
5313
|
session: AgentSession,
|
|
5238
|
-
async_mode: bool = False,
|
|
5239
5314
|
user_id: Optional[str] = None,
|
|
5240
5315
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
5241
|
-
|
|
5316
|
+
check_mcp_tools: bool = True,
|
|
5317
|
+
) -> List[Union[Toolkit, Callable, Function, Dict]]:
|
|
5242
5318
|
agent_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
5243
5319
|
|
|
5320
|
+
# Connect MCP tools
|
|
5321
|
+
await self._connect_mcp_tools()
|
|
5322
|
+
|
|
5244
5323
|
# Add provided tools
|
|
5245
5324
|
if self.tools is not None:
|
|
5246
|
-
|
|
5325
|
+
for tool in self.tools:
|
|
5326
|
+
if tool.__class__.__name__ in ["MCPTools", "MultiMCPTools"]:
|
|
5327
|
+
if tool.refresh_connection: # type: ignore
|
|
5328
|
+
try:
|
|
5329
|
+
is_alive = await tool.is_alive() # type: ignore
|
|
5330
|
+
if not is_alive:
|
|
5331
|
+
await tool.connect(force=True) # type: ignore
|
|
5332
|
+
except (RuntimeError, BaseException) as e:
|
|
5333
|
+
log_warning(f"Failed to check if MCP tool is alive or to connect to it: {e}")
|
|
5334
|
+
continue
|
|
5247
5335
|
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
if
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
break
|
|
5262
|
-
if "team" in func.parameters:
|
|
5263
|
-
self._rebuild_tools = True
|
|
5264
|
-
break
|
|
5265
|
-
if callable(tool):
|
|
5266
|
-
from inspect import signature
|
|
5267
|
-
|
|
5268
|
-
sig = signature(tool)
|
|
5269
|
-
if "agent" in sig.parameters:
|
|
5270
|
-
self._rebuild_tools = True
|
|
5271
|
-
break
|
|
5272
|
-
if "team" in sig.parameters:
|
|
5273
|
-
self._rebuild_tools = True
|
|
5274
|
-
break
|
|
5336
|
+
try:
|
|
5337
|
+
await tool.build_tools() # type: ignore
|
|
5338
|
+
except (RuntimeError, BaseException) as e:
|
|
5339
|
+
log_warning(f"Failed to build tools for {str(tool)}: {e}")
|
|
5340
|
+
continue
|
|
5341
|
+
|
|
5342
|
+
# Only add the tool if it successfully connected and built its tools
|
|
5343
|
+
if check_mcp_tools and not tool.initialized: # type: ignore
|
|
5344
|
+
continue
|
|
5345
|
+
|
|
5346
|
+
agent_tools.append(tool)
|
|
5347
|
+
else:
|
|
5348
|
+
agent_tools.append(tool)
|
|
5275
5349
|
|
|
5276
5350
|
# Add tools for accessing memory
|
|
5277
5351
|
if self.read_chat_history:
|
|
5278
5352
|
agent_tools.append(self._get_chat_history_function(session=session))
|
|
5279
|
-
self._rebuild_tools = True
|
|
5280
5353
|
if self.read_tool_call_history:
|
|
5281
5354
|
agent_tools.append(self._get_tool_call_history_function(session=session))
|
|
5282
|
-
self._rebuild_tools = True
|
|
5283
5355
|
if self.search_session_history:
|
|
5284
5356
|
agent_tools.append(
|
|
5285
|
-
await self._aget_previous_sessions_messages_function(
|
|
5357
|
+
await self._aget_previous_sessions_messages_function(
|
|
5358
|
+
num_history_sessions=self.num_history_sessions, user_id=user_id
|
|
5359
|
+
)
|
|
5286
5360
|
)
|
|
5287
|
-
self._rebuild_tools = True
|
|
5288
5361
|
|
|
5289
5362
|
if self.enable_agentic_memory:
|
|
5290
|
-
agent_tools.append(self._get_update_user_memory_function(user_id=user_id, async_mode=
|
|
5291
|
-
self._rebuild_tools = True
|
|
5363
|
+
agent_tools.append(self._get_update_user_memory_function(user_id=user_id, async_mode=True))
|
|
5292
5364
|
|
|
5293
5365
|
if self.enable_agentic_state:
|
|
5294
5366
|
agent_tools.append(Function(name="update_session_state", entrypoint=self._update_session_state_tool))
|
|
5295
5367
|
|
|
5296
5368
|
# Add tools for accessing knowledge
|
|
5297
5369
|
if self.knowledge is not None or self.knowledge_retriever is not None:
|
|
5298
|
-
# Check if knowledge retriever is an async function but used in sync mode
|
|
5299
|
-
from inspect import iscoroutinefunction
|
|
5300
|
-
|
|
5301
|
-
if not async_mode and self.knowledge_retriever and iscoroutinefunction(self.knowledge_retriever):
|
|
5302
|
-
log_warning(
|
|
5303
|
-
"Async knowledge retriever function is being used with synchronous agent.run() or agent.print_response(). "
|
|
5304
|
-
"It is recommended to use agent.arun() or agent.aprint_response() instead."
|
|
5305
|
-
)
|
|
5306
|
-
|
|
5307
5370
|
if self.search_knowledge:
|
|
5308
5371
|
# Use async or sync search based on async_mode
|
|
5309
5372
|
if self.enable_agentic_knowledge_filters:
|
|
5310
5373
|
agent_tools.append(
|
|
5311
5374
|
self._search_knowledge_base_with_agentic_filters_function(
|
|
5312
5375
|
run_response=run_response,
|
|
5313
|
-
async_mode=
|
|
5376
|
+
async_mode=True,
|
|
5314
5377
|
knowledge_filters=knowledge_filters,
|
|
5315
5378
|
)
|
|
5316
5379
|
)
|
|
@@ -5318,11 +5381,10 @@ class Agent:
|
|
|
5318
5381
|
agent_tools.append(
|
|
5319
5382
|
self._get_search_knowledge_base_function(
|
|
5320
5383
|
run_response=run_response,
|
|
5321
|
-
async_mode=
|
|
5384
|
+
async_mode=True,
|
|
5322
5385
|
knowledge_filters=knowledge_filters,
|
|
5323
5386
|
)
|
|
5324
5387
|
)
|
|
5325
|
-
self._rebuild_tools = True
|
|
5326
5388
|
|
|
5327
5389
|
if self.update_knowledge:
|
|
5328
5390
|
agent_tools.append(self.add_to_knowledge)
|
|
@@ -5332,231 +5394,105 @@ class Agent:
|
|
|
5332
5394
|
def _determine_tools_for_model(
|
|
5333
5395
|
self,
|
|
5334
5396
|
model: Model,
|
|
5397
|
+
processed_tools: List[Union[Toolkit, Callable, Function, Dict]],
|
|
5335
5398
|
run_response: RunOutput,
|
|
5336
5399
|
session: AgentSession,
|
|
5337
5400
|
session_state: Optional[Dict[str, Any]] = None,
|
|
5338
5401
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
if self._rebuild_tools:
|
|
5344
|
-
self._rebuild_tools = False
|
|
5345
|
-
|
|
5346
|
-
agent_tools = self.get_tools(
|
|
5347
|
-
run_response=run_response,
|
|
5348
|
-
session=session,
|
|
5349
|
-
async_mode=async_mode,
|
|
5350
|
-
user_id=user_id,
|
|
5351
|
-
knowledge_filters=knowledge_filters,
|
|
5352
|
-
)
|
|
5353
|
-
|
|
5354
|
-
self._tools_for_model = []
|
|
5355
|
-
self._functions_for_model = {}
|
|
5356
|
-
self._tool_instructions = []
|
|
5357
|
-
|
|
5358
|
-
# Get Agent tools
|
|
5359
|
-
if agent_tools is not None and len(agent_tools) > 0:
|
|
5360
|
-
log_debug("Processing tools for model")
|
|
5361
|
-
|
|
5362
|
-
# Check if we need strict mode for the functions for the model
|
|
5363
|
-
strict = False
|
|
5364
|
-
if (
|
|
5365
|
-
self.output_schema is not None
|
|
5366
|
-
and (self.structured_outputs or (not self.use_json_mode))
|
|
5367
|
-
and model.supports_native_structured_outputs
|
|
5368
|
-
):
|
|
5369
|
-
strict = True
|
|
5370
|
-
|
|
5371
|
-
for tool in agent_tools:
|
|
5372
|
-
if isinstance(tool, Dict):
|
|
5373
|
-
# If a dict is passed, it is a builtin tool
|
|
5374
|
-
# that is run by the model provider and not the Agent
|
|
5375
|
-
self._tools_for_model.append(tool)
|
|
5376
|
-
log_debug(f"Included builtin tool {tool}")
|
|
5377
|
-
|
|
5378
|
-
elif isinstance(tool, Toolkit):
|
|
5379
|
-
# For each function in the toolkit and process entrypoint
|
|
5380
|
-
for name, func in tool.functions.items():
|
|
5381
|
-
# If the function does not exist in self.functions
|
|
5382
|
-
if name not in self._functions_for_model:
|
|
5383
|
-
func._agent = self
|
|
5384
|
-
func.process_entrypoint(strict=strict)
|
|
5385
|
-
if strict and func.strict is None:
|
|
5386
|
-
func.strict = True
|
|
5387
|
-
if self.tool_hooks is not None:
|
|
5388
|
-
func.tool_hooks = self.tool_hooks
|
|
5389
|
-
self._functions_for_model[name] = func
|
|
5390
|
-
self._tools_for_model.append({"type": "function", "function": func.to_dict()})
|
|
5391
|
-
log_debug(f"Added tool {name} from {tool.name}")
|
|
5392
|
-
|
|
5393
|
-
# Add instructions from the toolkit
|
|
5394
|
-
if tool.add_instructions and tool.instructions is not None:
|
|
5395
|
-
self._tool_instructions.append(tool.instructions)
|
|
5396
|
-
|
|
5397
|
-
elif isinstance(tool, Function):
|
|
5398
|
-
if tool.name not in self._functions_for_model:
|
|
5399
|
-
tool._agent = self
|
|
5400
|
-
tool.process_entrypoint(strict=strict)
|
|
5401
|
-
if strict and tool.strict is None:
|
|
5402
|
-
tool.strict = True
|
|
5403
|
-
if self.tool_hooks is not None:
|
|
5404
|
-
tool.tool_hooks = self.tool_hooks
|
|
5405
|
-
self._functions_for_model[tool.name] = tool
|
|
5406
|
-
self._tools_for_model.append({"type": "function", "function": tool.to_dict()})
|
|
5407
|
-
log_debug(f"Added tool {tool.name}")
|
|
5408
|
-
|
|
5409
|
-
# Add instructions from the Function
|
|
5410
|
-
if tool.add_instructions and tool.instructions is not None:
|
|
5411
|
-
self._tool_instructions.append(tool.instructions)
|
|
5412
|
-
|
|
5413
|
-
elif callable(tool):
|
|
5414
|
-
try:
|
|
5415
|
-
function_name = tool.__name__
|
|
5416
|
-
if function_name not in self._functions_for_model:
|
|
5417
|
-
func = Function.from_callable(tool, strict=strict)
|
|
5418
|
-
func._agent = self
|
|
5419
|
-
if strict:
|
|
5420
|
-
func.strict = True
|
|
5421
|
-
if self.tool_hooks is not None:
|
|
5422
|
-
func.tool_hooks = self.tool_hooks
|
|
5423
|
-
self._functions_for_model[func.name] = func
|
|
5424
|
-
self._tools_for_model.append({"type": "function", "function": func.to_dict()})
|
|
5425
|
-
log_debug(f"Added tool {func.name}")
|
|
5426
|
-
except Exception as e:
|
|
5427
|
-
log_warning(f"Could not add tool {tool}: {e}")
|
|
5428
|
-
|
|
5429
|
-
# Update the session state for the functions
|
|
5430
|
-
if self._functions_for_model:
|
|
5431
|
-
from inspect import signature
|
|
5432
|
-
|
|
5433
|
-
# Check if any functions need media before collecting
|
|
5434
|
-
needs_media = any(
|
|
5435
|
-
any(param in signature(func.entrypoint).parameters for param in ["images", "videos", "audios", "files"])
|
|
5436
|
-
for func in self._functions_for_model.values()
|
|
5437
|
-
if func.entrypoint is not None
|
|
5438
|
-
)
|
|
5439
|
-
|
|
5440
|
-
# Only collect media if functions actually need them
|
|
5441
|
-
joint_images = collect_joint_images(run_response.input, session) if needs_media else None
|
|
5442
|
-
joint_files = collect_joint_files(run_response.input) if needs_media else None
|
|
5443
|
-
joint_audios = collect_joint_audios(run_response.input, session) if needs_media else None
|
|
5444
|
-
joint_videos = collect_joint_videos(run_response.input, session) if needs_media else None
|
|
5402
|
+
) -> List[Union[Function, dict]]:
|
|
5403
|
+
_function_names = []
|
|
5404
|
+
_functions: List[Union[Function, dict]] = []
|
|
5405
|
+
self._tool_instructions = []
|
|
5445
5406
|
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
func._images = joint_images
|
|
5450
|
-
func._files = joint_files
|
|
5451
|
-
func._audios = joint_audios
|
|
5452
|
-
func._videos = joint_videos
|
|
5407
|
+
# Get Agent tools
|
|
5408
|
+
if processed_tools is not None and len(processed_tools) > 0:
|
|
5409
|
+
log_debug("Processing tools for model")
|
|
5453
5410
|
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
async_mode: bool = False,
|
|
5463
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
5464
|
-
) -> None:
|
|
5465
|
-
if self._rebuild_tools:
|
|
5466
|
-
self._rebuild_tools = False
|
|
5467
|
-
|
|
5468
|
-
agent_tools = await self.aget_tools(
|
|
5469
|
-
run_response=run_response,
|
|
5470
|
-
session=session,
|
|
5471
|
-
async_mode=async_mode,
|
|
5472
|
-
user_id=user_id,
|
|
5473
|
-
knowledge_filters=knowledge_filters,
|
|
5474
|
-
)
|
|
5411
|
+
# Check if we need strict mode for the functions for the model
|
|
5412
|
+
strict = False
|
|
5413
|
+
if (
|
|
5414
|
+
self.output_schema is not None
|
|
5415
|
+
and (self.structured_outputs or (not self.use_json_mode))
|
|
5416
|
+
and model.supports_native_structured_outputs
|
|
5417
|
+
):
|
|
5418
|
+
strict = True
|
|
5475
5419
|
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5420
|
+
for tool in processed_tools:
|
|
5421
|
+
if isinstance(tool, Dict):
|
|
5422
|
+
# If a dict is passed, it is a builtin tool
|
|
5423
|
+
# that is run by the model provider and not the Agent
|
|
5424
|
+
_functions.append(tool)
|
|
5425
|
+
log_debug(f"Included builtin tool {tool}")
|
|
5479
5426
|
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5427
|
+
elif isinstance(tool, Toolkit):
|
|
5428
|
+
# For each function in the toolkit and process entrypoint
|
|
5429
|
+
for name, _func in tool.functions.items():
|
|
5430
|
+
if name in _function_names:
|
|
5431
|
+
continue
|
|
5432
|
+
_function_names.append(name)
|
|
5433
|
+
_func = _func.model_copy(deep=True)
|
|
5434
|
+
_func._agent = self
|
|
5435
|
+
_func.process_entrypoint(strict=strict)
|
|
5436
|
+
if strict and _func.strict is None:
|
|
5437
|
+
_func.strict = True
|
|
5438
|
+
if self.tool_hooks is not None:
|
|
5439
|
+
_func.tool_hooks = self.tool_hooks
|
|
5440
|
+
_functions.append(_func)
|
|
5441
|
+
log_debug(f"Added tool {name} from {tool.name}")
|
|
5442
|
+
|
|
5443
|
+
# Add instructions from the toolkit
|
|
5444
|
+
if tool.add_instructions and tool.instructions is not None:
|
|
5445
|
+
self._tool_instructions.append(tool.instructions)
|
|
5446
|
+
|
|
5447
|
+
elif isinstance(tool, Function):
|
|
5448
|
+
if tool.name in _function_names:
|
|
5449
|
+
continue
|
|
5450
|
+
_function_names.append(tool.name)
|
|
5451
|
+
|
|
5452
|
+
tool.process_entrypoint(strict=strict)
|
|
5453
|
+
tool = tool.model_copy(deep=True)
|
|
5454
|
+
|
|
5455
|
+
tool._agent = self
|
|
5456
|
+
if strict and tool.strict is None:
|
|
5457
|
+
tool.strict = True
|
|
5458
|
+
if self.tool_hooks is not None:
|
|
5459
|
+
tool.tool_hooks = self.tool_hooks
|
|
5460
|
+
_functions.append(tool)
|
|
5461
|
+
log_debug(f"Added tool {tool.name}")
|
|
5462
|
+
|
|
5463
|
+
# Add instructions from the Function
|
|
5464
|
+
if tool.add_instructions and tool.instructions is not None:
|
|
5465
|
+
self._tool_instructions.append(tool.instructions)
|
|
5483
5466
|
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
self.
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
# If the function does not exist in self.functions
|
|
5504
|
-
if name not in self._functions_for_model:
|
|
5505
|
-
func._agent = self
|
|
5506
|
-
func.process_entrypoint(strict=strict)
|
|
5507
|
-
if strict and func.strict is None:
|
|
5508
|
-
func.strict = True
|
|
5509
|
-
if self.tool_hooks is not None:
|
|
5510
|
-
func.tool_hooks = self.tool_hooks
|
|
5511
|
-
self._functions_for_model[name] = func
|
|
5512
|
-
self._tools_for_model.append({"type": "function", "function": func.to_dict()})
|
|
5513
|
-
log_debug(f"Added tool {name} from {tool.name}")
|
|
5514
|
-
|
|
5515
|
-
# Add instructions from the toolkit
|
|
5516
|
-
if tool.add_instructions and tool.instructions is not None:
|
|
5517
|
-
self._tool_instructions.append(tool.instructions)
|
|
5518
|
-
|
|
5519
|
-
elif isinstance(tool, Function):
|
|
5520
|
-
if tool.name not in self._functions_for_model:
|
|
5521
|
-
tool._agent = self
|
|
5522
|
-
tool.process_entrypoint(strict=strict)
|
|
5523
|
-
if strict and tool.strict is None:
|
|
5524
|
-
tool.strict = True
|
|
5525
|
-
if self.tool_hooks is not None:
|
|
5526
|
-
tool.tool_hooks = self.tool_hooks
|
|
5527
|
-
self._functions_for_model[tool.name] = tool
|
|
5528
|
-
self._tools_for_model.append({"type": "function", "function": tool.to_dict()})
|
|
5529
|
-
log_debug(f"Added tool {tool.name}")
|
|
5530
|
-
|
|
5531
|
-
# Add instructions from the Function
|
|
5532
|
-
if tool.add_instructions and tool.instructions is not None:
|
|
5533
|
-
self._tool_instructions.append(tool.instructions)
|
|
5534
|
-
|
|
5535
|
-
elif callable(tool):
|
|
5536
|
-
try:
|
|
5537
|
-
function_name = tool.__name__
|
|
5538
|
-
if function_name not in self._functions_for_model:
|
|
5539
|
-
func = Function.from_callable(tool, strict=strict)
|
|
5540
|
-
func._agent = self
|
|
5541
|
-
if strict:
|
|
5542
|
-
func.strict = True
|
|
5543
|
-
if self.tool_hooks is not None:
|
|
5544
|
-
func.tool_hooks = self.tool_hooks
|
|
5545
|
-
self._functions_for_model[func.name] = func
|
|
5546
|
-
self._tools_for_model.append({"type": "function", "function": func.to_dict()})
|
|
5547
|
-
log_debug(f"Added tool {func.name}")
|
|
5548
|
-
except Exception as e:
|
|
5549
|
-
log_warning(f"Could not add tool {tool}: {e}")
|
|
5467
|
+
elif callable(tool):
|
|
5468
|
+
try:
|
|
5469
|
+
function_name = tool.__name__
|
|
5470
|
+
|
|
5471
|
+
if function_name in _function_names:
|
|
5472
|
+
continue
|
|
5473
|
+
_function_names.append(function_name)
|
|
5474
|
+
|
|
5475
|
+
_func = Function.from_callable(tool, strict=strict)
|
|
5476
|
+
_func = _func.model_copy(deep=True)
|
|
5477
|
+
_func._agent = self
|
|
5478
|
+
if strict:
|
|
5479
|
+
_func.strict = True
|
|
5480
|
+
if self.tool_hooks is not None:
|
|
5481
|
+
_func.tool_hooks = self.tool_hooks
|
|
5482
|
+
_functions.append(_func)
|
|
5483
|
+
log_debug(f"Added tool {_func.name}")
|
|
5484
|
+
except Exception as e:
|
|
5485
|
+
log_warning(f"Could not add tool {tool}: {e}")
|
|
5550
5486
|
|
|
5551
5487
|
# Update the session state for the functions
|
|
5552
|
-
if
|
|
5488
|
+
if _functions:
|
|
5553
5489
|
from inspect import signature
|
|
5554
5490
|
|
|
5555
5491
|
# Check if any functions need media before collecting
|
|
5556
5492
|
needs_media = any(
|
|
5557
5493
|
any(param in signature(func.entrypoint).parameters for param in ["images", "videos", "audios", "files"])
|
|
5558
|
-
for func in
|
|
5559
|
-
if func.entrypoint is not None
|
|
5494
|
+
for func in _functions
|
|
5495
|
+
if isinstance(func, Function) and func.entrypoint is not None
|
|
5560
5496
|
)
|
|
5561
5497
|
|
|
5562
5498
|
# Only collect media if functions actually need them
|
|
@@ -5565,13 +5501,16 @@ class Agent:
|
|
|
5565
5501
|
joint_audios = collect_joint_audios(run_response.input, session) if needs_media else None
|
|
5566
5502
|
joint_videos = collect_joint_videos(run_response.input, session) if needs_media else None
|
|
5567
5503
|
|
|
5568
|
-
for func in
|
|
5569
|
-
func
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5504
|
+
for func in _functions: # type: ignore
|
|
5505
|
+
if isinstance(func, Function):
|
|
5506
|
+
func._session_state = session_state
|
|
5507
|
+
func._dependencies = dependencies
|
|
5508
|
+
func._images = joint_images
|
|
5509
|
+
func._files = joint_files
|
|
5510
|
+
func._audios = joint_audios
|
|
5511
|
+
func._videos = joint_videos
|
|
5512
|
+
|
|
5513
|
+
return _functions
|
|
5575
5514
|
|
|
5576
5515
|
def _model_should_return_structured_output(self):
|
|
5577
5516
|
self.model = cast(Model, self.model)
|
|
@@ -5671,6 +5610,18 @@ class Agent:
|
|
|
5671
5610
|
agent_data["model"] = self.model.to_dict()
|
|
5672
5611
|
return agent_data
|
|
5673
5612
|
|
|
5613
|
+
@staticmethod
|
|
5614
|
+
def cancel_run(run_id: str) -> bool:
|
|
5615
|
+
"""Cancel a running agent execution.
|
|
5616
|
+
|
|
5617
|
+
Args:
|
|
5618
|
+
run_id (str): The run_id to cancel.
|
|
5619
|
+
|
|
5620
|
+
Returns:
|
|
5621
|
+
bool: True if the run was found and marked for cancellation, False otherwise.
|
|
5622
|
+
"""
|
|
5623
|
+
return cancel_run_global(run_id)
|
|
5624
|
+
|
|
5674
5625
|
# -*- Session Database Functions
|
|
5675
5626
|
def _read_session(
|
|
5676
5627
|
self, session_id: str, session_type: SessionType = SessionType.AGENT
|
|
@@ -5774,8 +5725,8 @@ class Agent:
|
|
|
5774
5725
|
from time import time
|
|
5775
5726
|
|
|
5776
5727
|
# Returning cached session if we have one
|
|
5777
|
-
if self.
|
|
5778
|
-
return self.
|
|
5728
|
+
if self._cached_session is not None and self._cached_session.session_id == session_id:
|
|
5729
|
+
return self._cached_session
|
|
5779
5730
|
|
|
5780
5731
|
# Try to load from database
|
|
5781
5732
|
agent_session = None
|
|
@@ -5803,7 +5754,7 @@ class Agent:
|
|
|
5803
5754
|
)
|
|
5804
5755
|
|
|
5805
5756
|
if self.cache_session:
|
|
5806
|
-
self.
|
|
5757
|
+
self._cached_session = agent_session
|
|
5807
5758
|
|
|
5808
5759
|
return agent_session
|
|
5809
5760
|
|
|
@@ -5815,8 +5766,8 @@ class Agent:
|
|
|
5815
5766
|
from time import time
|
|
5816
5767
|
|
|
5817
5768
|
# Returning cached session if we have one
|
|
5818
|
-
if self.
|
|
5819
|
-
return self.
|
|
5769
|
+
if self._cached_session is not None and self._cached_session.session_id == session_id:
|
|
5770
|
+
return self._cached_session
|
|
5820
5771
|
|
|
5821
5772
|
# Try to load from database
|
|
5822
5773
|
agent_session = None
|
|
@@ -5846,10 +5797,11 @@ class Agent:
|
|
|
5846
5797
|
)
|
|
5847
5798
|
|
|
5848
5799
|
if self.cache_session:
|
|
5849
|
-
self.
|
|
5800
|
+
self._cached_session = agent_session
|
|
5850
5801
|
|
|
5851
5802
|
return agent_session
|
|
5852
5803
|
|
|
5804
|
+
# -*- Public Convenience Functions
|
|
5853
5805
|
def get_run_output(self, run_id: str, session_id: Optional[str] = None) -> Optional[RunOutput]:
|
|
5854
5806
|
"""
|
|
5855
5807
|
Get a RunOutput from the database.
|
|
@@ -5857,23 +5809,30 @@ class Agent:
|
|
|
5857
5809
|
Args:
|
|
5858
5810
|
run_id (str): The run_id to load from storage.
|
|
5859
5811
|
session_id (Optional[str]): The session_id to load from storage.
|
|
5812
|
+
Returns:
|
|
5813
|
+
Optional[RunOutput]: The RunOutput from the database or None if not found.
|
|
5860
5814
|
"""
|
|
5861
|
-
if
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5815
|
+
if not session_id and not self.session_id:
|
|
5816
|
+
raise Exception("No session_id provided")
|
|
5817
|
+
|
|
5818
|
+
session_id_to_load = session_id or self.session_id
|
|
5819
|
+
return cast(RunOutput, get_run_output_util(self, run_id=run_id, session_id=session_id_to_load))
|
|
5820
|
+
|
|
5821
|
+
async def aget_run_output(self, run_id: str, session_id: Optional[str] = None) -> Optional[RunOutput]:
|
|
5822
|
+
"""
|
|
5823
|
+
Get a RunOutput from the database.
|
|
5824
|
+
|
|
5825
|
+
Args:
|
|
5826
|
+
run_id (str): The run_id to load from storage.
|
|
5827
|
+
session_id (Optional[str]): The session_id to load from storage.
|
|
5828
|
+
Returns:
|
|
5829
|
+
Optional[RunOutput]: The RunOutput from the database or None if not found.
|
|
5830
|
+
"""
|
|
5831
|
+
if not session_id and not self.session_id:
|
|
5832
|
+
raise Exception("No session_id provided")
|
|
5833
|
+
|
|
5834
|
+
session_id_to_load = session_id or self.session_id
|
|
5835
|
+
return cast(RunOutput, await aget_run_output_util(self, run_id=run_id, session_id=session_id_to_load))
|
|
5877
5836
|
|
|
5878
5837
|
def get_last_run_output(self, session_id: Optional[str] = None) -> Optional[RunOutput]:
|
|
5879
5838
|
"""
|
|
@@ -5883,36 +5842,29 @@ class Agent:
|
|
|
5883
5842
|
session_id (Optional[str]): The session_id to load from storage.
|
|
5884
5843
|
|
|
5885
5844
|
Returns:
|
|
5886
|
-
RunOutput: The last run response from the database.
|
|
5845
|
+
Optional[RunOutput]: The last run response from the database or None if not found.
|
|
5887
5846
|
"""
|
|
5888
|
-
if
|
|
5889
|
-
|
|
5890
|
-
and self._agent_session.runs is not None
|
|
5891
|
-
and len(self._agent_session.runs) > 0
|
|
5892
|
-
):
|
|
5893
|
-
for run_output in reversed(self._agent_session.runs):
|
|
5894
|
-
if hasattr(run_output, "agent_id") and run_output.agent_id == self.id:
|
|
5895
|
-
return run_output
|
|
5896
|
-
else:
|
|
5897
|
-
session = self.get_session(session_id=session_id)
|
|
5898
|
-
if session is not None and session.runs is not None and len(session.runs) > 0:
|
|
5899
|
-
for run_output in reversed(session.runs):
|
|
5900
|
-
if hasattr(run_output, "agent_id") and run_output.agent_id == self.id:
|
|
5901
|
-
return run_output
|
|
5902
|
-
else:
|
|
5903
|
-
log_warning(f"No run responses found in Session {session_id}")
|
|
5904
|
-
return None
|
|
5847
|
+
if not session_id and not self.session_id:
|
|
5848
|
+
raise Exception("No session_id provided")
|
|
5905
5849
|
|
|
5906
|
-
|
|
5907
|
-
|
|
5850
|
+
session_id_to_load = session_id or self.session_id
|
|
5851
|
+
return cast(RunOutput, get_last_run_output_util(self, session_id=session_id_to_load))
|
|
5852
|
+
|
|
5853
|
+
async def aget_last_run_output(self, session_id: Optional[str] = None) -> Optional[RunOutput]:
|
|
5854
|
+
"""
|
|
5855
|
+
Get the last run response from the database.
|
|
5908
5856
|
|
|
5909
5857
|
Args:
|
|
5910
|
-
|
|
5858
|
+
session_id (Optional[str]): The session_id to load from storage.
|
|
5911
5859
|
|
|
5912
5860
|
Returns:
|
|
5913
|
-
|
|
5861
|
+
Optional[RunOutput]: The last run response from the database or None if not found.
|
|
5914
5862
|
"""
|
|
5915
|
-
|
|
5863
|
+
if not session_id and not self.session_id:
|
|
5864
|
+
raise Exception("No session_id provided")
|
|
5865
|
+
|
|
5866
|
+
session_id_to_load = session_id or self.session_id
|
|
5867
|
+
return cast(RunOutput, await aget_last_run_output_util(self, session_id=session_id_to_load))
|
|
5916
5868
|
|
|
5917
5869
|
def get_session(
|
|
5918
5870
|
self,
|
|
@@ -5932,9 +5884,12 @@ class Agent:
|
|
|
5932
5884
|
session_id_to_load = session_id or self.session_id
|
|
5933
5885
|
|
|
5934
5886
|
# If there is a cached session, return it
|
|
5935
|
-
if self.cache_session and hasattr(self, "
|
|
5936
|
-
if self.
|
|
5937
|
-
return self.
|
|
5887
|
+
if self.cache_session and hasattr(self, "_cached_session") and self._cached_session is not None:
|
|
5888
|
+
if self._cached_session.session_id == session_id_to_load:
|
|
5889
|
+
return self._cached_session
|
|
5890
|
+
|
|
5891
|
+
if self._has_async_db():
|
|
5892
|
+
raise ValueError("Async database not supported for get_session")
|
|
5938
5893
|
|
|
5939
5894
|
# Load and return the session from the database
|
|
5940
5895
|
if self.db is not None:
|
|
@@ -5965,7 +5920,7 @@ class Agent:
|
|
|
5965
5920
|
|
|
5966
5921
|
# Cache the session if relevant
|
|
5967
5922
|
if loaded_session is not None and self.cache_session:
|
|
5968
|
-
self.
|
|
5923
|
+
self._cached_session = loaded_session
|
|
5969
5924
|
|
|
5970
5925
|
return loaded_session
|
|
5971
5926
|
|
|
@@ -5990,29 +5945,53 @@ class Agent:
|
|
|
5990
5945
|
session_id_to_load = session_id or self.session_id
|
|
5991
5946
|
|
|
5992
5947
|
# If there is a cached session, return it
|
|
5993
|
-
if self.cache_session and hasattr(self, "
|
|
5994
|
-
if self.
|
|
5995
|
-
return self.
|
|
5948
|
+
if self.cache_session and hasattr(self, "_cached_session") and self._cached_session is not None:
|
|
5949
|
+
if self._cached_session.session_id == session_id_to_load:
|
|
5950
|
+
return self._cached_session
|
|
5996
5951
|
|
|
5997
5952
|
# Load and return the session from the database
|
|
5998
5953
|
if self.db is not None:
|
|
5999
|
-
|
|
5954
|
+
loaded_session = None
|
|
5955
|
+
|
|
5956
|
+
# We have a standalone agent, so we are loading an AgentSession
|
|
5957
|
+
if self.team_id is None and self.workflow_id is None:
|
|
5958
|
+
loaded_session = cast(
|
|
5959
|
+
AgentSession,
|
|
5960
|
+
await self._aread_session(session_id=session_id_to_load, session_type=SessionType.AGENT), # type: ignore
|
|
5961
|
+
)
|
|
5962
|
+
|
|
5963
|
+
# We have a team member agent, so we are loading a TeamSession
|
|
5964
|
+
if loaded_session is None and self.team_id is not None:
|
|
5965
|
+
# Load session for team member agents
|
|
5966
|
+
loaded_session = cast(
|
|
5967
|
+
TeamSession,
|
|
5968
|
+
await self._aread_session(session_id=session_id_to_load, session_type=SessionType.TEAM), # type: ignore
|
|
5969
|
+
)
|
|
5970
|
+
|
|
5971
|
+
# We have a workflow member agent, so we are loading a WorkflowSession
|
|
5972
|
+
if loaded_session is None and self.workflow_id is not None:
|
|
5973
|
+
# Load session for workflow memberagents
|
|
5974
|
+
loaded_session = cast(
|
|
5975
|
+
WorkflowSession,
|
|
5976
|
+
await self._aread_session(session_id=session_id_to_load, session_type=SessionType.WORKFLOW), # type: ignore
|
|
5977
|
+
)
|
|
6000
5978
|
|
|
6001
5979
|
# Cache the session if relevant
|
|
6002
|
-
if
|
|
6003
|
-
self.
|
|
5980
|
+
if loaded_session is not None and self.cache_session:
|
|
5981
|
+
self._cached_session = loaded_session
|
|
6004
5982
|
|
|
6005
|
-
return
|
|
5983
|
+
return loaded_session
|
|
6006
5984
|
|
|
6007
5985
|
log_debug(f"AgentSession {session_id_to_load} not found in db")
|
|
6008
5986
|
return None
|
|
6009
5987
|
|
|
6010
5988
|
def save_session(self, session: AgentSession) -> None:
|
|
6011
|
-
"""Save the AgentSession to storage
|
|
6012
|
-
|
|
6013
|
-
Returns:
|
|
6014
|
-
Optional[AgentSession]: The saved AgentSession or None if not saved.
|
|
6015
5989
|
"""
|
|
5990
|
+
Save the AgentSession to storage
|
|
5991
|
+
"""
|
|
5992
|
+
if self._has_async_db():
|
|
5993
|
+
raise ValueError("Async database not supported for save_session")
|
|
5994
|
+
|
|
6016
5995
|
# If the agent is a member of a team, do not save the session to the database
|
|
6017
5996
|
if (
|
|
6018
5997
|
self.db is not None
|
|
@@ -6029,10 +6008,8 @@ class Agent:
|
|
|
6029
6008
|
log_debug(f"Created or updated AgentSession record: {session.session_id}")
|
|
6030
6009
|
|
|
6031
6010
|
async def asave_session(self, session: AgentSession) -> None:
|
|
6032
|
-
"""
|
|
6033
|
-
|
|
6034
|
-
Returns:
|
|
6035
|
-
Optional[AgentSession]: The saved AgentSession or None if not saved.
|
|
6011
|
+
"""
|
|
6012
|
+
Save the AgentSession to storage
|
|
6036
6013
|
"""
|
|
6037
6014
|
# If the agent is a member of a team, do not save the session to the database
|
|
6038
6015
|
if (
|
|
@@ -6052,27 +6029,56 @@ class Agent:
|
|
|
6052
6029
|
log_debug(f"Created or updated AgentSession record: {session.session_id}")
|
|
6053
6030
|
|
|
6054
6031
|
def get_chat_history(self, session_id: Optional[str] = None) -> List[Message]:
|
|
6055
|
-
"""Read the chat history from the session
|
|
6056
|
-
if not session_id and not self.session_id:
|
|
6057
|
-
raise Exception("No session_id provided")
|
|
6032
|
+
"""Read the chat history from the session
|
|
6058
6033
|
|
|
6059
|
-
|
|
6060
|
-
|
|
6034
|
+
Args:
|
|
6035
|
+
session_id: The session ID to get the chat history for. If not provided, the current cached session ID is used.
|
|
6036
|
+
Returns:
|
|
6037
|
+
List[Message]: The chat history from the session.
|
|
6038
|
+
"""
|
|
6039
|
+
session_id = session_id or self.session_id
|
|
6040
|
+
if session_id is None:
|
|
6041
|
+
log_warning("Session ID is not set, cannot get chat history")
|
|
6042
|
+
return []
|
|
6061
6043
|
|
|
6062
|
-
|
|
6063
|
-
|
|
6044
|
+
return get_chat_history_util(self, session_id=session_id)
|
|
6045
|
+
|
|
6046
|
+
async def aget_chat_history(self, session_id: Optional[str] = None) -> List[Message]:
|
|
6047
|
+
"""Read the chat history from the session
|
|
6048
|
+
|
|
6049
|
+
Args:
|
|
6050
|
+
session_id: The session ID to get the chat history for. If not provided, the current cached session ID is used.
|
|
6051
|
+
Returns:
|
|
6052
|
+
List[Message]: The chat history from the session.
|
|
6053
|
+
"""
|
|
6054
|
+
session_id = session_id or self.session_id
|
|
6055
|
+
if session_id is None:
|
|
6056
|
+
log_warning("Session ID is not set, cannot get chat history")
|
|
6057
|
+
return []
|
|
6064
6058
|
|
|
6065
|
-
return
|
|
6059
|
+
return await aget_chat_history_util(self, session_id=session_id)
|
|
6066
6060
|
|
|
6061
|
+
# -*- Session Management Functions
|
|
6067
6062
|
def rename(self, name: str, session_id: Optional[str] = None) -> None:
|
|
6068
|
-
"""
|
|
6063
|
+
"""
|
|
6064
|
+
Rename the Agent and save to storage
|
|
6065
|
+
|
|
6066
|
+
Args:
|
|
6067
|
+
name (str): The new name for the Agent.
|
|
6068
|
+
session_id (Optional[str]): The session_id of the session where to store the new name. If not provided, the current cached session ID is used.
|
|
6069
|
+
"""
|
|
6069
6070
|
|
|
6070
6071
|
session_id = session_id or self.session_id
|
|
6071
6072
|
|
|
6072
6073
|
if session_id is None:
|
|
6073
6074
|
raise Exception("Session ID is not set")
|
|
6074
6075
|
|
|
6075
|
-
|
|
6076
|
+
if self._has_async_db():
|
|
6077
|
+
import asyncio
|
|
6078
|
+
|
|
6079
|
+
session = asyncio.run(self.aget_session(session_id=session_id))
|
|
6080
|
+
else:
|
|
6081
|
+
session = self.get_session(session_id=session_id)
|
|
6076
6082
|
|
|
6077
6083
|
if session is None:
|
|
6078
6084
|
raise Exception("Session not found")
|
|
@@ -6085,7 +6091,12 @@ class Agent:
|
|
|
6085
6091
|
session.agent_data = {"name": name}
|
|
6086
6092
|
|
|
6087
6093
|
# -*- Save to storage
|
|
6088
|
-
self.
|
|
6094
|
+
if self._has_async_db():
|
|
6095
|
+
import asyncio
|
|
6096
|
+
|
|
6097
|
+
asyncio.run(self.asave_session(session=session))
|
|
6098
|
+
else:
|
|
6099
|
+
self.save_session(session=session)
|
|
6089
6100
|
|
|
6090
6101
|
def set_session_name(
|
|
6091
6102
|
self,
|
|
@@ -6093,38 +6104,63 @@ class Agent:
|
|
|
6093
6104
|
autogenerate: bool = False,
|
|
6094
6105
|
session_name: Optional[str] = None,
|
|
6095
6106
|
) -> AgentSession:
|
|
6096
|
-
"""
|
|
6107
|
+
"""
|
|
6108
|
+
Set the session name and save to storage
|
|
6109
|
+
|
|
6110
|
+
Args:
|
|
6111
|
+
session_id: The session ID to set the name for. If not provided, the current cached session ID is used.
|
|
6112
|
+
autogenerate: Whether to autogenerate the session name.
|
|
6113
|
+
session_name: The session name to set. If not provided, the session name will be autogenerated.
|
|
6114
|
+
Returns:
|
|
6115
|
+
AgentSession: The updated session.
|
|
6116
|
+
"""
|
|
6097
6117
|
session_id = session_id or self.session_id
|
|
6098
6118
|
|
|
6099
6119
|
if session_id is None:
|
|
6100
6120
|
raise Exception("Session ID is not set")
|
|
6101
6121
|
|
|
6102
|
-
|
|
6103
|
-
|
|
6122
|
+
return cast(
|
|
6123
|
+
AgentSession,
|
|
6124
|
+
set_session_name_util(self, session_id=session_id, autogenerate=autogenerate, session_name=session_name),
|
|
6125
|
+
)
|
|
6104
6126
|
|
|
6105
|
-
|
|
6106
|
-
|
|
6127
|
+
async def aset_session_name(
|
|
6128
|
+
self,
|
|
6129
|
+
session_id: Optional[str] = None,
|
|
6130
|
+
autogenerate: bool = False,
|
|
6131
|
+
session_name: Optional[str] = None,
|
|
6132
|
+
) -> AgentSession:
|
|
6133
|
+
"""
|
|
6134
|
+
Set the session name and save to storage
|
|
6107
6135
|
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6136
|
+
Args:
|
|
6137
|
+
session_id: The session ID to set the name for. If not provided, the current cached session ID is used.
|
|
6138
|
+
autogenerate: Whether to autogenerate the session name.
|
|
6139
|
+
session_name: The session name to set. If not provided, the session name will be autogenerated.
|
|
6140
|
+
Returns:
|
|
6141
|
+
AgentSession: The updated session.
|
|
6142
|
+
"""
|
|
6143
|
+
session_id = session_id or self.session_id
|
|
6114
6144
|
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
session.session_data["session_name"] = session_name
|
|
6118
|
-
else:
|
|
6119
|
-
session.session_data = {"session_name": session_name}
|
|
6145
|
+
if session_id is None:
|
|
6146
|
+
raise Exception("Session ID is not set")
|
|
6120
6147
|
|
|
6121
|
-
|
|
6122
|
-
|
|
6148
|
+
return cast(
|
|
6149
|
+
AgentSession,
|
|
6150
|
+
await aset_session_name_util(
|
|
6151
|
+
self, session_id=session_id, autogenerate=autogenerate, session_name=session_name
|
|
6152
|
+
),
|
|
6153
|
+
)
|
|
6123
6154
|
|
|
6124
|
-
|
|
6155
|
+
def generate_session_name(self, session: AgentSession) -> str:
|
|
6156
|
+
"""
|
|
6157
|
+
Generate a name for the session using the first 6 messages from the memory
|
|
6125
6158
|
|
|
6126
|
-
|
|
6127
|
-
|
|
6159
|
+
Args:
|
|
6160
|
+
session (AgentSession): The session to generate a name for.
|
|
6161
|
+
Returns:
|
|
6162
|
+
str: The generated session name.
|
|
6163
|
+
"""
|
|
6128
6164
|
|
|
6129
6165
|
if self.model is None:
|
|
6130
6166
|
raise Exception("Model not set")
|
|
@@ -6151,32 +6187,68 @@ class Agent:
|
|
|
6151
6187
|
content = generated_name.content
|
|
6152
6188
|
if content is None:
|
|
6153
6189
|
log_error("Generated name is None. Trying again.")
|
|
6154
|
-
return self.
|
|
6190
|
+
return self.generate_session_name(session=session)
|
|
6155
6191
|
|
|
6156
6192
|
if len(content.split()) > 5:
|
|
6157
6193
|
log_error("Generated name is too long. It should be less than 5 words. Trying again.")
|
|
6158
|
-
return self.
|
|
6194
|
+
return self.generate_session_name(session=session)
|
|
6159
6195
|
return content.replace('"', "").strip()
|
|
6160
6196
|
|
|
6161
6197
|
def get_session_name(self, session_id: Optional[str] = None) -> str:
|
|
6162
|
-
"""
|
|
6198
|
+
"""
|
|
6199
|
+
Get the session name for the given session ID.
|
|
6200
|
+
|
|
6201
|
+
Args:
|
|
6202
|
+
session_id: The session ID to get the name for. If not provided, the current cached session ID is used.
|
|
6203
|
+
Returns:
|
|
6204
|
+
str: The session name.
|
|
6205
|
+
"""
|
|
6163
6206
|
session_id = session_id or self.session_id
|
|
6164
6207
|
if session_id is None:
|
|
6165
6208
|
raise Exception("Session ID is not set")
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6209
|
+
return get_session_name_util(self, session_id=session_id)
|
|
6210
|
+
|
|
6211
|
+
async def aget_session_name(self, session_id: Optional[str] = None) -> str:
|
|
6212
|
+
"""
|
|
6213
|
+
Get the session name for the given session ID.
|
|
6214
|
+
|
|
6215
|
+
Args:
|
|
6216
|
+
session_id: The session ID to get the name for. If not provided, the current cached session ID is used.
|
|
6217
|
+
Returns:
|
|
6218
|
+
str: The session name.
|
|
6219
|
+
"""
|
|
6220
|
+
session_id = session_id or self.session_id
|
|
6221
|
+
if session_id is None:
|
|
6222
|
+
raise Exception("Session ID is not set")
|
|
6223
|
+
return await aget_session_name_util(self, session_id=session_id)
|
|
6170
6224
|
|
|
6171
6225
|
def get_session_state(self, session_id: Optional[str] = None) -> Dict[str, Any]:
|
|
6172
|
-
"""
|
|
6226
|
+
"""
|
|
6227
|
+
Get the session state for the given session ID.
|
|
6228
|
+
|
|
6229
|
+
Args:
|
|
6230
|
+
session_id: The session ID to get the state for. If not provided, the current cached session ID is used.
|
|
6231
|
+
Returns:
|
|
6232
|
+
Dict[str, Any]: The session state.
|
|
6233
|
+
"""
|
|
6173
6234
|
session_id = session_id or self.session_id
|
|
6174
6235
|
if session_id is None:
|
|
6175
6236
|
raise Exception("Session ID is not set")
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6237
|
+
return get_session_state_util(self, session_id=session_id)
|
|
6238
|
+
|
|
6239
|
+
async def aget_session_state(self, session_id: Optional[str] = None) -> Dict[str, Any]:
|
|
6240
|
+
"""
|
|
6241
|
+
Get the session state for the given session ID.
|
|
6242
|
+
|
|
6243
|
+
Args:
|
|
6244
|
+
session_id: The session ID to get the state for. If not provided, the current cached session ID is used.
|
|
6245
|
+
Returns:
|
|
6246
|
+
Dict[str, Any]: The session state.
|
|
6247
|
+
"""
|
|
6248
|
+
session_id = session_id or self.session_id
|
|
6249
|
+
if session_id is None:
|
|
6250
|
+
raise Exception("Session ID is not set")
|
|
6251
|
+
return await aget_session_state_util(self, session_id=session_id)
|
|
6180
6252
|
|
|
6181
6253
|
def update_session_state(self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None) -> str:
|
|
6182
6254
|
"""
|
|
@@ -6190,20 +6262,7 @@ class Agent:
|
|
|
6190
6262
|
session_id = session_id or self.session_id
|
|
6191
6263
|
if session_id is None:
|
|
6192
6264
|
raise Exception("Session ID is not set")
|
|
6193
|
-
|
|
6194
|
-
if session is None:
|
|
6195
|
-
raise Exception("Session not found")
|
|
6196
|
-
|
|
6197
|
-
if session.session_data is not None and "session_state" not in session.session_data:
|
|
6198
|
-
session.session_data["session_state"] = {}
|
|
6199
|
-
|
|
6200
|
-
# Overwrite the loaded DB session state with the new session state
|
|
6201
|
-
for key, value in session_state_updates.items():
|
|
6202
|
-
session.session_data["session_state"][key] = value # type: ignore
|
|
6203
|
-
|
|
6204
|
-
self.save_session(session=session)
|
|
6205
|
-
|
|
6206
|
-
return session.session_data["session_state"] # type: ignore
|
|
6265
|
+
return update_session_state_util(self, session_state_updates=session_state_updates, session_id=session_id)
|
|
6207
6266
|
|
|
6208
6267
|
async def aupdate_session_state(
|
|
6209
6268
|
self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None
|
|
@@ -6219,52 +6278,88 @@ class Agent:
|
|
|
6219
6278
|
session_id = session_id or self.session_id
|
|
6220
6279
|
if session_id is None:
|
|
6221
6280
|
raise Exception("Session ID is not set")
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6281
|
+
return await aupdate_session_state_util(
|
|
6282
|
+
self, session_state_updates=session_state_updates, session_id=session_id
|
|
6283
|
+
)
|
|
6225
6284
|
|
|
6226
|
-
|
|
6227
|
-
|
|
6285
|
+
def get_session_metrics(self, session_id: Optional[str] = None) -> Optional[Metrics]:
|
|
6286
|
+
"""Get the session metrics for the given session ID.
|
|
6228
6287
|
|
|
6229
|
-
|
|
6230
|
-
session.
|
|
6288
|
+
Args:
|
|
6289
|
+
session_id: The session ID to get the metrics for. If not provided, the current cached session ID is used.
|
|
6290
|
+
Returns:
|
|
6291
|
+
Optional[Metrics]: The session metrics.
|
|
6292
|
+
"""
|
|
6293
|
+
session_id = session_id or self.session_id
|
|
6294
|
+
if session_id is None:
|
|
6295
|
+
raise Exception("Session ID is not set")
|
|
6231
6296
|
|
|
6232
|
-
|
|
6297
|
+
return get_session_metrics_util(self, session_id=session_id)
|
|
6233
6298
|
|
|
6234
|
-
|
|
6299
|
+
async def aget_session_metrics(self, session_id: Optional[str] = None) -> Optional[Metrics]:
|
|
6300
|
+
"""Get the session metrics for the given session ID.
|
|
6235
6301
|
|
|
6236
|
-
|
|
6237
|
-
|
|
6302
|
+
Args:
|
|
6303
|
+
session_id: The session ID to get the metrics for. If not provided, the current cached session ID is used.
|
|
6304
|
+
Returns:
|
|
6305
|
+
Optional[Metrics]: The session metrics.
|
|
6306
|
+
"""
|
|
6238
6307
|
session_id = session_id or self.session_id
|
|
6239
6308
|
if session_id is None:
|
|
6240
6309
|
raise Exception("Session ID is not set")
|
|
6241
6310
|
|
|
6242
|
-
|
|
6243
|
-
if session is None:
|
|
6244
|
-
raise Exception("Session not found")
|
|
6245
|
-
|
|
6246
|
-
if session.session_data is not None and session.session_data.get("session_metrics") is not None:
|
|
6247
|
-
if isinstance(session.session_data.get("session_metrics"), dict):
|
|
6248
|
-
return Metrics(**session.session_data.get("session_metrics", {}))
|
|
6249
|
-
elif isinstance(session.session_data.get("session_metrics"), Metrics):
|
|
6250
|
-
return session.session_data.get("session_metrics", None)
|
|
6251
|
-
return None
|
|
6311
|
+
return await aget_session_metrics_util(self, session_id=session_id)
|
|
6252
6312
|
|
|
6253
6313
|
def delete_session(self, session_id: str):
|
|
6254
6314
|
"""Delete the current session and save to storage"""
|
|
6255
6315
|
if self.db is None:
|
|
6256
6316
|
return
|
|
6257
|
-
|
|
6317
|
+
|
|
6258
6318
|
self.db.delete_session(session_id=session_id)
|
|
6259
6319
|
|
|
6320
|
+
async def adelete_session(self, session_id: str):
|
|
6321
|
+
"""Delete the current session and save to storage"""
|
|
6322
|
+
if self.db is None:
|
|
6323
|
+
return
|
|
6324
|
+
await self.db.delete_session(session_id=session_id) # type: ignore
|
|
6325
|
+
|
|
6260
6326
|
def get_messages_for_session(self, session_id: Optional[str] = None) -> List[Message]:
|
|
6261
|
-
"""Get messages for a session
|
|
6327
|
+
"""Get messages for a session
|
|
6328
|
+
|
|
6329
|
+
Args:
|
|
6330
|
+
session_id: The session ID to get the messages for. If not provided, the current cached session ID is used.
|
|
6331
|
+
Returns:
|
|
6332
|
+
List[Message]: The messages for the session.
|
|
6333
|
+
"""
|
|
6334
|
+
session_id = session_id or self.session_id
|
|
6335
|
+
if session_id is None:
|
|
6336
|
+
log_warning("Session ID is not set, cannot get messages for session")
|
|
6337
|
+
return []
|
|
6338
|
+
|
|
6339
|
+
session = self.get_session(session_id=session_id)
|
|
6340
|
+
|
|
6341
|
+
if session is None:
|
|
6342
|
+
raise Exception("Session not found")
|
|
6343
|
+
|
|
6344
|
+
# Only filter by agent_id if this is part of a team
|
|
6345
|
+
return session.get_messages_from_last_n_runs(
|
|
6346
|
+
agent_id=self.id if self.team_id is not None else None,
|
|
6347
|
+
)
|
|
6348
|
+
|
|
6349
|
+
async def aget_messages_for_session(self, session_id: Optional[str] = None) -> List[Message]:
|
|
6350
|
+
"""Get messages for a session
|
|
6351
|
+
|
|
6352
|
+
Args:
|
|
6353
|
+
session_id: The session ID to get the messages for. If not provided, the current cached session ID is used.
|
|
6354
|
+
Returns:
|
|
6355
|
+
List[Message]: The messages for the session.
|
|
6356
|
+
"""
|
|
6262
6357
|
session_id = session_id or self.session_id
|
|
6263
6358
|
if session_id is None:
|
|
6264
6359
|
log_warning("Session ID is not set, cannot get messages for session")
|
|
6265
6360
|
return []
|
|
6266
6361
|
|
|
6267
|
-
session = self.
|
|
6362
|
+
session = await self.aget_session(session_id=session_id)
|
|
6268
6363
|
|
|
6269
6364
|
if session is None:
|
|
6270
6365
|
raise Exception("Session not found")
|
|
@@ -6274,8 +6369,14 @@ class Agent:
|
|
|
6274
6369
|
agent_id=self.id if self.team_id is not None else None,
|
|
6275
6370
|
)
|
|
6276
6371
|
|
|
6277
|
-
def get_session_summary(self, session_id: Optional[str] = None):
|
|
6278
|
-
"""Get the session summary for the given session ID and user ID
|
|
6372
|
+
def get_session_summary(self, session_id: Optional[str] = None) -> Optional[SessionSummary]:
|
|
6373
|
+
"""Get the session summary for the given session ID and user ID
|
|
6374
|
+
|
|
6375
|
+
Args:
|
|
6376
|
+
session_id: The session ID to get the summary for. If not provided, the current cached session ID is used.
|
|
6377
|
+
Returns:
|
|
6378
|
+
SessionSummary: The session summary.
|
|
6379
|
+
"""
|
|
6279
6380
|
session_id = session_id if session_id is not None else self.session_id
|
|
6280
6381
|
if session_id is None:
|
|
6281
6382
|
raise ValueError("Session ID is required")
|
|
@@ -6287,8 +6388,33 @@ class Agent:
|
|
|
6287
6388
|
|
|
6288
6389
|
return session.get_session_summary()
|
|
6289
6390
|
|
|
6391
|
+
async def aget_session_summary(self, session_id: Optional[str] = None) -> Optional[SessionSummary]:
|
|
6392
|
+
"""Get the session summary for the given session ID and user ID.
|
|
6393
|
+
|
|
6394
|
+
Args:
|
|
6395
|
+
session_id: The session ID to get the summary for. If not provided, the current cached session ID is used.
|
|
6396
|
+
Returns:
|
|
6397
|
+
SessionSummary: The session summary.
|
|
6398
|
+
"""
|
|
6399
|
+
session_id = session_id if session_id is not None else self.session_id
|
|
6400
|
+
if session_id is None:
|
|
6401
|
+
raise ValueError("Session ID is required")
|
|
6402
|
+
|
|
6403
|
+
session = await self.aget_session(session_id=session_id)
|
|
6404
|
+
|
|
6405
|
+
if session is None:
|
|
6406
|
+
raise Exception(f"Session {session_id} not found")
|
|
6407
|
+
|
|
6408
|
+
return session.get_session_summary()
|
|
6409
|
+
|
|
6290
6410
|
def get_user_memories(self, user_id: Optional[str] = None) -> Optional[List[UserMemory]]:
|
|
6291
|
-
"""Get the user memories for the given user ID.
|
|
6411
|
+
"""Get the user memories for the given user ID.
|
|
6412
|
+
|
|
6413
|
+
Args:
|
|
6414
|
+
user_id: The user ID to get the memories for. If not provided, the current cached user ID is used.
|
|
6415
|
+
Returns:
|
|
6416
|
+
Optional[List[UserMemory]]: The user memories.
|
|
6417
|
+
"""
|
|
6292
6418
|
if self.memory_manager is None:
|
|
6293
6419
|
return None
|
|
6294
6420
|
user_id = user_id if user_id is not None else self.user_id
|
|
@@ -6298,7 +6424,13 @@ class Agent:
|
|
|
6298
6424
|
return self.memory_manager.get_user_memories(user_id=user_id)
|
|
6299
6425
|
|
|
6300
6426
|
async def aget_user_memories(self, user_id: Optional[str] = None) -> Optional[List[UserMemory]]:
|
|
6301
|
-
"""Get the user memories for the given user ID.
|
|
6427
|
+
"""Get the user memories for the given user ID.
|
|
6428
|
+
|
|
6429
|
+
Args:
|
|
6430
|
+
user_id: The user ID to get the memories for. If not provided, the current cached user ID is used.
|
|
6431
|
+
Returns:
|
|
6432
|
+
Optional[List[UserMemory]]: The user memories.
|
|
6433
|
+
"""
|
|
6302
6434
|
if self.memory_manager is None:
|
|
6303
6435
|
return None
|
|
6304
6436
|
user_id = user_id if user_id is not None else self.user_id
|
|
@@ -6308,19 +6440,28 @@ class Agent:
|
|
|
6308
6440
|
return await self.memory_manager.aget_user_memories(user_id=user_id)
|
|
6309
6441
|
|
|
6310
6442
|
def get_culture_knowledge(self) -> Optional[List[CulturalKnowledge]]:
|
|
6311
|
-
"""Get the cultural knowledge the agent has access to
|
|
6443
|
+
"""Get the cultural knowledge the agent has access to
|
|
6444
|
+
|
|
6445
|
+
Returns:
|
|
6446
|
+
Optional[List[CulturalKnowledge]]: The cultural knowledge.
|
|
6447
|
+
"""
|
|
6312
6448
|
if self.culture_manager is None:
|
|
6313
6449
|
return None
|
|
6314
6450
|
|
|
6315
6451
|
return self.culture_manager.get_all_knowledge()
|
|
6316
6452
|
|
|
6317
6453
|
async def aget_culture_knowledge(self) -> Optional[List[CulturalKnowledge]]:
|
|
6318
|
-
"""Get the cultural knowledge the agent has access to
|
|
6454
|
+
"""Get the cultural knowledge the agent has access to
|
|
6455
|
+
|
|
6456
|
+
Returns:
|
|
6457
|
+
Optional[List[CulturalKnowledge]]: The cultural knowledge.
|
|
6458
|
+
"""
|
|
6319
6459
|
if self.culture_manager is None:
|
|
6320
6460
|
return None
|
|
6321
6461
|
|
|
6322
6462
|
return await self.culture_manager.aget_all_knowledge()
|
|
6323
6463
|
|
|
6464
|
+
# -*- System & User Message Functions
|
|
6324
6465
|
def _format_message_with_state_variables(
|
|
6325
6466
|
self,
|
|
6326
6467
|
message: Any,
|
|
@@ -6365,6 +6506,7 @@ class Agent:
|
|
|
6365
6506
|
session: AgentSession,
|
|
6366
6507
|
session_state: Optional[Dict[str, Any]] = None,
|
|
6367
6508
|
user_id: Optional[str] = None,
|
|
6509
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
6368
6510
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
6369
6511
|
metadata: Optional[Dict[str, Any]] = None,
|
|
6370
6512
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -6436,7 +6578,7 @@ class Agent:
|
|
|
6436
6578
|
instructions.extend(_instructions)
|
|
6437
6579
|
|
|
6438
6580
|
# 3.1.1 Add instructions from the Model
|
|
6439
|
-
_model_instructions = self.model.get_instructions_for_model(
|
|
6581
|
+
_model_instructions = self.model.get_instructions_for_model(tools)
|
|
6440
6582
|
if _model_instructions is not None:
|
|
6441
6583
|
instructions.extend(_model_instructions)
|
|
6442
6584
|
|
|
@@ -6671,7 +6813,7 @@ class Agent:
|
|
|
6671
6813
|
)
|
|
6672
6814
|
|
|
6673
6815
|
# 3.3.12 Add the system message from the Model
|
|
6674
|
-
system_message_from_model = self.model.get_system_message_for_model(
|
|
6816
|
+
system_message_from_model = self.model.get_system_message_for_model(tools)
|
|
6675
6817
|
if system_message_from_model is not None:
|
|
6676
6818
|
system_message_content += system_message_from_model
|
|
6677
6819
|
|
|
@@ -6707,6 +6849,7 @@ class Agent:
|
|
|
6707
6849
|
session: AgentSession,
|
|
6708
6850
|
session_state: Optional[Dict[str, Any]] = None,
|
|
6709
6851
|
user_id: Optional[str] = None,
|
|
6852
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
6710
6853
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
6711
6854
|
metadata: Optional[Dict[str, Any]] = None,
|
|
6712
6855
|
) -> Optional[Message]:
|
|
@@ -6777,7 +6920,7 @@ class Agent:
|
|
|
6777
6920
|
instructions.extend(_instructions)
|
|
6778
6921
|
|
|
6779
6922
|
# 3.1.1 Add instructions from the Model
|
|
6780
|
-
_model_instructions = self.model.get_instructions_for_model(
|
|
6923
|
+
_model_instructions = self.model.get_instructions_for_model(tools)
|
|
6781
6924
|
if _model_instructions is not None:
|
|
6782
6925
|
instructions.extend(_model_instructions)
|
|
6783
6926
|
|
|
@@ -7015,7 +7158,7 @@ class Agent:
|
|
|
7015
7158
|
)
|
|
7016
7159
|
|
|
7017
7160
|
# 3.3.12 Add the system message from the Model
|
|
7018
|
-
system_message_from_model = self.model.get_system_message_for_model(
|
|
7161
|
+
system_message_from_model = self.model.get_system_message_for_model(tools)
|
|
7019
7162
|
if system_message_from_model is not None:
|
|
7020
7163
|
system_message_content += system_message_from_model
|
|
7021
7164
|
|
|
@@ -7234,6 +7377,7 @@ class Agent:
|
|
|
7234
7377
|
add_dependencies_to_context: Optional[bool] = None,
|
|
7235
7378
|
add_session_state_to_context: Optional[bool] = None,
|
|
7236
7379
|
metadata: Optional[Dict[str, Any]] = None,
|
|
7380
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
7237
7381
|
**kwargs: Any,
|
|
7238
7382
|
) -> RunMessages:
|
|
7239
7383
|
"""This function returns a RunMessages object with the following attributes:
|
|
@@ -7268,6 +7412,7 @@ class Agent:
|
|
|
7268
7412
|
session=session,
|
|
7269
7413
|
session_state=session_state,
|
|
7270
7414
|
user_id=user_id,
|
|
7415
|
+
tools=tools,
|
|
7271
7416
|
dependencies=dependencies,
|
|
7272
7417
|
metadata=metadata,
|
|
7273
7418
|
add_session_state_to_context=add_session_state_to_context,
|
|
@@ -7439,6 +7584,7 @@ class Agent:
|
|
|
7439
7584
|
add_dependencies_to_context: Optional[bool] = None,
|
|
7440
7585
|
add_session_state_to_context: Optional[bool] = None,
|
|
7441
7586
|
metadata: Optional[Dict[str, Any]] = None,
|
|
7587
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
7442
7588
|
**kwargs: Any,
|
|
7443
7589
|
) -> RunMessages:
|
|
7444
7590
|
"""This function returns a RunMessages object with the following attributes:
|
|
@@ -7473,6 +7619,7 @@ class Agent:
|
|
|
7473
7619
|
session=session,
|
|
7474
7620
|
session_state=session_state,
|
|
7475
7621
|
user_id=user_id,
|
|
7622
|
+
tools=tools,
|
|
7476
7623
|
dependencies=dependencies,
|
|
7477
7624
|
metadata=metadata,
|
|
7478
7625
|
)
|
|
@@ -9340,6 +9487,8 @@ class Agent:
|
|
|
9340
9487
|
document_name = query.replace(" ", "_").replace("?", "").replace("!", "").replace(".", "")
|
|
9341
9488
|
document_content = json.dumps({"query": query, "result": result})
|
|
9342
9489
|
log_info(f"Adding document to Knowledge: {document_name}: {document_content}")
|
|
9490
|
+
import asyncio
|
|
9491
|
+
|
|
9343
9492
|
from agno.knowledge.reader.text_reader import TextReader
|
|
9344
9493
|
|
|
9345
9494
|
asyncio.run(
|
|
@@ -9414,12 +9563,14 @@ class Agent:
|
|
|
9414
9563
|
|
|
9415
9564
|
return get_previous_session_messages
|
|
9416
9565
|
|
|
9417
|
-
async def _aget_previous_sessions_messages_function(
|
|
9566
|
+
async def _aget_previous_sessions_messages_function(
|
|
9567
|
+
self, num_history_sessions: Optional[int] = 2, user_id: Optional[str] = None
|
|
9568
|
+
) -> Function:
|
|
9418
9569
|
"""Factory function to create a get_previous_session_messages function.
|
|
9419
9570
|
|
|
9420
9571
|
Args:
|
|
9421
9572
|
num_history_sessions: The last n sessions to be taken from db
|
|
9422
|
-
|
|
9573
|
+
user_id: The user ID to filter sessions by
|
|
9423
9574
|
Returns:
|
|
9424
9575
|
Callable: A function that retrieves messages from previous sessions
|
|
9425
9576
|
"""
|
|
@@ -9437,12 +9588,22 @@ class Agent:
|
|
|
9437
9588
|
if self.db is None:
|
|
9438
9589
|
return "Previous session messages not available"
|
|
9439
9590
|
|
|
9440
|
-
if
|
|
9441
|
-
selected_sessions = await self.db.get_sessions(
|
|
9442
|
-
session_type=SessionType.AGENT,
|
|
9591
|
+
if self._has_async_db():
|
|
9592
|
+
selected_sessions = await self.db.get_sessions( # type: ignore
|
|
9593
|
+
session_type=SessionType.AGENT,
|
|
9594
|
+
limit=num_history_sessions,
|
|
9595
|
+
user_id=user_id,
|
|
9596
|
+
sort_by="created_at",
|
|
9597
|
+
sort_order="desc",
|
|
9443
9598
|
)
|
|
9444
9599
|
else:
|
|
9445
|
-
selected_sessions = self.db.get_sessions(
|
|
9600
|
+
selected_sessions = self.db.get_sessions(
|
|
9601
|
+
session_type=SessionType.AGENT,
|
|
9602
|
+
limit=num_history_sessions,
|
|
9603
|
+
user_id=user_id,
|
|
9604
|
+
sort_by="created_at",
|
|
9605
|
+
sort_order="desc",
|
|
9606
|
+
)
|
|
9446
9607
|
|
|
9447
9608
|
all_messages = []
|
|
9448
9609
|
seen_message_pairs = set()
|
|
@@ -9475,7 +9636,7 @@ class Agent:
|
|
|
9475
9636
|
|
|
9476
9637
|
return json.dumps([msg.to_dict() for msg in all_messages]) if all_messages else "No history found"
|
|
9477
9638
|
|
|
9478
|
-
return aget_previous_session_messages
|
|
9639
|
+
return Function.from_callable(aget_previous_session_messages, name="get_previous_session_messages")
|
|
9479
9640
|
|
|
9480
9641
|
###########################################################################
|
|
9481
9642
|
# Print Response
|