agno 2.2.0__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 +751 -575
- 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 +14 -3
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +30 -0
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/types.py +1 -0
- agno/memory/manager.py +28 -25
- agno/models/anthropic/claude.py +63 -6
- agno/models/base.py +255 -36
- 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 +28 -30
- agno/run/base.py +17 -1
- agno/run/team.py +28 -29
- agno/run/workflow.py +32 -17
- agno/session/agent.py +3 -0
- agno/session/summary.py +4 -1
- agno/session/team.py +1 -1
- agno/team/team.py +620 -374
- 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/message.py +60 -0
- 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/workflow/workflow.py +86 -1
- {agno-2.2.0.dist-info → agno-2.2.2.dist-info}/METADATA +31 -25
- {agno-2.2.0.dist-info → agno-2.2.2.dist-info}/RECORD +68 -64
- 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.0.dist-info → agno-2.2.2.dist-info}/WHEEL +0 -0
- {agno-2.2.0.dist-info → agno-2.2.2.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.0.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
|
)
|
|
@@ -111,7 +128,7 @@ from agno.utils.log import (
|
|
|
111
128
|
use_team_logger,
|
|
112
129
|
)
|
|
113
130
|
from agno.utils.merge_dict import merge_dictionaries
|
|
114
|
-
from agno.utils.message import get_text_from_message
|
|
131
|
+
from agno.utils.message import filter_tool_calls, get_text_from_message
|
|
115
132
|
from agno.utils.print_response.team import (
|
|
116
133
|
aprint_response,
|
|
117
134
|
aprint_response_stream,
|
|
@@ -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
|
|
|
@@ -189,12 +215,6 @@ class Team:
|
|
|
189
215
|
# If True, cache the current Team session in memory for faster access
|
|
190
216
|
cache_session: bool = False
|
|
191
217
|
|
|
192
|
-
# --- Team history settings ---
|
|
193
|
-
# add_history_to_context=true adds messages from the chat history to the messages list sent to the Model. This only applies to the team leader, not the members.
|
|
194
|
-
add_history_to_context: bool = False
|
|
195
|
-
# Number of historical runs to include in the messages
|
|
196
|
-
num_history_runs: int = 3
|
|
197
|
-
|
|
198
218
|
# Add this flag to control if the workflow should send the team history to the members. This means sending the team-level history to the members, not the agent-level history.
|
|
199
219
|
add_team_history_to_members: bool = False
|
|
200
220
|
# Number of historical runs to include in the messages sent to the members
|
|
@@ -354,6 +374,14 @@ class Team:
|
|
|
354
374
|
# If True, the team adds session summaries to the context
|
|
355
375
|
add_session_summary_to_context: Optional[bool] = None
|
|
356
376
|
|
|
377
|
+
# --- Team History ---
|
|
378
|
+
# add_history_to_context=true adds messages from the chat history to the messages list sent to the Model.
|
|
379
|
+
add_history_to_context: bool = False
|
|
380
|
+
# Number of historical runs to include in the messages
|
|
381
|
+
num_history_runs: int = 3
|
|
382
|
+
# Maximum number of tool calls to include from history (None = no limit)
|
|
383
|
+
max_tool_calls_from_history: Optional[int] = None
|
|
384
|
+
|
|
357
385
|
# --- Team Storage ---
|
|
358
386
|
# Metadata stored with this team
|
|
359
387
|
metadata: Optional[Dict[str, Any]] = None
|
|
@@ -421,8 +449,6 @@ class Team:
|
|
|
421
449
|
overwrite_db_session_state: bool = False,
|
|
422
450
|
resolve_in_context: bool = True,
|
|
423
451
|
cache_session: bool = False,
|
|
424
|
-
add_history_to_context: bool = False,
|
|
425
|
-
num_history_runs: int = 3,
|
|
426
452
|
add_team_history_to_members: bool = False,
|
|
427
453
|
num_team_history_runs: int = 3,
|
|
428
454
|
search_session_history: Optional[bool] = False,
|
|
@@ -458,6 +484,8 @@ class Team:
|
|
|
458
484
|
store_tool_messages: bool = True,
|
|
459
485
|
store_history_messages: bool = True,
|
|
460
486
|
send_media_to_model: bool = True,
|
|
487
|
+
add_history_to_context: bool = False,
|
|
488
|
+
num_history_runs: int = 3,
|
|
461
489
|
tools: Optional[List[Union[Toolkit, Callable, Function, Dict]]] = None,
|
|
462
490
|
tool_call_limit: Optional[int] = None,
|
|
463
491
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
@@ -480,6 +508,7 @@ class Team:
|
|
|
480
508
|
enable_session_summaries: bool = False,
|
|
481
509
|
session_summary_manager: Optional[SessionSummaryManager] = None,
|
|
482
510
|
add_session_summary_to_context: Optional[bool] = None,
|
|
511
|
+
max_tool_calls_from_history: Optional[int] = None,
|
|
483
512
|
metadata: Optional[Dict[str, Any]] = None,
|
|
484
513
|
reasoning: bool = False,
|
|
485
514
|
reasoning_model: Optional[Model] = None,
|
|
@@ -591,6 +620,9 @@ class Team:
|
|
|
591
620
|
self.enable_session_summaries = enable_session_summaries
|
|
592
621
|
self.session_summary_manager = session_summary_manager
|
|
593
622
|
self.add_session_summary_to_context = add_session_summary_to_context
|
|
623
|
+
self.add_history_to_context = add_history_to_context
|
|
624
|
+
self.num_history_runs = num_history_runs
|
|
625
|
+
self.max_tool_calls_from_history = max_tool_calls_from_history
|
|
594
626
|
self.metadata = metadata
|
|
595
627
|
|
|
596
628
|
self.reasoning = reasoning
|
|
@@ -634,21 +666,20 @@ class Team:
|
|
|
634
666
|
self.videos: Optional[List[Video]] = None
|
|
635
667
|
|
|
636
668
|
# Team session
|
|
637
|
-
self.
|
|
669
|
+
self._cached_session: Optional[TeamSession] = None
|
|
638
670
|
|
|
639
671
|
self._tool_instructions: Optional[List[str]] = None
|
|
640
|
-
self._functions_for_model: Optional[Dict[str, Function]] = None
|
|
641
|
-
self._tools_for_model: Optional[List[Dict[str, Any]]] = None
|
|
642
672
|
|
|
643
673
|
# True if we should parse a member response model
|
|
644
674
|
self._member_response_model: Optional[Type[BaseModel]] = None
|
|
645
675
|
|
|
646
676
|
self._formatter: Optional[SafeFormatter] = None
|
|
647
677
|
|
|
648
|
-
self._rebuild_tools = True
|
|
649
|
-
|
|
650
678
|
self._hooks_normalised = False
|
|
651
679
|
|
|
680
|
+
# List of MCP tools that were initialized on the last run
|
|
681
|
+
self._mcp_tools_initialized_on_run: List[Any] = []
|
|
682
|
+
|
|
652
683
|
# Lazy-initialized shared thread pool executor for background tasks (memory, cultural knowledge, etc.)
|
|
653
684
|
self._background_executor: Optional[Any] = None
|
|
654
685
|
|
|
@@ -669,6 +700,10 @@ class Team:
|
|
|
669
700
|
def should_parse_structured_output(self) -> bool:
|
|
670
701
|
return self.output_schema is not None and self.parse_response and self.parser_model is None
|
|
671
702
|
|
|
703
|
+
@property
|
|
704
|
+
def cached_session(self) -> Optional[TeamSession]:
|
|
705
|
+
return self._cached_session
|
|
706
|
+
|
|
672
707
|
def set_id(self) -> None:
|
|
673
708
|
"""Set the ID of the team if not set yet.
|
|
674
709
|
|
|
@@ -751,10 +786,21 @@ class Team:
|
|
|
751
786
|
member.team_id = self.id
|
|
752
787
|
member.set_id()
|
|
753
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
|
+
|
|
754
797
|
elif isinstance(member, Team):
|
|
755
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
|
|
756
802
|
for sub_member in member.members:
|
|
757
|
-
|
|
803
|
+
member._initialize_member(sub_member, debug_mode=debug_mode)
|
|
758
804
|
|
|
759
805
|
def _set_default_model(self) -> None:
|
|
760
806
|
# Set the default model
|
|
@@ -886,7 +932,8 @@ class Team:
|
|
|
886
932
|
def set_tools(self, tools: List[Union[Toolkit, Callable, Function, Dict]]):
|
|
887
933
|
self.tools = tools
|
|
888
934
|
|
|
889
|
-
|
|
935
|
+
@staticmethod
|
|
936
|
+
def cancel_run(run_id: str) -> bool:
|
|
890
937
|
"""Cancel a running team execution.
|
|
891
938
|
|
|
892
939
|
Args:
|
|
@@ -897,6 +944,21 @@ class Team:
|
|
|
897
944
|
"""
|
|
898
945
|
return cancel_run_global(run_id)
|
|
899
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
|
+
|
|
900
962
|
def _execute_pre_hooks(
|
|
901
963
|
self,
|
|
902
964
|
hooks: Optional[List[Callable[..., Any]]],
|
|
@@ -1006,7 +1068,9 @@ class Team:
|
|
|
1006
1068
|
# Filter arguments to only include those that the hook accepts
|
|
1007
1069
|
filtered_args = filter_hook_args(hook, all_args)
|
|
1008
1070
|
|
|
1009
|
-
|
|
1071
|
+
from inspect import iscoroutinefunction
|
|
1072
|
+
|
|
1073
|
+
if iscoroutinefunction(hook):
|
|
1010
1074
|
await hook(**filtered_args)
|
|
1011
1075
|
else:
|
|
1012
1076
|
# Synchronous function
|
|
@@ -1137,7 +1201,9 @@ class Team:
|
|
|
1137
1201
|
# Filter arguments to only include those that the hook accepts
|
|
1138
1202
|
filtered_args = filter_hook_args(hook, all_args)
|
|
1139
1203
|
|
|
1140
|
-
|
|
1204
|
+
from inspect import iscoroutinefunction
|
|
1205
|
+
|
|
1206
|
+
if iscoroutinefunction(hook):
|
|
1141
1207
|
await hook(**filtered_args)
|
|
1142
1208
|
else:
|
|
1143
1209
|
hook(**filtered_args)
|
|
@@ -1218,7 +1284,7 @@ class Team:
|
|
|
1218
1284
|
# Initialize team run context
|
|
1219
1285
|
team_run_context: Dict[str, Any] = {}
|
|
1220
1286
|
|
|
1221
|
-
self.
|
|
1287
|
+
_tools = self._determine_tools_for_model(
|
|
1222
1288
|
model=self.model,
|
|
1223
1289
|
run_response=run_response,
|
|
1224
1290
|
team_run_context=team_run_context,
|
|
@@ -1257,6 +1323,7 @@ class Team:
|
|
|
1257
1323
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
1258
1324
|
add_session_state_to_context=add_session_state_to_context,
|
|
1259
1325
|
metadata=metadata,
|
|
1326
|
+
tools=_tools,
|
|
1260
1327
|
**kwargs,
|
|
1261
1328
|
)
|
|
1262
1329
|
if len(run_messages.messages) == 0:
|
|
@@ -1286,8 +1353,7 @@ class Team:
|
|
|
1286
1353
|
model_response: ModelResponse = self.model.response(
|
|
1287
1354
|
messages=run_messages.messages,
|
|
1288
1355
|
response_format=response_format,
|
|
1289
|
-
tools=
|
|
1290
|
-
functions=self._functions_for_model,
|
|
1356
|
+
tools=_tools,
|
|
1291
1357
|
tool_choice=self.tool_choice,
|
|
1292
1358
|
tool_call_limit=self.tool_call_limit,
|
|
1293
1359
|
send_media_to_model=self.send_media_to_model,
|
|
@@ -1320,6 +1386,9 @@ class Team:
|
|
|
1320
1386
|
hooks=self.post_hooks, # type: ignore
|
|
1321
1387
|
run_output=run_response,
|
|
1322
1388
|
session=session,
|
|
1389
|
+
session_state=session_state,
|
|
1390
|
+
dependencies=dependencies,
|
|
1391
|
+
metadata=metadata,
|
|
1323
1392
|
user_id=user_id,
|
|
1324
1393
|
debug_mode=debug_mode,
|
|
1325
1394
|
**kwargs,
|
|
@@ -1427,7 +1496,7 @@ class Team:
|
|
|
1427
1496
|
# Initialize team run context
|
|
1428
1497
|
team_run_context: Dict[str, Any] = {}
|
|
1429
1498
|
|
|
1430
|
-
self.
|
|
1499
|
+
_tools = self._determine_tools_for_model(
|
|
1431
1500
|
model=self.model,
|
|
1432
1501
|
run_response=run_response,
|
|
1433
1502
|
team_run_context=team_run_context,
|
|
@@ -1466,6 +1535,7 @@ class Team:
|
|
|
1466
1535
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
1467
1536
|
add_session_state_to_context=add_session_state_to_context,
|
|
1468
1537
|
metadata=metadata,
|
|
1538
|
+
tools=_tools,
|
|
1469
1539
|
**kwargs,
|
|
1470
1540
|
)
|
|
1471
1541
|
if len(run_messages.messages) == 0:
|
|
@@ -1509,6 +1579,7 @@ class Team:
|
|
|
1509
1579
|
session=session,
|
|
1510
1580
|
run_response=run_response,
|
|
1511
1581
|
run_messages=run_messages,
|
|
1582
|
+
tools=_tools,
|
|
1512
1583
|
response_format=response_format,
|
|
1513
1584
|
stream_events=stream_events,
|
|
1514
1585
|
):
|
|
@@ -1519,6 +1590,7 @@ class Team:
|
|
|
1519
1590
|
session=session,
|
|
1520
1591
|
run_response=run_response,
|
|
1521
1592
|
run_messages=run_messages,
|
|
1593
|
+
tools=_tools,
|
|
1522
1594
|
response_format=response_format,
|
|
1523
1595
|
stream_events=stream_events,
|
|
1524
1596
|
):
|
|
@@ -2032,7 +2104,8 @@ class Team:
|
|
|
2032
2104
|
# 4. Determine tools for model
|
|
2033
2105
|
team_run_context: Dict[str, Any] = {}
|
|
2034
2106
|
self.model = cast(Model, self.model)
|
|
2035
|
-
self.
|
|
2107
|
+
await self._check_and_refresh_mcp_tools()
|
|
2108
|
+
_tools = self._determine_tools_for_model(
|
|
2036
2109
|
model=self.model,
|
|
2037
2110
|
run_response=run_response,
|
|
2038
2111
|
team_run_context=team_run_context,
|
|
@@ -2070,6 +2143,8 @@ class Team:
|
|
|
2070
2143
|
dependencies=dependencies,
|
|
2071
2144
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
2072
2145
|
add_session_state_to_context=add_session_state_to_context,
|
|
2146
|
+
metadata=metadata,
|
|
2147
|
+
tools=_tools,
|
|
2073
2148
|
**kwargs,
|
|
2074
2149
|
)
|
|
2075
2150
|
|
|
@@ -2077,8 +2152,6 @@ class Team:
|
|
|
2077
2152
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2078
2153
|
|
|
2079
2154
|
# 6. Start memory creation in background task
|
|
2080
|
-
import asyncio
|
|
2081
|
-
|
|
2082
2155
|
memory_task = None
|
|
2083
2156
|
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
2084
2157
|
log_debug("Starting memory creation in background task.")
|
|
@@ -2098,8 +2171,7 @@ class Team:
|
|
|
2098
2171
|
# 8. Get the model response for the team leader
|
|
2099
2172
|
model_response = await self.model.aresponse(
|
|
2100
2173
|
messages=run_messages.messages,
|
|
2101
|
-
tools=
|
|
2102
|
-
functions=self._functions_for_model,
|
|
2174
|
+
tools=_tools,
|
|
2103
2175
|
tool_choice=self.tool_choice,
|
|
2104
2176
|
tool_call_limit=self.tool_call_limit,
|
|
2105
2177
|
response_format=response_format,
|
|
@@ -2133,6 +2205,9 @@ class Team:
|
|
|
2133
2205
|
hooks=self.post_hooks, # type: ignore
|
|
2134
2206
|
run_output=run_response,
|
|
2135
2207
|
session=team_session,
|
|
2208
|
+
session_state=session_state,
|
|
2209
|
+
dependencies=dependencies,
|
|
2210
|
+
metadata=metadata,
|
|
2136
2211
|
user_id=user_id,
|
|
2137
2212
|
debug_mode=debug_mode,
|
|
2138
2213
|
**kwargs,
|
|
@@ -2177,6 +2252,7 @@ class Team:
|
|
|
2177
2252
|
|
|
2178
2253
|
return run_response
|
|
2179
2254
|
finally:
|
|
2255
|
+
await self._disconnect_mcp_tools()
|
|
2180
2256
|
# Cancel the memory task if it's still running
|
|
2181
2257
|
if memory_task is not None and not memory_task.done():
|
|
2182
2258
|
memory_task.cancel()
|
|
@@ -2265,7 +2341,8 @@ class Team:
|
|
|
2265
2341
|
# 5. Determine tools for model
|
|
2266
2342
|
team_run_context: Dict[str, Any] = {}
|
|
2267
2343
|
self.model = cast(Model, self.model)
|
|
2268
|
-
self.
|
|
2344
|
+
await self._check_and_refresh_mcp_tools()
|
|
2345
|
+
_tools = self._determine_tools_for_model(
|
|
2269
2346
|
model=self.model,
|
|
2270
2347
|
run_response=run_response,
|
|
2271
2348
|
team_run_context=team_run_context,
|
|
@@ -2302,14 +2379,13 @@ class Team:
|
|
|
2302
2379
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
2303
2380
|
add_session_state_to_context=add_session_state_to_context,
|
|
2304
2381
|
metadata=metadata,
|
|
2382
|
+
tools=_tools,
|
|
2305
2383
|
**kwargs,
|
|
2306
2384
|
)
|
|
2307
2385
|
|
|
2308
2386
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2309
2387
|
|
|
2310
2388
|
# 7. Start memory creation in background task
|
|
2311
|
-
import asyncio
|
|
2312
|
-
|
|
2313
2389
|
memory_task = None
|
|
2314
2390
|
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
2315
2391
|
log_debug("Starting memory creation in background task.")
|
|
@@ -2349,6 +2425,7 @@ class Team:
|
|
|
2349
2425
|
session=team_session,
|
|
2350
2426
|
run_response=run_response,
|
|
2351
2427
|
run_messages=run_messages,
|
|
2428
|
+
tools=_tools,
|
|
2352
2429
|
response_format=response_format,
|
|
2353
2430
|
stream_events=stream_events,
|
|
2354
2431
|
):
|
|
@@ -2359,6 +2436,7 @@ class Team:
|
|
|
2359
2436
|
session=team_session,
|
|
2360
2437
|
run_response=run_response,
|
|
2361
2438
|
run_messages=run_messages,
|
|
2439
|
+
tools=_tools,
|
|
2362
2440
|
response_format=response_format,
|
|
2363
2441
|
stream_events=stream_events,
|
|
2364
2442
|
):
|
|
@@ -2500,6 +2578,7 @@ class Team:
|
|
|
2500
2578
|
await self._acleanup_and_store(run_response=run_response, session=team_session)
|
|
2501
2579
|
|
|
2502
2580
|
finally:
|
|
2581
|
+
await self._disconnect_mcp_tools()
|
|
2503
2582
|
# Cancel the memory task if it's still running
|
|
2504
2583
|
if memory_task is not None and not memory_task.done():
|
|
2505
2584
|
memory_task.cancel()
|
|
@@ -2861,6 +2940,7 @@ class Team:
|
|
|
2861
2940
|
session: TeamSession,
|
|
2862
2941
|
run_response: TeamRunOutput,
|
|
2863
2942
|
run_messages: RunMessages,
|
|
2943
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
2864
2944
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2865
2945
|
stream_events: bool = False,
|
|
2866
2946
|
) -> Iterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
@@ -2880,8 +2960,7 @@ class Team:
|
|
|
2880
2960
|
for model_response_event in self.model.response_stream(
|
|
2881
2961
|
messages=run_messages.messages,
|
|
2882
2962
|
response_format=response_format,
|
|
2883
|
-
tools=
|
|
2884
|
-
functions=self._functions_for_model,
|
|
2963
|
+
tools=tools,
|
|
2885
2964
|
tool_choice=self.tool_choice,
|
|
2886
2965
|
tool_call_limit=self.tool_call_limit,
|
|
2887
2966
|
stream_model_response=stream_model_response,
|
|
@@ -2943,6 +3022,7 @@ class Team:
|
|
|
2943
3022
|
session: TeamSession,
|
|
2944
3023
|
run_response: TeamRunOutput,
|
|
2945
3024
|
run_messages: RunMessages,
|
|
3025
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
2946
3026
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2947
3027
|
stream_events: bool = False,
|
|
2948
3028
|
) -> AsyncIterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
@@ -2962,8 +3042,7 @@ class Team:
|
|
|
2962
3042
|
model_stream = self.model.aresponse_stream(
|
|
2963
3043
|
messages=run_messages.messages,
|
|
2964
3044
|
response_format=response_format,
|
|
2965
|
-
tools=
|
|
2966
|
-
functions=self._functions_for_model,
|
|
3045
|
+
tools=tools,
|
|
2967
3046
|
tool_choice=self.tool_choice,
|
|
2968
3047
|
tool_call_limit=self.tool_call_limit,
|
|
2969
3048
|
stream_model_response=stream_model_response,
|
|
@@ -3367,7 +3446,7 @@ class Team:
|
|
|
3367
3446
|
self._update_session_metrics(session=session)
|
|
3368
3447
|
|
|
3369
3448
|
# Save session to memory
|
|
3370
|
-
self.
|
|
3449
|
+
await self.asave_session(session=session)
|
|
3371
3450
|
|
|
3372
3451
|
def _make_memories(
|
|
3373
3452
|
self,
|
|
@@ -4870,7 +4949,30 @@ class Team:
|
|
|
4870
4949
|
except Exception as e:
|
|
4871
4950
|
log_warning(f"Failed to resolve context for '{key}': {e}")
|
|
4872
4951
|
|
|
4873
|
-
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(
|
|
4874
4976
|
self,
|
|
4875
4977
|
model: Model,
|
|
4876
4978
|
run_response: TeamRunOutput,
|
|
@@ -4891,13 +4993,18 @@ class Team:
|
|
|
4891
4993
|
add_dependencies_to_context: Optional[bool] = None,
|
|
4892
4994
|
add_session_state_to_context: Optional[bool] = None,
|
|
4893
4995
|
metadata: Optional[Dict[str, Any]] = None,
|
|
4894
|
-
|
|
4996
|
+
check_mcp_tools: bool = True,
|
|
4997
|
+
) -> List[Union[Function, dict]]:
|
|
4895
4998
|
# Prepare tools
|
|
4896
4999
|
_tools: List[Union[Toolkit, Callable, Function, Dict]] = []
|
|
4897
5000
|
|
|
4898
5001
|
# Add provided tools
|
|
4899
5002
|
if self.tools is not None:
|
|
4900
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
|
|
4901
5008
|
_tools.append(tool)
|
|
4902
5009
|
|
|
4903
5010
|
if self.read_chat_history:
|
|
@@ -4912,7 +5019,7 @@ class Team:
|
|
|
4912
5019
|
if self.search_session_history:
|
|
4913
5020
|
_tools.append(
|
|
4914
5021
|
self._get_previous_sessions_messages_function(
|
|
4915
|
-
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
|
|
4916
5023
|
)
|
|
4917
5024
|
)
|
|
4918
5025
|
|
|
@@ -4990,14 +5097,13 @@ class Team:
|
|
|
4990
5097
|
if self.get_member_information_tool:
|
|
4991
5098
|
_tools.append(self.get_member_information)
|
|
4992
5099
|
|
|
4993
|
-
self._functions_for_model = {}
|
|
4994
|
-
self._tools_for_model = []
|
|
4995
|
-
self._tool_instructions = []
|
|
4996
|
-
|
|
4997
5100
|
# Get Agent tools
|
|
4998
5101
|
if len(_tools) > 0:
|
|
4999
5102
|
log_debug("Processing tools for model")
|
|
5000
5103
|
|
|
5104
|
+
_function_names = []
|
|
5105
|
+
_functions: List[Union[Function, dict]] = []
|
|
5106
|
+
|
|
5001
5107
|
# Check if we need strict mode for the model
|
|
5002
5108
|
strict = False
|
|
5003
5109
|
if self.output_schema is not None and not self.use_json_mode and model.supports_native_structured_outputs:
|
|
@@ -5007,25 +5113,25 @@ class Team:
|
|
|
5007
5113
|
if isinstance(tool, Dict):
|
|
5008
5114
|
# If a dict is passed, it is a builtin tool
|
|
5009
5115
|
# that is run by the model provider and not the Agent
|
|
5010
|
-
|
|
5116
|
+
_functions.append(tool)
|
|
5011
5117
|
log_debug(f"Included builtin tool {tool}")
|
|
5012
5118
|
|
|
5013
5119
|
elif isinstance(tool, Toolkit):
|
|
5014
5120
|
# For each function in the toolkit and process entrypoint
|
|
5015
|
-
for name,
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
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}")
|
|
5029
5135
|
|
|
5030
5136
|
# Add instructions from the toolkit
|
|
5031
5137
|
if tool.add_instructions and tool.instructions is not None:
|
|
@@ -5034,18 +5140,18 @@ class Team:
|
|
|
5034
5140
|
self._tool_instructions.append(tool.instructions)
|
|
5035
5141
|
|
|
5036
5142
|
elif isinstance(tool, Function):
|
|
5037
|
-
if tool.name
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
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}")
|
|
5049
5155
|
|
|
5050
5156
|
# Add instructions from the Function
|
|
5051
5157
|
if tool.add_instructions and tool.instructions is not None:
|
|
@@ -5056,43 +5162,49 @@ class Team:
|
|
|
5056
5162
|
elif callable(tool):
|
|
5057
5163
|
# We add the tools, which are callable functions
|
|
5058
5164
|
try:
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
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
|
|
5063
5172
|
if strict:
|
|
5064
|
-
|
|
5173
|
+
_func.strict = True
|
|
5065
5174
|
if self.tool_hooks:
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
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}")
|
|
5070
5178
|
except Exception as e:
|
|
5071
5179
|
log_warning(f"Could not add tool {tool}: {e}")
|
|
5072
5180
|
|
|
5073
|
-
if
|
|
5181
|
+
if _functions:
|
|
5074
5182
|
from inspect import signature
|
|
5075
5183
|
|
|
5076
5184
|
# Check if any functions need media before collecting
|
|
5077
5185
|
needs_media = any(
|
|
5078
5186
|
any(param in signature(func.entrypoint).parameters for param in ["images", "videos", "audios", "files"])
|
|
5079
|
-
for func in
|
|
5080
|
-
if func.entrypoint is not None
|
|
5187
|
+
for func in _functions
|
|
5188
|
+
if isinstance(func, Function) and func.entrypoint is not None
|
|
5081
5189
|
)
|
|
5082
5190
|
|
|
5083
|
-
if
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
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
|
|
5089
5196
|
|
|
5090
|
-
|
|
5197
|
+
for func in _functions: # type: ignore
|
|
5198
|
+
if isinstance(func, Function):
|
|
5199
|
+
func._session_state = session_state
|
|
5200
|
+
func._dependencies = dependencies
|
|
5091
5201
|
func._images = joint_images
|
|
5092
5202
|
func._files = joint_files
|
|
5093
5203
|
func._audios = joint_audios
|
|
5094
5204
|
func._videos = joint_videos
|
|
5095
5205
|
|
|
5206
|
+
return _functions
|
|
5207
|
+
|
|
5096
5208
|
def get_members_system_message_content(self, indent: int = 0) -> str:
|
|
5097
5209
|
system_message_content = ""
|
|
5098
5210
|
for idx, member in enumerate(self.members):
|
|
@@ -5136,6 +5248,7 @@ class Team:
|
|
|
5136
5248
|
files: Optional[Sequence[File]] = None,
|
|
5137
5249
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
5138
5250
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5251
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5139
5252
|
add_session_state_to_context: Optional[bool] = None,
|
|
5140
5253
|
) -> Optional[Message]:
|
|
5141
5254
|
"""Get the system message for the team."""
|
|
@@ -5189,7 +5302,7 @@ class Team:
|
|
|
5189
5302
|
instructions.extend(_instructions)
|
|
5190
5303
|
|
|
5191
5304
|
# 1.2 Add instructions from the Model
|
|
5192
|
-
_model_instructions = self.model.get_instructions_for_model(
|
|
5305
|
+
_model_instructions = self.model.get_instructions_for_model(tools)
|
|
5193
5306
|
if _model_instructions is not None:
|
|
5194
5307
|
instructions.extend(_model_instructions)
|
|
5195
5308
|
|
|
@@ -5392,7 +5505,7 @@ class Team:
|
|
|
5392
5505
|
metadata=metadata,
|
|
5393
5506
|
)
|
|
5394
5507
|
|
|
5395
|
-
system_message_from_model = self.model.get_system_message_for_model(
|
|
5508
|
+
system_message_from_model = self.model.get_system_message_for_model(tools)
|
|
5396
5509
|
if system_message_from_model is not None:
|
|
5397
5510
|
system_message_content += system_message_from_model
|
|
5398
5511
|
|
|
@@ -5429,6 +5542,7 @@ class Team:
|
|
|
5429
5542
|
files: Optional[Sequence[File]] = None,
|
|
5430
5543
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
5431
5544
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5545
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5432
5546
|
add_session_state_to_context: Optional[bool] = None,
|
|
5433
5547
|
) -> Optional[Message]:
|
|
5434
5548
|
"""Get the system message for the team."""
|
|
@@ -5482,7 +5596,7 @@ class Team:
|
|
|
5482
5596
|
instructions.extend(_instructions)
|
|
5483
5597
|
|
|
5484
5598
|
# 1.2 Add instructions from the Model
|
|
5485
|
-
_model_instructions = self.model.get_instructions_for_model(
|
|
5599
|
+
_model_instructions = self.model.get_instructions_for_model(tools)
|
|
5486
5600
|
if _model_instructions is not None:
|
|
5487
5601
|
instructions.extend(_model_instructions)
|
|
5488
5602
|
|
|
@@ -5690,7 +5804,7 @@ class Team:
|
|
|
5690
5804
|
metadata=metadata,
|
|
5691
5805
|
)
|
|
5692
5806
|
|
|
5693
|
-
system_message_from_model = self.model.get_system_message_for_model(
|
|
5807
|
+
system_message_from_model = self.model.get_system_message_for_model(tools)
|
|
5694
5808
|
if system_message_from_model is not None:
|
|
5695
5809
|
system_message_content += system_message_from_model
|
|
5696
5810
|
|
|
@@ -5737,6 +5851,7 @@ class Team:
|
|
|
5737
5851
|
add_dependencies_to_context: Optional[bool] = None,
|
|
5738
5852
|
add_session_state_to_context: Optional[bool] = None,
|
|
5739
5853
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5854
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5740
5855
|
**kwargs: Any,
|
|
5741
5856
|
) -> RunMessages:
|
|
5742
5857
|
"""This function returns a RunMessages object with the following attributes:
|
|
@@ -5767,6 +5882,7 @@ class Team:
|
|
|
5767
5882
|
dependencies=dependencies,
|
|
5768
5883
|
metadata=metadata,
|
|
5769
5884
|
add_session_state_to_context=add_session_state_to_context,
|
|
5885
|
+
tools=tools,
|
|
5770
5886
|
)
|
|
5771
5887
|
if system_message is not None:
|
|
5772
5888
|
run_messages.system_message = system_message
|
|
@@ -5824,6 +5940,10 @@ class Team:
|
|
|
5824
5940
|
for _msg in history_copy:
|
|
5825
5941
|
_msg.from_history = True
|
|
5826
5942
|
|
|
5943
|
+
# Filter tool calls from history messages
|
|
5944
|
+
if self.max_tool_calls_from_history is not None:
|
|
5945
|
+
filter_tool_calls(history_copy, self.max_tool_calls_from_history)
|
|
5946
|
+
|
|
5827
5947
|
log_debug(f"Adding {len(history_copy)} messages from history")
|
|
5828
5948
|
|
|
5829
5949
|
# Extend the messages with the history
|
|
@@ -5871,6 +5991,7 @@ class Team:
|
|
|
5871
5991
|
add_dependencies_to_context: Optional[bool] = None,
|
|
5872
5992
|
add_session_state_to_context: Optional[bool] = None,
|
|
5873
5993
|
metadata: Optional[Dict[str, Any]] = None,
|
|
5994
|
+
tools: Optional[List[Union[Function, dict]]] = None,
|
|
5874
5995
|
**kwargs: Any,
|
|
5875
5996
|
) -> RunMessages:
|
|
5876
5997
|
"""This function returns a RunMessages object with the following attributes:
|
|
@@ -5901,6 +6022,7 @@ class Team:
|
|
|
5901
6022
|
dependencies=dependencies,
|
|
5902
6023
|
metadata=metadata,
|
|
5903
6024
|
add_session_state_to_context=add_session_state_to_context,
|
|
6025
|
+
tools=tools,
|
|
5904
6026
|
)
|
|
5905
6027
|
if system_message is not None:
|
|
5906
6028
|
run_messages.system_message = system_message
|
|
@@ -5951,6 +6073,10 @@ class Team:
|
|
|
5951
6073
|
for _msg in history_copy:
|
|
5952
6074
|
_msg.from_history = True
|
|
5953
6075
|
|
|
6076
|
+
# Filter tool calls from history messages
|
|
6077
|
+
if self.max_tool_calls_from_history is not None:
|
|
6078
|
+
filter_tool_calls(history_copy, self.max_tool_calls_from_history)
|
|
6079
|
+
|
|
5954
6080
|
log_debug(f"Adding {len(history_copy)} messages from history")
|
|
5955
6081
|
|
|
5956
6082
|
# Extend the messages with the history
|
|
@@ -6494,7 +6620,7 @@ class Team:
|
|
|
6494
6620
|
return f"Updated session state: {session_state}"
|
|
6495
6621
|
|
|
6496
6622
|
def _get_previous_sessions_messages_function(
|
|
6497
|
-
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
|
|
6498
6624
|
):
|
|
6499
6625
|
"""Factory function to create a get_previous_session_messages function.
|
|
6500
6626
|
|
|
@@ -6571,13 +6697,22 @@ class Team:
|
|
|
6571
6697
|
return "Previous session messages not available"
|
|
6572
6698
|
|
|
6573
6699
|
self.db = cast(AsyncBaseDb, self.db)
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
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
|
+
)
|
|
6581
6716
|
|
|
6582
6717
|
all_messages = []
|
|
6583
6718
|
seen_message_pairs = set()
|
|
@@ -6657,14 +6792,14 @@ class Team:
|
|
|
6657
6792
|
) -> Optional[str]:
|
|
6658
6793
|
team_member_interactions_str = None
|
|
6659
6794
|
if self.share_member_interactions:
|
|
6660
|
-
team_member_interactions_str =
|
|
6661
|
-
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
|
|
6662
6797
|
images.extend(context_images)
|
|
6663
|
-
if context_videos :=
|
|
6798
|
+
if context_videos := get_team_run_context_videos(team_run_context=team_run_context): # type: ignore
|
|
6664
6799
|
videos.extend(context_videos)
|
|
6665
|
-
if context_audio :=
|
|
6800
|
+
if context_audio := get_team_run_context_audio(team_run_context=team_run_context): # type: ignore
|
|
6666
6801
|
audio.extend(context_audio)
|
|
6667
|
-
if context_files :=
|
|
6802
|
+
if context_files := get_team_run_context_files(team_run_context=team_run_context): # type: ignore
|
|
6668
6803
|
files.extend(context_files)
|
|
6669
6804
|
return team_member_interactions_str
|
|
6670
6805
|
|
|
@@ -6731,6 +6866,11 @@ class Team:
|
|
|
6731
6866
|
# 1. Initialize the member agent
|
|
6732
6867
|
self._initialize_member(member_agent)
|
|
6733
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
|
+
|
|
6734
6874
|
# 2. Handle respond_directly nuances
|
|
6735
6875
|
if self.respond_directly:
|
|
6736
6876
|
# Since we return the response directly from the member agent, we need to set the output schema from the team down.
|
|
@@ -6802,7 +6942,7 @@ class Team:
|
|
|
6802
6942
|
normalized_task = str(member_agent_task.content)
|
|
6803
6943
|
else:
|
|
6804
6944
|
normalized_task = ""
|
|
6805
|
-
|
|
6945
|
+
add_interaction_to_team_run_context(
|
|
6806
6946
|
team_run_context=team_run_context,
|
|
6807
6947
|
member_name=member_name,
|
|
6808
6948
|
task=normalized_task,
|
|
@@ -6860,6 +7000,7 @@ class Team:
|
|
|
6860
7000
|
use_agent_logger()
|
|
6861
7001
|
|
|
6862
7002
|
member_session_state_copy = copy(session_state)
|
|
7003
|
+
|
|
6863
7004
|
if stream:
|
|
6864
7005
|
member_agent_run_response_stream = member_agent.run(
|
|
6865
7006
|
input=member_agent_task if not history else history,
|
|
@@ -6986,6 +7127,7 @@ class Team:
|
|
|
6986
7127
|
use_agent_logger()
|
|
6987
7128
|
|
|
6988
7129
|
member_session_state_copy = copy(session_state)
|
|
7130
|
+
|
|
6989
7131
|
if stream:
|
|
6990
7132
|
member_agent_run_response_stream = member_agent.arun( # type: ignore
|
|
6991
7133
|
input=member_agent_task if not history else history,
|
|
@@ -7290,6 +7432,7 @@ class Team:
|
|
|
7290
7432
|
|
|
7291
7433
|
async def run_member_agent(agent=current_agent) -> str:
|
|
7292
7434
|
member_session_state_copy = copy(session_state)
|
|
7435
|
+
|
|
7293
7436
|
member_agent_run_response = await agent.arun(
|
|
7294
7437
|
input=member_agent_task if not history else history,
|
|
7295
7438
|
user_id=user_id,
|
|
@@ -7424,57 +7567,6 @@ class Team:
|
|
|
7424
7567
|
log_warning(f"Error upserting session into db: {e}")
|
|
7425
7568
|
return None
|
|
7426
7569
|
|
|
7427
|
-
def get_run_output(
|
|
7428
|
-
self, run_id: str, session_id: Optional[str] = None
|
|
7429
|
-
) -> Optional[Union[TeamRunOutput, RunOutput]]:
|
|
7430
|
-
"""
|
|
7431
|
-
Get a RunOutput from the database.
|
|
7432
|
-
|
|
7433
|
-
Args:
|
|
7434
|
-
run_id (str): The run_id to load from storage.
|
|
7435
|
-
session_id (Optional[str]): The session_id to load from storage.
|
|
7436
|
-
"""
|
|
7437
|
-
if self._team_session is not None:
|
|
7438
|
-
run_response = self._team_session.get_run(run_id=run_id)
|
|
7439
|
-
if run_response is not None:
|
|
7440
|
-
return run_response
|
|
7441
|
-
else:
|
|
7442
|
-
log_warning(f"RunOutput {run_id} not found in AgentSession {self._team_session.session_id}")
|
|
7443
|
-
return None
|
|
7444
|
-
else:
|
|
7445
|
-
team_session = self.get_session(session_id=session_id)
|
|
7446
|
-
if team_session is not None:
|
|
7447
|
-
run_response = team_session.get_run(run_id=run_id)
|
|
7448
|
-
if run_response is not None:
|
|
7449
|
-
return cast(TeamRunOutput, run_response)
|
|
7450
|
-
else:
|
|
7451
|
-
log_warning(f"RunOutput {run_id} not found in AgentSession {session_id}")
|
|
7452
|
-
return None
|
|
7453
|
-
|
|
7454
|
-
def get_last_run_output(self, session_id: Optional[str] = None) -> Optional[TeamRunOutput]:
|
|
7455
|
-
"""
|
|
7456
|
-
Get the last run response from the database.
|
|
7457
|
-
|
|
7458
|
-
Args:
|
|
7459
|
-
session_id (Optional[str]): The session_id to load from storage.
|
|
7460
|
-
|
|
7461
|
-
Returns:
|
|
7462
|
-
RunOutput: The last run response from the database.
|
|
7463
|
-
"""
|
|
7464
|
-
if self._team_session is not None and self._team_session.runs is not None and len(self._team_session.runs) > 0:
|
|
7465
|
-
run_response = self._team_session.runs[-1]
|
|
7466
|
-
if run_response is not None:
|
|
7467
|
-
return run_response # type: ignore
|
|
7468
|
-
else:
|
|
7469
|
-
agent_session = self.get_session(session_id=session_id)
|
|
7470
|
-
if agent_session is not None and agent_session.runs is not None and len(agent_session.runs) > 0:
|
|
7471
|
-
run_response = agent_session.runs[-1]
|
|
7472
|
-
if run_response is not None:
|
|
7473
|
-
return run_response # type: ignore
|
|
7474
|
-
else:
|
|
7475
|
-
log_warning(f"No run responses found in AgentSession {session_id}")
|
|
7476
|
-
return None
|
|
7477
|
-
|
|
7478
7570
|
def _read_or_create_session(self, session_id: str, user_id: Optional[str] = None) -> TeamSession:
|
|
7479
7571
|
"""Load the TeamSession from storage
|
|
7480
7572
|
|
|
@@ -7486,8 +7578,8 @@ class Team:
|
|
|
7486
7578
|
from agno.session.team import TeamSession
|
|
7487
7579
|
|
|
7488
7580
|
# Return existing session if we have one
|
|
7489
|
-
if self.
|
|
7490
|
-
return self.
|
|
7581
|
+
if self._cached_session is not None and self._cached_session.session_id == session_id:
|
|
7582
|
+
return self._cached_session
|
|
7491
7583
|
|
|
7492
7584
|
# Try to load from database
|
|
7493
7585
|
team_session = None
|
|
@@ -7514,7 +7606,7 @@ class Team:
|
|
|
7514
7606
|
|
|
7515
7607
|
# Cache the session if relevant
|
|
7516
7608
|
if team_session is not None and self.cache_session:
|
|
7517
|
-
self.
|
|
7609
|
+
self._cached_session = team_session
|
|
7518
7610
|
|
|
7519
7611
|
return team_session
|
|
7520
7612
|
|
|
@@ -7529,8 +7621,8 @@ class Team:
|
|
|
7529
7621
|
from agno.session.team import TeamSession
|
|
7530
7622
|
|
|
7531
7623
|
# Return existing session if we have one
|
|
7532
|
-
if self.
|
|
7533
|
-
return self.
|
|
7624
|
+
if self._cached_session is not None and self._cached_session.session_id == session_id:
|
|
7625
|
+
return self._cached_session
|
|
7534
7626
|
|
|
7535
7627
|
# Try to load from database
|
|
7536
7628
|
team_session = None
|
|
@@ -7555,10 +7647,116 @@ class Team:
|
|
|
7555
7647
|
|
|
7556
7648
|
# Cache the session if relevant
|
|
7557
7649
|
if team_session is not None and self.cache_session:
|
|
7558
|
-
self.
|
|
7650
|
+
self._cached_session = team_session
|
|
7559
7651
|
|
|
7560
7652
|
return team_session
|
|
7561
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
|
+
|
|
7562
7760
|
def get_session(
|
|
7563
7761
|
self,
|
|
7564
7762
|
session_id: Optional[str] = None,
|
|
@@ -7572,14 +7770,17 @@ class Team:
|
|
|
7572
7770
|
TeamSession: The TeamSession loaded from the database or created if it does not exist.
|
|
7573
7771
|
"""
|
|
7574
7772
|
if not session_id and not self.session_id:
|
|
7575
|
-
|
|
7773
|
+
raise Exception("No session_id provided")
|
|
7576
7774
|
|
|
7577
7775
|
session_id_to_load = session_id or self.session_id
|
|
7578
7776
|
|
|
7579
7777
|
# If there is a cached session, return it
|
|
7580
|
-
if self.cache_session and hasattr(self, "
|
|
7581
|
-
if self.
|
|
7582
|
-
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")
|
|
7583
7784
|
|
|
7584
7785
|
# Load and return the session from the database
|
|
7585
7786
|
if self.db is not None:
|
|
@@ -7613,30 +7814,44 @@ class Team:
|
|
|
7613
7814
|
TeamSession: The TeamSession loaded from the database or created if it does not exist.
|
|
7614
7815
|
"""
|
|
7615
7816
|
if not session_id and not self.session_id:
|
|
7616
|
-
|
|
7817
|
+
raise Exception("No session_id provided")
|
|
7617
7818
|
|
|
7618
7819
|
session_id_to_load = session_id or self.session_id
|
|
7619
7820
|
|
|
7620
7821
|
# If there is a cached session, return it
|
|
7621
|
-
if self.cache_session and hasattr(self, "
|
|
7622
|
-
if self.
|
|
7623
|
-
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
|
|
7624
7825
|
|
|
7625
7826
|
# Load and return the session from the database
|
|
7626
7827
|
if self.db is not None:
|
|
7627
|
-
|
|
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
|
|
7628
7835
|
|
|
7629
7836
|
# Cache the session if relevant
|
|
7630
|
-
if
|
|
7631
|
-
self.
|
|
7837
|
+
if loaded_session is not None and self.cache_session:
|
|
7838
|
+
self._cached_session = loaded_session
|
|
7632
7839
|
|
|
7633
|
-
return
|
|
7840
|
+
return loaded_session
|
|
7634
7841
|
|
|
7635
7842
|
log_debug(f"TeamSession {session_id_to_load} not found in db")
|
|
7636
7843
|
return None
|
|
7637
7844
|
|
|
7638
7845
|
def save_session(self, session: TeamSession) -> None:
|
|
7639
|
-
"""
|
|
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
|
+
|
|
7640
7855
|
if self.db is not None and self.parent_team_id is None and self.workflow_id is None:
|
|
7641
7856
|
if session.session_data is not None and "session_state" in session.session_data:
|
|
7642
7857
|
session.session_data["session_state"].pop("current_session_id", None) # type: ignore
|
|
@@ -7657,7 +7872,12 @@ class Team:
|
|
|
7657
7872
|
log_debug(f"Created or updated TeamSession record: {session.session_id}")
|
|
7658
7873
|
|
|
7659
7874
|
async def asave_session(self, session: TeamSession) -> None:
|
|
7660
|
-
"""
|
|
7875
|
+
"""
|
|
7876
|
+
Save the TeamSession to storage
|
|
7877
|
+
|
|
7878
|
+
Args:
|
|
7879
|
+
session: The TeamSession to save.
|
|
7880
|
+
"""
|
|
7661
7881
|
if self.db is not None and self.parent_team_id is None and self.workflow_id is None:
|
|
7662
7882
|
if session.session_data is not None and "session_state" in session.session_data:
|
|
7663
7883
|
session.session_data["session_state"].pop("current_session_id", None) # type: ignore
|
|
@@ -7676,49 +7896,15 @@ class Team:
|
|
|
7676
7896
|
self._upsert_session(session=session)
|
|
7677
7897
|
log_debug(f"Created or updated TeamSession record: {session.session_id}")
|
|
7678
7898
|
|
|
7679
|
-
def
|
|
7680
|
-
"""
|
|
7681
|
-
|
|
7682
|
-
from agno.utils.merge_dict import merge_dictionaries
|
|
7683
|
-
|
|
7684
|
-
# Get the session_state from the database and merge with proper precedence
|
|
7685
|
-
# At this point session_state contains: agent_defaults + run_params
|
|
7686
|
-
if session.session_data is not None and "session_state" in session.session_data:
|
|
7687
|
-
session_state_from_db = session.session_data.get("session_state")
|
|
7688
|
-
|
|
7689
|
-
if (
|
|
7690
|
-
session_state_from_db is not None
|
|
7691
|
-
and isinstance(session_state_from_db, dict)
|
|
7692
|
-
and len(session_state_from_db) > 0
|
|
7693
|
-
and not self.overwrite_db_session_state
|
|
7694
|
-
):
|
|
7695
|
-
# This preserves precedence: run_params > db_state > agent_defaults
|
|
7696
|
-
merged_state = session_state_from_db.copy()
|
|
7697
|
-
merge_dictionaries(merged_state, session_state)
|
|
7698
|
-
session_state.clear()
|
|
7699
|
-
session_state.update(merged_state)
|
|
7700
|
-
|
|
7701
|
-
# Update the session_state in the session
|
|
7702
|
-
if session.session_data is not None:
|
|
7703
|
-
session.session_data["session_state"] = session_state
|
|
7704
|
-
|
|
7705
|
-
return session_state
|
|
7706
|
-
|
|
7707
|
-
def _update_metadata(self, session: TeamSession):
|
|
7708
|
-
"""Update the extra_data in the session"""
|
|
7709
|
-
from agno.utils.merge_dict import merge_dictionaries
|
|
7710
|
-
|
|
7711
|
-
# Read metadata from the database
|
|
7712
|
-
if session.metadata is not None:
|
|
7713
|
-
# If metadata is set in the agent, update the database metadata with the agent's metadata
|
|
7714
|
-
if self.metadata is not None:
|
|
7715
|
-
# Updates agent's session metadata in place
|
|
7716
|
-
merge_dictionaries(session.metadata, self.metadata)
|
|
7717
|
-
# Update the current metadata with the metadata from the database which is updated in place
|
|
7718
|
-
self.metadata = session.metadata
|
|
7899
|
+
def generate_session_name(self, session: TeamSession) -> str:
|
|
7900
|
+
"""
|
|
7901
|
+
Generate a name for the team session
|
|
7719
7902
|
|
|
7720
|
-
|
|
7721
|
-
|
|
7903
|
+
Args:
|
|
7904
|
+
session: The TeamSession to generate a name for.
|
|
7905
|
+
Returns:
|
|
7906
|
+
str: The generated session name.
|
|
7907
|
+
"""
|
|
7722
7908
|
|
|
7723
7909
|
if self.model is None:
|
|
7724
7910
|
raise Exception("Model not set")
|
|
@@ -7746,62 +7932,113 @@ class Team:
|
|
|
7746
7932
|
content = generated_name.content
|
|
7747
7933
|
if content is None:
|
|
7748
7934
|
log_error("Generated name is None. Trying again.")
|
|
7749
|
-
return self.
|
|
7935
|
+
return self.generate_session_name(session=session)
|
|
7750
7936
|
if len(content.split()) > 15:
|
|
7751
7937
|
log_error("Generated name is too long. Trying again.")
|
|
7752
|
-
return self.
|
|
7938
|
+
return self.generate_session_name(session=session)
|
|
7753
7939
|
return content.replace('"', "").strip()
|
|
7754
7940
|
|
|
7755
7941
|
def set_session_name(
|
|
7756
7942
|
self, session_id: Optional[str] = None, autogenerate: bool = False, session_name: Optional[str] = None
|
|
7757
7943
|
) -> TeamSession:
|
|
7758
|
-
"""
|
|
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
|
+
"""
|
|
7759
7954
|
session_id = session_id or self.session_id
|
|
7760
7955
|
|
|
7761
7956
|
if session_id is None:
|
|
7762
7957
|
raise Exception("Session ID is not set")
|
|
7763
7958
|
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
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
|
+
)
|
|
7769
7963
|
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
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
|
|
7776
7969
|
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
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
|
|
7780
7978
|
|
|
7781
|
-
|
|
7782
|
-
|
|
7979
|
+
if session_id is None:
|
|
7980
|
+
raise Exception("Session ID is not set")
|
|
7783
7981
|
|
|
7784
|
-
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
|
+
)
|
|
7785
7988
|
|
|
7786
7989
|
def get_session_name(self, session_id: Optional[str] = None) -> str:
|
|
7787
|
-
"""
|
|
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
|
+
"""
|
|
7788
7998
|
session_id = session_id or self.session_id
|
|
7789
7999
|
if session_id is None:
|
|
7790
8000
|
raise Exception("Session ID is not set")
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
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)
|
|
7795
8016
|
|
|
7796
8017
|
def get_session_state(self, session_id: Optional[str] = None) -> Dict[str, Any]:
|
|
7797
|
-
"""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
|
+
"""
|
|
7798
8025
|
session_id = session_id or self.session_id
|
|
7799
8026
|
if session_id is None:
|
|
7800
8027
|
raise Exception("Session ID is not set")
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
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)
|
|
7805
8042
|
|
|
7806
8043
|
def update_session_state(self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None) -> str:
|
|
7807
8044
|
"""
|
|
@@ -7815,19 +8052,7 @@ class Team:
|
|
|
7815
8052
|
session_id = session_id or self.session_id
|
|
7816
8053
|
if session_id is None:
|
|
7817
8054
|
raise Exception("Session ID is not set")
|
|
7818
|
-
|
|
7819
|
-
if session is None:
|
|
7820
|
-
raise Exception("Session not found")
|
|
7821
|
-
|
|
7822
|
-
if session.session_data is not None and "session_state" not in session.session_data:
|
|
7823
|
-
session.session_data["session_state"] = {}
|
|
7824
|
-
|
|
7825
|
-
for key, value in session_state_updates.items():
|
|
7826
|
-
session.session_data["session_state"][key] = value # type: ignore
|
|
7827
|
-
|
|
7828
|
-
self.save_session(session=session)
|
|
7829
|
-
|
|
7830
|
-
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)
|
|
7831
8056
|
|
|
7832
8057
|
async def aupdate_session_state(
|
|
7833
8058
|
self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None
|
|
@@ -7843,64 +8068,117 @@ class Team:
|
|
|
7843
8068
|
session_id = session_id or self.session_id
|
|
7844
8069
|
if session_id is None:
|
|
7845
8070
|
raise Exception("Session ID is not set")
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
8071
|
+
return await aupdate_session_state_util(
|
|
8072
|
+
entity=self, session_state_updates=session_state_updates, session_id=session_id
|
|
8073
|
+
)
|
|
7849
8074
|
|
|
7850
|
-
|
|
7851
|
-
|
|
8075
|
+
def get_session_metrics(self, session_id: Optional[str] = None) -> Optional[Metrics]:
|
|
8076
|
+
"""Get the session metrics for the given session ID.
|
|
7852
8077
|
|
|
7853
|
-
|
|
7854
|
-
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")
|
|
7855
8086
|
|
|
7856
|
-
|
|
8087
|
+
return get_session_metrics_util(self, session_id=session_id)
|
|
7857
8088
|
|
|
7858
|
-
|
|
8089
|
+
async def aget_session_metrics(self, session_id: Optional[str] = None) -> Optional[Metrics]:
|
|
8090
|
+
"""Get the session metrics for the given session ID.
|
|
7859
8091
|
|
|
7860
|
-
|
|
7861
|
-
|
|
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
|
+
"""
|
|
7862
8097
|
session_id = session_id or self.session_id
|
|
7863
8098
|
if session_id is None:
|
|
7864
8099
|
raise Exception("Session ID is not set")
|
|
7865
8100
|
|
|
7866
|
-
|
|
7867
|
-
if session is None:
|
|
7868
|
-
raise Exception("Session not found")
|
|
8101
|
+
return await aget_session_metrics_util(self, session_id=session_id)
|
|
7869
8102
|
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
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
|
|
8107
|
+
|
|
8108
|
+
self.db.delete_session(session_id=session_id)
|
|
7876
8109
|
|
|
7877
|
-
def
|
|
8110
|
+
async def adelete_session(self, session_id: str):
|
|
7878
8111
|
"""Delete the current session and save to storage"""
|
|
7879
|
-
if self.db is
|
|
7880
|
-
|
|
8112
|
+
if self.db is None:
|
|
8113
|
+
return
|
|
8114
|
+
await self.db.delete_session(session_id=session_id) # type: ignore
|
|
7881
8115
|
|
|
7882
8116
|
def get_chat_history(self, session_id: Optional[str] = None) -> List[Message]:
|
|
7883
|
-
"""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
|
+
"""
|
|
7884
8138
|
session_id = session_id or self.session_id
|
|
7885
8139
|
if session_id is None:
|
|
7886
|
-
|
|
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
|
+
"""
|
|
8152
|
+
session_id = session_id or self.session_id
|
|
8153
|
+
if session_id is None:
|
|
8154
|
+
log_warning("Session ID is not set, cannot get messages for session")
|
|
7887
8155
|
return []
|
|
7888
8156
|
|
|
7889
8157
|
session = self.get_session(session_id=session_id) # type: ignore
|
|
7890
8158
|
|
|
7891
8159
|
if session is None:
|
|
7892
|
-
|
|
8160
|
+
log_warning(f"Session {session_id} not found")
|
|
8161
|
+
return []
|
|
8162
|
+
|
|
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
|
+
)
|
|
7893
8167
|
|
|
7894
|
-
|
|
8168
|
+
async def aget_messages_for_session(self, session_id: Optional[str] = None) -> List[Message]:
|
|
8169
|
+
"""Get messages for a session
|
|
7895
8170
|
|
|
7896
|
-
|
|
7897
|
-
|
|
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
|
+
"""
|
|
7898
8176
|
session_id = session_id or self.session_id
|
|
7899
8177
|
if session_id is None:
|
|
7900
8178
|
log_warning("Session ID is not set, cannot get messages for session")
|
|
7901
8179
|
return []
|
|
7902
8180
|
|
|
7903
|
-
session = self.
|
|
8181
|
+
session = await self.aget_session(session_id=session_id) # type: ignore
|
|
7904
8182
|
|
|
7905
8183
|
if session is None:
|
|
7906
8184
|
log_warning(f"Session {session_id} not found")
|
|
@@ -7911,8 +8189,14 @@ class Team:
|
|
|
7911
8189
|
team_id=self.id,
|
|
7912
8190
|
)
|
|
7913
8191
|
|
|
7914
|
-
def get_session_summary(self, session_id: Optional[str] = None):
|
|
7915
|
-
"""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
|
+
"""
|
|
7916
8200
|
session_id = session_id if session_id is not None else self.session_id
|
|
7917
8201
|
if session_id is None:
|
|
7918
8202
|
raise ValueError("Session ID is required")
|
|
@@ -7924,8 +8208,33 @@ class Team:
|
|
|
7924
8208
|
|
|
7925
8209
|
return session.get_session_summary() # type: ignore
|
|
7926
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
|
+
|
|
7927
8230
|
def get_user_memories(self, user_id: Optional[str] = None) -> Optional[List[UserMemory]]:
|
|
7928
|
-
"""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
|
+
"""
|
|
7929
8238
|
if self.memory_manager is None:
|
|
7930
8239
|
return None
|
|
7931
8240
|
user_id = user_id if user_id is not None else self.user_id
|
|
@@ -7934,86 +8243,21 @@ class Team:
|
|
|
7934
8243
|
|
|
7935
8244
|
return self.memory_manager.get_user_memories(user_id=user_id)
|
|
7936
8245
|
|
|
7937
|
-
def
|
|
7938
|
-
|
|
7939
|
-
team_run_context: Dict[str, Any],
|
|
7940
|
-
member_name: str,
|
|
7941
|
-
task: str,
|
|
7942
|
-
run_response: Union[RunOutput, TeamRunOutput],
|
|
7943
|
-
) -> None:
|
|
7944
|
-
if "member_responses" not in team_run_context:
|
|
7945
|
-
team_run_context["member_responses"] = []
|
|
7946
|
-
team_run_context["member_responses"].append(
|
|
7947
|
-
{
|
|
7948
|
-
"member_name": member_name,
|
|
7949
|
-
"task": task,
|
|
7950
|
-
"run_response": run_response,
|
|
7951
|
-
}
|
|
7952
|
-
)
|
|
7953
|
-
log_debug(f"Updated team run context with member name: {member_name}")
|
|
7954
|
-
|
|
7955
|
-
def _get_team_member_interactions_str(self, team_run_context: Dict[str, Any]) -> str:
|
|
7956
|
-
if not team_run_context:
|
|
7957
|
-
return ""
|
|
7958
|
-
team_member_interactions_str = ""
|
|
7959
|
-
if "member_responses" in team_run_context:
|
|
7960
|
-
team_member_interactions_str += (
|
|
7961
|
-
"<member_interaction_context>\nSee below interactions wit other team members.\n"
|
|
7962
|
-
)
|
|
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.
|
|
7963
8248
|
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
team_member_interactions_str += "\n"
|
|
7975
|
-
team_member_interactions_str += "</member_interaction_context>\n"
|
|
7976
|
-
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"
|
|
7977
8259
|
|
|
7978
|
-
|
|
7979
|
-
if not team_run_context:
|
|
7980
|
-
return []
|
|
7981
|
-
images = []
|
|
7982
|
-
if "member_responses" in team_run_context:
|
|
7983
|
-
for interaction in team_run_context["member_responses"]:
|
|
7984
|
-
if interaction["run_response"].images:
|
|
7985
|
-
images.extend(interaction["run_response"].images)
|
|
7986
|
-
return images
|
|
7987
|
-
|
|
7988
|
-
def _get_team_run_context_videos(self, team_run_context: Dict[str, Any]) -> List[Video]:
|
|
7989
|
-
if not team_run_context:
|
|
7990
|
-
return []
|
|
7991
|
-
videos = []
|
|
7992
|
-
if "member_responses" in team_run_context:
|
|
7993
|
-
for interaction in team_run_context["member_responses"]:
|
|
7994
|
-
if interaction["run_response"].videos:
|
|
7995
|
-
videos.extend(interaction["run_response"].videos)
|
|
7996
|
-
return videos
|
|
7997
|
-
|
|
7998
|
-
def _get_team_run_context_audio(self, team_run_context: Dict[str, Any]) -> List[Audio]:
|
|
7999
|
-
if not team_run_context:
|
|
8000
|
-
return []
|
|
8001
|
-
audio = []
|
|
8002
|
-
if "member_responses" in team_run_context:
|
|
8003
|
-
for interaction in team_run_context["member_responses"]:
|
|
8004
|
-
if interaction["run_response"].audio:
|
|
8005
|
-
audio.extend(interaction["run_response"].audio)
|
|
8006
|
-
return audio
|
|
8007
|
-
|
|
8008
|
-
def _get_team_run_context_files(self, team_run_context: Dict[str, Any]) -> List[File]:
|
|
8009
|
-
if not team_run_context:
|
|
8010
|
-
return []
|
|
8011
|
-
files = []
|
|
8012
|
-
if "member_responses" in team_run_context:
|
|
8013
|
-
for interaction in team_run_context["member_responses"]:
|
|
8014
|
-
if interaction["run_response"].files:
|
|
8015
|
-
files.extend(interaction["run_response"].files)
|
|
8016
|
-
return files
|
|
8260
|
+
return await self.memory_manager.aget_user_memories(user_id=user_id)
|
|
8017
8261
|
|
|
8018
8262
|
###########################################################################
|
|
8019
8263
|
# Handle images, videos and audio
|
|
@@ -8162,6 +8406,8 @@ class Team:
|
|
|
8162
8406
|
document_name = query.replace(" ", "_").replace("?", "").replace("!", "").replace(".", "")
|
|
8163
8407
|
document_content = json.dumps({"query": query, "result": result})
|
|
8164
8408
|
log_info(f"Adding document to Knowledge: {document_name}: {document_content}")
|
|
8409
|
+
import asyncio
|
|
8410
|
+
|
|
8165
8411
|
from agno.knowledge.reader.text_reader import TextReader
|
|
8166
8412
|
|
|
8167
8413
|
asyncio.run(
|