agno 2.2.1__py3-none-any.whl → 2.2.2__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/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 +26 -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 +591 -365
- 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.2.dist-info}/METADATA +28 -25
- {agno-2.2.1.dist-info → agno-2.2.2.dist-info}/RECORD +64 -61
- 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.2.dist-info}/WHEEL +0 -0
- {agno-2.2.1.dist-info → agno-2.2.2.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.1.dist-info → agno-2.2.2.dist-info}/top_level.txt +0 -0
agno/team/team.py
CHANGED
|
@@ -59,18 +59,35 @@ from agno.run.cancel import (
|
|
|
59
59
|
from agno.run.messages import RunMessages
|
|
60
60
|
from agno.run.team import TeamRunEvent, TeamRunInput, TeamRunOutput, TeamRunOutputEvent
|
|
61
61
|
from agno.session import SessionSummaryManager, TeamSession, WorkflowSession
|
|
62
|
+
from agno.session.summary import SessionSummary
|
|
62
63
|
from agno.tools import Toolkit
|
|
63
64
|
from agno.tools.function import Function
|
|
64
65
|
from agno.utils.agent import (
|
|
66
|
+
aget_chat_history_util,
|
|
67
|
+
aget_last_run_output_util,
|
|
68
|
+
aget_run_output_util,
|
|
69
|
+
aget_session_metrics_util,
|
|
70
|
+
aget_session_name_util,
|
|
71
|
+
aget_session_state_util,
|
|
72
|
+
aset_session_name_util,
|
|
73
|
+
aupdate_session_state_util,
|
|
65
74
|
await_for_background_tasks,
|
|
66
75
|
await_for_background_tasks_stream,
|
|
67
76
|
collect_joint_audios,
|
|
68
77
|
collect_joint_files,
|
|
69
78
|
collect_joint_images,
|
|
70
79
|
collect_joint_videos,
|
|
80
|
+
get_chat_history_util,
|
|
81
|
+
get_last_run_output_util,
|
|
82
|
+
get_run_output_util,
|
|
83
|
+
get_session_metrics_util,
|
|
84
|
+
get_session_name_util,
|
|
85
|
+
get_session_state_util,
|
|
71
86
|
scrub_history_messages_from_run_output,
|
|
72
87
|
scrub_media_from_run_output,
|
|
73
88
|
scrub_tool_results_from_run_output,
|
|
89
|
+
set_session_name_util,
|
|
90
|
+
update_session_state_util,
|
|
74
91
|
wait_for_background_tasks,
|
|
75
92
|
wait_for_background_tasks_stream,
|
|
76
93
|
)
|
|
@@ -131,7 +148,16 @@ from agno.utils.response import (
|
|
|
131
148
|
)
|
|
132
149
|
from agno.utils.safe_formatter import SafeFormatter
|
|
133
150
|
from agno.utils.string import generate_id_from_name, parse_response_model_str
|
|
134
|
-
from agno.utils.team import
|
|
151
|
+
from agno.utils.team import (
|
|
152
|
+
add_interaction_to_team_run_context,
|
|
153
|
+
format_member_agent_task,
|
|
154
|
+
get_member_id,
|
|
155
|
+
get_team_member_interactions_str,
|
|
156
|
+
get_team_run_context_audio,
|
|
157
|
+
get_team_run_context_files,
|
|
158
|
+
get_team_run_context_images,
|
|
159
|
+
get_team_run_context_videos,
|
|
160
|
+
)
|
|
135
161
|
from agno.utils.timer import Timer
|
|
136
162
|
|
|
137
163
|
|
|
@@ -640,21 +666,20 @@ class Team:
|
|
|
640
666
|
self.videos: Optional[List[Video]] = None
|
|
641
667
|
|
|
642
668
|
# Team session
|
|
643
|
-
self.
|
|
669
|
+
self._cached_session: Optional[TeamSession] = None
|
|
644
670
|
|
|
645
671
|
self._tool_instructions: Optional[List[str]] = None
|
|
646
|
-
self._functions_for_model: Optional[Dict[str, Function]] = None
|
|
647
|
-
self._tools_for_model: Optional[List[Dict[str, Any]]] = None
|
|
648
672
|
|
|
649
673
|
# True if we should parse a member response model
|
|
650
674
|
self._member_response_model: Optional[Type[BaseModel]] = None
|
|
651
675
|
|
|
652
676
|
self._formatter: Optional[SafeFormatter] = None
|
|
653
677
|
|
|
654
|
-
self._rebuild_tools = True
|
|
655
|
-
|
|
656
678
|
self._hooks_normalised = False
|
|
657
679
|
|
|
680
|
+
# List of MCP tools that were initialized on the last run
|
|
681
|
+
self._mcp_tools_initialized_on_run: List[Any] = []
|
|
682
|
+
|
|
658
683
|
# Lazy-initialized shared thread pool executor for background tasks (memory, cultural knowledge, etc.)
|
|
659
684
|
self._background_executor: Optional[Any] = None
|
|
660
685
|
|
|
@@ -675,6 +700,10 @@ class Team:
|
|
|
675
700
|
def should_parse_structured_output(self) -> bool:
|
|
676
701
|
return self.output_schema is not None and self.parse_response and self.parser_model is None
|
|
677
702
|
|
|
703
|
+
@property
|
|
704
|
+
def cached_session(self) -> Optional[TeamSession]:
|
|
705
|
+
return self._cached_session
|
|
706
|
+
|
|
678
707
|
def set_id(self) -> None:
|
|
679
708
|
"""Set the ID of the team if not set yet.
|
|
680
709
|
|
|
@@ -757,10 +786,21 @@ class Team:
|
|
|
757
786
|
member.team_id = self.id
|
|
758
787
|
member.set_id()
|
|
759
788
|
|
|
789
|
+
# Inherit team models if agent has no explicit model
|
|
790
|
+
for model_type in ["model", "reasoning_model", "parser_model", "output_model"]:
|
|
791
|
+
if getattr(member, model_type) is None and getattr(self, model_type) is not None:
|
|
792
|
+
setattr(member, model_type, getattr(self, model_type))
|
|
793
|
+
log_info(
|
|
794
|
+
f"Agent '{member.name or member.id}' inheriting {model_type} from Team: {getattr(self, model_type).id}"
|
|
795
|
+
)
|
|
796
|
+
|
|
760
797
|
elif isinstance(member, Team):
|
|
761
798
|
member.parent_team_id = self.id
|
|
799
|
+
# Initialize the sub-team's model first so it has its model set
|
|
800
|
+
member._set_default_model()
|
|
801
|
+
# Then let the sub-team initialize its own members so they inherit from the sub-team
|
|
762
802
|
for sub_member in member.members:
|
|
763
|
-
|
|
803
|
+
member._initialize_member(sub_member, debug_mode=debug_mode)
|
|
764
804
|
|
|
765
805
|
def _set_default_model(self) -> None:
|
|
766
806
|
# Set the default model
|
|
@@ -892,7 +932,8 @@ class Team:
|
|
|
892
932
|
def set_tools(self, tools: List[Union[Toolkit, Callable, Function, Dict]]):
|
|
893
933
|
self.tools = tools
|
|
894
934
|
|
|
895
|
-
|
|
935
|
+
@staticmethod
|
|
936
|
+
def cancel_run(run_id: str) -> bool:
|
|
896
937
|
"""Cancel a running team execution.
|
|
897
938
|
|
|
898
939
|
Args:
|
|
@@ -903,6 +944,21 @@ class Team:
|
|
|
903
944
|
"""
|
|
904
945
|
return cancel_run_global(run_id)
|
|
905
946
|
|
|
947
|
+
async def _connect_mcp_tools(self) -> None:
|
|
948
|
+
"""Connect the MCP tools to the agent."""
|
|
949
|
+
if self.tools is not None:
|
|
950
|
+
for tool in self.tools:
|
|
951
|
+
if tool.__class__.__name__ in ["MCPTools", "MultiMCPTools"] and not tool.initialized: # type: ignore
|
|
952
|
+
# Connect the MCP server
|
|
953
|
+
await tool.connect() # type: ignore
|
|
954
|
+
self._mcp_tools_initialized_on_run.append(tool)
|
|
955
|
+
|
|
956
|
+
async def _disconnect_mcp_tools(self) -> None:
|
|
957
|
+
"""Disconnect the MCP tools from the agent."""
|
|
958
|
+
for tool in self._mcp_tools_initialized_on_run:
|
|
959
|
+
await tool.close()
|
|
960
|
+
self._mcp_tools_initialized_on_run = []
|
|
961
|
+
|
|
906
962
|
def _execute_pre_hooks(
|
|
907
963
|
self,
|
|
908
964
|
hooks: Optional[List[Callable[..., Any]]],
|
|
@@ -1012,7 +1068,9 @@ class Team:
|
|
|
1012
1068
|
# Filter arguments to only include those that the hook accepts
|
|
1013
1069
|
filtered_args = filter_hook_args(hook, all_args)
|
|
1014
1070
|
|
|
1015
|
-
|
|
1071
|
+
from inspect import iscoroutinefunction
|
|
1072
|
+
|
|
1073
|
+
if iscoroutinefunction(hook):
|
|
1016
1074
|
await hook(**filtered_args)
|
|
1017
1075
|
else:
|
|
1018
1076
|
# Synchronous function
|
|
@@ -1143,7 +1201,9 @@ class Team:
|
|
|
1143
1201
|
# Filter arguments to only include those that the hook accepts
|
|
1144
1202
|
filtered_args = filter_hook_args(hook, all_args)
|
|
1145
1203
|
|
|
1146
|
-
|
|
1204
|
+
from inspect import iscoroutinefunction
|
|
1205
|
+
|
|
1206
|
+
if iscoroutinefunction(hook):
|
|
1147
1207
|
await hook(**filtered_args)
|
|
1148
1208
|
else:
|
|
1149
1209
|
hook(**filtered_args)
|
|
@@ -1224,7 +1284,7 @@ class Team:
|
|
|
1224
1284
|
# Initialize team run context
|
|
1225
1285
|
team_run_context: Dict[str, Any] = {}
|
|
1226
1286
|
|
|
1227
|
-
self.
|
|
1287
|
+
_tools = self._determine_tools_for_model(
|
|
1228
1288
|
model=self.model,
|
|
1229
1289
|
run_response=run_response,
|
|
1230
1290
|
team_run_context=team_run_context,
|
|
@@ -1263,6 +1323,7 @@ class Team:
|
|
|
1263
1323
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
1264
1324
|
add_session_state_to_context=add_session_state_to_context,
|
|
1265
1325
|
metadata=metadata,
|
|
1326
|
+
tools=_tools,
|
|
1266
1327
|
**kwargs,
|
|
1267
1328
|
)
|
|
1268
1329
|
if len(run_messages.messages) == 0:
|
|
@@ -1292,8 +1353,7 @@ class Team:
|
|
|
1292
1353
|
model_response: ModelResponse = self.model.response(
|
|
1293
1354
|
messages=run_messages.messages,
|
|
1294
1355
|
response_format=response_format,
|
|
1295
|
-
tools=
|
|
1296
|
-
functions=self._functions_for_model,
|
|
1356
|
+
tools=_tools,
|
|
1297
1357
|
tool_choice=self.tool_choice,
|
|
1298
1358
|
tool_call_limit=self.tool_call_limit,
|
|
1299
1359
|
send_media_to_model=self.send_media_to_model,
|
|
@@ -1436,7 +1496,7 @@ class Team:
|
|
|
1436
1496
|
# Initialize team run context
|
|
1437
1497
|
team_run_context: Dict[str, Any] = {}
|
|
1438
1498
|
|
|
1439
|
-
self.
|
|
1499
|
+
_tools = self._determine_tools_for_model(
|
|
1440
1500
|
model=self.model,
|
|
1441
1501
|
run_response=run_response,
|
|
1442
1502
|
team_run_context=team_run_context,
|
|
@@ -1475,6 +1535,7 @@ class Team:
|
|
|
1475
1535
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
1476
1536
|
add_session_state_to_context=add_session_state_to_context,
|
|
1477
1537
|
metadata=metadata,
|
|
1538
|
+
tools=_tools,
|
|
1478
1539
|
**kwargs,
|
|
1479
1540
|
)
|
|
1480
1541
|
if len(run_messages.messages) == 0:
|
|
@@ -1518,6 +1579,7 @@ class Team:
|
|
|
1518
1579
|
session=session,
|
|
1519
1580
|
run_response=run_response,
|
|
1520
1581
|
run_messages=run_messages,
|
|
1582
|
+
tools=_tools,
|
|
1521
1583
|
response_format=response_format,
|
|
1522
1584
|
stream_events=stream_events,
|
|
1523
1585
|
):
|
|
@@ -1528,6 +1590,7 @@ class Team:
|
|
|
1528
1590
|
session=session,
|
|
1529
1591
|
run_response=run_response,
|
|
1530
1592
|
run_messages=run_messages,
|
|
1593
|
+
tools=_tools,
|
|
1531
1594
|
response_format=response_format,
|
|
1532
1595
|
stream_events=stream_events,
|
|
1533
1596
|
):
|
|
@@ -2041,7 +2104,8 @@ class Team:
|
|
|
2041
2104
|
# 4. Determine tools for model
|
|
2042
2105
|
team_run_context: Dict[str, Any] = {}
|
|
2043
2106
|
self.model = cast(Model, self.model)
|
|
2044
|
-
self.
|
|
2107
|
+
await self._check_and_refresh_mcp_tools()
|
|
2108
|
+
_tools = self._determine_tools_for_model(
|
|
2045
2109
|
model=self.model,
|
|
2046
2110
|
run_response=run_response,
|
|
2047
2111
|
team_run_context=team_run_context,
|
|
@@ -2079,6 +2143,8 @@ class Team:
|
|
|
2079
2143
|
dependencies=dependencies,
|
|
2080
2144
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
2081
2145
|
add_session_state_to_context=add_session_state_to_context,
|
|
2146
|
+
metadata=metadata,
|
|
2147
|
+
tools=_tools,
|
|
2082
2148
|
**kwargs,
|
|
2083
2149
|
)
|
|
2084
2150
|
|
|
@@ -2086,8 +2152,6 @@ class Team:
|
|
|
2086
2152
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2087
2153
|
|
|
2088
2154
|
# 6. Start memory creation in background task
|
|
2089
|
-
import asyncio
|
|
2090
|
-
|
|
2091
2155
|
memory_task = None
|
|
2092
2156
|
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
2093
2157
|
log_debug("Starting memory creation in background task.")
|
|
@@ -2107,8 +2171,7 @@ class Team:
|
|
|
2107
2171
|
# 8. Get the model response for the team leader
|
|
2108
2172
|
model_response = await self.model.aresponse(
|
|
2109
2173
|
messages=run_messages.messages,
|
|
2110
|
-
tools=
|
|
2111
|
-
functions=self._functions_for_model,
|
|
2174
|
+
tools=_tools,
|
|
2112
2175
|
tool_choice=self.tool_choice,
|
|
2113
2176
|
tool_call_limit=self.tool_call_limit,
|
|
2114
2177
|
response_format=response_format,
|
|
@@ -2189,6 +2252,7 @@ class Team:
|
|
|
2189
2252
|
|
|
2190
2253
|
return run_response
|
|
2191
2254
|
finally:
|
|
2255
|
+
await self._disconnect_mcp_tools()
|
|
2192
2256
|
# Cancel the memory task if it's still running
|
|
2193
2257
|
if memory_task is not None and not memory_task.done():
|
|
2194
2258
|
memory_task.cancel()
|
|
@@ -2277,7 +2341,8 @@ class Team:
|
|
|
2277
2341
|
# 5. Determine tools for model
|
|
2278
2342
|
team_run_context: Dict[str, Any] = {}
|
|
2279
2343
|
self.model = cast(Model, self.model)
|
|
2280
|
-
self.
|
|
2344
|
+
await self._check_and_refresh_mcp_tools()
|
|
2345
|
+
_tools = self._determine_tools_for_model(
|
|
2281
2346
|
model=self.model,
|
|
2282
2347
|
run_response=run_response,
|
|
2283
2348
|
team_run_context=team_run_context,
|
|
@@ -2314,14 +2379,13 @@ class Team:
|
|
|
2314
2379
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
2315
2380
|
add_session_state_to_context=add_session_state_to_context,
|
|
2316
2381
|
metadata=metadata,
|
|
2382
|
+
tools=_tools,
|
|
2317
2383
|
**kwargs,
|
|
2318
2384
|
)
|
|
2319
2385
|
|
|
2320
2386
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2321
2387
|
|
|
2322
2388
|
# 7. Start memory creation in background task
|
|
2323
|
-
import asyncio
|
|
2324
|
-
|
|
2325
2389
|
memory_task = None
|
|
2326
2390
|
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
2327
2391
|
log_debug("Starting memory creation in background task.")
|
|
@@ -2361,6 +2425,7 @@ class Team:
|
|
|
2361
2425
|
session=team_session,
|
|
2362
2426
|
run_response=run_response,
|
|
2363
2427
|
run_messages=run_messages,
|
|
2428
|
+
tools=_tools,
|
|
2364
2429
|
response_format=response_format,
|
|
2365
2430
|
stream_events=stream_events,
|
|
2366
2431
|
):
|
|
@@ -2371,6 +2436,7 @@ class Team:
|
|
|
2371
2436
|
session=team_session,
|
|
2372
2437
|
run_response=run_response,
|
|
2373
2438
|
run_messages=run_messages,
|
|
2439
|
+
tools=_tools,
|
|
2374
2440
|
response_format=response_format,
|
|
2375
2441
|
stream_events=stream_events,
|
|
2376
2442
|
):
|
|
@@ -2512,6 +2578,7 @@ class Team:
|
|
|
2512
2578
|
await self._acleanup_and_store(run_response=run_response, session=team_session)
|
|
2513
2579
|
|
|
2514
2580
|
finally:
|
|
2581
|
+
await self._disconnect_mcp_tools()
|
|
2515
2582
|
# Cancel the memory task if it's still running
|
|
2516
2583
|
if memory_task is not None and not memory_task.done():
|
|
2517
2584
|
memory_task.cancel()
|
|
@@ -2873,6 +2940,7 @@ class Team:
|
|
|
2873
2940
|
session: TeamSession,
|
|
2874
2941
|
run_response: TeamRunOutput,
|
|
2875
2942
|
run_messages: RunMessages,
|
|
2943
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
2876
2944
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2877
2945
|
stream_events: bool = False,
|
|
2878
2946
|
) -> Iterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
@@ -2892,8 +2960,7 @@ class Team:
|
|
|
2892
2960
|
for model_response_event in self.model.response_stream(
|
|
2893
2961
|
messages=run_messages.messages,
|
|
2894
2962
|
response_format=response_format,
|
|
2895
|
-
tools=
|
|
2896
|
-
functions=self._functions_for_model,
|
|
2963
|
+
tools=tools,
|
|
2897
2964
|
tool_choice=self.tool_choice,
|
|
2898
2965
|
tool_call_limit=self.tool_call_limit,
|
|
2899
2966
|
stream_model_response=stream_model_response,
|
|
@@ -2955,6 +3022,7 @@ class Team:
|
|
|
2955
3022
|
session: TeamSession,
|
|
2956
3023
|
run_response: TeamRunOutput,
|
|
2957
3024
|
run_messages: RunMessages,
|
|
3025
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
2958
3026
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2959
3027
|
stream_events: bool = False,
|
|
2960
3028
|
) -> AsyncIterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
@@ -2974,8 +3042,7 @@ class Team:
|
|
|
2974
3042
|
model_stream = self.model.aresponse_stream(
|
|
2975
3043
|
messages=run_messages.messages,
|
|
2976
3044
|
response_format=response_format,
|
|
2977
|
-
tools=
|
|
2978
|
-
functions=self._functions_for_model,
|
|
3045
|
+
tools=tools,
|
|
2979
3046
|
tool_choice=self.tool_choice,
|
|
2980
3047
|
tool_call_limit=self.tool_call_limit,
|
|
2981
3048
|
stream_model_response=stream_model_response,
|
|
@@ -3379,7 +3446,7 @@ class Team:
|
|
|
3379
3446
|
self._update_session_metrics(session=session)
|
|
3380
3447
|
|
|
3381
3448
|
# Save session to memory
|
|
3382
|
-
self.
|
|
3449
|
+
await self.asave_session(session=session)
|
|
3383
3450
|
|
|
3384
3451
|
def _make_memories(
|
|
3385
3452
|
self,
|
|
@@ -4882,7 +4949,30 @@ class Team:
|
|
|
4882
4949
|
except Exception as e:
|
|
4883
4950
|
log_warning(f"Failed to resolve context for '{key}': {e}")
|
|
4884
4951
|
|
|
4885
|
-
def
|
|
4952
|
+
async def _check_and_refresh_mcp_tools(self) -> None:
|
|
4953
|
+
# Connect MCP tools
|
|
4954
|
+
await self._connect_mcp_tools()
|
|
4955
|
+
|
|
4956
|
+
# Add provided tools
|
|
4957
|
+
if self.tools is not None:
|
|
4958
|
+
for tool in self.tools:
|
|
4959
|
+
if tool.__class__.__name__ in ["MCPTools", "MultiMCPTools"]:
|
|
4960
|
+
if tool.refresh_connection: # type: ignore
|
|
4961
|
+
try:
|
|
4962
|
+
is_alive = await tool.is_alive() # type: ignore
|
|
4963
|
+
if not is_alive:
|
|
4964
|
+
await tool.connect(force=True) # type: ignore
|
|
4965
|
+
except (RuntimeError, BaseException) as e:
|
|
4966
|
+
log_warning(f"Failed to check if MCP tool is alive: {e}")
|
|
4967
|
+
continue
|
|
4968
|
+
|
|
4969
|
+
try:
|
|
4970
|
+
await tool.build_tools() # type: ignore
|
|
4971
|
+
except (RuntimeError, BaseException) as e:
|
|
4972
|
+
log_warning(f"Failed to build tools for {str(tool)}: {e}")
|
|
4973
|
+
continue
|
|
4974
|
+
|
|
4975
|
+
def _determine_tools_for_model(
|
|
4886
4976
|
self,
|
|
4887
4977
|
model: Model,
|
|
4888
4978
|
run_response: TeamRunOutput,
|
|
@@ -4903,13 +4993,18 @@ class Team:
|
|
|
4903
4993
|
add_dependencies_to_context: Optional[bool] = None,
|
|
4904
4994
|
add_session_state_to_context: Optional[bool] = None,
|
|
4905
4995
|
metadata: Optional[Dict[str, Any]] = None,
|
|
4906
|
-
|
|
4996
|
+
check_mcp_tools: bool = True,
|
|
4997
|
+
) -> List[Union[Function, dict]]:
|
|
4907
4998
|
# Prepare tools
|
|
4908
4999
|
_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
4909
5000
|
|
|
4910
5001
|
# Add provided tools
|
|
4911
5002
|
if self.tools is not None:
|
|
4912
5003
|
for tool in self.tools:
|
|
5004
|
+
if tool.__class__.__name__ in ["MCPTools", "MultiMCPTools"]:
|
|
5005
|
+
# Only add the tool if it successfully connected and built its tools
|
|
5006
|
+
if check_mcp_tools and not tool.initialized: # type: ignore
|
|
5007
|
+
continue
|
|
4913
5008
|
_tools.append(tool)
|
|
4914
5009
|
|
|
4915
5010
|
if self.read_chat_history:
|
|
@@ -4924,7 +5019,7 @@ class Team:
|
|
|
4924
5019
|
if self.search_session_history:
|
|
4925
5020
|
_tools.append(
|
|
4926
5021
|
self._get_previous_sessions_messages_function(
|
|
4927
|
-
num_history_sessions=self.num_history_sessions, user_id=user_id
|
|
5022
|
+
num_history_sessions=self.num_history_sessions, user_id=user_id, async_mode=async_mode
|
|
4928
5023
|
)
|
|
4929
5024
|
)
|
|
4930
5025
|
|
|
@@ -5002,14 +5097,13 @@ class Team:
|
|
|
5002
5097
|
if self.get_member_information_tool:
|
|
5003
5098
|
_tools.append(self.get_member_information)
|
|
5004
5099
|
|
|
5005
|
-
self._functions_for_model = {}
|
|
5006
|
-
self._tools_for_model = []
|
|
5007
|
-
self._tool_instructions = []
|
|
5008
|
-
|
|
5009
5100
|
# Get Agent tools
|
|
5010
5101
|
if len(_tools) > 0:
|
|
5011
5102
|
log_debug("Processing tools for model")
|
|
5012
5103
|
|
|
5104
|
+
_function_names = []
|
|
5105
|
+
_functions: List[Union[Function, dict]] = []
|
|
5106
|
+
|
|
5013
5107
|
# Check if we need strict mode for the model
|
|
5014
5108
|
strict = False
|
|
5015
5109
|
if self.output_schema is not None and not self.use_json_mode and model.supports_native_structured_outputs:
|
|
@@ -5019,25 +5113,25 @@ class Team:
|
|
|
5019
5113
|
if isinstance(tool, Dict):
|
|
5020
5114
|
# If a dict is passed, it is a builtin tool
|
|
5021
5115
|
# that is run by the model provider and not the Agent
|
|
5022
|
-
|
|
5116
|
+
_functions.append(tool)
|
|
5023
5117
|
log_debug(f"Included builtin tool {tool}")
|
|
5024
5118
|
|
|
5025
5119
|
elif isinstance(tool, Toolkit):
|
|
5026
5120
|
# For each function in the toolkit and process entrypoint
|
|
5027
|
-
for name,
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5121
|
+
for name, _func in tool.functions.items():
|
|
5122
|
+
if name in _function_names:
|
|
5123
|
+
continue
|
|
5124
|
+
_function_names.append(name)
|
|
5125
|
+
_func = _func.model_copy(deep=True)
|
|
5126
|
+
|
|
5127
|
+
_func._team = self
|
|
5128
|
+
_func.process_entrypoint(strict=strict)
|
|
5129
|
+
if strict:
|
|
5130
|
+
_func.strict = True
|
|
5131
|
+
if self.tool_hooks:
|
|
5132
|
+
_func.tool_hooks = self.tool_hooks
|
|
5133
|
+
_functions.append(_func)
|
|
5134
|
+
log_debug(f"Added tool {_func.name} from {tool.name}")
|
|
5041
5135
|
|
|
5042
5136
|
# Add instructions from the toolkit
|
|
5043
5137
|
if tool.add_instructions and tool.instructions is not None:
|
|
@@ -5046,18 +5140,18 @@ class Team:
|
|
|
5046
5140
|
self._tool_instructions.append(tool.instructions)
|
|
5047
5141
|
|
|
5048
5142
|
elif isinstance(tool, Function):
|
|
5049
|
-
if tool.name
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5143
|
+
if tool.name in _function_names:
|
|
5144
|
+
continue
|
|
5145
|
+
_function_names.append(tool.name)
|
|
5146
|
+
tool = tool.model_copy(deep=True)
|
|
5147
|
+
tool._team = self
|
|
5148
|
+
tool.process_entrypoint(strict=strict)
|
|
5149
|
+
if strict and tool.strict is None:
|
|
5150
|
+
tool.strict = True
|
|
5151
|
+
if self.tool_hooks:
|
|
5152
|
+
tool.tool_hooks = self.tool_hooks
|
|
5153
|
+
_functions.append(tool)
|
|
5154
|
+
log_debug(f"Added tool {tool.name}")
|
|
5061
5155
|
|
|
5062
5156
|
# Add instructions from the Function
|
|
5063
5157
|
if tool.add_instructions and tool.instructions is not None:
|
|
@@ -5068,43 +5162,49 @@ class Team:
|
|
|
5068
5162
|
elif callable(tool):
|
|
5069
5163
|
# We add the tools, which are callable functions
|
|
5070
5164
|
try:
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5165
|
+
_func = Function.from_callable(tool, strict=strict)
|
|
5166
|
+
_func = _func.model_copy(deep=True)
|
|
5167
|
+
if _func.name in _function_names:
|
|
5168
|
+
continue
|
|
5169
|
+
_function_names.append(_func.name)
|
|
5170
|
+
|
|
5171
|
+
_func._team = self
|
|
5075
5172
|
if strict:
|
|
5076
|
-
|
|
5173
|
+
_func.strict = True
|
|
5077
5174
|
if self.tool_hooks:
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
log_debug(f"Added tool {func.name}")
|
|
5175
|
+
_func.tool_hooks = self.tool_hooks
|
|
5176
|
+
_functions.append(_func)
|
|
5177
|
+
log_debug(f"Added tool {_func.name}")
|
|
5082
5178
|
except Exception as e:
|
|
5083
5179
|
log_warning(f"Could not add tool {tool}: {e}")
|
|
5084
5180
|
|
|
5085
|
-
if
|
|
5181
|
+
if _functions:
|
|
5086
5182
|
from inspect import signature
|
|
5087
5183
|
|
|
5088
5184
|
# Check if any functions need media before collecting
|
|
5089
5185
|
needs_media = any(
|
|
5090
5186
|
any(param in signature(func.entrypoint).parameters for param in ["images", "videos", "audios", "files"])
|
|
5091
|
-
for func in
|
|
5092
|
-
if func.entrypoint is not None
|
|
5187
|
+
for func in _functions
|
|
5188
|
+
if isinstance(func, Function) and func.entrypoint is not None
|
|
5093
5189
|
)
|
|
5094
5190
|
|
|
5095
|
-
if
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
joint_videos = collect_joint_videos(run_response.input, session) # type: ignore
|
|
5191
|
+
# Only collect media if functions actually need them
|
|
5192
|
+
joint_images = collect_joint_images(run_response.input, session) if needs_media else None # type: ignore
|
|
5193
|
+
joint_files = collect_joint_files(run_response.input) if needs_media else None # type: ignore
|
|
5194
|
+
joint_audios = collect_joint_audios(run_response.input, session) if needs_media else None # type: ignore
|
|
5195
|
+
joint_videos = collect_joint_videos(run_response.input, session) if needs_media else None # type: ignore
|
|
5101
5196
|
|
|
5102
|
-
|
|
5197
|
+
for func in _functions: # type: ignore
|
|
5198
|
+
if isinstance(func, Function):
|
|
5199
|
+
func._session_state = session_state
|
|
5200
|
+
func._dependencies = dependencies
|
|
5103
5201
|
func._images = joint_images
|
|
5104
5202
|
func._files = joint_files
|
|
5105
5203
|
func._audios = joint_audios
|
|
5106
5204
|
func._videos = joint_videos
|
|
5107
5205
|
|
|
5206
|
+
return _functions
|
|
5207
|
+
|
|
5108
5208
|
def get_members_system_message_content(self, indent: int = 0) -> str:
|
|
5109
5209
|
system_message_content = ""
|
|
5110
5210
|
for idx, member in enumerate(self.members):
|
|
@@ -5148,6 +5248,7 @@ class Team:
|
|
|
5148
5248
|
files: Optional[Sequence[File]] = None,
|
|
5149
5249
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
5150
5250
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5251
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5151
5252
|
add_session_state_to_context: Optional[bool] = None,
|
|
5152
5253
|
) -> Optional[Message]:
|
|
5153
5254
|
"""Get the system message for the team."""
|
|
@@ -5201,7 +5302,7 @@ class Team:
|
|
|
5201
5302
|
instructions.extend(_instructions)
|
|
5202
5303
|
|
|
5203
5304
|
# 1.2 Add instructions from the Model
|
|
5204
|
-
_model_instructions = self.model.get_instructions_for_model(
|
|
5305
|
+
_model_instructions = self.model.get_instructions_for_model(tools)
|
|
5205
5306
|
if _model_instructions is not None:
|
|
5206
5307
|
instructions.extend(_model_instructions)
|
|
5207
5308
|
|
|
@@ -5404,7 +5505,7 @@ class Team:
|
|
|
5404
5505
|
metadata=metadata,
|
|
5405
5506
|
)
|
|
5406
5507
|
|
|
5407
|
-
system_message_from_model = self.model.get_system_message_for_model(
|
|
5508
|
+
system_message_from_model = self.model.get_system_message_for_model(tools)
|
|
5408
5509
|
if system_message_from_model is not None:
|
|
5409
5510
|
system_message_content += system_message_from_model
|
|
5410
5511
|
|
|
@@ -5441,6 +5542,7 @@ class Team:
|
|
|
5441
5542
|
files: Optional[Sequence[File]] = None,
|
|
5442
5543
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
5443
5544
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5545
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5444
5546
|
add_session_state_to_context: Optional[bool] = None,
|
|
5445
5547
|
) -> Optional[Message]:
|
|
5446
5548
|
"""Get the system message for the team."""
|
|
@@ -5494,7 +5596,7 @@ class Team:
|
|
|
5494
5596
|
instructions.extend(_instructions)
|
|
5495
5597
|
|
|
5496
5598
|
# 1.2 Add instructions from the Model
|
|
5497
|
-
_model_instructions = self.model.get_instructions_for_model(
|
|
5599
|
+
_model_instructions = self.model.get_instructions_for_model(tools)
|
|
5498
5600
|
if _model_instructions is not None:
|
|
5499
5601
|
instructions.extend(_model_instructions)
|
|
5500
5602
|
|
|
@@ -5702,7 +5804,7 @@ class Team:
|
|
|
5702
5804
|
metadata=metadata,
|
|
5703
5805
|
)
|
|
5704
5806
|
|
|
5705
|
-
system_message_from_model = self.model.get_system_message_for_model(
|
|
5807
|
+
system_message_from_model = self.model.get_system_message_for_model(tools)
|
|
5706
5808
|
if system_message_from_model is not None:
|
|
5707
5809
|
system_message_content += system_message_from_model
|
|
5708
5810
|
|
|
@@ -5749,6 +5851,7 @@ class Team:
|
|
|
5749
5851
|
add_dependencies_to_context: Optional[bool] = None,
|
|
5750
5852
|
add_session_state_to_context: Optional[bool] = None,
|
|
5751
5853
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5854
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5752
5855
|
**kwargs: Any,
|
|
5753
5856
|
) -> RunMessages:
|
|
5754
5857
|
"""This function returns a RunMessages object with the following attributes:
|
|
@@ -5779,6 +5882,7 @@ class Team:
|
|
|
5779
5882
|
dependencies=dependencies,
|
|
5780
5883
|
metadata=metadata,
|
|
5781
5884
|
add_session_state_to_context=add_session_state_to_context,
|
|
5885
|
+
tools=tools,
|
|
5782
5886
|
)
|
|
5783
5887
|
if system_message is not None:
|
|
5784
5888
|
run_messages.system_message = system_message
|
|
@@ -5887,6 +5991,7 @@ class Team:
|
|
|
5887
5991
|
add_dependencies_to_context: Optional[bool] = None,
|
|
5888
5992
|
add_session_state_to_context: Optional[bool] = None,
|
|
5889
5993
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5994
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5890
5995
|
**kwargs: Any,
|
|
5891
5996
|
) -> RunMessages:
|
|
5892
5997
|
"""This function returns a RunMessages object with the following attributes:
|
|
@@ -5917,6 +6022,7 @@ class Team:
|
|
|
5917
6022
|
dependencies=dependencies,
|
|
5918
6023
|
metadata=metadata,
|
|
5919
6024
|
add_session_state_to_context=add_session_state_to_context,
|
|
6025
|
+
tools=tools,
|
|
5920
6026
|
)
|
|
5921
6027
|
if system_message is not None:
|
|
5922
6028
|
run_messages.system_message = system_message
|
|
@@ -6514,7 +6620,7 @@ class Team:
|
|
|
6514
6620
|
return f"Updated session state: {session_state}"
|
|
6515
6621
|
|
|
6516
6622
|
def _get_previous_sessions_messages_function(
|
|
6517
|
-
self, num_history_sessions: Optional[int] = 2, user_id: Optional[str] = None
|
|
6623
|
+
self, num_history_sessions: Optional[int] = 2, user_id: Optional[str] = None, async_mode: bool = False
|
|
6518
6624
|
):
|
|
6519
6625
|
"""Factory function to create a get_previous_session_messages function.
|
|
6520
6626
|
|
|
@@ -6591,13 +6697,22 @@ class Team:
|
|
|
6591
6697
|
return "Previous session messages not available"
|
|
6592
6698
|
|
|
6593
6699
|
self.db = cast(AsyncBaseDb, self.db)
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6700
|
+
if self._has_async_db():
|
|
6701
|
+
selected_sessions = await self.db.get_sessions( # type: ignore
|
|
6702
|
+
session_type=SessionType.TEAM,
|
|
6703
|
+
limit=num_history_sessions,
|
|
6704
|
+
user_id=user_id,
|
|
6705
|
+
sort_by="created_at",
|
|
6706
|
+
sort_order="desc",
|
|
6707
|
+
)
|
|
6708
|
+
else:
|
|
6709
|
+
selected_sessions = self.db.get_sessions( # type: ignore
|
|
6710
|
+
session_type=SessionType.TEAM,
|
|
6711
|
+
limit=num_history_sessions,
|
|
6712
|
+
user_id=user_id,
|
|
6713
|
+
sort_by="created_at",
|
|
6714
|
+
sort_order="desc",
|
|
6715
|
+
)
|
|
6601
6716
|
|
|
6602
6717
|
all_messages = []
|
|
6603
6718
|
seen_message_pairs = set()
|
|
@@ -6677,14 +6792,14 @@ class Team:
|
|
|
6677
6792
|
) -> Optional[str]:
|
|
6678
6793
|
team_member_interactions_str = None
|
|
6679
6794
|
if self.share_member_interactions:
|
|
6680
|
-
team_member_interactions_str =
|
|
6681
|
-
if context_images :=
|
|
6795
|
+
team_member_interactions_str = get_team_member_interactions_str(team_run_context=team_run_context) # type: ignore
|
|
6796
|
+
if context_images := get_team_run_context_images(team_run_context=team_run_context): # type: ignore
|
|
6682
6797
|
images.extend(context_images)
|
|
6683
|
-
if context_videos :=
|
|
6798
|
+
if context_videos := get_team_run_context_videos(team_run_context=team_run_context): # type: ignore
|
|
6684
6799
|
videos.extend(context_videos)
|
|
6685
|
-
if context_audio :=
|
|
6800
|
+
if context_audio := get_team_run_context_audio(team_run_context=team_run_context): # type: ignore
|
|
6686
6801
|
audio.extend(context_audio)
|
|
6687
|
-
if context_files :=
|
|
6802
|
+
if context_files := get_team_run_context_files(team_run_context=team_run_context): # type: ignore
|
|
6688
6803
|
files.extend(context_files)
|
|
6689
6804
|
return team_member_interactions_str
|
|
6690
6805
|
|
|
@@ -6751,6 +6866,11 @@ class Team:
|
|
|
6751
6866
|
# 1. Initialize the member agent
|
|
6752
6867
|
self._initialize_member(member_agent)
|
|
6753
6868
|
|
|
6869
|
+
# If team has send_media_to_model=False, ensure member agent also has it set to False
|
|
6870
|
+
# This allows tools to access files while preventing models from receiving them
|
|
6871
|
+
if not self.send_media_to_model:
|
|
6872
|
+
member_agent.send_media_to_model = False
|
|
6873
|
+
|
|
6754
6874
|
# 2. Handle respond_directly nuances
|
|
6755
6875
|
if self.respond_directly:
|
|
6756
6876
|
# Since we return the response directly from the member agent, we need to set the output schema from the team down.
|
|
@@ -6822,7 +6942,7 @@ class Team:
|
|
|
6822
6942
|
normalized_task = str(member_agent_task.content)
|
|
6823
6943
|
else:
|
|
6824
6944
|
normalized_task = ""
|
|
6825
|
-
|
|
6945
|
+
add_interaction_to_team_run_context(
|
|
6826
6946
|
team_run_context=team_run_context,
|
|
6827
6947
|
member_name=member_name,
|
|
6828
6948
|
task=normalized_task,
|
|
@@ -6880,6 +7000,7 @@ class Team:
|
|
|
6880
7000
|
use_agent_logger()
|
|
6881
7001
|
|
|
6882
7002
|
member_session_state_copy = copy(session_state)
|
|
7003
|
+
|
|
6883
7004
|
if stream:
|
|
6884
7005
|
member_agent_run_response_stream = member_agent.run(
|
|
6885
7006
|
input=member_agent_task if not history else history,
|
|
@@ -7006,6 +7127,7 @@ class Team:
|
|
|
7006
7127
|
use_agent_logger()
|
|
7007
7128
|
|
|
7008
7129
|
member_session_state_copy = copy(session_state)
|
|
7130
|
+
|
|
7009
7131
|
if stream:
|
|
7010
7132
|
member_agent_run_response_stream = member_agent.arun( # type: ignore
|
|
7011
7133
|
input=member_agent_task if not history else history,
|
|
@@ -7310,6 +7432,7 @@ class Team:
|
|
|
7310
7432
|
|
|
7311
7433
|
async def run_member_agent(agent=current_agent) -> str:
|
|
7312
7434
|
member_session_state_copy = copy(session_state)
|
|
7435
|
+
|
|
7313
7436
|
member_agent_run_response = await agent.arun(
|
|
7314
7437
|
input=member_agent_task if not history else history,
|
|
7315
7438
|
user_id=user_id,
|
|
@@ -7444,57 +7567,6 @@ class Team:
|
|
|
7444
7567
|
log_warning(f"Error upserting session into db: {e}")
|
|
7445
7568
|
return None
|
|
7446
7569
|
|
|
7447
|
-
def get_run_output(
|
|
7448
|
-
self, run_id: str, session_id: Optional[str] = None
|
|
7449
|
-
) -> Optional[Union[TeamRunOutput, RunOutput]]:
|
|
7450
|
-
"""
|
|
7451
|
-
Get a RunOutput from the database.
|
|
7452
|
-
|
|
7453
|
-
Args:
|
|
7454
|
-
run_id (str): The run_id to load from storage.
|
|
7455
|
-
session_id (Optional[str]): The session_id to load from storage.
|
|
7456
|
-
"""
|
|
7457
|
-
if self._team_session is not None:
|
|
7458
|
-
run_response = self._team_session.get_run(run_id=run_id)
|
|
7459
|
-
if run_response is not None:
|
|
7460
|
-
return run_response
|
|
7461
|
-
else:
|
|
7462
|
-
log_warning(f"RunOutput {run_id} not found in AgentSession {self._team_session.session_id}")
|
|
7463
|
-
return None
|
|
7464
|
-
else:
|
|
7465
|
-
team_session = self.get_session(session_id=session_id)
|
|
7466
|
-
if team_session is not None:
|
|
7467
|
-
run_response = team_session.get_run(run_id=run_id)
|
|
7468
|
-
if run_response is not None:
|
|
7469
|
-
return cast(TeamRunOutput, run_response)
|
|
7470
|
-
else:
|
|
7471
|
-
log_warning(f"RunOutput {run_id} not found in AgentSession {session_id}")
|
|
7472
|
-
return None
|
|
7473
|
-
|
|
7474
|
-
def get_last_run_output(self, session_id: Optional[str] = None) -> Optional[TeamRunOutput]:
|
|
7475
|
-
"""
|
|
7476
|
-
Get the last run response from the database.
|
|
7477
|
-
|
|
7478
|
-
Args:
|
|
7479
|
-
session_id (Optional[str]): The session_id to load from storage.
|
|
7480
|
-
|
|
7481
|
-
Returns:
|
|
7482
|
-
RunOutput: The last run response from the database.
|
|
7483
|
-
"""
|
|
7484
|
-
if self._team_session is not None and self._team_session.runs is not None and len(self._team_session.runs) > 0:
|
|
7485
|
-
run_response = self._team_session.runs[-1]
|
|
7486
|
-
if run_response is not None:
|
|
7487
|
-
return run_response # type: ignore
|
|
7488
|
-
else:
|
|
7489
|
-
agent_session = self.get_session(session_id=session_id)
|
|
7490
|
-
if agent_session is not None and agent_session.runs is not None and len(agent_session.runs) > 0:
|
|
7491
|
-
run_response = agent_session.runs[-1]
|
|
7492
|
-
if run_response is not None:
|
|
7493
|
-
return run_response # type: ignore
|
|
7494
|
-
else:
|
|
7495
|
-
log_warning(f"No run responses found in AgentSession {session_id}")
|
|
7496
|
-
return None
|
|
7497
|
-
|
|
7498
7570
|
def _read_or_create_session(self, session_id: str, user_id: Optional[str] = None) -> TeamSession:
|
|
7499
7571
|
"""Load the TeamSession from storage
|
|
7500
7572
|
|
|
@@ -7506,8 +7578,8 @@ class Team:
|
|
|
7506
7578
|
from agno.session.team import TeamSession
|
|
7507
7579
|
|
|
7508
7580
|
# Return existing session if we have one
|
|
7509
|
-
if self.
|
|
7510
|
-
return self.
|
|
7581
|
+
if self._cached_session is not None and self._cached_session.session_id == session_id:
|
|
7582
|
+
return self._cached_session
|
|
7511
7583
|
|
|
7512
7584
|
# Try to load from database
|
|
7513
7585
|
team_session = None
|
|
@@ -7534,7 +7606,7 @@ class Team:
|
|
|
7534
7606
|
|
|
7535
7607
|
# Cache the session if relevant
|
|
7536
7608
|
if team_session is not None and self.cache_session:
|
|
7537
|
-
self.
|
|
7609
|
+
self._cached_session = team_session
|
|
7538
7610
|
|
|
7539
7611
|
return team_session
|
|
7540
7612
|
|
|
@@ -7549,8 +7621,8 @@ class Team:
|
|
|
7549
7621
|
from agno.session.team import TeamSession
|
|
7550
7622
|
|
|
7551
7623
|
# Return existing session if we have one
|
|
7552
|
-
if self.
|
|
7553
|
-
return self.
|
|
7624
|
+
if self._cached_session is not None and self._cached_session.session_id == session_id:
|
|
7625
|
+
return self._cached_session
|
|
7554
7626
|
|
|
7555
7627
|
# Try to load from database
|
|
7556
7628
|
team_session = None
|
|
@@ -7575,10 +7647,116 @@ class Team:
|
|
|
7575
7647
|
|
|
7576
7648
|
# Cache the session if relevant
|
|
7577
7649
|
if team_session is not None and self.cache_session:
|
|
7578
|
-
self.
|
|
7650
|
+
self._cached_session = team_session
|
|
7579
7651
|
|
|
7580
7652
|
return team_session
|
|
7581
7653
|
|
|
7654
|
+
def _load_session_state(self, session: TeamSession, session_state: Dict[str, Any]) -> Dict[str, Any]:
|
|
7655
|
+
"""Load and return the stored session_state from the database, optionally merging it with the given one"""
|
|
7656
|
+
|
|
7657
|
+
from agno.utils.merge_dict import merge_dictionaries
|
|
7658
|
+
|
|
7659
|
+
# Get the session_state from the database and merge with proper precedence
|
|
7660
|
+
# At this point session_state contains: agent_defaults + run_params
|
|
7661
|
+
if session.session_data is not None and "session_state" in session.session_data:
|
|
7662
|
+
session_state_from_db = session.session_data.get("session_state")
|
|
7663
|
+
|
|
7664
|
+
if (
|
|
7665
|
+
session_state_from_db is not None
|
|
7666
|
+
and isinstance(session_state_from_db, dict)
|
|
7667
|
+
and len(session_state_from_db) > 0
|
|
7668
|
+
and not self.overwrite_db_session_state
|
|
7669
|
+
):
|
|
7670
|
+
# This preserves precedence: run_params > db_state > agent_defaults
|
|
7671
|
+
merged_state = session_state_from_db.copy()
|
|
7672
|
+
merge_dictionaries(merged_state, session_state)
|
|
7673
|
+
session_state.clear()
|
|
7674
|
+
session_state.update(merged_state)
|
|
7675
|
+
|
|
7676
|
+
# Update the session_state in the session
|
|
7677
|
+
if session.session_data is not None:
|
|
7678
|
+
session.session_data["session_state"] = session_state
|
|
7679
|
+
|
|
7680
|
+
return session_state
|
|
7681
|
+
|
|
7682
|
+
def _update_metadata(self, session: TeamSession):
|
|
7683
|
+
"""Update the extra_data in the session"""
|
|
7684
|
+
from agno.utils.merge_dict import merge_dictionaries
|
|
7685
|
+
|
|
7686
|
+
# Read metadata from the database
|
|
7687
|
+
if session.metadata is not None:
|
|
7688
|
+
# If metadata is set in the agent, update the database metadata with the agent's metadata
|
|
7689
|
+
if self.metadata is not None:
|
|
7690
|
+
# Updates agent's session metadata in place
|
|
7691
|
+
merge_dictionaries(session.metadata, self.metadata)
|
|
7692
|
+
# Update the current metadata with the metadata from the database which is updated in place
|
|
7693
|
+
self.metadata = session.metadata
|
|
7694
|
+
|
|
7695
|
+
# -*- Public convenience functions
|
|
7696
|
+
def get_run_output(
|
|
7697
|
+
self, run_id: str, session_id: Optional[str] = None
|
|
7698
|
+
) -> Optional[Union[TeamRunOutput, RunOutput]]:
|
|
7699
|
+
"""
|
|
7700
|
+
Get a RunOutput or TeamRunOutput from the database. Handles cached sessions.
|
|
7701
|
+
|
|
7702
|
+
Args:
|
|
7703
|
+
run_id (str): The run_id to load from storage.
|
|
7704
|
+
session_id (Optional[str]): The session_id to load from storage.
|
|
7705
|
+
"""
|
|
7706
|
+
if not session_id and not self.session_id:
|
|
7707
|
+
raise Exception("No session_id provided")
|
|
7708
|
+
|
|
7709
|
+
session_id_to_load = session_id or self.session_id
|
|
7710
|
+
return get_run_output_util(self, run_id=run_id, session_id=session_id_to_load)
|
|
7711
|
+
|
|
7712
|
+
async def aget_run_output(
|
|
7713
|
+
self, run_id: str, session_id: Optional[str] = None
|
|
7714
|
+
) -> Optional[Union[TeamRunOutput, RunOutput]]:
|
|
7715
|
+
"""
|
|
7716
|
+
Get a RunOutput or TeamRunOutput from the database. Handles cached sessions.
|
|
7717
|
+
|
|
7718
|
+
Args:
|
|
7719
|
+
run_id (str): The run_id to load from storage.
|
|
7720
|
+
session_id (Optional[str]): The session_id to load from storage.
|
|
7721
|
+
"""
|
|
7722
|
+
if not session_id and not self.session_id:
|
|
7723
|
+
raise Exception("No session_id provided")
|
|
7724
|
+
|
|
7725
|
+
session_id_to_load = session_id or self.session_id
|
|
7726
|
+
return await aget_run_output_util(self, run_id=run_id, session_id=session_id_to_load)
|
|
7727
|
+
|
|
7728
|
+
def get_last_run_output(self, session_id: Optional[str] = None) -> Optional[TeamRunOutput]:
|
|
7729
|
+
"""
|
|
7730
|
+
Get the last run response from the database.
|
|
7731
|
+
|
|
7732
|
+
Args:
|
|
7733
|
+
session_id (Optional[str]): The session_id to load from storage.
|
|
7734
|
+
|
|
7735
|
+
Returns:
|
|
7736
|
+
RunOutput: The last run response from the database.
|
|
7737
|
+
"""
|
|
7738
|
+
if not session_id and not self.session_id:
|
|
7739
|
+
raise Exception("No session_id provided")
|
|
7740
|
+
|
|
7741
|
+
session_id_to_load = session_id or self.session_id
|
|
7742
|
+
return cast(TeamRunOutput, get_last_run_output_util(self, session_id=session_id_to_load))
|
|
7743
|
+
|
|
7744
|
+
async def aget_last_run_output(self, session_id: Optional[str] = None) -> Optional[TeamRunOutput]:
|
|
7745
|
+
"""
|
|
7746
|
+
Get the last run response from the database.
|
|
7747
|
+
|
|
7748
|
+
Args:
|
|
7749
|
+
session_id (Optional[str]): The session_id to load from storage.
|
|
7750
|
+
|
|
7751
|
+
Returns:
|
|
7752
|
+
RunOutput: The last run response from the database.
|
|
7753
|
+
"""
|
|
7754
|
+
if not session_id and not self.session_id:
|
|
7755
|
+
raise Exception("No session_id provided")
|
|
7756
|
+
|
|
7757
|
+
session_id_to_load = session_id or self.session_id
|
|
7758
|
+
return cast(TeamRunOutput, await aget_last_run_output_util(self, session_id=session_id_to_load))
|
|
7759
|
+
|
|
7582
7760
|
def get_session(
|
|
7583
7761
|
self,
|
|
7584
7762
|
session_id: Optional[str] = None,
|
|
@@ -7592,14 +7770,17 @@ class Team:
|
|
|
7592
7770
|
TeamSession: The TeamSession loaded from the database or created if it does not exist.
|
|
7593
7771
|
"""
|
|
7594
7772
|
if not session_id and not self.session_id:
|
|
7595
|
-
|
|
7773
|
+
raise Exception("No session_id provided")
|
|
7596
7774
|
|
|
7597
7775
|
session_id_to_load = session_id or self.session_id
|
|
7598
7776
|
|
|
7599
7777
|
# If there is a cached session, return it
|
|
7600
|
-
if self.cache_session and hasattr(self, "
|
|
7601
|
-
if self.
|
|
7602
|
-
return self.
|
|
7778
|
+
if self.cache_session and hasattr(self, "_cached_session") and self._cached_session is not None:
|
|
7779
|
+
if self._cached_session.session_id == session_id_to_load:
|
|
7780
|
+
return self._cached_session
|
|
7781
|
+
|
|
7782
|
+
if self._has_async_db():
|
|
7783
|
+
raise ValueError("Async database not supported for get_session")
|
|
7603
7784
|
|
|
7604
7785
|
# Load and return the session from the database
|
|
7605
7786
|
if self.db is not None:
|
|
@@ -7633,30 +7814,44 @@ class Team:
|
|
|
7633
7814
|
TeamSession: The TeamSession loaded from the database or created if it does not exist.
|
|
7634
7815
|
"""
|
|
7635
7816
|
if not session_id and not self.session_id:
|
|
7636
|
-
|
|
7817
|
+
raise Exception("No session_id provided")
|
|
7637
7818
|
|
|
7638
7819
|
session_id_to_load = session_id or self.session_id
|
|
7639
7820
|
|
|
7640
7821
|
# If there is a cached session, return it
|
|
7641
|
-
if self.cache_session and hasattr(self, "
|
|
7642
|
-
if self.
|
|
7643
|
-
return self.
|
|
7822
|
+
if self.cache_session and hasattr(self, "_cached_session") and self._cached_session is not None:
|
|
7823
|
+
if self._cached_session.session_id == session_id_to_load:
|
|
7824
|
+
return self._cached_session
|
|
7644
7825
|
|
|
7645
7826
|
# Load and return the session from the database
|
|
7646
7827
|
if self.db is not None:
|
|
7647
|
-
|
|
7828
|
+
loaded_session = None
|
|
7829
|
+
# We have a standalone team, so we are loading a TeamSession
|
|
7830
|
+
if self.workflow_id is None:
|
|
7831
|
+
loaded_session = cast(TeamSession, await self._aread_session(session_id=session_id_to_load)) # type: ignore
|
|
7832
|
+
# We have a workflow team, so we are loading a WorkflowSession
|
|
7833
|
+
else:
|
|
7834
|
+
loaded_session = cast(WorkflowSession, await self._aread_session(session_id=session_id_to_load)) # type: ignore
|
|
7648
7835
|
|
|
7649
7836
|
# Cache the session if relevant
|
|
7650
|
-
if
|
|
7651
|
-
self.
|
|
7837
|
+
if loaded_session is not None and self.cache_session:
|
|
7838
|
+
self._cached_session = loaded_session
|
|
7652
7839
|
|
|
7653
|
-
return
|
|
7840
|
+
return loaded_session
|
|
7654
7841
|
|
|
7655
7842
|
log_debug(f"TeamSession {session_id_to_load} not found in db")
|
|
7656
7843
|
return None
|
|
7657
7844
|
|
|
7658
7845
|
def save_session(self, session: TeamSession) -> None:
|
|
7659
|
-
"""
|
|
7846
|
+
"""
|
|
7847
|
+
Save the TeamSession to storage
|
|
7848
|
+
|
|
7849
|
+
Args:
|
|
7850
|
+
session: The TeamSession to save.
|
|
7851
|
+
"""
|
|
7852
|
+
if self._has_async_db():
|
|
7853
|
+
raise ValueError("Async database not supported for save_session")
|
|
7854
|
+
|
|
7660
7855
|
if self.db is not None and self.parent_team_id is None and self.workflow_id is None:
|
|
7661
7856
|
if session.session_data is not None and "session_state" in session.session_data:
|
|
7662
7857
|
session.session_data["session_state"].pop("current_session_id", None) # type: ignore
|
|
@@ -7677,7 +7872,12 @@ class Team:
|
|
|
7677
7872
|
log_debug(f"Created or updated TeamSession record: {session.session_id}")
|
|
7678
7873
|
|
|
7679
7874
|
async def asave_session(self, session: TeamSession) -> None:
|
|
7680
|
-
"""
|
|
7875
|
+
"""
|
|
7876
|
+
Save the TeamSession to storage
|
|
7877
|
+
|
|
7878
|
+
Args:
|
|
7879
|
+
session: The TeamSession to save.
|
|
7880
|
+
"""
|
|
7681
7881
|
if self.db is not None and self.parent_team_id is None and self.workflow_id is None:
|
|
7682
7882
|
if session.session_data is not None and "session_state" in session.session_data:
|
|
7683
7883
|
session.session_data["session_state"].pop("current_session_id", None) # type: ignore
|
|
@@ -7696,49 +7896,15 @@ class Team:
|
|
|
7696
7896
|
self._upsert_session(session=session)
|
|
7697
7897
|
log_debug(f"Created or updated TeamSession record: {session.session_id}")
|
|
7698
7898
|
|
|
7699
|
-
def
|
|
7700
|
-
"""
|
|
7701
|
-
|
|
7702
|
-
from agno.utils.merge_dict import merge_dictionaries
|
|
7703
|
-
|
|
7704
|
-
# Get the session_state from the database and merge with proper precedence
|
|
7705
|
-
# At this point session_state contains: agent_defaults + run_params
|
|
7706
|
-
if session.session_data is not None and "session_state" in session.session_data:
|
|
7707
|
-
session_state_from_db = session.session_data.get("session_state")
|
|
7708
|
-
|
|
7709
|
-
if (
|
|
7710
|
-
session_state_from_db is not None
|
|
7711
|
-
and isinstance(session_state_from_db, dict)
|
|
7712
|
-
and len(session_state_from_db) > 0
|
|
7713
|
-
and not self.overwrite_db_session_state
|
|
7714
|
-
):
|
|
7715
|
-
# This preserves precedence: run_params > db_state > agent_defaults
|
|
7716
|
-
merged_state = session_state_from_db.copy()
|
|
7717
|
-
merge_dictionaries(merged_state, session_state)
|
|
7718
|
-
session_state.clear()
|
|
7719
|
-
session_state.update(merged_state)
|
|
7720
|
-
|
|
7721
|
-
# Update the session_state in the session
|
|
7722
|
-
if session.session_data is not None:
|
|
7723
|
-
session.session_data["session_state"] = session_state
|
|
7724
|
-
|
|
7725
|
-
return session_state
|
|
7726
|
-
|
|
7727
|
-
def _update_metadata(self, session: TeamSession):
|
|
7728
|
-
"""Update the extra_data in the session"""
|
|
7729
|
-
from agno.utils.merge_dict import merge_dictionaries
|
|
7730
|
-
|
|
7731
|
-
# Read metadata from the database
|
|
7732
|
-
if session.metadata is not None:
|
|
7733
|
-
# If metadata is set in the agent, update the database metadata with the agent's metadata
|
|
7734
|
-
if self.metadata is not None:
|
|
7735
|
-
# Updates agent's session metadata in place
|
|
7736
|
-
merge_dictionaries(session.metadata, self.metadata)
|
|
7737
|
-
# Update the current metadata with the metadata from the database which is updated in place
|
|
7738
|
-
self.metadata = session.metadata
|
|
7899
|
+
def generate_session_name(self, session: TeamSession) -> str:
|
|
7900
|
+
"""
|
|
7901
|
+
Generate a name for the team session
|
|
7739
7902
|
|
|
7740
|
-
|
|
7741
|
-
|
|
7903
|
+
Args:
|
|
7904
|
+
session: The TeamSession to generate a name for.
|
|
7905
|
+
Returns:
|
|
7906
|
+
str: The generated session name.
|
|
7907
|
+
"""
|
|
7742
7908
|
|
|
7743
7909
|
if self.model is None:
|
|
7744
7910
|
raise Exception("Model not set")
|
|
@@ -7766,62 +7932,113 @@ class Team:
|
|
|
7766
7932
|
content = generated_name.content
|
|
7767
7933
|
if content is None:
|
|
7768
7934
|
log_error("Generated name is None. Trying again.")
|
|
7769
|
-
return self.
|
|
7935
|
+
return self.generate_session_name(session=session)
|
|
7770
7936
|
if len(content.split()) > 15:
|
|
7771
7937
|
log_error("Generated name is too long. Trying again.")
|
|
7772
|
-
return self.
|
|
7938
|
+
return self.generate_session_name(session=session)
|
|
7773
7939
|
return content.replace('"', "").strip()
|
|
7774
7940
|
|
|
7775
7941
|
def set_session_name(
|
|
7776
7942
|
self, session_id: Optional[str] = None, autogenerate: bool = False, session_name: Optional[str] = None
|
|
7777
7943
|
) -> TeamSession:
|
|
7778
|
-
"""
|
|
7944
|
+
"""
|
|
7945
|
+
Set the session name and save to storage
|
|
7946
|
+
|
|
7947
|
+
Args:
|
|
7948
|
+
session_id: The session ID to set the name for. If not provided, the current cached session ID is used.
|
|
7949
|
+
autogenerate: Whether to autogenerate the session name.
|
|
7950
|
+
session_name: The session name to set. If not provided, the session name will be autogenerated.
|
|
7951
|
+
Returns:
|
|
7952
|
+
TeamSession: The updated session.
|
|
7953
|
+
"""
|
|
7779
7954
|
session_id = session_id or self.session_id
|
|
7780
7955
|
|
|
7781
7956
|
if session_id is None:
|
|
7782
7957
|
raise Exception("Session ID is not set")
|
|
7783
7958
|
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
raise Exception("Session not found")
|
|
7959
|
+
return cast(
|
|
7960
|
+
TeamSession,
|
|
7961
|
+
set_session_name_util(self, session_id=session_id, autogenerate=autogenerate, session_name=session_name),
|
|
7962
|
+
)
|
|
7789
7963
|
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
raise Exception("Session Name is not set")
|
|
7964
|
+
async def aset_session_name(
|
|
7965
|
+
self, session_id: Optional[str] = None, autogenerate: bool = False, session_name: Optional[str] = None
|
|
7966
|
+
) -> TeamSession:
|
|
7967
|
+
"""
|
|
7968
|
+
Set the session name and save to storage
|
|
7796
7969
|
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
session.
|
|
7970
|
+
Args:
|
|
7971
|
+
session_id: The session ID to set the name for. If not provided, the current cached session ID is used.
|
|
7972
|
+
autogenerate: Whether to autogenerate the session name.
|
|
7973
|
+
session_name: The session name to set. If not provided, the session name will be autogenerated.
|
|
7974
|
+
Returns:
|
|
7975
|
+
TeamSession: The updated session.
|
|
7976
|
+
"""
|
|
7977
|
+
session_id = session_id or self.session_id
|
|
7800
7978
|
|
|
7801
|
-
|
|
7802
|
-
|
|
7979
|
+
if session_id is None:
|
|
7980
|
+
raise Exception("Session ID is not set")
|
|
7803
7981
|
|
|
7804
|
-
return
|
|
7982
|
+
return cast(
|
|
7983
|
+
TeamSession,
|
|
7984
|
+
await aset_session_name_util(
|
|
7985
|
+
self, session_id=session_id, autogenerate=autogenerate, session_name=session_name
|
|
7986
|
+
),
|
|
7987
|
+
)
|
|
7805
7988
|
|
|
7806
7989
|
def get_session_name(self, session_id: Optional[str] = None) -> str:
|
|
7807
|
-
"""
|
|
7990
|
+
"""
|
|
7991
|
+
Get the session name for the given session ID.
|
|
7992
|
+
|
|
7993
|
+
Args:
|
|
7994
|
+
session_id: The session ID to get the name for. If not provided, the current cached session ID is used.
|
|
7995
|
+
Returns:
|
|
7996
|
+
str: The session name.
|
|
7997
|
+
"""
|
|
7808
7998
|
session_id = session_id or self.session_id
|
|
7809
7999
|
if session_id is None:
|
|
7810
8000
|
raise Exception("Session ID is not set")
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
8001
|
+
return get_session_name_util(self, session_id=session_id)
|
|
8002
|
+
|
|
8003
|
+
async def aget_session_name(self, session_id: Optional[str] = None) -> str:
|
|
8004
|
+
"""
|
|
8005
|
+
Get the session name for the given session ID.
|
|
8006
|
+
|
|
8007
|
+
Args:
|
|
8008
|
+
session_id: The session ID to get the name for. If not provided, the current cached session ID is used.
|
|
8009
|
+
Returns:
|
|
8010
|
+
str: The session name.
|
|
8011
|
+
"""
|
|
8012
|
+
session_id = session_id or self.session_id
|
|
8013
|
+
if session_id is None:
|
|
8014
|
+
raise Exception("Session ID is not set")
|
|
8015
|
+
return await aget_session_name_util(self, session_id=session_id)
|
|
7815
8016
|
|
|
7816
8017
|
def get_session_state(self, session_id: Optional[str] = None) -> Dict[str, Any]:
|
|
7817
|
-
"""Get the session state for the given session ID
|
|
8018
|
+
"""Get the session state for the given session ID.
|
|
8019
|
+
|
|
8020
|
+
Args:
|
|
8021
|
+
session_id: The session ID to get the state for. If not provided, the current cached session ID is used.
|
|
8022
|
+
Returns:
|
|
8023
|
+
Dict[str, Any]: The session state.
|
|
8024
|
+
"""
|
|
7818
8025
|
session_id = session_id or self.session_id
|
|
7819
8026
|
if session_id is None:
|
|
7820
8027
|
raise Exception("Session ID is not set")
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
8028
|
+
return get_session_state_util(self, session_id=session_id)
|
|
8029
|
+
|
|
8030
|
+
async def aget_session_state(self, session_id: Optional[str] = None) -> Dict[str, Any]:
|
|
8031
|
+
"""Get the session state for the given session ID.
|
|
8032
|
+
|
|
8033
|
+
Args:
|
|
8034
|
+
session_id: The session ID to get the state for. If not provided, the current cached session ID is used.
|
|
8035
|
+
Returns:
|
|
8036
|
+
Dict[str, Any]: The session state.
|
|
8037
|
+
"""
|
|
8038
|
+
session_id = session_id or self.session_id
|
|
8039
|
+
if session_id is None:
|
|
8040
|
+
raise Exception("Session ID is not set")
|
|
8041
|
+
return await aget_session_state_util(self, session_id=session_id)
|
|
7825
8042
|
|
|
7826
8043
|
def update_session_state(self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None) -> str:
|
|
7827
8044
|
"""
|
|
@@ -7835,19 +8052,7 @@ class Team:
|
|
|
7835
8052
|
session_id = session_id or self.session_id
|
|
7836
8053
|
if session_id is None:
|
|
7837
8054
|
raise Exception("Session ID is not set")
|
|
7838
|
-
|
|
7839
|
-
if session is None:
|
|
7840
|
-
raise Exception("Session not found")
|
|
7841
|
-
|
|
7842
|
-
if session.session_data is not None and "session_state" not in session.session_data:
|
|
7843
|
-
session.session_data["session_state"] = {}
|
|
7844
|
-
|
|
7845
|
-
for key, value in session_state_updates.items():
|
|
7846
|
-
session.session_data["session_state"][key] = value # type: ignore
|
|
7847
|
-
|
|
7848
|
-
self.save_session(session=session)
|
|
7849
|
-
|
|
7850
|
-
return session.session_data["session_state"] # type: ignore
|
|
8055
|
+
return update_session_state_util(self, session_state_updates=session_state_updates, session_id=session_id)
|
|
7851
8056
|
|
|
7852
8057
|
async def aupdate_session_state(
|
|
7853
8058
|
self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None
|
|
@@ -7863,64 +8068,117 @@ class Team:
|
|
|
7863
8068
|
session_id = session_id or self.session_id
|
|
7864
8069
|
if session_id is None:
|
|
7865
8070
|
raise Exception("Session ID is not set")
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
8071
|
+
return await aupdate_session_state_util(
|
|
8072
|
+
entity=self, session_state_updates=session_state_updates, session_id=session_id
|
|
8073
|
+
)
|
|
7869
8074
|
|
|
7870
|
-
|
|
7871
|
-
|
|
8075
|
+
def get_session_metrics(self, session_id: Optional[str] = None) -> Optional[Metrics]:
|
|
8076
|
+
"""Get the session metrics for the given session ID.
|
|
7872
8077
|
|
|
7873
|
-
|
|
7874
|
-
session.
|
|
8078
|
+
Args:
|
|
8079
|
+
session_id: The session ID to get the metrics for. If not provided, the current cached session ID is used.
|
|
8080
|
+
Returns:
|
|
8081
|
+
Optional[Metrics]: The session metrics.
|
|
8082
|
+
"""
|
|
8083
|
+
session_id = session_id or self.session_id
|
|
8084
|
+
if session_id is None:
|
|
8085
|
+
raise Exception("Session ID is not set")
|
|
7875
8086
|
|
|
7876
|
-
|
|
8087
|
+
return get_session_metrics_util(self, session_id=session_id)
|
|
7877
8088
|
|
|
7878
|
-
|
|
8089
|
+
async def aget_session_metrics(self, session_id: Optional[str] = None) -> Optional[Metrics]:
|
|
8090
|
+
"""Get the session metrics for the given session ID.
|
|
7879
8091
|
|
|
7880
|
-
|
|
7881
|
-
|
|
8092
|
+
Args:
|
|
8093
|
+
session_id: The session ID to get the metrics for. If not provided, the current cached session ID is used.
|
|
8094
|
+
Returns:
|
|
8095
|
+
Optional[Metrics]: The session metrics.
|
|
8096
|
+
"""
|
|
7882
8097
|
session_id = session_id or self.session_id
|
|
7883
8098
|
if session_id is None:
|
|
7884
8099
|
raise Exception("Session ID is not set")
|
|
7885
8100
|
|
|
7886
|
-
|
|
7887
|
-
if session is None:
|
|
7888
|
-
raise Exception("Session not found")
|
|
8101
|
+
return await aget_session_metrics_util(self, session_id=session_id)
|
|
7889
8102
|
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
return session.session_data.get("session_metrics")
|
|
7895
|
-
return None
|
|
8103
|
+
def delete_session(self, session_id: str):
|
|
8104
|
+
"""Delete the current session and save to storage"""
|
|
8105
|
+
if self.db is None:
|
|
8106
|
+
return
|
|
7896
8107
|
|
|
7897
|
-
|
|
8108
|
+
self.db.delete_session(session_id=session_id)
|
|
8109
|
+
|
|
8110
|
+
async def adelete_session(self, session_id: str):
|
|
7898
8111
|
"""Delete the current session and save to storage"""
|
|
7899
|
-
if self.db is
|
|
7900
|
-
|
|
8112
|
+
if self.db is None:
|
|
8113
|
+
return
|
|
8114
|
+
await self.db.delete_session(session_id=session_id) # type: ignore
|
|
7901
8115
|
|
|
7902
8116
|
def get_chat_history(self, session_id: Optional[str] = None) -> List[Message]:
|
|
7903
|
-
"""Read the chat history from the session
|
|
8117
|
+
"""Read the chat history from the session
|
|
8118
|
+
|
|
8119
|
+
Args:
|
|
8120
|
+
session_id: The session ID to get the chat history for. If not provided, the current cached session ID is used.
|
|
8121
|
+
Returns:
|
|
8122
|
+
List[Message]: The chat history from the session.
|
|
8123
|
+
"""
|
|
8124
|
+
session_id = session_id or self.session_id
|
|
8125
|
+
if session_id is None:
|
|
8126
|
+
raise Exception("Session ID is not set")
|
|
8127
|
+
|
|
8128
|
+
return get_chat_history_util(self, session_id=session_id)
|
|
8129
|
+
|
|
8130
|
+
async def aget_chat_history(self, session_id: Optional[str] = None) -> List[Message]:
|
|
8131
|
+
"""Read the chat history from the session
|
|
8132
|
+
|
|
8133
|
+
Args:
|
|
8134
|
+
session_id: The session ID to get the chat history for. If not provided, the current cached session ID is used.
|
|
8135
|
+
Returns:
|
|
8136
|
+
List[Message]: The chat history from the session.
|
|
8137
|
+
"""
|
|
8138
|
+
session_id = session_id or self.session_id
|
|
8139
|
+
if session_id is None:
|
|
8140
|
+
raise Exception("Session ID is not set")
|
|
8141
|
+
|
|
8142
|
+
return await aget_chat_history_util(self, session_id=session_id)
|
|
8143
|
+
|
|
8144
|
+
def get_messages_for_session(self, session_id: Optional[str] = None) -> List[Message]:
|
|
8145
|
+
"""Get messages for a session
|
|
8146
|
+
|
|
8147
|
+
Args:
|
|
8148
|
+
session_id: The session ID to get the messages for. If not provided, the current cached session ID is used.
|
|
8149
|
+
Returns:
|
|
8150
|
+
List[Message]: The messages for the session.
|
|
8151
|
+
"""
|
|
7904
8152
|
session_id = session_id or self.session_id
|
|
7905
8153
|
if session_id is None:
|
|
7906
|
-
log_warning("Session ID is not set, cannot get
|
|
8154
|
+
log_warning("Session ID is not set, cannot get messages for session")
|
|
7907
8155
|
return []
|
|
7908
8156
|
|
|
7909
8157
|
session = self.get_session(session_id=session_id) # type: ignore
|
|
7910
8158
|
|
|
7911
8159
|
if session is None:
|
|
7912
|
-
|
|
8160
|
+
log_warning(f"Session {session_id} not found")
|
|
8161
|
+
return []
|
|
7913
8162
|
|
|
7914
|
-
|
|
8163
|
+
# Only filter by agent_id if this is part of a team
|
|
8164
|
+
return session.get_messages_from_last_n_runs(
|
|
8165
|
+
team_id=self.id,
|
|
8166
|
+
)
|
|
7915
8167
|
|
|
7916
|
-
def
|
|
7917
|
-
"""Get messages for a session
|
|
8168
|
+
async def aget_messages_for_session(self, session_id: Optional[str] = None) -> List[Message]:
|
|
8169
|
+
"""Get messages for a session
|
|
8170
|
+
|
|
8171
|
+
Args:
|
|
8172
|
+
session_id: The session ID to get the messages for. If not provided, the current cached session ID is used.
|
|
8173
|
+
Returns:
|
|
8174
|
+
List[Message]: The messages for the session.
|
|
8175
|
+
"""
|
|
7918
8176
|
session_id = session_id or self.session_id
|
|
7919
8177
|
if session_id is None:
|
|
7920
8178
|
log_warning("Session ID is not set, cannot get messages for session")
|
|
7921
8179
|
return []
|
|
7922
8180
|
|
|
7923
|
-
session = self.
|
|
8181
|
+
session = await self.aget_session(session_id=session_id) # type: ignore
|
|
7924
8182
|
|
|
7925
8183
|
if session is None:
|
|
7926
8184
|
log_warning(f"Session {session_id} not found")
|
|
@@ -7931,8 +8189,14 @@ class Team:
|
|
|
7931
8189
|
team_id=self.id,
|
|
7932
8190
|
)
|
|
7933
8191
|
|
|
7934
|
-
def get_session_summary(self, session_id: Optional[str] = None):
|
|
7935
|
-
"""Get the session summary for the given session ID and user ID.
|
|
8192
|
+
def get_session_summary(self, session_id: Optional[str] = None) -> Optional[SessionSummary]:
|
|
8193
|
+
"""Get the session summary for the given session ID and user ID.
|
|
8194
|
+
|
|
8195
|
+
Args:
|
|
8196
|
+
session_id: The session ID to get the summary for. If not provided, the current cached session ID is used.
|
|
8197
|
+
Returns:
|
|
8198
|
+
SessionSummary: The session summary.
|
|
8199
|
+
"""
|
|
7936
8200
|
session_id = session_id if session_id is not None else self.session_id
|
|
7937
8201
|
if session_id is None:
|
|
7938
8202
|
raise ValueError("Session ID is required")
|
|
@@ -7944,8 +8208,33 @@ class Team:
|
|
|
7944
8208
|
|
|
7945
8209
|
return session.get_session_summary() # type: ignore
|
|
7946
8210
|
|
|
8211
|
+
async def aget_session_summary(self, session_id: Optional[str] = None) -> Optional[SessionSummary]:
|
|
8212
|
+
"""Get the session summary for the given session ID and user ID.
|
|
8213
|
+
|
|
8214
|
+
Args:
|
|
8215
|
+
session_id: The session ID to get the summary for. If not provided, the current cached session ID is used.
|
|
8216
|
+
Returns:
|
|
8217
|
+
SessionSummary: The session summary.
|
|
8218
|
+
"""
|
|
8219
|
+
session_id = session_id if session_id is not None else self.session_id
|
|
8220
|
+
if session_id is None:
|
|
8221
|
+
raise ValueError("Session ID is required")
|
|
8222
|
+
|
|
8223
|
+
session = await self.aget_session(session_id=session_id)
|
|
8224
|
+
|
|
8225
|
+
if session is None:
|
|
8226
|
+
raise Exception(f"Session {session_id} not found")
|
|
8227
|
+
|
|
8228
|
+
return session.get_session_summary() # type: ignore
|
|
8229
|
+
|
|
7947
8230
|
def get_user_memories(self, user_id: Optional[str] = None) -> Optional[List[UserMemory]]:
|
|
7948
|
-
"""Get the user memories for the given user ID.
|
|
8231
|
+
"""Get the user memories for the given user ID.
|
|
8232
|
+
|
|
8233
|
+
Args:
|
|
8234
|
+
user_id: The user ID to get the memories for. If not provided, the current cached user ID is used.
|
|
8235
|
+
Returns:
|
|
8236
|
+
Optional[List[UserMemory]]: The user memories.
|
|
8237
|
+
"""
|
|
7949
8238
|
if self.memory_manager is None:
|
|
7950
8239
|
return None
|
|
7951
8240
|
user_id = user_id if user_id is not None else self.user_id
|
|
@@ -7954,86 +8243,21 @@ class Team:
|
|
|
7954
8243
|
|
|
7955
8244
|
return self.memory_manager.get_user_memories(user_id=user_id)
|
|
7956
8245
|
|
|
7957
|
-
def
|
|
7958
|
-
|
|
7959
|
-
team_run_context: Dict[str, Any],
|
|
7960
|
-
member_name: str,
|
|
7961
|
-
task: str,
|
|
7962
|
-
run_response: Union[RunOutput, TeamRunOutput],
|
|
7963
|
-
) -> None:
|
|
7964
|
-
if "member_responses" not in team_run_context:
|
|
7965
|
-
team_run_context["member_responses"] = []
|
|
7966
|
-
team_run_context["member_responses"].append(
|
|
7967
|
-
{
|
|
7968
|
-
"member_name": member_name,
|
|
7969
|
-
"task": task,
|
|
7970
|
-
"run_response": run_response,
|
|
7971
|
-
}
|
|
7972
|
-
)
|
|
7973
|
-
log_debug(f"Updated team run context with member name: {member_name}")
|
|
8246
|
+
async def aget_user_memories(self, user_id: Optional[str] = None) -> Optional[List[UserMemory]]:
|
|
8247
|
+
"""Get the user memories for the given user ID.
|
|
7974
8248
|
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
response_dict = interaction["run_response"].to_dict()
|
|
7986
|
-
response_content = (
|
|
7987
|
-
response_dict.get("content")
|
|
7988
|
-
or ",".join([tool.get("content", "") for tool in response_dict.get("tools", [])])
|
|
7989
|
-
or ""
|
|
7990
|
-
)
|
|
7991
|
-
team_member_interactions_str += f"Member: {interaction['member_name']}\n"
|
|
7992
|
-
team_member_interactions_str += f"Task: {interaction['task']}\n"
|
|
7993
|
-
team_member_interactions_str += f"Response: {response_content}\n"
|
|
7994
|
-
team_member_interactions_str += "\n"
|
|
7995
|
-
team_member_interactions_str += "</member_interaction_context>\n"
|
|
7996
|
-
return team_member_interactions_str
|
|
8249
|
+
Args:
|
|
8250
|
+
user_id: The user ID to get the memories for. If not provided, the current cached user ID is used.
|
|
8251
|
+
Returns:
|
|
8252
|
+
Optional[List[UserMemory]]: The user memories.
|
|
8253
|
+
"""
|
|
8254
|
+
if self.memory_manager is None:
|
|
8255
|
+
return None
|
|
8256
|
+
user_id = user_id if user_id is not None else self.user_id
|
|
8257
|
+
if user_id is None:
|
|
8258
|
+
user_id = "default"
|
|
7997
8259
|
|
|
7998
|
-
|
|
7999
|
-
if not team_run_context:
|
|
8000
|
-
return []
|
|
8001
|
-
images = []
|
|
8002
|
-
if "member_responses" in team_run_context:
|
|
8003
|
-
for interaction in team_run_context["member_responses"]:
|
|
8004
|
-
if interaction["run_response"].images:
|
|
8005
|
-
images.extend(interaction["run_response"].images)
|
|
8006
|
-
return images
|
|
8007
|
-
|
|
8008
|
-
def _get_team_run_context_videos(self, team_run_context: Dict[str, Any]) -> List[Video]:
|
|
8009
|
-
if not team_run_context:
|
|
8010
|
-
return []
|
|
8011
|
-
videos = []
|
|
8012
|
-
if "member_responses" in team_run_context:
|
|
8013
|
-
for interaction in team_run_context["member_responses"]:
|
|
8014
|
-
if interaction["run_response"].videos:
|
|
8015
|
-
videos.extend(interaction["run_response"].videos)
|
|
8016
|
-
return videos
|
|
8017
|
-
|
|
8018
|
-
def _get_team_run_context_audio(self, team_run_context: Dict[str, Any]) -> List[Audio]:
|
|
8019
|
-
if not team_run_context:
|
|
8020
|
-
return []
|
|
8021
|
-
audio = []
|
|
8022
|
-
if "member_responses" in team_run_context:
|
|
8023
|
-
for interaction in team_run_context["member_responses"]:
|
|
8024
|
-
if interaction["run_response"].audio:
|
|
8025
|
-
audio.extend(interaction["run_response"].audio)
|
|
8026
|
-
return audio
|
|
8027
|
-
|
|
8028
|
-
def _get_team_run_context_files(self, team_run_context: Dict[str, Any]) -> List[File]:
|
|
8029
|
-
if not team_run_context:
|
|
8030
|
-
return []
|
|
8031
|
-
files = []
|
|
8032
|
-
if "member_responses" in team_run_context:
|
|
8033
|
-
for interaction in team_run_context["member_responses"]:
|
|
8034
|
-
if interaction["run_response"].files:
|
|
8035
|
-
files.extend(interaction["run_response"].files)
|
|
8036
|
-
return files
|
|
8260
|
+
return await self.memory_manager.aget_user_memories(user_id=user_id)
|
|
8037
8261
|
|
|
8038
8262
|
###########################################################################
|
|
8039
8263
|
# Handle images, videos and audio
|
|
@@ -8182,6 +8406,8 @@ class Team:
|
|
|
8182
8406
|
document_name = query.replace(" ", "_").replace("?", "").replace("!", "").replace(".", "")
|
|
8183
8407
|
document_content = json.dumps({"query": query, "result": result})
|
|
8184
8408
|
log_info(f"Adding document to Knowledge: {document_name}: {document_content}")
|
|
8409
|
+
import asyncio
|
|
8410
|
+
|
|
8185
8411
|
from agno.knowledge.reader.text_reader import TextReader
|
|
8186
8412
|
|
|
8187
8413
|
asyncio.run(
|