agno 2.0.0rc1__py3-none-any.whl → 2.0.1__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 +101 -140
- agno/db/mongo/mongo.py +8 -3
- agno/eval/accuracy.py +12 -5
- agno/knowledge/chunking/strategy.py +14 -14
- agno/knowledge/knowledge.py +156 -120
- agno/knowledge/reader/arxiv_reader.py +5 -5
- agno/knowledge/reader/csv_reader.py +6 -77
- agno/knowledge/reader/docx_reader.py +5 -5
- agno/knowledge/reader/firecrawl_reader.py +5 -5
- agno/knowledge/reader/json_reader.py +5 -5
- agno/knowledge/reader/markdown_reader.py +31 -9
- agno/knowledge/reader/pdf_reader.py +10 -123
- agno/knowledge/reader/reader_factory.py +65 -72
- agno/knowledge/reader/s3_reader.py +44 -114
- agno/knowledge/reader/text_reader.py +5 -5
- agno/knowledge/reader/url_reader.py +75 -31
- agno/knowledge/reader/web_search_reader.py +6 -29
- agno/knowledge/reader/website_reader.py +5 -5
- agno/knowledge/reader/wikipedia_reader.py +5 -5
- agno/knowledge/reader/youtube_reader.py +6 -6
- agno/knowledge/reranker/__init__.py +9 -0
- agno/knowledge/utils.py +10 -10
- agno/media.py +269 -268
- agno/models/aws/bedrock.py +3 -7
- agno/models/base.py +50 -54
- agno/models/google/gemini.py +11 -10
- agno/models/message.py +4 -4
- agno/models/ollama/chat.py +1 -1
- agno/models/openai/chat.py +33 -14
- agno/models/response.py +5 -5
- agno/os/app.py +40 -29
- agno/os/mcp.py +39 -59
- agno/os/router.py +547 -16
- agno/os/routers/evals/evals.py +197 -12
- agno/os/routers/knowledge/knowledge.py +428 -14
- agno/os/routers/memory/memory.py +250 -28
- agno/os/routers/metrics/metrics.py +125 -7
- agno/os/routers/session/session.py +393 -25
- agno/os/schema.py +55 -2
- agno/run/agent.py +37 -28
- agno/run/base.py +9 -19
- agno/run/team.py +110 -19
- agno/run/workflow.py +41 -28
- agno/team/team.py +808 -1080
- agno/tools/brightdata.py +3 -3
- agno/tools/cartesia.py +3 -5
- agno/tools/dalle.py +7 -4
- agno/tools/desi_vocal.py +2 -2
- agno/tools/e2b.py +6 -6
- agno/tools/eleven_labs.py +3 -3
- agno/tools/fal.py +4 -4
- agno/tools/function.py +7 -7
- agno/tools/giphy.py +2 -2
- agno/tools/lumalab.py +3 -3
- agno/tools/mcp.py +1 -2
- agno/tools/models/azure_openai.py +2 -2
- agno/tools/models/gemini.py +3 -3
- agno/tools/models/groq.py +3 -5
- agno/tools/models/nebius.py +2 -2
- agno/tools/models_labs.py +5 -5
- agno/tools/openai.py +4 -9
- agno/tools/opencv.py +3 -3
- agno/tools/replicate.py +7 -7
- agno/utils/events.py +5 -5
- agno/utils/gemini.py +1 -1
- agno/utils/log.py +52 -2
- agno/utils/mcp.py +57 -5
- agno/utils/models/aws_claude.py +1 -1
- agno/utils/models/claude.py +0 -8
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/print_response/team.py +177 -73
- agno/utils/streamlit.py +27 -0
- agno/vectordb/lancedb/lance_db.py +82 -25
- agno/workflow/step.py +7 -7
- agno/workflow/types.py +13 -13
- agno/workflow/workflow.py +37 -28
- {agno-2.0.0rc1.dist-info → agno-2.0.1.dist-info}/METADATA +140 -1
- {agno-2.0.0rc1.dist-info → agno-2.0.1.dist-info}/RECORD +83 -84
- agno-2.0.1.dist-info/licenses/LICENSE +201 -0
- agno/knowledge/reader/gcs_reader.py +0 -67
- agno-2.0.0rc1.dist-info/licenses/LICENSE +0 -375
- {agno-2.0.0rc1.dist-info → agno-2.0.1.dist-info}/WHEEL +0 -0
- {agno-2.0.0rc1.dist-info → agno-2.0.1.dist-info}/top_level.txt +0 -0
agno/team/team.py
CHANGED
|
@@ -33,7 +33,7 @@ from agno.agent import Agent
|
|
|
33
33
|
from agno.db.base import BaseDb, SessionType, UserMemory
|
|
34
34
|
from agno.exceptions import ModelProviderError, RunCancelledException
|
|
35
35
|
from agno.knowledge.knowledge import Knowledge
|
|
36
|
-
from agno.media import Audio,
|
|
36
|
+
from agno.media import Audio, File, Image, Video
|
|
37
37
|
from agno.memory import MemoryManager
|
|
38
38
|
from agno.models.base import Model
|
|
39
39
|
from agno.models.message import Message, MessageReferences
|
|
@@ -51,7 +51,7 @@ from agno.run.cancel import (
|
|
|
51
51
|
register_run,
|
|
52
52
|
)
|
|
53
53
|
from agno.run.messages import RunMessages
|
|
54
|
-
from agno.run.team import TeamRunEvent, TeamRunOutput, TeamRunOutputEvent
|
|
54
|
+
from agno.run.team import TeamRunEvent, TeamRunInput, TeamRunOutput, TeamRunOutputEvent
|
|
55
55
|
from agno.session import SessionSummaryManager, TeamSession
|
|
56
56
|
from agno.tools import Toolkit
|
|
57
57
|
from agno.tools.function import Function
|
|
@@ -100,7 +100,6 @@ from agno.utils.reasoning import (
|
|
|
100
100
|
from agno.utils.response import (
|
|
101
101
|
async_generator_wrapper,
|
|
102
102
|
check_if_run_cancelled,
|
|
103
|
-
escape_markdown_tags,
|
|
104
103
|
generator_wrapper,
|
|
105
104
|
)
|
|
106
105
|
from agno.utils.safe_formatter import SafeFormatter
|
|
@@ -117,8 +116,6 @@ class Team:
|
|
|
117
116
|
|
|
118
117
|
members: List[Union[Agent, "Team"]]
|
|
119
118
|
|
|
120
|
-
mode: Literal["route", "coordinate", "collaborate"] = "coordinate"
|
|
121
|
-
|
|
122
119
|
# Model for this Team
|
|
123
120
|
model: Optional[Model] = None
|
|
124
121
|
|
|
@@ -132,6 +129,14 @@ class Team:
|
|
|
132
129
|
# If this team is part of a team itself, this is the role of the team
|
|
133
130
|
role: Optional[str] = None
|
|
134
131
|
|
|
132
|
+
# If True, the team leader won't process responses from the members and instead will return them directly
|
|
133
|
+
# Should not be used in combination with delegate_task_to_all_members
|
|
134
|
+
respond_directly: bool = False
|
|
135
|
+
# If True, the team leader will delegate the task to all members, instead of deciding for a subset
|
|
136
|
+
delegate_task_to_all_members: bool = False
|
|
137
|
+
# Set to false if you want to send the run input directly to the member agents
|
|
138
|
+
determine_input_for_members: bool = True
|
|
139
|
+
|
|
135
140
|
# --- If this Team is part of a workflow ---
|
|
136
141
|
# Optional workflow ID. Indicates this team is part of a workflow.
|
|
137
142
|
workflow_id: Optional[str] = None
|
|
@@ -145,9 +150,9 @@ class Team:
|
|
|
145
150
|
session_id: Optional[str] = None
|
|
146
151
|
# Session state (stored in the database to persist across runs)
|
|
147
152
|
session_state: Optional[Dict[str, Any]] = None
|
|
148
|
-
#
|
|
153
|
+
# Set to True to add the session_state to the context
|
|
149
154
|
add_session_state_to_context: bool = False
|
|
150
|
-
#
|
|
155
|
+
# Set to True to give the team tools to update the session_state dynamically
|
|
151
156
|
enable_agentic_state: bool = False
|
|
152
157
|
# If True, cache the current Team session in memory for faster access
|
|
153
158
|
cache_session: bool = False
|
|
@@ -221,8 +226,6 @@ class Team:
|
|
|
221
226
|
references_format: Literal["json", "yaml"] = "json"
|
|
222
227
|
|
|
223
228
|
# --- Tools ---
|
|
224
|
-
# If True, enable the team agent to update the team context and automatically send the team context to the members
|
|
225
|
-
enable_agentic_context: bool = False
|
|
226
229
|
# If True, send all previous member interactions to members
|
|
227
230
|
share_member_interactions: bool = False
|
|
228
231
|
# If True, add a tool to get information about the team members
|
|
@@ -234,6 +237,11 @@ class Team:
|
|
|
234
237
|
# If True, read the team history
|
|
235
238
|
read_team_history: bool = False
|
|
236
239
|
|
|
240
|
+
# If False, media (images, videos, audio, files) is only available to tools and not sent to the LLM
|
|
241
|
+
send_media_to_model: bool = True
|
|
242
|
+
# If True, store media in run output
|
|
243
|
+
store_media: bool = True
|
|
244
|
+
|
|
237
245
|
# --- Team Tools ---
|
|
238
246
|
# A list of tools provided to the Model.
|
|
239
247
|
# Tools are functions the model may generate JSON inputs for.
|
|
@@ -342,11 +350,13 @@ class Team:
|
|
|
342
350
|
def __init__(
|
|
343
351
|
self,
|
|
344
352
|
members: List[Union[Agent, "Team"]],
|
|
345
|
-
|
|
353
|
+
id: Optional[str] = None,
|
|
346
354
|
model: Optional[Model] = None,
|
|
347
355
|
name: Optional[str] = None,
|
|
348
356
|
role: Optional[str] = None,
|
|
349
|
-
|
|
357
|
+
respond_directly: bool = False,
|
|
358
|
+
determine_input_for_members: bool = True,
|
|
359
|
+
delegate_task_to_all_members: bool = False,
|
|
350
360
|
user_id: Optional[str] = None,
|
|
351
361
|
session_id: Optional[str] = None,
|
|
352
362
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -376,11 +386,12 @@ class Team:
|
|
|
376
386
|
update_knowledge: bool = False,
|
|
377
387
|
knowledge_retriever: Optional[Callable[..., Optional[List[Union[Dict, str]]]]] = None,
|
|
378
388
|
references_format: Literal["json", "yaml"] = "json",
|
|
379
|
-
enable_agentic_context: bool = False,
|
|
380
389
|
share_member_interactions: bool = False,
|
|
381
390
|
get_member_information_tool: bool = False,
|
|
382
391
|
search_knowledge: bool = True,
|
|
383
392
|
read_team_history: bool = False,
|
|
393
|
+
store_media: bool = True,
|
|
394
|
+
send_media_to_model: bool = True,
|
|
384
395
|
tools: Optional[List[Union[Toolkit, Callable, Function, Dict]]] = None,
|
|
385
396
|
tool_call_limit: Optional[int] = None,
|
|
386
397
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
@@ -424,14 +435,16 @@ class Team:
|
|
|
424
435
|
):
|
|
425
436
|
self.members = members
|
|
426
437
|
|
|
427
|
-
self.mode = mode
|
|
428
|
-
|
|
429
438
|
self.model = model
|
|
430
439
|
|
|
431
440
|
self.name = name
|
|
432
441
|
self.id = id
|
|
433
442
|
self.role = role
|
|
434
443
|
|
|
444
|
+
self.respond_directly = respond_directly
|
|
445
|
+
self.determine_input_for_members = determine_input_for_members
|
|
446
|
+
self.delegate_task_to_all_members = delegate_task_to_all_members
|
|
447
|
+
|
|
435
448
|
self.user_id = user_id
|
|
436
449
|
self.session_id = session_id
|
|
437
450
|
self.session_state = session_state
|
|
@@ -465,12 +478,14 @@ class Team:
|
|
|
465
478
|
self.knowledge_retriever = knowledge_retriever
|
|
466
479
|
self.references_format = references_format
|
|
467
480
|
|
|
468
|
-
self.enable_agentic_context = enable_agentic_context
|
|
469
481
|
self.share_member_interactions = share_member_interactions
|
|
470
482
|
self.get_member_information_tool = get_member_information_tool
|
|
471
483
|
self.search_knowledge = search_knowledge
|
|
472
484
|
self.read_team_history = read_team_history
|
|
473
485
|
|
|
486
|
+
self.store_media = store_media
|
|
487
|
+
self.send_media_to_model = send_media_to_model
|
|
488
|
+
|
|
474
489
|
self.tools = tools
|
|
475
490
|
self.tool_choice = tool_choice
|
|
476
491
|
self.tool_call_limit = tool_call_limit
|
|
@@ -531,11 +546,11 @@ class Team:
|
|
|
531
546
|
|
|
532
547
|
# TODO: Remove these
|
|
533
548
|
# Images generated during this session
|
|
534
|
-
self.images: Optional[List[
|
|
549
|
+
self.images: Optional[List[Image]] = None
|
|
535
550
|
# Audio generated during this session
|
|
536
|
-
self.audio: Optional[List[
|
|
551
|
+
self.audio: Optional[List[Audio]] = None
|
|
537
552
|
# Videos generated during this session
|
|
538
|
-
self.videos: Optional[List[
|
|
553
|
+
self.videos: Optional[List[Video]] = None
|
|
539
554
|
|
|
540
555
|
# Team session
|
|
541
556
|
self._team_session: Optional[TeamSession] = None
|
|
@@ -591,6 +606,15 @@ class Team:
|
|
|
591
606
|
if isinstance(input, Message):
|
|
592
607
|
input = input.content # type: ignore
|
|
593
608
|
|
|
609
|
+
# If input is a string, convert it to a dict
|
|
610
|
+
if isinstance(input, str):
|
|
611
|
+
import json
|
|
612
|
+
|
|
613
|
+
try:
|
|
614
|
+
input = json.loads(input)
|
|
615
|
+
except Exception as e:
|
|
616
|
+
raise ValueError(f"Failed to parse input. Is it a valid JSON string?: {e}")
|
|
617
|
+
|
|
594
618
|
# Case 1: Message is already a BaseModel instance
|
|
595
619
|
if isinstance(input, BaseModel):
|
|
596
620
|
if isinstance(input, self.input_schema):
|
|
@@ -715,6 +739,15 @@ class Team:
|
|
|
715
739
|
return session_id, user_id, session_state # type: ignore
|
|
716
740
|
|
|
717
741
|
def initialize_team(self, debug_mode: Optional[bool] = None) -> None:
|
|
742
|
+
# Make sure for the team, we are using the team logger
|
|
743
|
+
use_team_logger()
|
|
744
|
+
|
|
745
|
+
if self.delegate_task_to_all_members and self.respond_directly:
|
|
746
|
+
log_warning(
|
|
747
|
+
"delegate_task_to_all_members and respond_directly are both enabled. The task will be delegated to all members."
|
|
748
|
+
)
|
|
749
|
+
self.respond_directly = False
|
|
750
|
+
|
|
718
751
|
self._set_default_model()
|
|
719
752
|
|
|
720
753
|
# Set debug mode
|
|
@@ -738,9 +771,6 @@ class Team:
|
|
|
738
771
|
for member in self.members:
|
|
739
772
|
self._initialize_member(member, debug_mode=self.debug_mode)
|
|
740
773
|
|
|
741
|
-
# Make sure for the team, we are using the team logger
|
|
742
|
-
use_team_logger()
|
|
743
|
-
|
|
744
774
|
def add_tool(self, tool: Union[Toolkit, Callable, Function, Dict]):
|
|
745
775
|
if not self.tools:
|
|
746
776
|
self.tools = []
|
|
@@ -812,6 +842,11 @@ class Team:
|
|
|
812
842
|
# Update TeamRunOutput
|
|
813
843
|
self._update_run_response(model_response=model_response, run_response=run_response, run_messages=run_messages)
|
|
814
844
|
|
|
845
|
+
if self.store_media:
|
|
846
|
+
self._store_media(run_response, model_response)
|
|
847
|
+
else:
|
|
848
|
+
self._scrub_media_from_run_output(run_response)
|
|
849
|
+
|
|
815
850
|
# 4. Add the RunOutput to Team Session
|
|
816
851
|
session.upsert_run(run_response=run_response)
|
|
817
852
|
|
|
@@ -1010,7 +1045,6 @@ class Team:
|
|
|
1010
1045
|
videos: Optional[Sequence[Video]] = None,
|
|
1011
1046
|
files: Optional[Sequence[File]] = None,
|
|
1012
1047
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1013
|
-
store_member_responses: Optional[bool] = None,
|
|
1014
1048
|
add_history_to_context: Optional[bool] = None,
|
|
1015
1049
|
add_dependencies_to_context: Optional[bool] = None,
|
|
1016
1050
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -1036,7 +1070,6 @@ class Team:
|
|
|
1036
1070
|
videos: Optional[Sequence[Video]] = None,
|
|
1037
1071
|
files: Optional[Sequence[File]] = None,
|
|
1038
1072
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1039
|
-
store_member_responses: Optional[bool] = None,
|
|
1040
1073
|
add_history_to_context: Optional[bool] = None,
|
|
1041
1074
|
add_dependencies_to_context: Optional[bool] = None,
|
|
1042
1075
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -1061,7 +1094,6 @@ class Team:
|
|
|
1061
1094
|
images: Optional[Sequence[Image]] = None,
|
|
1062
1095
|
videos: Optional[Sequence[Video]] = None,
|
|
1063
1096
|
files: Optional[Sequence[File]] = None,
|
|
1064
|
-
store_member_responses: Optional[bool] = None,
|
|
1065
1097
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1066
1098
|
add_history_to_context: Optional[bool] = None,
|
|
1067
1099
|
add_dependencies_to_context: Optional[bool] = None,
|
|
@@ -1077,9 +1109,6 @@ class Team:
|
|
|
1077
1109
|
# Validate input against input_schema if provided
|
|
1078
1110
|
validated_input = self._validate_input(input)
|
|
1079
1111
|
|
|
1080
|
-
if store_member_responses is not None:
|
|
1081
|
-
self.store_member_responses = store_member_responses
|
|
1082
|
-
|
|
1083
1112
|
# Create a run_id for this specific run
|
|
1084
1113
|
run_id = str(uuid4())
|
|
1085
1114
|
|
|
@@ -1090,6 +1119,15 @@ class Team:
|
|
|
1090
1119
|
# Initialize Team
|
|
1091
1120
|
self.initialize_team(debug_mode=debug_mode)
|
|
1092
1121
|
|
|
1122
|
+
image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
|
|
1123
|
+
images=images, videos=videos, audios=audio
|
|
1124
|
+
)
|
|
1125
|
+
|
|
1126
|
+
# Create RunInput to capture the original user input
|
|
1127
|
+
run_input = TeamRunInput(
|
|
1128
|
+
input_content=input, images=image_artifacts, videos=video_artifacts, audios=audio_artifacts, files=files
|
|
1129
|
+
)
|
|
1130
|
+
|
|
1093
1131
|
# Read existing session from database
|
|
1094
1132
|
team_session = self._read_or_create_session(session_id=session_id, user_id=user_id)
|
|
1095
1133
|
self._update_metadata(session=team_session)
|
|
@@ -1129,9 +1167,6 @@ class Team:
|
|
|
1129
1167
|
if stream is None:
|
|
1130
1168
|
stream = False if self.stream is None else self.stream
|
|
1131
1169
|
|
|
1132
|
-
if store_member_responses is None:
|
|
1133
|
-
store_member_responses = False if self.store_member_responses is None else self.store_member_responses
|
|
1134
|
-
|
|
1135
1170
|
if stream_intermediate_steps is None:
|
|
1136
1171
|
stream_intermediate_steps = (
|
|
1137
1172
|
False if self.stream_intermediate_steps is None else self.stream_intermediate_steps
|
|
@@ -1163,6 +1198,7 @@ class Team:
|
|
|
1163
1198
|
team_id=self.id,
|
|
1164
1199
|
team_name=self.name,
|
|
1165
1200
|
metadata=metadata,
|
|
1201
|
+
input=run_input,
|
|
1166
1202
|
)
|
|
1167
1203
|
|
|
1168
1204
|
run_response.model = self.model.id if self.model is not None else None
|
|
@@ -1186,7 +1222,6 @@ class Team:
|
|
|
1186
1222
|
audio=audio,
|
|
1187
1223
|
files=files,
|
|
1188
1224
|
workflow_context=workflow_context,
|
|
1189
|
-
store_member_responses=store_member_responses,
|
|
1190
1225
|
debug_mode=debug_mode,
|
|
1191
1226
|
add_history_to_context=add_history,
|
|
1192
1227
|
dependencies=run_dependencies,
|
|
@@ -1203,8 +1238,6 @@ class Team:
|
|
|
1203
1238
|
for attempt in range(num_attempts):
|
|
1204
1239
|
# Initialize the current run
|
|
1205
1240
|
|
|
1206
|
-
log_debug(f"Team Mode: '{self.mode}'", center=True)
|
|
1207
|
-
|
|
1208
1241
|
# Run the team
|
|
1209
1242
|
try:
|
|
1210
1243
|
run_messages = self._get_run_messages(
|
|
@@ -1227,10 +1260,6 @@ class Team:
|
|
|
1227
1260
|
if len(run_messages.messages) == 0:
|
|
1228
1261
|
log_error("No messages to be sent to the model.")
|
|
1229
1262
|
|
|
1230
|
-
self.run_messages = run_messages
|
|
1231
|
-
if len(run_messages.messages) == 0:
|
|
1232
|
-
log_error("No messages to be sent to the model.")
|
|
1233
|
-
|
|
1234
1263
|
if stream:
|
|
1235
1264
|
response_iterator = self._run_stream(
|
|
1236
1265
|
run_response=run_response,
|
|
@@ -1311,7 +1340,6 @@ class Team:
|
|
|
1311
1340
|
session: TeamSession,
|
|
1312
1341
|
user_id: Optional[str] = None,
|
|
1313
1342
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
1314
|
-
workflow_context: Optional[Dict] = None,
|
|
1315
1343
|
) -> TeamRunOutput:
|
|
1316
1344
|
"""Run the Team and return the response.
|
|
1317
1345
|
|
|
@@ -1358,6 +1386,11 @@ class Team:
|
|
|
1358
1386
|
# Update TeamRunOutput
|
|
1359
1387
|
self._update_run_response(model_response=model_response, run_response=run_response, run_messages=run_messages)
|
|
1360
1388
|
|
|
1389
|
+
if self.store_media:
|
|
1390
|
+
self._store_media(run_response, model_response)
|
|
1391
|
+
else:
|
|
1392
|
+
self._scrub_media_from_run_output(run_response)
|
|
1393
|
+
|
|
1361
1394
|
# 3. Add the run to memory
|
|
1362
1395
|
session.upsert_run(run_response=run_response)
|
|
1363
1396
|
|
|
@@ -1554,7 +1587,6 @@ class Team:
|
|
|
1554
1587
|
videos: Optional[Sequence[Video]] = None,
|
|
1555
1588
|
files: Optional[Sequence[File]] = None,
|
|
1556
1589
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1557
|
-
store_member_responses: Optional[bool] = None,
|
|
1558
1590
|
add_history_to_context: Optional[bool] = None,
|
|
1559
1591
|
add_dependencies_to_context: Optional[bool] = None,
|
|
1560
1592
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -1579,7 +1611,6 @@ class Team:
|
|
|
1579
1611
|
images: Optional[Sequence[Image]] = None,
|
|
1580
1612
|
videos: Optional[Sequence[Video]] = None,
|
|
1581
1613
|
files: Optional[Sequence[File]] = None,
|
|
1582
|
-
store_member_responses: Optional[bool] = None,
|
|
1583
1614
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1584
1615
|
add_history_to_context: Optional[bool] = None,
|
|
1585
1616
|
add_dependencies_to_context: Optional[bool] = None,
|
|
@@ -1606,7 +1637,6 @@ class Team:
|
|
|
1606
1637
|
videos: Optional[Sequence[Video]] = None,
|
|
1607
1638
|
files: Optional[Sequence[File]] = None,
|
|
1608
1639
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1609
|
-
store_member_responses: Optional[bool] = None,
|
|
1610
1640
|
add_history_to_context: Optional[bool] = None,
|
|
1611
1641
|
add_dependencies_to_context: Optional[bool] = None,
|
|
1612
1642
|
add_session_state_to_context: Optional[bool] = None,
|
|
@@ -1621,9 +1651,6 @@ class Team:
|
|
|
1621
1651
|
# Validate input against input_schema if provided
|
|
1622
1652
|
validated_input = self._validate_input(input)
|
|
1623
1653
|
|
|
1624
|
-
if store_member_responses is not None:
|
|
1625
|
-
self.store_member_responses = store_member_responses
|
|
1626
|
-
|
|
1627
1654
|
# Create a run_id for this specific run
|
|
1628
1655
|
run_id = str(uuid4())
|
|
1629
1656
|
|
|
@@ -1634,6 +1661,15 @@ class Team:
|
|
|
1634
1661
|
# Initialize Team
|
|
1635
1662
|
self.initialize_team(debug_mode=debug_mode)
|
|
1636
1663
|
|
|
1664
|
+
image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
|
|
1665
|
+
images=images, videos=videos, audios=audio
|
|
1666
|
+
)
|
|
1667
|
+
|
|
1668
|
+
# Create RunInput to capture the original user input
|
|
1669
|
+
run_input = TeamRunInput(
|
|
1670
|
+
input_content=input, images=image_artifacts, videos=video_artifacts, audios=audio_artifacts, files=files
|
|
1671
|
+
)
|
|
1672
|
+
|
|
1637
1673
|
team_session = self._read_or_create_session(session_id=session_id, user_id=user_id)
|
|
1638
1674
|
self._update_metadata(session=team_session)
|
|
1639
1675
|
|
|
@@ -1671,9 +1707,6 @@ class Team:
|
|
|
1671
1707
|
if stream is None:
|
|
1672
1708
|
stream = False if self.stream is None else self.stream
|
|
1673
1709
|
|
|
1674
|
-
if store_member_responses is None:
|
|
1675
|
-
store_member_responses = False if self.store_member_responses is None else self.store_member_responses
|
|
1676
|
-
|
|
1677
1710
|
if stream_intermediate_steps is None:
|
|
1678
1711
|
stream_intermediate_steps = (
|
|
1679
1712
|
False if self.stream_intermediate_steps is None else self.stream_intermediate_steps
|
|
@@ -1706,6 +1739,7 @@ class Team:
|
|
|
1706
1739
|
team_id=self.id,
|
|
1707
1740
|
team_name=self.name,
|
|
1708
1741
|
metadata=metadata,
|
|
1742
|
+
input=run_input,
|
|
1709
1743
|
)
|
|
1710
1744
|
|
|
1711
1745
|
run_response.model = self.model.id if self.model is not None else None
|
|
@@ -1729,7 +1763,6 @@ class Team:
|
|
|
1729
1763
|
audio=audio,
|
|
1730
1764
|
files=files,
|
|
1731
1765
|
workflow_context=workflow_context,
|
|
1732
|
-
store_member_responses=store_member_responses,
|
|
1733
1766
|
debug_mode=debug_mode,
|
|
1734
1767
|
add_history_to_context=add_history_to_context,
|
|
1735
1768
|
dependencies=dependencies,
|
|
@@ -1744,8 +1777,6 @@ class Team:
|
|
|
1744
1777
|
num_attempts = retries + 1
|
|
1745
1778
|
|
|
1746
1779
|
for attempt in range(num_attempts):
|
|
1747
|
-
log_debug(f"Mode: '{self.mode}'", center=True)
|
|
1748
|
-
|
|
1749
1780
|
# Run the team
|
|
1750
1781
|
try:
|
|
1751
1782
|
run_messages = self._get_run_messages(
|
|
@@ -1837,6 +1868,21 @@ class Team:
|
|
|
1837
1868
|
|
|
1838
1869
|
raise Exception(f"Failed after {num_attempts} attempts.")
|
|
1839
1870
|
|
|
1871
|
+
def _store_media(self, run_response: TeamRunOutput, model_response: ModelResponse):
|
|
1872
|
+
"""Store media from model response in run_response for persistence"""
|
|
1873
|
+
# Handle generated media fields from ModelResponse (generated media)
|
|
1874
|
+
if model_response.images is not None:
|
|
1875
|
+
for image in model_response.images:
|
|
1876
|
+
self._add_image(image, run_response) # Generated images go to run_response.images
|
|
1877
|
+
|
|
1878
|
+
if model_response.videos is not None:
|
|
1879
|
+
for video in model_response.videos:
|
|
1880
|
+
self._add_video(video, run_response) # Generated videos go to run_response.videos
|
|
1881
|
+
|
|
1882
|
+
if model_response.audios is not None:
|
|
1883
|
+
for audio in model_response.audios:
|
|
1884
|
+
self._add_audio(audio, run_response) # Generated audio go to run_response.audio
|
|
1885
|
+
|
|
1840
1886
|
def _update_run_response(
|
|
1841
1887
|
self, model_response: ModelResponse, run_response: TeamRunOutput, run_messages: RunMessages
|
|
1842
1888
|
):
|
|
@@ -1871,19 +1917,6 @@ class Team:
|
|
|
1871
1917
|
else:
|
|
1872
1918
|
run_response.tools.extend(model_response.tool_executions)
|
|
1873
1919
|
|
|
1874
|
-
# Handle unified media fields from ModelResponse
|
|
1875
|
-
if model_response.images is not None:
|
|
1876
|
-
for image in model_response.images:
|
|
1877
|
-
self._add_image(image, run_response)
|
|
1878
|
-
|
|
1879
|
-
if model_response.videos is not None:
|
|
1880
|
-
for video in model_response.videos:
|
|
1881
|
-
self._add_video(video, run_response)
|
|
1882
|
-
|
|
1883
|
-
if model_response.audios is not None:
|
|
1884
|
-
for audio in model_response.audios:
|
|
1885
|
-
self._add_audio(audio, run_response)
|
|
1886
|
-
|
|
1887
1920
|
# Update the run_response audio with the model response audio
|
|
1888
1921
|
if model_response.audio is not None:
|
|
1889
1922
|
run_response.response_audio = model_response.audio
|
|
@@ -2018,7 +2051,7 @@ class Team:
|
|
|
2018
2051
|
stream_model_response=stream_model_response,
|
|
2019
2052
|
) # type: ignore
|
|
2020
2053
|
async for model_response_event in model_stream:
|
|
2021
|
-
for
|
|
2054
|
+
for event in self._handle_model_response_chunk(
|
|
2022
2055
|
session=session,
|
|
2023
2056
|
run_response=run_response,
|
|
2024
2057
|
full_model_response=full_model_response,
|
|
@@ -2028,7 +2061,7 @@ class Team:
|
|
|
2028
2061
|
parse_structured_output=self.should_parse_structured_output,
|
|
2029
2062
|
workflow_context=workflow_context,
|
|
2030
2063
|
):
|
|
2031
|
-
yield
|
|
2064
|
+
yield event
|
|
2032
2065
|
|
|
2033
2066
|
# Handle structured outputs
|
|
2034
2067
|
if (self.output_schema is not None) and not self.use_json_mode and (full_model_response.parsed is not None):
|
|
@@ -2084,6 +2117,15 @@ class Team:
|
|
|
2084
2117
|
model_response_event, tuple(get_args(TeamRunOutputEvent))
|
|
2085
2118
|
):
|
|
2086
2119
|
if self.stream_member_events:
|
|
2120
|
+
if model_response_event.event == TeamRunEvent.custom_event: # type: ignore
|
|
2121
|
+
if hasattr(model_response_event, "team_id"):
|
|
2122
|
+
model_response_event.team_id = self.id
|
|
2123
|
+
if hasattr(model_response_event, "team_name"):
|
|
2124
|
+
model_response_event.team_name = self.name
|
|
2125
|
+
if not model_response_event.session_id: # type: ignore
|
|
2126
|
+
model_response_event.session_id = session.session_id # type: ignore
|
|
2127
|
+
if not model_response_event.run_id: # type: ignore
|
|
2128
|
+
model_response_event.run_id = run_response.run_id # type: ignore
|
|
2087
2129
|
# We just bubble the event up
|
|
2088
2130
|
yield self._handle_event(model_response_event, run_response) # type: ignore
|
|
2089
2131
|
else:
|
|
@@ -2113,28 +2155,38 @@ class Team:
|
|
|
2113
2155
|
should_yield = True
|
|
2114
2156
|
|
|
2115
2157
|
# Process thinking
|
|
2116
|
-
if model_response_event.reasoning_content is not None:
|
|
2117
|
-
if not full_model_response.reasoning_content:
|
|
2118
|
-
full_model_response.reasoning_content = model_response_event.reasoning_content
|
|
2119
|
-
else:
|
|
2120
|
-
full_model_response.reasoning_content += model_response_event.reasoning_content
|
|
2121
|
-
should_yield = True
|
|
2122
|
-
|
|
2123
|
-
if model_response_event.citations is not None:
|
|
2124
|
-
# We get citations in one chunk
|
|
2125
|
-
full_model_response.citations = model_response_event.citations
|
|
2126
|
-
should_yield = True
|
|
2127
|
-
|
|
2128
|
-
# Process audio
|
|
2129
2158
|
if model_response_event.audio is not None:
|
|
2130
2159
|
if full_model_response.audio is None:
|
|
2131
|
-
full_model_response.audio =
|
|
2160
|
+
full_model_response.audio = Audio(id=str(uuid4()), content=b"", transcript="")
|
|
2132
2161
|
|
|
2133
2162
|
if model_response_event.audio.id is not None:
|
|
2134
2163
|
full_model_response.audio.id = model_response_event.audio.id # type: ignore
|
|
2164
|
+
|
|
2135
2165
|
if model_response_event.audio.content is not None:
|
|
2136
|
-
|
|
2166
|
+
# Handle both base64 string and bytes content
|
|
2167
|
+
if isinstance(model_response_event.audio.content, str):
|
|
2168
|
+
# Decode base64 string to bytes
|
|
2169
|
+
try:
|
|
2170
|
+
import base64
|
|
2171
|
+
|
|
2172
|
+
decoded_content = base64.b64decode(model_response_event.audio.content)
|
|
2173
|
+
if full_model_response.audio.content is None:
|
|
2174
|
+
full_model_response.audio.content = b""
|
|
2175
|
+
full_model_response.audio.content += decoded_content
|
|
2176
|
+
except Exception:
|
|
2177
|
+
# If decode fails, encode string as bytes
|
|
2178
|
+
if full_model_response.audio.content is None:
|
|
2179
|
+
full_model_response.audio.content = b""
|
|
2180
|
+
full_model_response.audio.content += model_response_event.audio.content.encode("utf-8")
|
|
2181
|
+
elif isinstance(model_response_event.audio.content, bytes):
|
|
2182
|
+
# Content is already bytes
|
|
2183
|
+
if full_model_response.audio.content is None:
|
|
2184
|
+
full_model_response.audio.content = b""
|
|
2185
|
+
full_model_response.audio.content += model_response_event.audio.content
|
|
2186
|
+
|
|
2137
2187
|
if model_response_event.audio.transcript is not None:
|
|
2188
|
+
if full_model_response.audio.transcript is None:
|
|
2189
|
+
full_model_response.audio.transcript = ""
|
|
2138
2190
|
full_model_response.audio.transcript += model_response_event.audio.transcript # type: ignore
|
|
2139
2191
|
if model_response_event.audio.expires_at is not None:
|
|
2140
2192
|
full_model_response.audio.expires_at = model_response_event.audio.expires_at # type: ignore
|
|
@@ -2937,31 +2989,85 @@ class Team:
|
|
|
2937
2989
|
return member.name or entity_id
|
|
2938
2990
|
return entity_id
|
|
2939
2991
|
|
|
2940
|
-
def
|
|
2992
|
+
def _scrub_media_from_run_output(self, run_response: TeamRunOutput) -> None:
|
|
2993
|
+
"""
|
|
2994
|
+
Completely remove all media from RunOutput when store_media=False.
|
|
2995
|
+
This includes media in input, output artifacts, and all messages.
|
|
2996
|
+
"""
|
|
2997
|
+
# 1. Scrub RunInput media
|
|
2998
|
+
if run_response.input is not None:
|
|
2999
|
+
run_response.input.images = []
|
|
3000
|
+
run_response.input.videos = []
|
|
3001
|
+
run_response.input.audios = []
|
|
3002
|
+
run_response.input.files = []
|
|
3003
|
+
|
|
3004
|
+
# 2. RunOutput artifact media are skipped since we don't store them when store_media=False
|
|
3005
|
+
|
|
3006
|
+
# 3. Scrub media from all messages
|
|
3007
|
+
if run_response.messages:
|
|
3008
|
+
for message in run_response.messages:
|
|
3009
|
+
self._scrub_media_from_message(message)
|
|
3010
|
+
|
|
3011
|
+
# 4. Scrub media from additional_input messages if any
|
|
3012
|
+
if run_response.additional_input:
|
|
3013
|
+
for message in run_response.additional_input:
|
|
3014
|
+
self._scrub_media_from_message(message)
|
|
3015
|
+
|
|
3016
|
+
# 5. Scrub media from reasoning_messages if any
|
|
3017
|
+
if run_response.reasoning_messages:
|
|
3018
|
+
for message in run_response.reasoning_messages:
|
|
3019
|
+
self._scrub_media_from_message(message)
|
|
3020
|
+
|
|
3021
|
+
def _scrub_media_from_message(self, message: Message) -> None:
|
|
3022
|
+
"""Remove all media from a Message object."""
|
|
3023
|
+
# Input media
|
|
3024
|
+
message.images = None
|
|
3025
|
+
message.videos = None
|
|
3026
|
+
message.audio = None
|
|
3027
|
+
message.files = None
|
|
3028
|
+
|
|
3029
|
+
# Output media
|
|
3030
|
+
message.audio_output = None
|
|
3031
|
+
message.image_output = None
|
|
3032
|
+
message.video_output = None
|
|
3033
|
+
|
|
3034
|
+
def _validate_media_object_id(
|
|
2941
3035
|
self,
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
) ->
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3036
|
+
images: Optional[Sequence[Image]] = None,
|
|
3037
|
+
videos: Optional[Sequence[Video]] = None,
|
|
3038
|
+
audios: Optional[Sequence[Audio]] = None,
|
|
3039
|
+
) -> tuple:
|
|
3040
|
+
image_list = None
|
|
3041
|
+
if images:
|
|
3042
|
+
image_list = []
|
|
3043
|
+
for img in images:
|
|
3044
|
+
if not img.id:
|
|
3045
|
+
from uuid import uuid4
|
|
3046
|
+
|
|
3047
|
+
img.id = str(uuid4())
|
|
3048
|
+
image_list.append(img)
|
|
3049
|
+
|
|
3050
|
+
video_list = None
|
|
3051
|
+
if videos:
|
|
3052
|
+
video_list = []
|
|
3053
|
+
for vid in videos:
|
|
3054
|
+
if not vid.id:
|
|
3055
|
+
from uuid import uuid4
|
|
3056
|
+
|
|
3057
|
+
vid.id = str(uuid4())
|
|
3058
|
+
video_list.append(vid)
|
|
3059
|
+
|
|
3060
|
+
audio_list = None
|
|
3061
|
+
if audios:
|
|
3062
|
+
audio_list = []
|
|
3063
|
+
for aud in audios:
|
|
3064
|
+
if not aud.id:
|
|
3065
|
+
from uuid import uuid4
|
|
3066
|
+
|
|
3067
|
+
aud.id = str(uuid4())
|
|
3068
|
+
audio_list.append(aud)
|
|
3069
|
+
|
|
3070
|
+
return image_list, video_list, audio_list
|
|
2965
3071
|
|
|
2966
3072
|
def cli_app(
|
|
2967
3073
|
self,
|
|
@@ -3632,6 +3738,137 @@ class Team:
|
|
|
3632
3738
|
except Exception as e:
|
|
3633
3739
|
log_warning(f"Failed to resolve context for '{key}': {e}")
|
|
3634
3740
|
|
|
3741
|
+
def _collect_joint_images(
|
|
3742
|
+
self,
|
|
3743
|
+
run_input: Optional[TeamRunInput] = None,
|
|
3744
|
+
session: Optional[TeamSession] = None,
|
|
3745
|
+
) -> Optional[Sequence[Image]]:
|
|
3746
|
+
"""Collect images from input, session history, and current run response."""
|
|
3747
|
+
joint_images: List[Image] = []
|
|
3748
|
+
|
|
3749
|
+
# 1. Add images from current input
|
|
3750
|
+
if run_input and run_input.images:
|
|
3751
|
+
joint_images.extend(run_input.images)
|
|
3752
|
+
log_debug(f"Added {len(run_input.images)} input images to joint list")
|
|
3753
|
+
|
|
3754
|
+
# 2. Add images from session history (from both input and generated sources)
|
|
3755
|
+
try:
|
|
3756
|
+
if session and session.runs:
|
|
3757
|
+
for historical_run in session.runs:
|
|
3758
|
+
# Add generated images from previous runs
|
|
3759
|
+
if historical_run.images:
|
|
3760
|
+
joint_images.extend(historical_run.images)
|
|
3761
|
+
log_debug(
|
|
3762
|
+
f"Added {len(historical_run.images)} generated images from historical run {historical_run.run_id}"
|
|
3763
|
+
)
|
|
3764
|
+
|
|
3765
|
+
# Add input images from previous runs
|
|
3766
|
+
if historical_run.input and historical_run.input.images:
|
|
3767
|
+
joint_images.extend(historical_run.input.images)
|
|
3768
|
+
log_debug(
|
|
3769
|
+
f"Added {len(historical_run.input.images)} input images from historical run {historical_run.run_id}"
|
|
3770
|
+
)
|
|
3771
|
+
except Exception as e:
|
|
3772
|
+
log_debug(f"Could not access session history for images: {e}")
|
|
3773
|
+
|
|
3774
|
+
if joint_images:
|
|
3775
|
+
log_debug(f"Images Available to Model: {len(joint_images)} images")
|
|
3776
|
+
return joint_images if joint_images else None
|
|
3777
|
+
|
|
3778
|
+
def _collect_joint_videos(
|
|
3779
|
+
self,
|
|
3780
|
+
run_input: Optional[TeamRunInput] = None,
|
|
3781
|
+
session: Optional[TeamSession] = None,
|
|
3782
|
+
) -> Optional[Sequence[Video]]:
|
|
3783
|
+
"""Collect videos from input, session history, and current run response."""
|
|
3784
|
+
joint_videos: List[Video] = []
|
|
3785
|
+
|
|
3786
|
+
# 1. Add videos from current input
|
|
3787
|
+
if run_input and run_input.videos:
|
|
3788
|
+
joint_videos.extend(run_input.videos)
|
|
3789
|
+
log_debug(f"Added {len(run_input.videos)} input videos to joint list")
|
|
3790
|
+
|
|
3791
|
+
# 2. Add videos from session history (from both input and generated sources)
|
|
3792
|
+
try:
|
|
3793
|
+
if session and session.runs:
|
|
3794
|
+
for historical_run in session.runs:
|
|
3795
|
+
# Add generated videos from previous runs
|
|
3796
|
+
if historical_run.videos:
|
|
3797
|
+
joint_videos.extend(historical_run.videos)
|
|
3798
|
+
log_debug(
|
|
3799
|
+
f"Added {len(historical_run.videos)} generated videos from historical run {historical_run.run_id}"
|
|
3800
|
+
)
|
|
3801
|
+
|
|
3802
|
+
# Add input videos from previous runs
|
|
3803
|
+
if historical_run.input and historical_run.input.videos:
|
|
3804
|
+
joint_videos.extend(historical_run.input.videos)
|
|
3805
|
+
log_debug(
|
|
3806
|
+
f"Added {len(historical_run.input.videos)} input videos from historical run {historical_run.run_id}"
|
|
3807
|
+
)
|
|
3808
|
+
except Exception as e:
|
|
3809
|
+
log_debug(f"Could not access session history for videos: {e}")
|
|
3810
|
+
|
|
3811
|
+
if joint_videos:
|
|
3812
|
+
log_debug(f"Videos Available to Model: {len(joint_videos)} videos")
|
|
3813
|
+
return joint_videos if joint_videos else None
|
|
3814
|
+
|
|
3815
|
+
def _collect_joint_audios(
|
|
3816
|
+
self,
|
|
3817
|
+
run_input: Optional[TeamRunInput] = None,
|
|
3818
|
+
session: Optional[TeamSession] = None,
|
|
3819
|
+
) -> Optional[Sequence[Audio]]:
|
|
3820
|
+
"""Collect audios from input, session history, and current run response."""
|
|
3821
|
+
joint_audios: List[Audio] = []
|
|
3822
|
+
|
|
3823
|
+
# 1. Add audios from current input
|
|
3824
|
+
if run_input and run_input.audios:
|
|
3825
|
+
joint_audios.extend(run_input.audios)
|
|
3826
|
+
log_debug(f"Added {len(run_input.audios)} input audios to joint list")
|
|
3827
|
+
|
|
3828
|
+
# 2. Add audios from session history (from both input and generated sources)
|
|
3829
|
+
try:
|
|
3830
|
+
if session and session.runs:
|
|
3831
|
+
for historical_run in session.runs:
|
|
3832
|
+
# Add generated audios from previous runs
|
|
3833
|
+
if historical_run.audio:
|
|
3834
|
+
joint_audios.extend(historical_run.audio)
|
|
3835
|
+
log_debug(
|
|
3836
|
+
f"Added {len(historical_run.audio)} generated audios from historical run {historical_run.run_id}"
|
|
3837
|
+
)
|
|
3838
|
+
|
|
3839
|
+
# Add input audios from previous runs
|
|
3840
|
+
if historical_run.input and historical_run.input.audios:
|
|
3841
|
+
joint_audios.extend(historical_run.input.audios)
|
|
3842
|
+
log_debug(
|
|
3843
|
+
f"Added {len(historical_run.input.audios)} input audios from historical run {historical_run.run_id}"
|
|
3844
|
+
)
|
|
3845
|
+
except Exception as e:
|
|
3846
|
+
log_debug(f"Could not access session history for audios: {e}")
|
|
3847
|
+
|
|
3848
|
+
if joint_audios:
|
|
3849
|
+
log_debug(f"Audios Available to Model: {len(joint_audios)} audios")
|
|
3850
|
+
return joint_audios if joint_audios else None
|
|
3851
|
+
|
|
3852
|
+
def _collect_joint_files(
|
|
3853
|
+
self,
|
|
3854
|
+
run_input: Optional[TeamRunInput] = None,
|
|
3855
|
+
) -> Optional[Sequence[File]]:
|
|
3856
|
+
"""Collect files from input and session history."""
|
|
3857
|
+
from agno.utils.log import log_debug
|
|
3858
|
+
|
|
3859
|
+
joint_files: List[File] = []
|
|
3860
|
+
|
|
3861
|
+
# 1. Add files from current input
|
|
3862
|
+
if run_input and run_input.files:
|
|
3863
|
+
joint_files.extend(run_input.files)
|
|
3864
|
+
|
|
3865
|
+
# TODO: Files aren't stored in session history yet and dont have a FileArtifact
|
|
3866
|
+
|
|
3867
|
+
if joint_files:
|
|
3868
|
+
log_debug(f"Files Available to Model: {len(joint_files)} files")
|
|
3869
|
+
|
|
3870
|
+
return joint_files if joint_files else None
|
|
3871
|
+
|
|
3635
3872
|
def determine_tools_for_model(
|
|
3636
3873
|
self,
|
|
3637
3874
|
model: Model,
|
|
@@ -3648,7 +3885,6 @@ class Team:
|
|
|
3648
3885
|
audio: Optional[Sequence[Audio]] = None,
|
|
3649
3886
|
files: Optional[Sequence[File]] = None,
|
|
3650
3887
|
workflow_context: Optional[Dict] = None,
|
|
3651
|
-
store_member_responses: bool = False,
|
|
3652
3888
|
debug_mode: Optional[bool] = None,
|
|
3653
3889
|
add_history_to_context: Optional[bool] = None,
|
|
3654
3890
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
@@ -3700,94 +3936,46 @@ class Team:
|
|
|
3700
3936
|
if self.knowledge is not None and self.update_knowledge:
|
|
3701
3937
|
_tools.append(self.add_to_knowledge)
|
|
3702
3938
|
|
|
3703
|
-
if
|
|
3939
|
+
# Get the user message if we are using the input directly
|
|
3940
|
+
user_message = None
|
|
3941
|
+
if self.determine_input_for_members is False:
|
|
3704
3942
|
user_message = self._get_user_message(
|
|
3705
3943
|
run_response=run_response,
|
|
3706
3944
|
session_state=session_state,
|
|
3707
3945
|
input_message=input_message,
|
|
3946
|
+
user_id=user_id,
|
|
3708
3947
|
audio=audio,
|
|
3709
3948
|
images=images,
|
|
3710
3949
|
videos=videos,
|
|
3711
3950
|
files=files,
|
|
3712
|
-
user_id=user_id,
|
|
3713
3951
|
dependencies=dependencies,
|
|
3714
3952
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
3715
3953
|
metadata=metadata,
|
|
3716
3954
|
)
|
|
3717
|
-
forward_task_func: Function = self._get_forward_task_function(
|
|
3718
|
-
input=user_message,
|
|
3719
|
-
run_response=run_response,
|
|
3720
|
-
session_state=session_state,
|
|
3721
|
-
team_run_context=team_run_context,
|
|
3722
|
-
user_id=user_id,
|
|
3723
|
-
session=session,
|
|
3724
|
-
stream=self.stream or False,
|
|
3725
|
-
stream_intermediate_steps=self.stream_intermediate_steps,
|
|
3726
|
-
async_mode=async_mode,
|
|
3727
|
-
images=images, # type: ignore
|
|
3728
|
-
videos=videos, # type: ignore
|
|
3729
|
-
audio=audio, # type: ignore
|
|
3730
|
-
files=files, # type: ignore
|
|
3731
|
-
knowledge_filters=knowledge_filters,
|
|
3732
|
-
workflow_context=workflow_context,
|
|
3733
|
-
store_member_responses=store_member_responses,
|
|
3734
|
-
debug_mode=debug_mode,
|
|
3735
|
-
add_history_to_context=add_history_to_context,
|
|
3736
|
-
dependencies=dependencies,
|
|
3737
|
-
)
|
|
3738
|
-
_tools.append(forward_task_func)
|
|
3739
|
-
if self.get_member_information_tool:
|
|
3740
|
-
_tools.append(self.get_member_information)
|
|
3741
|
-
|
|
3742
|
-
elif self.mode == "coordinate":
|
|
3743
|
-
_tools.append(
|
|
3744
|
-
self._get_delegate_task_function(
|
|
3745
|
-
run_response=run_response,
|
|
3746
|
-
session=session,
|
|
3747
|
-
session_state=session_state,
|
|
3748
|
-
team_run_context=team_run_context,
|
|
3749
|
-
user_id=user_id,
|
|
3750
|
-
stream=self.stream or False,
|
|
3751
|
-
stream_intermediate_steps=self.stream_intermediate_steps,
|
|
3752
|
-
async_mode=async_mode,
|
|
3753
|
-
images=images, # type: ignore
|
|
3754
|
-
videos=videos, # type: ignore
|
|
3755
|
-
audio=audio, # type: ignore
|
|
3756
|
-
files=files, # type: ignore
|
|
3757
|
-
knowledge_filters=knowledge_filters,
|
|
3758
|
-
workflow_context=workflow_context,
|
|
3759
|
-
store_member_responses=store_member_responses,
|
|
3760
|
-
debug_mode=debug_mode,
|
|
3761
|
-
add_history_to_context=add_history_to_context,
|
|
3762
|
-
dependencies=dependencies,
|
|
3763
|
-
)
|
|
3764
|
-
)
|
|
3765
|
-
if self.get_member_information_tool:
|
|
3766
|
-
_tools.append(self.get_member_information)
|
|
3767
3955
|
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
_tools.append(run_member_agents_func)
|
|
3956
|
+
delegate_task_func = self._get_delegate_task_function(
|
|
3957
|
+
run_response=run_response,
|
|
3958
|
+
session=session,
|
|
3959
|
+
session_state=session_state,
|
|
3960
|
+
team_run_context=team_run_context,
|
|
3961
|
+
input=user_message,
|
|
3962
|
+
user_id=user_id,
|
|
3963
|
+
stream=self.stream or False,
|
|
3964
|
+
stream_intermediate_steps=self.stream_intermediate_steps,
|
|
3965
|
+
async_mode=async_mode,
|
|
3966
|
+
images=images, # type: ignore
|
|
3967
|
+
videos=videos, # type: ignore
|
|
3968
|
+
audio=audio, # type: ignore
|
|
3969
|
+
files=files, # type: ignore
|
|
3970
|
+
knowledge_filters=knowledge_filters,
|
|
3971
|
+
workflow_context=workflow_context,
|
|
3972
|
+
debug_mode=debug_mode,
|
|
3973
|
+
add_history_to_context=add_history_to_context,
|
|
3974
|
+
)
|
|
3788
3975
|
|
|
3789
|
-
|
|
3790
|
-
|
|
3976
|
+
_tools.append(delegate_task_func)
|
|
3977
|
+
if self.get_member_information_tool:
|
|
3978
|
+
_tools.append(self.get_member_information)
|
|
3791
3979
|
|
|
3792
3980
|
self._functions_for_model = {}
|
|
3793
3981
|
self._tools_for_model = []
|
|
@@ -3866,6 +4054,29 @@ class Team:
|
|
|
3866
4054
|
except Exception as e:
|
|
3867
4055
|
log_warning(f"Could not add tool {tool}: {e}")
|
|
3868
4056
|
|
|
4057
|
+
if self._functions_for_model:
|
|
4058
|
+
from inspect import signature
|
|
4059
|
+
|
|
4060
|
+
# Check if any functions need media before collecting
|
|
4061
|
+
needs_media = any(
|
|
4062
|
+
any(param in signature(func.entrypoint).parameters for param in ["images", "videos", "audios", "files"])
|
|
4063
|
+
for func in self._functions_for_model.values()
|
|
4064
|
+
if func.entrypoint is not None
|
|
4065
|
+
)
|
|
4066
|
+
|
|
4067
|
+
if needs_media:
|
|
4068
|
+
# Only collect media if functions actually need them
|
|
4069
|
+
joint_images = self._collect_joint_images(run_response.input, session)
|
|
4070
|
+
joint_files = self._collect_joint_files(run_response.input)
|
|
4071
|
+
joint_audios = self._collect_joint_audios(run_response.input, session)
|
|
4072
|
+
joint_videos = self._collect_joint_videos(run_response.input, session)
|
|
4073
|
+
|
|
4074
|
+
for func in self._functions_for_model.values():
|
|
4075
|
+
func._images = joint_images
|
|
4076
|
+
func._files = joint_files
|
|
4077
|
+
func._audios = joint_audios
|
|
4078
|
+
func._videos = joint_videos
|
|
4079
|
+
|
|
3869
4080
|
def get_members_system_message_content(self, indent: int = 0) -> str:
|
|
3870
4081
|
system_message_content = ""
|
|
3871
4082
|
for idx, member in enumerate(self.members):
|
|
@@ -4039,9 +4250,17 @@ class Team:
|
|
|
4039
4250
|
system_message_content += "</team_members>\n"
|
|
4040
4251
|
|
|
4041
4252
|
system_message_content += "\n<how_to_respond>\n"
|
|
4042
|
-
|
|
4253
|
+
|
|
4254
|
+
if self.delegate_task_to_all_members:
|
|
4255
|
+
system_message_content += (
|
|
4256
|
+
"- You can either respond directly or use the `delegate_task_to_members` tool to delegate a task to all members in your team to get a collaborative response.\n"
|
|
4257
|
+
"- To delegate a task to all members in your team, call `delegate_task_to_members` ONLY once. This will delegate a task to all members in your team.\n"
|
|
4258
|
+
"- Analyze the responses from all members and evaluate whether the task has been completed.\n"
|
|
4259
|
+
"- If you feel the task has been completed, you can stop and respond to the user.\n"
|
|
4260
|
+
)
|
|
4261
|
+
else:
|
|
4043
4262
|
system_message_content += (
|
|
4044
|
-
"- Your role is to
|
|
4263
|
+
"- Your role is to delegate tasks to members in your team with the highest likelihood of completing the user's request.\n"
|
|
4045
4264
|
"- Carefully analyze the tools available to the members and their roles before delegating tasks.\n"
|
|
4046
4265
|
"- You cannot use a member tool directly. You can only delegate tasks to members.\n"
|
|
4047
4266
|
"- When you delegate a task to another member, make sure to include:\n"
|
|
@@ -4055,24 +4274,6 @@ class Team:
|
|
|
4055
4274
|
"- For simple greetings, thanks, or questions about the team itself, you should respond directly.\n"
|
|
4056
4275
|
"- For all work requests, tasks, or questions requiring expertise, route to appropriate team members.\n"
|
|
4057
4276
|
)
|
|
4058
|
-
elif self.mode == "route":
|
|
4059
|
-
system_message_content += (
|
|
4060
|
-
"- Your role is to forward tasks to members in your team with the highest likelihood of completing the user's request.\n"
|
|
4061
|
-
"- Carefully analyze the tools available to the members and their roles before forwarding tasks.\n"
|
|
4062
|
-
"- When you forward a task to another Agent, make sure to include:\n"
|
|
4063
|
-
" - member_id (str): The ID of the member to forward the task to. Use only the ID of the member, not the ID of the team followed by the ID of the member.\n"
|
|
4064
|
-
" - expected_output (str): The expected output.\n"
|
|
4065
|
-
"- You can forward tasks to multiple members at once.\n"
|
|
4066
|
-
"- For simple greetings, thanks, or questions about the team itself, you should respond directly.\n"
|
|
4067
|
-
"- For all work requests, tasks, or questions requiring expertise, route to appropriate team members.\n"
|
|
4068
|
-
)
|
|
4069
|
-
elif self.mode == "collaborate":
|
|
4070
|
-
system_message_content += (
|
|
4071
|
-
"- You can either respond directly or use the `run_member_agents` tool to run all members in your team to get a collaborative response.\n"
|
|
4072
|
-
"- To run the members in your team, call `run_member_agents` ONLY once. This will run all members in your team.\n"
|
|
4073
|
-
"- Analyze the responses from all members and evaluate whether the task has been completed.\n"
|
|
4074
|
-
"- If you feel the task has been completed, you can stop and respond to the user.\n"
|
|
4075
|
-
)
|
|
4076
4277
|
system_message_content += "</how_to_respond>\n\n"
|
|
4077
4278
|
|
|
4078
4279
|
# Attached media
|
|
@@ -4357,10 +4558,10 @@ class Team:
|
|
|
4357
4558
|
return Message(
|
|
4358
4559
|
role="user",
|
|
4359
4560
|
content="",
|
|
4360
|
-
images=images,
|
|
4361
|
-
audio=audio,
|
|
4362
|
-
videos=videos,
|
|
4363
|
-
files=files,
|
|
4561
|
+
images=None if not self.send_media_to_model else images,
|
|
4562
|
+
audio=None if not self.send_media_to_model else audio,
|
|
4563
|
+
videos=None if not self.send_media_to_model else videos,
|
|
4564
|
+
files=None if not self.send_media_to_model else files,
|
|
4364
4565
|
**kwargs,
|
|
4365
4566
|
)
|
|
4366
4567
|
else:
|
|
@@ -4381,10 +4582,10 @@ class Team:
|
|
|
4381
4582
|
return Message(
|
|
4382
4583
|
role="user",
|
|
4383
4584
|
content=input_content,
|
|
4384
|
-
images=images,
|
|
4385
|
-
audio=audio,
|
|
4386
|
-
videos=videos,
|
|
4387
|
-
files=files,
|
|
4585
|
+
images=None if not self.send_media_to_model else images,
|
|
4586
|
+
audio=None if not self.send_media_to_model else audio,
|
|
4587
|
+
videos=None if not self.send_media_to_model else videos,
|
|
4588
|
+
files=None if not self.send_media_to_model else files,
|
|
4388
4589
|
**kwargs,
|
|
4389
4590
|
)
|
|
4390
4591
|
|
|
@@ -4473,10 +4674,10 @@ class Team:
|
|
|
4473
4674
|
return Message(
|
|
4474
4675
|
role="user",
|
|
4475
4676
|
content=user_msg_content,
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
videos=videos,
|
|
4479
|
-
files=files,
|
|
4677
|
+
images=None if not self.send_media_to_model else images,
|
|
4678
|
+
audio=None if not self.send_media_to_model else audio,
|
|
4679
|
+
videos=None if not self.send_media_to_model else videos,
|
|
4680
|
+
files=None if not self.send_media_to_model else files,
|
|
4480
4681
|
**kwargs,
|
|
4481
4682
|
)
|
|
4482
4683
|
|
|
@@ -4831,11 +5032,11 @@ class Team:
|
|
|
4831
5032
|
if self.share_member_interactions:
|
|
4832
5033
|
team_member_interactions_str = self._get_team_member_interactions_str(team_run_context=team_run_context) # type: ignore
|
|
4833
5034
|
if context_images := self._get_team_run_context_images(team_run_context=team_run_context): # type: ignore
|
|
4834
|
-
images.extend(
|
|
5035
|
+
images.extend(context_images)
|
|
4835
5036
|
if context_videos := self._get_team_run_context_videos(team_run_context=team_run_context): # type: ignore
|
|
4836
|
-
videos.extend(
|
|
5037
|
+
videos.extend(context_videos)
|
|
4837
5038
|
if context_audio := self._get_team_run_context_audio(team_run_context=team_run_context): # type: ignore
|
|
4838
|
-
audio.extend(
|
|
5039
|
+
audio.extend(context_audio)
|
|
4839
5040
|
return team_member_interactions_str
|
|
4840
5041
|
|
|
4841
5042
|
def _find_member_by_id(self, member_id: str) -> Optional[Tuple[int, Union[Agent, "Team"]]]:
|
|
@@ -4865,7 +5066,7 @@ class Team:
|
|
|
4865
5066
|
|
|
4866
5067
|
return None
|
|
4867
5068
|
|
|
4868
|
-
def
|
|
5069
|
+
def _get_delegate_task_function(
|
|
4869
5070
|
self,
|
|
4870
5071
|
run_response: TeamRunOutput,
|
|
4871
5072
|
session: TeamSession,
|
|
@@ -4875,12 +5076,13 @@ class Team:
|
|
|
4875
5076
|
stream: bool = False,
|
|
4876
5077
|
stream_intermediate_steps: bool = False,
|
|
4877
5078
|
async_mode: bool = False,
|
|
5079
|
+
input: Optional[Message] = None, # Used for determine_input_for_memberss=False
|
|
4878
5080
|
images: Optional[List[Image]] = None,
|
|
4879
5081
|
videos: Optional[List[Video]] = None,
|
|
4880
5082
|
audio: Optional[List[Audio]] = None,
|
|
4881
5083
|
files: Optional[List[File]] = None,
|
|
5084
|
+
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
4882
5085
|
workflow_context: Optional[Dict] = None,
|
|
4883
|
-
store_member_responses: bool = False,
|
|
4884
5086
|
debug_mode: Optional[bool] = None,
|
|
4885
5087
|
add_history_to_context: Optional[bool] = None,
|
|
4886
5088
|
) -> Function:
|
|
@@ -4893,555 +5095,84 @@ class Team:
|
|
|
4893
5095
|
if not files:
|
|
4894
5096
|
files = []
|
|
4895
5097
|
|
|
4896
|
-
def
|
|
4897
|
-
task_description: str, expected_output: Optional[str] = None
|
|
4898
|
-
)
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
Args:
|
|
4903
|
-
task_description (str): The task description to send to the member agents.
|
|
4904
|
-
expected_output (str, optional): The expected output from the member agents.
|
|
4905
|
-
|
|
4906
|
-
Returns:
|
|
4907
|
-
str: The responses from the member agents.
|
|
4908
|
-
"""
|
|
4909
|
-
# Make sure for the member agent, we are using the agent logger
|
|
4910
|
-
use_agent_logger()
|
|
5098
|
+
def _setup_delegate_task_to_member(
|
|
5099
|
+
member_agent: Union[Agent, "Team"], task_description: str, expected_output: Optional[str] = None
|
|
5100
|
+
):
|
|
5101
|
+
# 1. Initialize the member agent
|
|
5102
|
+
self._initialize_member(member_agent)
|
|
4911
5103
|
|
|
4912
|
-
#
|
|
5104
|
+
# 2. Determine team context to send
|
|
4913
5105
|
team_member_interactions_str = self._determine_team_member_interactions(
|
|
4914
5106
|
team_run_context, images, videos, audio
|
|
4915
5107
|
)
|
|
4916
5108
|
|
|
4917
|
-
|
|
4918
|
-
member_agent_task = format_member_agent_task(
|
|
4919
|
-
task_description, expected_output, team_member_interactions_str
|
|
4920
|
-
)
|
|
5109
|
+
member_agent_task: Union[str, Message]
|
|
4921
5110
|
|
|
4922
|
-
|
|
4923
|
-
|
|
5111
|
+
# 3. Create the member agent task or use the input directly
|
|
5112
|
+
if self.determine_input_for_members is False:
|
|
5113
|
+
member_agent_task = input # type: ignore
|
|
5114
|
+
else:
|
|
5115
|
+
# Don't override the expected output of a member agent
|
|
5116
|
+
if member_agent.expected_output is not None:
|
|
5117
|
+
expected_output = None
|
|
5118
|
+
|
|
5119
|
+
member_agent_task = format_member_agent_task( # type: ignore
|
|
5120
|
+
task_description, expected_output, team_member_interactions_str
|
|
5121
|
+
)
|
|
4924
5122
|
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
5123
|
+
# 4. Add history for the member if enabled
|
|
5124
|
+
history = None
|
|
5125
|
+
if member_agent.add_history_to_context:
|
|
5126
|
+
history = self._get_history_for_member_agent(session, member_agent)
|
|
5127
|
+
if history:
|
|
5128
|
+
if isinstance(member_agent_task, str):
|
|
4930
5129
|
history.append(Message(role="user", content=member_agent_task))
|
|
5130
|
+
else:
|
|
5131
|
+
history.append(member_agent_task)
|
|
4931
5132
|
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
# All members have the same session_id
|
|
4938
|
-
session_id=session.session_id,
|
|
4939
|
-
session_state=member_session_state_copy, # Send a copy to the agent
|
|
4940
|
-
images=images,
|
|
4941
|
-
videos=videos,
|
|
4942
|
-
audio=audio,
|
|
4943
|
-
files=files,
|
|
4944
|
-
stream=True,
|
|
4945
|
-
stream_intermediate_steps=stream_intermediate_steps,
|
|
4946
|
-
workflow_context=workflow_context,
|
|
4947
|
-
debug_mode=debug_mode,
|
|
4948
|
-
add_history_to_context=add_history_to_context,
|
|
4949
|
-
yield_run_response=True,
|
|
4950
|
-
)
|
|
4951
|
-
member_agent_run_response = None
|
|
4952
|
-
for member_agent_run_response_chunk in member_agent_run_response_stream:
|
|
4953
|
-
# If we get the full run response, we can break out of the loop
|
|
4954
|
-
if isinstance(member_agent_run_response_chunk, TeamRunOutput) or isinstance(
|
|
4955
|
-
member_agent_run_response_chunk, RunOutput
|
|
4956
|
-
):
|
|
4957
|
-
member_agent_run_response = member_agent_run_response_chunk # type: ignore
|
|
4958
|
-
break
|
|
4959
|
-
check_if_run_cancelled(member_agent_run_response_chunk)
|
|
4960
|
-
yield member_agent_run_response_chunk
|
|
5133
|
+
# 5. Handle respond_directly
|
|
5134
|
+
if self.respond_directly:
|
|
5135
|
+
# Since we return the response directly from the member agent, we need to set the output schema from the team down.
|
|
5136
|
+
if not member_agent.output_schema and self.output_schema:
|
|
5137
|
+
member_agent.output_schema = self.output_schema
|
|
4961
5138
|
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
user_id=user_id,
|
|
4966
|
-
# All members have the same session_id
|
|
4967
|
-
session_id=session.session_id,
|
|
4968
|
-
session_state=member_session_state_copy, # Send a copy to the agent
|
|
4969
|
-
images=images,
|
|
4970
|
-
videos=videos,
|
|
4971
|
-
audio=audio,
|
|
4972
|
-
files=files,
|
|
4973
|
-
stream=False,
|
|
4974
|
-
workflow_context=workflow_context,
|
|
4975
|
-
debug_mode=debug_mode,
|
|
4976
|
-
add_history_to_context=add_history_to_context,
|
|
4977
|
-
)
|
|
4978
|
-
|
|
4979
|
-
check_if_run_cancelled(member_agent_run_response) # type: ignore
|
|
4980
|
-
|
|
4981
|
-
try:
|
|
4982
|
-
if member_agent_run_response.content is None and ( # type: ignore
|
|
4983
|
-
member_agent_run_response.tools is None or len(member_agent_run_response.tools) == 0 # type: ignore
|
|
4984
|
-
):
|
|
4985
|
-
yield f"Agent {member_agent.name}: No response from the member agent."
|
|
4986
|
-
elif isinstance(member_agent_run_response.content, str): # type: ignore
|
|
4987
|
-
if len(member_agent_run_response.content.strip()) > 0: # type: ignore
|
|
4988
|
-
yield f"Agent {member_agent.name}: {member_agent_run_response.content}" # type: ignore
|
|
4989
|
-
elif (
|
|
4990
|
-
member_agent_run_response.tools is not None and len(member_agent_run_response.tools) > 0 # type: ignore
|
|
4991
|
-
):
|
|
4992
|
-
yield f"Agent {member_agent.name}: {','.join([tool.result for tool in member_agent_run_response.tools])}" # type: ignore
|
|
4993
|
-
elif issubclass(type(member_agent_run_response.content), BaseModel): # type: ignore
|
|
4994
|
-
yield f"Agent {member_agent.name}: {member_agent_run_response.content.model_dump_json(indent=2)}" # type: ignore
|
|
4995
|
-
else:
|
|
4996
|
-
import json
|
|
4997
|
-
|
|
4998
|
-
yield f"Agent {member_agent.name}: {json.dumps(member_agent_run_response.content, indent=2)}" # type: ignore
|
|
4999
|
-
except Exception as e:
|
|
5000
|
-
yield f"Agent {member_agent.name}: Error - {str(e)}"
|
|
5001
|
-
|
|
5002
|
-
# Add team run id to the member run
|
|
5003
|
-
if member_agent_run_response is not None:
|
|
5004
|
-
member_agent_run_response.parent_run_id = run_response.run_id # type: ignore
|
|
5005
|
-
|
|
5006
|
-
# Update the memory
|
|
5007
|
-
member_name = member_agent.name if member_agent.name else f"agent_{member_agent_index}"
|
|
5008
|
-
self._add_interaction_to_team_run_context(
|
|
5009
|
-
team_run_context=team_run_context,
|
|
5010
|
-
member_name=member_name,
|
|
5011
|
-
task=task_description,
|
|
5012
|
-
run_response=member_agent_run_response, # type: ignore
|
|
5013
|
-
)
|
|
5014
|
-
|
|
5015
|
-
# Add the member run to the team run response
|
|
5016
|
-
if self.store_member_responses and run_response and member_agent_run_response:
|
|
5017
|
-
run_response.add_member_run(member_agent_run_response)
|
|
5018
|
-
|
|
5019
|
-
# Add the member run to the team session
|
|
5020
|
-
if member_agent_run_response:
|
|
5021
|
-
session.upsert_run(member_agent_run_response)
|
|
5022
|
-
|
|
5023
|
-
# Update team session state
|
|
5024
|
-
merge_dictionaries(session_state, member_session_state_copy) # type: ignore
|
|
5025
|
-
|
|
5026
|
-
# Update the team media
|
|
5027
|
-
if member_agent_run_response is not None:
|
|
5028
|
-
self._update_team_media(member_agent_run_response) # type: ignore
|
|
5029
|
-
|
|
5030
|
-
# Afterward, switch back to the team logger
|
|
5031
|
-
use_team_logger()
|
|
5032
|
-
|
|
5033
|
-
async def arun_member_agents(
|
|
5034
|
-
task_description: str, expected_output: Optional[str] = None
|
|
5035
|
-
) -> AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
5036
|
-
"""
|
|
5037
|
-
Send the same task to all the member agents and return the responses.
|
|
5038
|
-
|
|
5039
|
-
Args:
|
|
5040
|
-
task_description (str): The task description to send to the member agents.
|
|
5041
|
-
expected_output (str): The expected output from the member agents.
|
|
5042
|
-
|
|
5043
|
-
Returns:
|
|
5044
|
-
str: The responses from the member agents.
|
|
5045
|
-
"""
|
|
5046
|
-
# Make sure for the member agent, we are using the agent logger
|
|
5047
|
-
use_agent_logger()
|
|
5048
|
-
|
|
5049
|
-
# 1. Determine team context to send
|
|
5050
|
-
team_member_interactions_str = self._determine_team_member_interactions(
|
|
5051
|
-
team_run_context, images, videos, audio
|
|
5052
|
-
)
|
|
5053
|
-
|
|
5054
|
-
if stream:
|
|
5055
|
-
# Concurrent streaming: launch each member as a streaming worker and merge events
|
|
5056
|
-
done_marker = object()
|
|
5057
|
-
queue: "asyncio.Queue[Union[RunOutputEvent, TeamRunOutputEvent, str, object]]" = asyncio.Queue()
|
|
5058
|
-
|
|
5059
|
-
async def stream_member(agent: Union[Agent, "Team"], idx: int) -> None:
|
|
5060
|
-
# Compute expected output per agent (do not mutate shared var)
|
|
5061
|
-
local_expected_output = None if agent.expected_output is not None else expected_output
|
|
5062
|
-
|
|
5063
|
-
member_agent_task = format_member_agent_task(
|
|
5064
|
-
task_description, local_expected_output, team_member_interactions_str
|
|
5065
|
-
)
|
|
5066
|
-
|
|
5067
|
-
# Add history for the member if enabled
|
|
5068
|
-
history = None
|
|
5069
|
-
if agent.add_history_to_context:
|
|
5070
|
-
history = self._get_history_for_member_agent(session, agent)
|
|
5071
|
-
if history:
|
|
5072
|
-
history.append(Message(role="user", content=member_agent_task))
|
|
5073
|
-
|
|
5074
|
-
member_session_state_copy = copy(session_state)
|
|
5075
|
-
|
|
5076
|
-
# Stream events from the member
|
|
5077
|
-
member_stream = agent.arun( # type: ignore
|
|
5078
|
-
input=member_agent_task if history is None else history,
|
|
5079
|
-
user_id=user_id,
|
|
5080
|
-
session_id=session.session_id,
|
|
5081
|
-
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5082
|
-
images=images,
|
|
5083
|
-
videos=videos,
|
|
5084
|
-
audio=audio,
|
|
5085
|
-
files=files,
|
|
5086
|
-
stream=True,
|
|
5087
|
-
stream_intermediate_steps=stream_intermediate_steps,
|
|
5088
|
-
debug_mode=debug_mode,
|
|
5089
|
-
yield_run_response=True,
|
|
5090
|
-
)
|
|
5091
|
-
member_agent_run_response = None
|
|
5092
|
-
try:
|
|
5093
|
-
async for member_agent_run_output_event in member_stream:
|
|
5094
|
-
if isinstance(member_agent_run_output_event, TeamRunOutput) or isinstance(
|
|
5095
|
-
member_agent_run_output_event, RunOutput
|
|
5096
|
-
):
|
|
5097
|
-
member_agent_run_response = member_agent_run_output_event # type: ignore
|
|
5098
|
-
break
|
|
5099
|
-
check_if_run_cancelled(member_agent_run_output_event)
|
|
5100
|
-
await queue.put(member_agent_run_output_event)
|
|
5101
|
-
finally:
|
|
5102
|
-
# Add team run id to the member run
|
|
5103
|
-
if member_agent_run_response is not None:
|
|
5104
|
-
member_agent_run_response.parent_run_id = run_response.run_id # type: ignore
|
|
5105
|
-
|
|
5106
|
-
member_name = agent.name if agent.name else f"agent_{idx}"
|
|
5107
|
-
self._add_interaction_to_team_run_context(
|
|
5108
|
-
team_run_context=team_run_context,
|
|
5109
|
-
member_name=member_name,
|
|
5110
|
-
task=task_description,
|
|
5111
|
-
run_response=member_agent_run_response, # type: ignore
|
|
5112
|
-
)
|
|
5113
|
-
|
|
5114
|
-
# Add the member run to the team run response
|
|
5115
|
-
if store_member_responses and run_response:
|
|
5116
|
-
run_response.add_member_run(member_agent_run_response) # type: ignore
|
|
5117
|
-
|
|
5118
|
-
# Add the member run to the team session
|
|
5119
|
-
session.upsert_run(member_agent_run_response) # type: ignore
|
|
5120
|
-
|
|
5121
|
-
# Update team session state
|
|
5122
|
-
merge_dictionaries(session_state, member_session_state_copy) # type: ignore
|
|
5123
|
-
|
|
5124
|
-
# Update the team media
|
|
5125
|
-
if member_agent_run_response is not None:
|
|
5126
|
-
self._update_team_media(member_agent_run_response)
|
|
5127
|
-
|
|
5128
|
-
# Signal completion for this member
|
|
5129
|
-
await queue.put(done_marker)
|
|
5130
|
-
|
|
5131
|
-
# Initialize and launch all members
|
|
5132
|
-
tasks: List[asyncio.Task[None]] = []
|
|
5133
|
-
for member_agent_index, member_agent in enumerate(self.members):
|
|
5134
|
-
current_agent = member_agent
|
|
5135
|
-
current_index = member_agent_index
|
|
5136
|
-
self._initialize_member(current_agent)
|
|
5137
|
-
tasks.append(asyncio.create_task(stream_member(current_agent, current_index)))
|
|
5138
|
-
|
|
5139
|
-
# Drain queue until all members reported done
|
|
5140
|
-
completed = 0
|
|
5141
|
-
try:
|
|
5142
|
-
while completed < len(tasks):
|
|
5143
|
-
item = await queue.get()
|
|
5144
|
-
if item is done_marker:
|
|
5145
|
-
completed += 1
|
|
5146
|
-
else:
|
|
5147
|
-
yield item # type: ignore
|
|
5148
|
-
finally:
|
|
5149
|
-
# Ensure tasks do not leak on cancellation
|
|
5150
|
-
for t in tasks:
|
|
5151
|
-
if not t.done():
|
|
5152
|
-
t.cancel()
|
|
5153
|
-
# Await cancellation to suppress warnings
|
|
5154
|
-
for t in tasks:
|
|
5155
|
-
with contextlib.suppress(Exception):
|
|
5156
|
-
await t
|
|
5157
|
-
else:
|
|
5158
|
-
# Non-streaming concurrent run of members; collect results when done
|
|
5159
|
-
tasks = []
|
|
5160
|
-
for member_agent_index, member_agent in enumerate(self.members):
|
|
5161
|
-
current_agent = member_agent
|
|
5162
|
-
current_index = member_agent_index
|
|
5163
|
-
self._initialize_member(current_agent)
|
|
5164
|
-
|
|
5165
|
-
# Compute expected output per agent (do not mutate shared var)
|
|
5166
|
-
local_expected_output = None if current_agent.expected_output is not None else expected_output
|
|
5167
|
-
|
|
5168
|
-
member_agent_task = format_member_agent_task(
|
|
5169
|
-
task_description, local_expected_output, team_member_interactions_str
|
|
5170
|
-
)
|
|
5171
|
-
|
|
5172
|
-
# Add history for the member if enabled
|
|
5173
|
-
history = None
|
|
5174
|
-
if current_agent.add_history_to_context:
|
|
5175
|
-
history = self._get_history_for_member_agent(session, current_agent)
|
|
5176
|
-
if history:
|
|
5177
|
-
history.append(Message(role="user", content=member_agent_task))
|
|
5178
|
-
|
|
5179
|
-
async def run_member_agent(agent=current_agent) -> str:
|
|
5180
|
-
member_session_state_copy = copy(session_state)
|
|
5181
|
-
member_agent_run_response = await agent.arun(
|
|
5182
|
-
input=member_agent_task if history is None else history,
|
|
5183
|
-
user_id=user_id,
|
|
5184
|
-
# All members have the same session_id
|
|
5185
|
-
session_id=session.session_id,
|
|
5186
|
-
images=images,
|
|
5187
|
-
videos=videos,
|
|
5188
|
-
audio=audio,
|
|
5189
|
-
files=files,
|
|
5190
|
-
stream=False,
|
|
5191
|
-
debug_mode=debug_mode,
|
|
5192
|
-
)
|
|
5193
|
-
check_if_run_cancelled(member_agent_run_response)
|
|
5194
|
-
|
|
5195
|
-
# Add team run id to the member run
|
|
5196
|
-
if member_agent_run_response is not None:
|
|
5197
|
-
member_agent_run_response.parent_run_id = run_response.run_id # type: ignore
|
|
5198
|
-
|
|
5199
|
-
# Update the memory
|
|
5200
|
-
member_name = member_agent.name if member_agent.name else f"agent_{member_agent_index}"
|
|
5201
|
-
self._add_interaction_to_team_run_context(
|
|
5202
|
-
team_run_context=team_run_context,
|
|
5203
|
-
member_name=member_name,
|
|
5204
|
-
task=task_description,
|
|
5205
|
-
run_response=member_agent_run_response, # type: ignore
|
|
5206
|
-
)
|
|
5207
|
-
|
|
5208
|
-
# Add the member run to the team run response
|
|
5209
|
-
if store_member_responses and run_response and member_agent_run_response:
|
|
5210
|
-
run_response.add_member_run(member_agent_run_response)
|
|
5211
|
-
|
|
5212
|
-
# Add the member run to the team session
|
|
5213
|
-
if member_agent_run_response:
|
|
5214
|
-
session.upsert_run(member_agent_run_response)
|
|
5215
|
-
|
|
5216
|
-
# Update team session state
|
|
5217
|
-
merge_dictionaries(session_state, member_session_state_copy) # type: ignore
|
|
5218
|
-
|
|
5219
|
-
# Update the team media
|
|
5220
|
-
if member_agent_run_response is not None:
|
|
5221
|
-
self._update_team_media(member_agent_run_response) # type: ignore
|
|
5222
|
-
|
|
5223
|
-
try:
|
|
5224
|
-
if member_agent_run_response.content is None and (
|
|
5225
|
-
member_agent_run_response.tools is None or len(member_agent_run_response.tools) == 0
|
|
5226
|
-
):
|
|
5227
|
-
return f"Agent {member_name}: No response from the member agent."
|
|
5228
|
-
elif isinstance(member_agent_run_response.content, str):
|
|
5229
|
-
if len(member_agent_run_response.content.strip()) > 0:
|
|
5230
|
-
return f"Agent {member_name}: {member_agent_run_response.content}"
|
|
5231
|
-
elif (
|
|
5232
|
-
member_agent_run_response.tools is not None
|
|
5233
|
-
and len(member_agent_run_response.tools) > 0
|
|
5234
|
-
):
|
|
5235
|
-
return f"Agent {member_name}: {','.join([tool.result for tool in member_agent_run_response.tools])}"
|
|
5236
|
-
elif issubclass(type(member_agent_run_response.content), BaseModel):
|
|
5237
|
-
return f"Agent {member_name}: {member_agent_run_response.content.model_dump_json(indent=2)}" # type: ignore
|
|
5238
|
-
else:
|
|
5239
|
-
import json
|
|
5240
|
-
|
|
5241
|
-
return f"Agent {member_name}: {json.dumps(member_agent_run_response.content, indent=2)}"
|
|
5242
|
-
except Exception as e:
|
|
5243
|
-
return f"Agent {member_name}: Error - {str(e)}"
|
|
5244
|
-
|
|
5245
|
-
return f"Agent {member_name}: No Response"
|
|
5246
|
-
|
|
5247
|
-
tasks.append(run_member_agent) # type: ignore
|
|
5248
|
-
|
|
5249
|
-
results = await asyncio.gather(*[task() for task in tasks]) # type: ignore
|
|
5250
|
-
for result in results:
|
|
5251
|
-
yield result
|
|
5252
|
-
|
|
5253
|
-
# Afterward, switch back to the team logger
|
|
5254
|
-
use_team_logger()
|
|
5255
|
-
|
|
5256
|
-
if async_mode:
|
|
5257
|
-
run_member_agents_function = arun_member_agents # type: ignore
|
|
5258
|
-
else:
|
|
5259
|
-
run_member_agents_function = run_member_agents # type: ignore
|
|
5260
|
-
|
|
5261
|
-
run_member_agents_func = Function.from_callable(
|
|
5262
|
-
run_member_agents_function, name="run_member_agents", strict=True
|
|
5263
|
-
)
|
|
5264
|
-
|
|
5265
|
-
return run_member_agents_func
|
|
5266
|
-
|
|
5267
|
-
def _get_delegate_task_function(
|
|
5268
|
-
self,
|
|
5269
|
-
run_response: TeamRunOutput,
|
|
5270
|
-
session: TeamSession,
|
|
5271
|
-
session_state: Dict[str, Any],
|
|
5272
|
-
team_run_context: Dict[str, Any],
|
|
5273
|
-
user_id: Optional[str] = None,
|
|
5274
|
-
stream: bool = False,
|
|
5275
|
-
stream_intermediate_steps: bool = False,
|
|
5276
|
-
async_mode: bool = False,
|
|
5277
|
-
images: Optional[List[Image]] = None,
|
|
5278
|
-
videos: Optional[List[Video]] = None,
|
|
5279
|
-
audio: Optional[List[Audio]] = None,
|
|
5280
|
-
files: Optional[List[File]] = None,
|
|
5281
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
5282
|
-
workflow_context: Optional[Dict] = None,
|
|
5283
|
-
store_member_responses: bool = False,
|
|
5284
|
-
debug_mode: Optional[bool] = None,
|
|
5285
|
-
add_history_to_context: Optional[bool] = None,
|
|
5286
|
-
dependencies: Optional[Dict[str, Any]] = None,
|
|
5287
|
-
) -> Function:
|
|
5288
|
-
if not images:
|
|
5289
|
-
images = []
|
|
5290
|
-
if not videos:
|
|
5291
|
-
videos = []
|
|
5292
|
-
if not audio:
|
|
5293
|
-
audio = []
|
|
5294
|
-
if not files:
|
|
5295
|
-
files = []
|
|
5296
|
-
|
|
5297
|
-
def delegate_task_to_member(
|
|
5298
|
-
member_id: str, task_description: str, expected_output: Optional[str] = None
|
|
5299
|
-
) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
5300
|
-
"""Use this function to delegate a task to the selected team member.
|
|
5301
|
-
You must provide a clear and concise description of the task the member should achieve AND the expected output.
|
|
5302
|
-
|
|
5303
|
-
Args:
|
|
5304
|
-
member_id (str): The ID of the member to delegate the task to. Use only the ID of the member, not the ID of the team followed by the ID of the member.
|
|
5305
|
-
task_description (str): A clear and concise description of the task the member should achieve.
|
|
5306
|
-
expected_output (str, optional): The expected output from the member (optional).
|
|
5307
|
-
Returns:
|
|
5308
|
-
str: The result of the delegated task.
|
|
5309
|
-
"""
|
|
5310
|
-
# 1. Find the member agent using the helper function
|
|
5311
|
-
result = self._find_member_by_id(member_id)
|
|
5312
|
-
history = None
|
|
5313
|
-
if result is None:
|
|
5314
|
-
yield f"Member with ID {member_id} not found in the team or any subteams. Please choose the correct member from the list of members:\n\n{self.get_members_system_message_content(indent=0)}"
|
|
5315
|
-
return
|
|
5316
|
-
|
|
5317
|
-
member_agent_index, member_agent = result
|
|
5318
|
-
self._initialize_member(member_agent)
|
|
5319
|
-
|
|
5320
|
-
# 2. Determine team context to send
|
|
5321
|
-
team_member_interactions_str = self._determine_team_member_interactions(
|
|
5322
|
-
team_run_context, images, videos, audio
|
|
5323
|
-
)
|
|
5324
|
-
|
|
5325
|
-
# 3. Create the member agent task
|
|
5326
|
-
# Don't override the expected output of a member agent
|
|
5327
|
-
if member_agent.expected_output is not None:
|
|
5328
|
-
expected_output = None
|
|
5329
|
-
member_agent_task = format_member_agent_task(
|
|
5330
|
-
task_description, expected_output, team_member_interactions_str
|
|
5331
|
-
)
|
|
5332
|
-
|
|
5333
|
-
# 4. Add history for the member if enabled
|
|
5334
|
-
if member_agent.add_history_to_context:
|
|
5335
|
-
history = self._get_history_for_member_agent(session, member_agent)
|
|
5336
|
-
if history:
|
|
5337
|
-
history.append(Message(role="user", content=member_agent_task))
|
|
5338
|
-
|
|
5339
|
-
# Make sure for the member agent, we are using the agent logger
|
|
5340
|
-
use_agent_logger()
|
|
5341
|
-
|
|
5342
|
-
# Handle enable_agentic_knowledge_filters on the member agent
|
|
5343
|
-
if self.enable_agentic_knowledge_filters and not member_agent.enable_agentic_knowledge_filters:
|
|
5344
|
-
member_agent.enable_agentic_knowledge_filters = self.enable_agentic_knowledge_filters
|
|
5345
|
-
|
|
5346
|
-
member_session_state_copy = copy(session_state)
|
|
5347
|
-
if stream:
|
|
5348
|
-
member_agent_run_response_stream = member_agent.run(
|
|
5349
|
-
input=member_agent_task if history is None else history,
|
|
5350
|
-
user_id=user_id,
|
|
5351
|
-
# All members have the same session_id
|
|
5352
|
-
session_id=session.session_id,
|
|
5353
|
-
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5354
|
-
images=images,
|
|
5355
|
-
videos=videos,
|
|
5356
|
-
audio=audio,
|
|
5357
|
-
files=files,
|
|
5358
|
-
stream=True,
|
|
5359
|
-
stream_intermediate_steps=stream_intermediate_steps,
|
|
5360
|
-
debug_mode=debug_mode,
|
|
5361
|
-
add_history_to_context=add_history_to_context,
|
|
5362
|
-
workflow_context=workflow_context,
|
|
5363
|
-
knowledge_filters=knowledge_filters
|
|
5364
|
-
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5365
|
-
else None,
|
|
5366
|
-
yield_run_response=True,
|
|
5367
|
-
)
|
|
5368
|
-
member_agent_run_response = None
|
|
5369
|
-
for member_agent_run_output_event in member_agent_run_response_stream:
|
|
5370
|
-
if isinstance(member_agent_run_output_event, TeamRunOutput) or isinstance(
|
|
5371
|
-
member_agent_run_output_event, RunOutput
|
|
5372
|
-
):
|
|
5373
|
-
member_agent_run_response = member_agent_run_output_event # type: ignore
|
|
5374
|
-
break
|
|
5375
|
-
check_if_run_cancelled(member_agent_run_output_event)
|
|
5376
|
-
|
|
5377
|
-
# Yield the member event directly
|
|
5378
|
-
yield member_agent_run_output_event
|
|
5379
|
-
else:
|
|
5380
|
-
member_agent_run_response = member_agent.run( # type: ignore
|
|
5381
|
-
input=member_agent_task if history is None else history,
|
|
5382
|
-
user_id=user_id,
|
|
5383
|
-
# All members have the same session_id
|
|
5384
|
-
session_id=session.session_id,
|
|
5385
|
-
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5386
|
-
images=images,
|
|
5387
|
-
videos=videos,
|
|
5388
|
-
audio=audio,
|
|
5389
|
-
files=files,
|
|
5390
|
-
stream=False,
|
|
5391
|
-
debug_mode=debug_mode,
|
|
5392
|
-
add_history_to_context=add_history_to_context,
|
|
5393
|
-
knowledge_filters=knowledge_filters
|
|
5394
|
-
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5395
|
-
else None,
|
|
5396
|
-
)
|
|
5397
|
-
|
|
5398
|
-
check_if_run_cancelled(member_agent_run_response) # type: ignore
|
|
5399
|
-
|
|
5400
|
-
try:
|
|
5401
|
-
if member_agent_run_response.content is None and ( # type: ignore
|
|
5402
|
-
member_agent_run_response.tools is None or len(member_agent_run_response.tools) == 0 # type: ignore
|
|
5403
|
-
):
|
|
5404
|
-
yield "No response from the member agent."
|
|
5405
|
-
elif isinstance(member_agent_run_response.content, str): # type: ignore
|
|
5406
|
-
content = member_agent_run_response.content.strip() # type: ignore
|
|
5407
|
-
if len(content) > 0:
|
|
5408
|
-
yield content
|
|
5409
|
-
|
|
5410
|
-
# If the content is empty but we have tool calls
|
|
5411
|
-
elif member_agent_run_response.tools is not None and len(member_agent_run_response.tools) > 0: # type: ignore
|
|
5412
|
-
tool_str = ""
|
|
5413
|
-
for tool in member_agent_run_response.tools: # type: ignore
|
|
5414
|
-
if tool.result:
|
|
5415
|
-
tool_str += f"{tool.result},"
|
|
5416
|
-
yield tool_str.rstrip(",")
|
|
5417
|
-
|
|
5418
|
-
elif issubclass(type(member_agent_run_response.content), BaseModel): # type: ignore
|
|
5419
|
-
yield member_agent_run_response.content.model_dump_json(indent=2) # type: ignore
|
|
5420
|
-
else:
|
|
5421
|
-
import json
|
|
5139
|
+
# If the member will produce structured output, we need to parse the response
|
|
5140
|
+
if member_agent.output_schema is not None:
|
|
5141
|
+
self._member_response_model = member_agent.output_schema
|
|
5422
5142
|
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5143
|
+
# 6. Handle enable_agentic_knowledge_filters on the member agent
|
|
5144
|
+
if self.enable_agentic_knowledge_filters and not member_agent.enable_agentic_knowledge_filters:
|
|
5145
|
+
member_agent.enable_agentic_knowledge_filters = self.enable_agentic_knowledge_filters
|
|
5426
5146
|
|
|
5427
|
-
|
|
5428
|
-
use_team_logger()
|
|
5147
|
+
return member_agent_task, history
|
|
5429
5148
|
|
|
5149
|
+
def _process_delegate_task_to_member(
|
|
5150
|
+
member_agent_run_response: Optional[Union[TeamRunOutput, RunOutput]],
|
|
5151
|
+
member_agent: Union[Agent, "Team"],
|
|
5152
|
+
member_agent_task: Union[str, Message],
|
|
5153
|
+
member_session_state_copy: Dict[str, Any],
|
|
5154
|
+
):
|
|
5430
5155
|
# Add team run id to the member run
|
|
5431
5156
|
if member_agent_run_response is not None:
|
|
5432
5157
|
member_agent_run_response.parent_run_id = run_response.run_id # type: ignore
|
|
5433
5158
|
|
|
5434
|
-
# Update the
|
|
5435
|
-
member_name = member_agent.name if member_agent.name else
|
|
5159
|
+
# Update the team run context
|
|
5160
|
+
member_name = member_agent.name if member_agent.name else member_agent.id if member_agent.id else "Unknown"
|
|
5161
|
+
if isinstance(member_agent_task, str):
|
|
5162
|
+
normalized_task = member_agent_task
|
|
5163
|
+
elif member_agent_task.content:
|
|
5164
|
+
normalized_task = str(member_agent_task.content)
|
|
5165
|
+
else:
|
|
5166
|
+
normalized_task = ""
|
|
5436
5167
|
self._add_interaction_to_team_run_context(
|
|
5437
5168
|
team_run_context=team_run_context,
|
|
5438
5169
|
member_name=member_name,
|
|
5439
|
-
task=
|
|
5170
|
+
task=normalized_task,
|
|
5440
5171
|
run_response=member_agent_run_response, # type: ignore
|
|
5441
5172
|
)
|
|
5442
5173
|
|
|
5443
|
-
# Add the member run to the team run response
|
|
5444
|
-
if
|
|
5174
|
+
# Add the member run to the team run response if enabled
|
|
5175
|
+
if run_response and member_agent_run_response:
|
|
5445
5176
|
run_response.add_member_run(member_agent_run_response)
|
|
5446
5177
|
|
|
5447
5178
|
# Add the member run to the team session
|
|
@@ -5455,9 +5186,9 @@ class Team:
|
|
|
5455
5186
|
if member_agent_run_response is not None:
|
|
5456
5187
|
self._update_team_media(member_agent_run_response) # type: ignore
|
|
5457
5188
|
|
|
5458
|
-
|
|
5189
|
+
def delegate_task_to_member(
|
|
5459
5190
|
member_id: str, task_description: str, expected_output: Optional[str] = None
|
|
5460
|
-
) ->
|
|
5191
|
+
) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
5461
5192
|
"""Use this function to delegate a task to the selected team member.
|
|
5462
5193
|
You must provide a clear and concise description of the task the member should achieve AND the expected output.
|
|
5463
5194
|
|
|
@@ -5476,41 +5207,16 @@ class Team:
|
|
|
5476
5207
|
yield f"Member with ID {member_id} not found in the team or any subteams. Please choose the correct member from the list of members:\n\n{self.get_members_system_message_content(indent=0)}"
|
|
5477
5208
|
return
|
|
5478
5209
|
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
# 2. Determine team context to send
|
|
5483
|
-
team_member_interactions_str = self._determine_team_member_interactions(
|
|
5484
|
-
team_run_context=team_run_context, images=images, videos=videos, audio=audio
|
|
5485
|
-
)
|
|
5486
|
-
|
|
5487
|
-
# 3. Create the member agent task
|
|
5488
|
-
# Don't override the expected output of a member agent
|
|
5489
|
-
if member_agent.expected_output is not None:
|
|
5490
|
-
expected_output = None
|
|
5491
|
-
member_agent_task = format_member_agent_task(
|
|
5492
|
-
task_description, expected_output, team_member_interactions_str
|
|
5493
|
-
)
|
|
5494
|
-
|
|
5495
|
-
# 4. Add history for the member if enabled
|
|
5496
|
-
if member_agent.add_history_to_context:
|
|
5497
|
-
history = self._get_history_for_member_agent(session, member_agent)
|
|
5498
|
-
if history:
|
|
5499
|
-
history.append(Message(role="user", content=member_agent_task))
|
|
5210
|
+
_, member_agent = result
|
|
5211
|
+
member_agent_task, history = _setup_delegate_task_to_member(member_agent, task_description, expected_output)
|
|
5500
5212
|
|
|
5501
5213
|
# Make sure for the member agent, we are using the agent logger
|
|
5502
5214
|
use_agent_logger()
|
|
5503
5215
|
|
|
5504
|
-
# Handle enable_agentic_knowledge_filters
|
|
5505
|
-
if self.enable_agentic_knowledge_filters and not member_agent.enable_agentic_knowledge_filters:
|
|
5506
|
-
member_agent.enable_agentic_knowledge_filters = self.enable_agentic_knowledge_filters
|
|
5507
|
-
|
|
5508
|
-
member_input = member_agent_task if history is None else history
|
|
5509
|
-
|
|
5510
5216
|
member_session_state_copy = copy(session_state)
|
|
5511
5217
|
if stream:
|
|
5512
|
-
member_agent_run_response_stream = member_agent.
|
|
5513
|
-
input=
|
|
5218
|
+
member_agent_run_response_stream = member_agent.run(
|
|
5219
|
+
input=member_agent_task if not history else history,
|
|
5514
5220
|
user_id=user_id,
|
|
5515
5221
|
# All members have the same session_id
|
|
5516
5222
|
session_id=session.session_id,
|
|
@@ -5530,217 +5236,22 @@ class Team:
|
|
|
5530
5236
|
yield_run_response=True,
|
|
5531
5237
|
)
|
|
5532
5238
|
member_agent_run_response = None
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5239
|
+
for member_agent_run_output_event in member_agent_run_response_stream:
|
|
5240
|
+
# If we get the final response, we can break out of the loop
|
|
5241
|
+
if isinstance(member_agent_run_output_event, TeamRunOutput) or isinstance(
|
|
5242
|
+
member_agent_run_output_event, RunOutput
|
|
5536
5243
|
):
|
|
5537
|
-
member_agent_run_response =
|
|
5244
|
+
member_agent_run_response = member_agent_run_output_event # type: ignore
|
|
5538
5245
|
break
|
|
5539
|
-
check_if_run_cancelled(member_agent_run_response_event)
|
|
5540
|
-
yield member_agent_run_response_event
|
|
5541
|
-
else:
|
|
5542
|
-
member_agent_run_response = await member_agent.arun( # type: ignore
|
|
5543
|
-
input=member_input,
|
|
5544
|
-
user_id=user_id,
|
|
5545
|
-
# All members have the same session_id
|
|
5546
|
-
session_id=session.session_id,
|
|
5547
|
-
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5548
|
-
images=images,
|
|
5549
|
-
videos=videos,
|
|
5550
|
-
audio=audio,
|
|
5551
|
-
files=files,
|
|
5552
|
-
stream=False,
|
|
5553
|
-
debug_mode=debug_mode,
|
|
5554
|
-
add_history_to_context=add_history_to_context,
|
|
5555
|
-
knowledge_filters=knowledge_filters
|
|
5556
|
-
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5557
|
-
else None,
|
|
5558
|
-
)
|
|
5559
|
-
check_if_run_cancelled(member_agent_run_response) # type: ignore
|
|
5560
|
-
|
|
5561
|
-
try:
|
|
5562
|
-
if member_agent_run_response.content is None and ( # type: ignore
|
|
5563
|
-
member_agent_run_response.tools is None or len(member_agent_run_response.tools) == 0 # type: ignore
|
|
5564
|
-
):
|
|
5565
|
-
yield "No response from the member agent."
|
|
5566
|
-
elif isinstance(member_agent_run_response.content, str): # type: ignore
|
|
5567
|
-
if len(member_agent_run_response.content.strip()) > 0: # type: ignore
|
|
5568
|
-
yield member_agent_run_response.content # type: ignore
|
|
5569
|
-
|
|
5570
|
-
# If the content is empty but we have tool calls
|
|
5571
|
-
elif (
|
|
5572
|
-
member_agent_run_response.tools is not None # type: ignore
|
|
5573
|
-
and len(member_agent_run_response.tools) > 0 # type: ignore
|
|
5574
|
-
):
|
|
5575
|
-
yield ",".join([tool.result for tool in member_agent_run_response.tools if tool.result]) # type: ignore
|
|
5576
|
-
elif issubclass(type(member_agent_run_response.content), BaseModel): # type: ignore
|
|
5577
|
-
yield member_agent_run_response.content.model_dump_json(indent=2) # type: ignore
|
|
5578
|
-
else:
|
|
5579
|
-
import json
|
|
5580
|
-
|
|
5581
|
-
yield json.dumps(member_agent_run_response.content, indent=2) # type: ignore
|
|
5582
|
-
except Exception as e:
|
|
5583
|
-
yield str(e)
|
|
5584
|
-
|
|
5585
|
-
# Afterward, switch back to the team logger
|
|
5586
|
-
use_team_logger()
|
|
5587
|
-
|
|
5588
|
-
# Add team run id to the member run
|
|
5589
|
-
if member_agent_run_response is not None:
|
|
5590
|
-
member_agent_run_response.parent_run_id = run_response.run_id # type: ignore
|
|
5591
|
-
|
|
5592
|
-
# Update the memory
|
|
5593
|
-
member_name = member_agent.name if member_agent.name else f"agent_{member_agent_index}"
|
|
5594
|
-
self._add_interaction_to_team_run_context(
|
|
5595
|
-
team_run_context=team_run_context,
|
|
5596
|
-
member_name=member_name,
|
|
5597
|
-
task=task_description,
|
|
5598
|
-
run_response=member_agent_run_response, # type: ignore
|
|
5599
|
-
)
|
|
5600
|
-
|
|
5601
|
-
# Add the member run to the team run response
|
|
5602
|
-
if store_member_responses and run_response and member_agent_run_response:
|
|
5603
|
-
run_response.add_member_run(member_agent_run_response)
|
|
5604
|
-
|
|
5605
|
-
# Add the member run to the team session
|
|
5606
|
-
if member_agent_run_response:
|
|
5607
|
-
session.upsert_run(member_agent_run_response)
|
|
5608
|
-
|
|
5609
|
-
# Update team session state
|
|
5610
|
-
merge_dictionaries(session_state, member_session_state_copy) # type: ignore
|
|
5611
|
-
|
|
5612
|
-
# Update the team media
|
|
5613
|
-
if member_agent_run_response is not None:
|
|
5614
|
-
self._update_team_media(member_agent_run_response) # type: ignore
|
|
5615
|
-
|
|
5616
|
-
if async_mode:
|
|
5617
|
-
delegate_function = adelegate_task_to_member # type: ignore
|
|
5618
|
-
else:
|
|
5619
|
-
delegate_function = delegate_task_to_member # type: ignore
|
|
5620
|
-
|
|
5621
|
-
delegate_func = Function.from_callable(delegate_function, name="delegate_task_to_member", strict=True)
|
|
5622
|
-
|
|
5623
|
-
return delegate_func
|
|
5624
|
-
|
|
5625
|
-
def _get_forward_task_function(
|
|
5626
|
-
self,
|
|
5627
|
-
input: Message,
|
|
5628
|
-
run_response: TeamRunOutput,
|
|
5629
|
-
team_run_context: Dict[str, Any],
|
|
5630
|
-
session: TeamSession,
|
|
5631
|
-
session_state: Dict[str, Any],
|
|
5632
|
-
user_id: Optional[str] = None,
|
|
5633
|
-
stream: bool = False,
|
|
5634
|
-
stream_intermediate_steps: bool = False,
|
|
5635
|
-
async_mode: bool = False,
|
|
5636
|
-
images: Optional[Sequence[Image]] = None,
|
|
5637
|
-
videos: Optional[Sequence[Video]] = None,
|
|
5638
|
-
audio: Optional[Sequence[Audio]] = None,
|
|
5639
|
-
files: Optional[Sequence[File]] = None,
|
|
5640
|
-
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
5641
|
-
workflow_context: Optional[Dict] = None,
|
|
5642
|
-
store_member_responses: bool = False,
|
|
5643
|
-
debug_mode: Optional[bool] = None,
|
|
5644
|
-
add_history_to_context: Optional[bool] = None,
|
|
5645
|
-
dependencies: Optional[Dict[str, Any]] = None,
|
|
5646
|
-
) -> Function:
|
|
5647
|
-
if not images:
|
|
5648
|
-
images = []
|
|
5649
|
-
if not videos:
|
|
5650
|
-
videos = []
|
|
5651
|
-
if not audio:
|
|
5652
|
-
audio = []
|
|
5653
|
-
if not files:
|
|
5654
|
-
files = []
|
|
5655
|
-
|
|
5656
|
-
def forward_task_to_member(
|
|
5657
|
-
member_id: str, expected_output: Optional[str] = None
|
|
5658
|
-
) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
5659
|
-
"""Use this function to forward the request to the selected team member.
|
|
5660
|
-
Args:
|
|
5661
|
-
member_id (str): The ID of the member to delegate the task to. Use only the ID of the member, not the ID of the team followed by the ID of the member.
|
|
5662
|
-
expected_output (str, optional): The expected output from the member (optional).
|
|
5663
|
-
Returns:
|
|
5664
|
-
str: The result of the delegated task.
|
|
5665
|
-
"""
|
|
5666
|
-
self._member_response_model = None
|
|
5667
|
-
|
|
5668
|
-
# Find the member agent using the helper function
|
|
5669
|
-
result = self._find_member_by_id(member_id)
|
|
5670
|
-
history = None
|
|
5671
|
-
if result is None:
|
|
5672
|
-
yield f"Member with ID {member_id} not found in the team or any subteams. Please choose the correct member from the list of members:\n\n{self.get_members_system_message_content(indent=0)}"
|
|
5673
|
-
return
|
|
5674
|
-
|
|
5675
|
-
member_agent_index, member_agent = result
|
|
5676
|
-
self._initialize_member(member_agent)
|
|
5677
|
-
|
|
5678
|
-
# Since we return the response directly from the member agent, we need to set the response model from the team down.
|
|
5679
|
-
if not member_agent.output_schema and self.output_schema:
|
|
5680
|
-
member_agent.output_schema = self.output_schema
|
|
5681
|
-
|
|
5682
|
-
# If the member will produce structured output, we need to parse the response
|
|
5683
|
-
if member_agent.output_schema is not None:
|
|
5684
|
-
self._member_response_model = member_agent.output_schema
|
|
5685
|
-
|
|
5686
|
-
# Make sure for the member agent, we are using the agent logger
|
|
5687
|
-
use_agent_logger()
|
|
5688
|
-
|
|
5689
|
-
# If found in subteam, include the path in the task description
|
|
5690
|
-
member_agent_task = input.get_content_string() if input is not None else ""
|
|
5691
|
-
|
|
5692
|
-
# Add history for the member if enabled
|
|
5693
|
-
should_add_member_history = (
|
|
5694
|
-
add_history_to_context if add_history_to_context is not None else member_agent.add_history_to_context
|
|
5695
|
-
)
|
|
5696
|
-
if should_add_member_history:
|
|
5697
|
-
history = self._get_history_for_member_agent(session, member_agent)
|
|
5698
|
-
if history:
|
|
5699
|
-
history.append(Message(role="user", content=member_agent_task))
|
|
5700
|
-
|
|
5701
|
-
# Don't override the expected output of a member agent
|
|
5702
|
-
if member_agent.expected_output is None and expected_output:
|
|
5703
|
-
member_agent_task += f"\n\n<expected_output>\n{expected_output}\n</expected_output>"
|
|
5704
5246
|
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
member_agent.enable_agentic_knowledge_filters = self.enable_agentic_knowledge_filters
|
|
5247
|
+
# Check if the run is cancelled
|
|
5248
|
+
check_if_run_cancelled(member_agent_run_output_event)
|
|
5708
5249
|
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
if stream:
|
|
5712
|
-
member_agent_run_response_stream = member_agent.run(
|
|
5713
|
-
input=member_agent_task if history is None else history,
|
|
5714
|
-
user_id=user_id,
|
|
5715
|
-
# All members have the same session_id
|
|
5716
|
-
session_id=session.session_id,
|
|
5717
|
-
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5718
|
-
images=images,
|
|
5719
|
-
videos=videos,
|
|
5720
|
-
audio=audio,
|
|
5721
|
-
files=files,
|
|
5722
|
-
stream=True,
|
|
5723
|
-
stream_intermediate_steps=stream_intermediate_steps,
|
|
5724
|
-
debug_mode=debug_mode,
|
|
5725
|
-
add_history_to_context=add_history_to_context,
|
|
5726
|
-
workflow_context=workflow_context,
|
|
5727
|
-
knowledge_filters=knowledge_filters
|
|
5728
|
-
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5729
|
-
else None,
|
|
5730
|
-
yield_run_response=True,
|
|
5731
|
-
)
|
|
5732
|
-
member_agent_run_response = None
|
|
5733
|
-
for member_agent_run_response_chunk in member_agent_run_response_stream:
|
|
5734
|
-
if isinstance(member_agent_run_response_chunk, TeamRunOutput) or isinstance(
|
|
5735
|
-
member_agent_run_response_chunk, RunOutput
|
|
5736
|
-
):
|
|
5737
|
-
member_agent_run_response = member_agent_run_response_chunk # type: ignore
|
|
5738
|
-
break
|
|
5739
|
-
check_if_run_cancelled(member_agent_run_response_chunk)
|
|
5740
|
-
yield member_agent_run_response_chunk
|
|
5250
|
+
# Yield the member event directly
|
|
5251
|
+
yield member_agent_run_output_event
|
|
5741
5252
|
else:
|
|
5742
5253
|
member_agent_run_response = member_agent.run( # type: ignore
|
|
5743
|
-
input=member_agent_task if history
|
|
5254
|
+
input=member_agent_task if not history else history,
|
|
5744
5255
|
user_id=user_id,
|
|
5745
5256
|
# All members have the same session_id
|
|
5746
5257
|
session_id=session.session_id,
|
|
@@ -5751,11 +5262,13 @@ class Team:
|
|
|
5751
5262
|
files=files,
|
|
5752
5263
|
stream=False,
|
|
5753
5264
|
debug_mode=debug_mode,
|
|
5265
|
+
workflow_context=workflow_context,
|
|
5754
5266
|
add_history_to_context=add_history_to_context,
|
|
5755
5267
|
knowledge_filters=knowledge_filters
|
|
5756
5268
|
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5757
5269
|
else None,
|
|
5758
5270
|
)
|
|
5271
|
+
|
|
5759
5272
|
check_if_run_cancelled(member_agent_run_response) # type: ignore
|
|
5760
5273
|
|
|
5761
5274
|
try:
|
|
@@ -5764,13 +5277,12 @@ class Team:
|
|
|
5764
5277
|
):
|
|
5765
5278
|
yield "No response from the member agent."
|
|
5766
5279
|
elif isinstance(member_agent_run_response.content, str): # type: ignore
|
|
5767
|
-
|
|
5768
|
-
|
|
5280
|
+
content = member_agent_run_response.content.strip() # type: ignore
|
|
5281
|
+
if len(content) > 0:
|
|
5282
|
+
yield content
|
|
5769
5283
|
|
|
5770
5284
|
# If the content is empty but we have tool calls
|
|
5771
|
-
elif (
|
|
5772
|
-
member_agent_run_response.tools is not None and len(member_agent_run_response.tools) > 0 # type: ignore
|
|
5773
|
-
):
|
|
5285
|
+
elif member_agent_run_response.tools is not None and len(member_agent_run_response.tools) > 0: # type: ignore
|
|
5774
5286
|
tool_str = ""
|
|
5775
5287
|
for tool in member_agent_run_response.tools: # type: ignore
|
|
5776
5288
|
if tool.result:
|
|
@@ -5789,46 +5301,23 @@ class Team:
|
|
|
5789
5301
|
# Afterward, switch back to the team logger
|
|
5790
5302
|
use_team_logger()
|
|
5791
5303
|
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
member_agent_run_response.parent_run_id = run_response.run_id # type: ignore
|
|
5795
|
-
|
|
5796
|
-
# Update the memory
|
|
5797
|
-
member_name = member_agent.name if member_agent.name else f"agent_{member_agent_index}"
|
|
5798
|
-
self._add_interaction_to_team_run_context(
|
|
5799
|
-
team_run_context=team_run_context,
|
|
5800
|
-
member_name=member_name,
|
|
5801
|
-
task=member_agent_task,
|
|
5802
|
-
run_response=member_agent_run_response, # type: ignore
|
|
5304
|
+
_process_delegate_task_to_member(
|
|
5305
|
+
member_agent_run_response, member_agent, member_agent_task, member_session_state_copy
|
|
5803
5306
|
)
|
|
5804
5307
|
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
run_response.add_member_run(member_agent_run_response)
|
|
5808
|
-
|
|
5809
|
-
# Add the member run to the team session
|
|
5810
|
-
if member_agent_run_response:
|
|
5811
|
-
session.upsert_run(member_agent_run_response)
|
|
5812
|
-
|
|
5813
|
-
# Update team session state
|
|
5814
|
-
merge_dictionaries(session_state, member_session_state_copy) # type: ignore
|
|
5815
|
-
|
|
5816
|
-
# Update the team media
|
|
5817
|
-
if member_agent_run_response is not None:
|
|
5818
|
-
self._update_team_media(member_agent_run_response) # type: ignore
|
|
5819
|
-
|
|
5820
|
-
async def aforward_task_to_member(
|
|
5821
|
-
member_id: str, expected_output: Optional[str] = None
|
|
5308
|
+
async def adelegate_task_to_member(
|
|
5309
|
+
member_id: str, task_description: str, expected_output: Optional[str] = None
|
|
5822
5310
|
) -> AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
5823
|
-
"""Use this function to
|
|
5311
|
+
"""Use this function to delegate a task to the selected team member.
|
|
5312
|
+
You must provide a clear and concise description of the task the member should achieve AND the expected output.
|
|
5824
5313
|
|
|
5825
5314
|
Args:
|
|
5826
5315
|
member_id (str): The ID of the member to delegate the task to. Use only the ID of the member, not the ID of the team followed by the ID of the member.
|
|
5316
|
+
task_description (str): A clear and concise description of the task the member should achieve.
|
|
5827
5317
|
expected_output (str, optional): The expected output from the member (optional).
|
|
5828
5318
|
Returns:
|
|
5829
5319
|
str: The result of the delegated task.
|
|
5830
5320
|
"""
|
|
5831
|
-
self._member_response_model = None
|
|
5832
5321
|
|
|
5833
5322
|
# Find the member agent using the helper function
|
|
5834
5323
|
result = self._find_member_by_id(member_id)
|
|
@@ -5837,38 +5326,16 @@ class Team:
|
|
|
5837
5326
|
yield f"Member with ID {member_id} not found in the team or any subteams. Please choose the correct member from the list of members:\n\n{self.get_members_system_message_content(indent=0)}"
|
|
5838
5327
|
return
|
|
5839
5328
|
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
# If the member will produce structured output, we need to parse the response
|
|
5844
|
-
if member_agent.output_schema is not None:
|
|
5845
|
-
self._member_response_model = member_agent.output_schema
|
|
5329
|
+
_, member_agent = result
|
|
5330
|
+
member_agent_task, history = _setup_delegate_task_to_member(member_agent, task_description, expected_output)
|
|
5846
5331
|
|
|
5847
5332
|
# Make sure for the member agent, we are using the agent logger
|
|
5848
5333
|
use_agent_logger()
|
|
5849
5334
|
|
|
5850
|
-
# If found in subteam, include the path in the task description
|
|
5851
|
-
member_agent_task = input.get_content_string() if input is not None else ""
|
|
5852
|
-
|
|
5853
|
-
if member_agent.add_history_to_context:
|
|
5854
|
-
history = self._get_history_for_member_agent(session, member_agent)
|
|
5855
|
-
if history:
|
|
5856
|
-
history.append(Message(role="user", content=member_agent_task))
|
|
5857
|
-
|
|
5858
|
-
# Don't override the expected output of a member agent
|
|
5859
|
-
if member_agent.expected_output is None and expected_output:
|
|
5860
|
-
member_agent_task += f"\n\n<expected_output>\n{expected_output}\n</expected_output>"
|
|
5861
|
-
|
|
5862
|
-
# Handle enable_agentic_knowledge_filters
|
|
5863
|
-
if self.enable_agentic_knowledge_filters and not member_agent.enable_agentic_knowledge_filters:
|
|
5864
|
-
member_agent.enable_agentic_knowledge_filters = self.enable_agentic_knowledge_filters
|
|
5865
|
-
|
|
5866
|
-
member_input = member_agent_task if history is None else history
|
|
5867
|
-
# 2. Get the response from the member agent
|
|
5868
5335
|
member_session_state_copy = copy(session_state)
|
|
5869
5336
|
if stream:
|
|
5870
5337
|
member_agent_run_response_stream = member_agent.arun( # type: ignore
|
|
5871
|
-
input=
|
|
5338
|
+
input=member_agent_task if not history else history,
|
|
5872
5339
|
user_id=user_id,
|
|
5873
5340
|
# All members have the same session_id
|
|
5874
5341
|
session_id=session.session_id,
|
|
@@ -5879,9 +5346,9 @@ class Team:
|
|
|
5879
5346
|
files=files,
|
|
5880
5347
|
stream=True,
|
|
5881
5348
|
stream_intermediate_steps=stream_intermediate_steps,
|
|
5882
|
-
workflow_context=workflow_context,
|
|
5883
5349
|
debug_mode=debug_mode,
|
|
5884
5350
|
add_history_to_context=add_history_to_context,
|
|
5351
|
+
workflow_context=workflow_context,
|
|
5885
5352
|
knowledge_filters=knowledge_filters
|
|
5886
5353
|
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5887
5354
|
else None,
|
|
@@ -5889,16 +5356,21 @@ class Team:
|
|
|
5889
5356
|
)
|
|
5890
5357
|
member_agent_run_response = None
|
|
5891
5358
|
async for member_agent_run_response_event in member_agent_run_response_stream:
|
|
5359
|
+
# If we get the final response, we can break out of the loop
|
|
5892
5360
|
if isinstance(member_agent_run_response_event, TeamRunOutput) or isinstance(
|
|
5893
5361
|
member_agent_run_response_event, RunOutput
|
|
5894
5362
|
):
|
|
5895
5363
|
member_agent_run_response = member_agent_run_response_event # type: ignore
|
|
5896
5364
|
break
|
|
5365
|
+
|
|
5366
|
+
# Check if the run is cancelled
|
|
5897
5367
|
check_if_run_cancelled(member_agent_run_response_event)
|
|
5368
|
+
|
|
5369
|
+
# Yield the member event directly
|
|
5898
5370
|
yield member_agent_run_response_event
|
|
5899
5371
|
else:
|
|
5900
5372
|
member_agent_run_response = await member_agent.arun( # type: ignore
|
|
5901
|
-
input=
|
|
5373
|
+
input=member_agent_task if not history else history,
|
|
5902
5374
|
user_id=user_id,
|
|
5903
5375
|
# All members have the same session_id
|
|
5904
5376
|
session_id=session.session_id,
|
|
@@ -5909,9 +5381,10 @@ class Team:
|
|
|
5909
5381
|
files=files,
|
|
5910
5382
|
stream=False,
|
|
5911
5383
|
debug_mode=debug_mode,
|
|
5384
|
+
workflow_context=workflow_context,
|
|
5912
5385
|
add_history_to_context=add_history_to_context,
|
|
5913
5386
|
knowledge_filters=knowledge_filters
|
|
5914
|
-
if
|
|
5387
|
+
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5915
5388
|
else None,
|
|
5916
5389
|
)
|
|
5917
5390
|
check_if_run_cancelled(member_agent_run_response) # type: ignore
|
|
@@ -5927,7 +5400,8 @@ class Team:
|
|
|
5927
5400
|
|
|
5928
5401
|
# If the content is empty but we have tool calls
|
|
5929
5402
|
elif (
|
|
5930
|
-
member_agent_run_response.tools is not None
|
|
5403
|
+
member_agent_run_response.tools is not None # type: ignore
|
|
5404
|
+
and len(member_agent_run_response.tools) > 0 # type: ignore
|
|
5931
5405
|
):
|
|
5932
5406
|
yield ",".join([tool.result for tool in member_agent_run_response.tools if tool.result]) # type: ignore
|
|
5933
5407
|
elif issubclass(type(member_agent_run_response.content), BaseModel): # type: ignore
|
|
@@ -5942,45 +5416,295 @@ class Team:
|
|
|
5942
5416
|
# Afterward, switch back to the team logger
|
|
5943
5417
|
use_team_logger()
|
|
5944
5418
|
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
member_agent_run_response.parent_run_id = run_response.run_id # type: ignore
|
|
5948
|
-
|
|
5949
|
-
# Update the memory
|
|
5950
|
-
member_name = member_agent.name if member_agent.name else f"agent_{member_agent_index}"
|
|
5951
|
-
self._add_interaction_to_team_run_context(
|
|
5952
|
-
team_run_context=team_run_context,
|
|
5953
|
-
member_name=member_name,
|
|
5954
|
-
task=member_agent_task,
|
|
5955
|
-
run_response=member_agent_run_response, # type: ignore
|
|
5419
|
+
_process_delegate_task_to_member(
|
|
5420
|
+
member_agent_run_response, member_agent, member_agent_task, member_session_state_copy
|
|
5956
5421
|
)
|
|
5957
5422
|
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5423
|
+
# When the task should be delegated to all members
|
|
5424
|
+
def delegate_task_to_members(
|
|
5425
|
+
task_description: str, expected_output: Optional[str] = None
|
|
5426
|
+
) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
5427
|
+
"""
|
|
5428
|
+
Use this function to delegate a task to all the member agents and return a response.
|
|
5429
|
+
You must provide a clear and concise description of the task the member should achieve AND the expected output.
|
|
5961
5430
|
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5431
|
+
Args:
|
|
5432
|
+
task_description (str): A clear and concise description of the task to send to member agents.
|
|
5433
|
+
expected_output (str, optional): The expected output from the member agents (optional).
|
|
5434
|
+
Returns:
|
|
5435
|
+
str: The result of the delegated task.
|
|
5436
|
+
"""
|
|
5965
5437
|
|
|
5966
|
-
#
|
|
5967
|
-
|
|
5438
|
+
# Run all the members sequentially
|
|
5439
|
+
for _, member_agent in enumerate(self.members):
|
|
5440
|
+
member_agent_task, history = _setup_delegate_task_to_member(
|
|
5441
|
+
member_agent, task_description, expected_output
|
|
5442
|
+
)
|
|
5968
5443
|
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5444
|
+
member_session_state_copy = copy(session_state)
|
|
5445
|
+
if stream:
|
|
5446
|
+
member_agent_run_response_stream = member_agent.run(
|
|
5447
|
+
input=member_agent_task if not history else history,
|
|
5448
|
+
user_id=user_id,
|
|
5449
|
+
# All members have the same session_id
|
|
5450
|
+
session_id=session.session_id,
|
|
5451
|
+
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5452
|
+
images=images,
|
|
5453
|
+
videos=videos,
|
|
5454
|
+
audio=audio,
|
|
5455
|
+
files=files,
|
|
5456
|
+
stream=True,
|
|
5457
|
+
stream_intermediate_steps=stream_intermediate_steps,
|
|
5458
|
+
workflow_context=workflow_context,
|
|
5459
|
+
knowledge_filters=knowledge_filters
|
|
5460
|
+
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5461
|
+
else None,
|
|
5462
|
+
debug_mode=debug_mode,
|
|
5463
|
+
add_history_to_context=add_history_to_context,
|
|
5464
|
+
yield_run_response=True,
|
|
5465
|
+
)
|
|
5466
|
+
member_agent_run_response = None
|
|
5467
|
+
for member_agent_run_response_chunk in member_agent_run_response_stream:
|
|
5468
|
+
# If we get the final response, we can break out of the loop
|
|
5469
|
+
if isinstance(member_agent_run_response_chunk, TeamRunOutput) or isinstance(
|
|
5470
|
+
member_agent_run_response_chunk, RunOutput
|
|
5471
|
+
):
|
|
5472
|
+
member_agent_run_response = member_agent_run_response_chunk # type: ignore
|
|
5473
|
+
break
|
|
5972
5474
|
|
|
5973
|
-
|
|
5974
|
-
|
|
5475
|
+
# Check if the run is cancelled
|
|
5476
|
+
check_if_run_cancelled(member_agent_run_response_chunk)
|
|
5477
|
+
|
|
5478
|
+
# Yield the member event directly
|
|
5479
|
+
yield member_agent_run_response_chunk
|
|
5480
|
+
|
|
5481
|
+
else:
|
|
5482
|
+
member_agent_run_response = member_agent.run( # type: ignore
|
|
5483
|
+
input=member_agent_task if not history else history,
|
|
5484
|
+
user_id=user_id,
|
|
5485
|
+
# All members have the same session_id
|
|
5486
|
+
session_id=session.session_id,
|
|
5487
|
+
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5488
|
+
images=images,
|
|
5489
|
+
videos=videos,
|
|
5490
|
+
audio=audio,
|
|
5491
|
+
files=files,
|
|
5492
|
+
stream=False,
|
|
5493
|
+
workflow_context=workflow_context,
|
|
5494
|
+
knowledge_filters=knowledge_filters
|
|
5495
|
+
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5496
|
+
else None,
|
|
5497
|
+
debug_mode=debug_mode,
|
|
5498
|
+
add_history_to_context=add_history_to_context,
|
|
5499
|
+
)
|
|
5500
|
+
|
|
5501
|
+
check_if_run_cancelled(member_agent_run_response) # type: ignore
|
|
5502
|
+
|
|
5503
|
+
try:
|
|
5504
|
+
if member_agent_run_response.content is None and ( # type: ignore
|
|
5505
|
+
member_agent_run_response.tools is None or len(member_agent_run_response.tools) == 0 # type: ignore
|
|
5506
|
+
):
|
|
5507
|
+
yield f"Agent {member_agent.name}: No response from the member agent."
|
|
5508
|
+
elif isinstance(member_agent_run_response.content, str): # type: ignore
|
|
5509
|
+
if len(member_agent_run_response.content.strip()) > 0: # type: ignore
|
|
5510
|
+
yield f"Agent {member_agent.name}: {member_agent_run_response.content}" # type: ignore
|
|
5511
|
+
elif (
|
|
5512
|
+
member_agent_run_response.tools is not None and len(member_agent_run_response.tools) > 0 # type: ignore
|
|
5513
|
+
):
|
|
5514
|
+
yield f"Agent {member_agent.name}: {','.join([tool.result for tool in member_agent_run_response.tools])}" # type: ignore
|
|
5515
|
+
elif issubclass(type(member_agent_run_response.content), BaseModel): # type: ignore
|
|
5516
|
+
yield f"Agent {member_agent.name}: {member_agent_run_response.content.model_dump_json(indent=2)}" # type: ignore
|
|
5517
|
+
else:
|
|
5518
|
+
import json
|
|
5519
|
+
|
|
5520
|
+
yield f"Agent {member_agent.name}: {json.dumps(member_agent_run_response.content, indent=2)}" # type: ignore
|
|
5521
|
+
except Exception as e:
|
|
5522
|
+
yield f"Agent {member_agent.name}: Error - {str(e)}"
|
|
5523
|
+
|
|
5524
|
+
_process_delegate_task_to_member(
|
|
5525
|
+
member_agent_run_response, member_agent, member_agent_task, member_session_state_copy
|
|
5526
|
+
)
|
|
5527
|
+
|
|
5528
|
+
# After all the member runs, switch back to the team logger
|
|
5529
|
+
use_team_logger()
|
|
5530
|
+
|
|
5531
|
+
# When the task should be delegated to all members
|
|
5532
|
+
async def adelegate_task_to_members(
|
|
5533
|
+
task_description: str, expected_output: Optional[str] = None
|
|
5534
|
+
) -> AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
5535
|
+
"""Use this function to delegate a task to all the member agents and return a response.
|
|
5536
|
+
You must provide a clear and concise description of the task to send to member agents AND the expected output.
|
|
5537
|
+
|
|
5538
|
+
Args:
|
|
5539
|
+
task_description (str): A clear and concise description of the task to send to member agents.
|
|
5540
|
+
expected_output (str, optional): The expected output from the member agents (optional).
|
|
5541
|
+
Returns:
|
|
5542
|
+
str: The result of the delegated task.
|
|
5543
|
+
"""
|
|
5544
|
+
|
|
5545
|
+
if stream:
|
|
5546
|
+
# Concurrent streaming: launch each member as a streaming worker and merge events
|
|
5547
|
+
done_marker = object()
|
|
5548
|
+
queue: "asyncio.Queue[Union[RunOutputEvent, TeamRunOutputEvent, str, object]]" = asyncio.Queue()
|
|
5549
|
+
|
|
5550
|
+
async def stream_member(agent: Union[Agent, "Team"], idx: int) -> None:
|
|
5551
|
+
member_agent_task, history = _setup_delegate_task_to_member(
|
|
5552
|
+
agent, task_description, expected_output
|
|
5553
|
+
)
|
|
5554
|
+
member_session_state_copy = copy(session_state)
|
|
5555
|
+
|
|
5556
|
+
member_stream = agent.arun( # type: ignore
|
|
5557
|
+
input=member_agent_task if not history else history,
|
|
5558
|
+
user_id=user_id,
|
|
5559
|
+
session_id=session.session_id,
|
|
5560
|
+
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5561
|
+
images=images,
|
|
5562
|
+
videos=videos,
|
|
5563
|
+
audio=audio,
|
|
5564
|
+
files=files,
|
|
5565
|
+
stream=True,
|
|
5566
|
+
stream_intermediate_steps=stream_intermediate_steps,
|
|
5567
|
+
workflow_context=workflow_context,
|
|
5568
|
+
debug_mode=debug_mode,
|
|
5569
|
+
knowledge_filters=knowledge_filters
|
|
5570
|
+
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5571
|
+
else None,
|
|
5572
|
+
add_history_to_context=add_history_to_context,
|
|
5573
|
+
yield_run_response=True,
|
|
5574
|
+
)
|
|
5575
|
+
member_agent_run_response = None
|
|
5576
|
+
try:
|
|
5577
|
+
async for member_agent_run_output_event in member_stream:
|
|
5578
|
+
if isinstance(member_agent_run_output_event, TeamRunOutput) or isinstance(
|
|
5579
|
+
member_agent_run_output_event, RunOutput
|
|
5580
|
+
):
|
|
5581
|
+
member_agent_run_response = member_agent_run_output_event # type: ignore
|
|
5582
|
+
break
|
|
5583
|
+
check_if_run_cancelled(member_agent_run_output_event)
|
|
5584
|
+
await queue.put(member_agent_run_output_event)
|
|
5585
|
+
finally:
|
|
5586
|
+
_process_delegate_task_to_member(
|
|
5587
|
+
member_agent_run_response, member_agent, member_agent_task, member_session_state_copy
|
|
5588
|
+
)
|
|
5589
|
+
|
|
5590
|
+
# Initialize and launch all members
|
|
5591
|
+
tasks: List[asyncio.Task[None]] = []
|
|
5592
|
+
for member_agent_index, member_agent in enumerate(self.members):
|
|
5593
|
+
current_agent = member_agent
|
|
5594
|
+
current_index = member_agent_index
|
|
5595
|
+
self._initialize_member(current_agent)
|
|
5596
|
+
tasks.append(asyncio.create_task(stream_member(current_agent, current_index)))
|
|
5597
|
+
|
|
5598
|
+
# Drain queue until all members reported done
|
|
5599
|
+
completed = 0
|
|
5600
|
+
try:
|
|
5601
|
+
while completed < len(tasks):
|
|
5602
|
+
item = await queue.get()
|
|
5603
|
+
if item is done_marker:
|
|
5604
|
+
completed += 1
|
|
5605
|
+
else:
|
|
5606
|
+
yield item # type: ignore
|
|
5607
|
+
finally:
|
|
5608
|
+
# Ensure tasks do not leak on cancellation
|
|
5609
|
+
for t in tasks:
|
|
5610
|
+
if not t.done():
|
|
5611
|
+
t.cancel()
|
|
5612
|
+
# Await cancellation to suppress warnings
|
|
5613
|
+
for t in tasks:
|
|
5614
|
+
with contextlib.suppress(Exception):
|
|
5615
|
+
await t
|
|
5616
|
+
|
|
5617
|
+
else:
|
|
5618
|
+
# Non-streaming concurrent run of members; collect results when done
|
|
5619
|
+
tasks = []
|
|
5620
|
+
for member_agent_index, member_agent in enumerate(self.members):
|
|
5621
|
+
current_agent = member_agent
|
|
5622
|
+
current_index = member_agent_index
|
|
5623
|
+
member_agent_task, history = _setup_delegate_task_to_member(
|
|
5624
|
+
current_agent, task_description, expected_output
|
|
5625
|
+
)
|
|
5626
|
+
|
|
5627
|
+
async def run_member_agent(agent=current_agent) -> str:
|
|
5628
|
+
member_session_state_copy = copy(session_state)
|
|
5629
|
+
member_agent_run_response = await agent.arun(
|
|
5630
|
+
input=member_agent_task if not history else history,
|
|
5631
|
+
user_id=user_id,
|
|
5632
|
+
# All members have the same session_id
|
|
5633
|
+
session_id=session.session_id,
|
|
5634
|
+
session_state=member_session_state_copy, # Send a copy to the agent
|
|
5635
|
+
images=images,
|
|
5636
|
+
videos=videos,
|
|
5637
|
+
audio=audio,
|
|
5638
|
+
files=files,
|
|
5639
|
+
stream=False,
|
|
5640
|
+
stream_intermediate_steps=stream_intermediate_steps,
|
|
5641
|
+
debug_mode=debug_mode,
|
|
5642
|
+
workflow_context=workflow_context,
|
|
5643
|
+
knowledge_filters=knowledge_filters
|
|
5644
|
+
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
5645
|
+
else None,
|
|
5646
|
+
add_history_to_context=add_history_to_context,
|
|
5647
|
+
)
|
|
5648
|
+
check_if_run_cancelled(member_agent_run_response)
|
|
5649
|
+
|
|
5650
|
+
_process_delegate_task_to_member(
|
|
5651
|
+
member_agent_run_response, member_agent, member_agent_task, member_session_state_copy
|
|
5652
|
+
)
|
|
5653
|
+
|
|
5654
|
+
member_name = member_agent.name if member_agent.name else f"agent_{member_agent_index}"
|
|
5655
|
+
try:
|
|
5656
|
+
if member_agent_run_response.content is None and (
|
|
5657
|
+
member_agent_run_response.tools is None or len(member_agent_run_response.tools) == 0
|
|
5658
|
+
):
|
|
5659
|
+
return f"Agent {member_name}: No response from the member agent."
|
|
5660
|
+
elif isinstance(member_agent_run_response.content, str):
|
|
5661
|
+
if len(member_agent_run_response.content.strip()) > 0:
|
|
5662
|
+
return f"Agent {member_name}: {member_agent_run_response.content}"
|
|
5663
|
+
elif (
|
|
5664
|
+
member_agent_run_response.tools is not None
|
|
5665
|
+
and len(member_agent_run_response.tools) > 0
|
|
5666
|
+
):
|
|
5667
|
+
return f"Agent {member_name}: {','.join([tool.result for tool in member_agent_run_response.tools])}"
|
|
5668
|
+
elif issubclass(type(member_agent_run_response.content), BaseModel):
|
|
5669
|
+
return f"Agent {member_name}: {member_agent_run_response.content.model_dump_json(indent=2)}" # type: ignore
|
|
5670
|
+
else:
|
|
5671
|
+
import json
|
|
5672
|
+
|
|
5673
|
+
return f"Agent {member_name}: {json.dumps(member_agent_run_response.content, indent=2)}"
|
|
5674
|
+
except Exception as e:
|
|
5675
|
+
return f"Agent {member_name}: Error - {str(e)}"
|
|
5676
|
+
|
|
5677
|
+
return f"Agent {member_name}: No Response"
|
|
5678
|
+
|
|
5679
|
+
tasks.append(run_member_agent) # type: ignore
|
|
5680
|
+
|
|
5681
|
+
results = await asyncio.gather(*[task() for task in tasks]) # type: ignore
|
|
5682
|
+
for result in results:
|
|
5683
|
+
yield result
|
|
5684
|
+
|
|
5685
|
+
# After all the member runs, switch back to the team logger
|
|
5686
|
+
use_team_logger()
|
|
5687
|
+
|
|
5688
|
+
if self.delegate_task_to_all_members:
|
|
5689
|
+
if async_mode:
|
|
5690
|
+
delegate_function = adelegate_task_to_members # type: ignore
|
|
5691
|
+
else:
|
|
5692
|
+
delegate_function = delegate_task_to_members # type: ignore
|
|
5693
|
+
|
|
5694
|
+
delegate_func = Function.from_callable(delegate_function, name="delegate_task_to_members")
|
|
5975
5695
|
else:
|
|
5976
|
-
|
|
5696
|
+
if async_mode:
|
|
5697
|
+
delegate_function = adelegate_task_to_member # type: ignore
|
|
5698
|
+
else:
|
|
5699
|
+
delegate_function = delegate_task_to_member # type: ignore
|
|
5977
5700
|
|
|
5978
|
-
|
|
5701
|
+
delegate_func = Function.from_callable(delegate_function, name="delegate_task_to_member")
|
|
5979
5702
|
|
|
5980
|
-
|
|
5981
|
-
|
|
5703
|
+
if self.respond_directly:
|
|
5704
|
+
delegate_func.stop_after_tool_call = True
|
|
5705
|
+
delegate_func.show_result = True
|
|
5982
5706
|
|
|
5983
|
-
return
|
|
5707
|
+
return delegate_func
|
|
5984
5708
|
|
|
5985
5709
|
###########################################################################
|
|
5986
5710
|
# Session Management
|
|
@@ -6128,7 +5852,7 @@ class Team:
|
|
|
6128
5852
|
|
|
6129
5853
|
return team_session
|
|
6130
5854
|
|
|
6131
|
-
|
|
5855
|
+
log_debug(f"TeamSession {session_id_to_load} not found in db")
|
|
6132
5856
|
return None
|
|
6133
5857
|
|
|
6134
5858
|
def save_session(self, session: TeamSession) -> None:
|
|
@@ -6138,6 +5862,12 @@ class Team:
|
|
|
6138
5862
|
session.session_data["session_state"].pop("current_session_id", None) # type: ignore
|
|
6139
5863
|
session.session_data["session_state"].pop("current_user_id", None) # type: ignore
|
|
6140
5864
|
session.session_data["session_state"].pop("current_run_id", None) # type: ignore
|
|
5865
|
+
|
|
5866
|
+
# scrub the member responses if not storing them
|
|
5867
|
+
if not self.store_member_responses and session.runs is not None:
|
|
5868
|
+
for run in session.runs:
|
|
5869
|
+
if hasattr(run, "member_responses"):
|
|
5870
|
+
run.member_responses = []
|
|
6141
5871
|
self._upsert_session(session=session)
|
|
6142
5872
|
log_debug(f"Created or updated TeamSession record: {session.session_id}")
|
|
6143
5873
|
|
|
@@ -6376,7 +6106,7 @@ class Team:
|
|
|
6376
6106
|
team_member_interactions_str += "</member interactions>\n"
|
|
6377
6107
|
return team_member_interactions_str
|
|
6378
6108
|
|
|
6379
|
-
def _get_team_run_context_images(self, team_run_context: Dict[str, Any]) -> List[
|
|
6109
|
+
def _get_team_run_context_images(self, team_run_context: Dict[str, Any]) -> List[Image]:
|
|
6380
6110
|
if not team_run_context:
|
|
6381
6111
|
return []
|
|
6382
6112
|
images = []
|
|
@@ -6386,7 +6116,7 @@ class Team:
|
|
|
6386
6116
|
images.extend(interaction["run_response"].images)
|
|
6387
6117
|
return images
|
|
6388
6118
|
|
|
6389
|
-
def _get_team_run_context_videos(self, team_run_context: Dict[str, Any]) -> List[
|
|
6119
|
+
def _get_team_run_context_videos(self, team_run_context: Dict[str, Any]) -> List[Video]:
|
|
6390
6120
|
if not team_run_context:
|
|
6391
6121
|
return []
|
|
6392
6122
|
videos = []
|
|
@@ -6396,7 +6126,7 @@ class Team:
|
|
|
6396
6126
|
videos.extend(interaction["run_response"].videos)
|
|
6397
6127
|
return videos
|
|
6398
6128
|
|
|
6399
|
-
def _get_team_run_context_audio(self, team_run_context: Dict[str, Any]) -> List[
|
|
6129
|
+
def _get_team_run_context_audio(self, team_run_context: Dict[str, Any]) -> List[Audio]:
|
|
6400
6130
|
if not team_run_context:
|
|
6401
6131
|
return []
|
|
6402
6132
|
audio = []
|
|
@@ -6410,21 +6140,21 @@ class Team:
|
|
|
6410
6140
|
# Handle images, videos and audio
|
|
6411
6141
|
###########################################################################
|
|
6412
6142
|
|
|
6413
|
-
def _add_image(self, image:
|
|
6143
|
+
def _add_image(self, image: Image, run_response: TeamRunOutput) -> None:
|
|
6414
6144
|
"""Add an image to both the agent's stateful storage and the current run response"""
|
|
6415
6145
|
# Add to run response
|
|
6416
6146
|
if run_response.images is None:
|
|
6417
6147
|
run_response.images = []
|
|
6418
6148
|
run_response.images.append(image)
|
|
6419
6149
|
|
|
6420
|
-
def _add_video(self, video:
|
|
6150
|
+
def _add_video(self, video: Video, run_response: TeamRunOutput) -> None:
|
|
6421
6151
|
"""Add a video to both the agent's stateful storage and the current run response"""
|
|
6422
6152
|
# Add to run response
|
|
6423
6153
|
if run_response.videos is None:
|
|
6424
6154
|
run_response.videos = []
|
|
6425
6155
|
run_response.videos.append(video)
|
|
6426
6156
|
|
|
6427
|
-
def _add_audio(self, audio:
|
|
6157
|
+
def _add_audio(self, audio: Audio, run_response: TeamRunOutput) -> None:
|
|
6428
6158
|
"""Add audio to both the agent's stateful storage and the current run response"""
|
|
6429
6159
|
# Add to run response
|
|
6430
6160
|
if run_response.audio is None:
|
|
@@ -6867,8 +6597,6 @@ class Team:
|
|
|
6867
6597
|
team_data["team_id"] = self.id
|
|
6868
6598
|
if self.model is not None:
|
|
6869
6599
|
team_data["model"] = self.model.to_dict()
|
|
6870
|
-
if self.mode is not None:
|
|
6871
|
-
team_data["mode"] = self.mode
|
|
6872
6600
|
return team_data
|
|
6873
6601
|
|
|
6874
6602
|
###########################################################################
|