agno 2.1.10__py3-none-any.whl → 2.2.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 +1594 -1248
- agno/knowledge/knowledge.py +11 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +14 -0
- agno/knowledge/types.py +1 -0
- agno/models/anthropic/claude.py +2 -2
- agno/models/base.py +4 -4
- agno/models/ollama/chat.py +7 -2
- agno/os/app.py +1 -1
- agno/os/interfaces/a2a/router.py +2 -2
- agno/os/interfaces/agui/router.py +2 -2
- agno/os/router.py +7 -7
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/health.py +6 -2
- agno/os/routers/knowledge/schemas.py +49 -47
- agno/os/routers/memory/schemas.py +16 -16
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +382 -7
- agno/os/schema.py +254 -231
- agno/os/utils.py +1 -1
- agno/run/agent.py +54 -1
- agno/run/team.py +48 -0
- agno/run/workflow.py +15 -5
- agno/session/summary.py +45 -13
- agno/session/team.py +90 -5
- agno/team/team.py +1130 -849
- agno/utils/agent.py +372 -0
- agno/utils/events.py +144 -2
- agno/utils/message.py +60 -0
- agno/utils/print_response/agent.py +10 -6
- agno/utils/print_response/team.py +6 -4
- agno/utils/print_response/workflow.py +7 -5
- agno/utils/team.py +9 -8
- agno/workflow/condition.py +17 -9
- agno/workflow/loop.py +18 -10
- agno/workflow/parallel.py +14 -6
- agno/workflow/router.py +16 -8
- agno/workflow/step.py +14 -6
- agno/workflow/steps.py +14 -6
- agno/workflow/workflow.py +331 -123
- {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/METADATA +63 -23
- {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/RECORD +45 -43
- {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/WHEEL +0 -0
- {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/licenses/LICENSE +0 -0
- {agno-2.1.10.dist-info → agno-2.2.1.dist-info}/top_level.txt +0 -0
agno/team/team.py
CHANGED
|
@@ -10,7 +10,6 @@ from typing import (
|
|
|
10
10
|
Any,
|
|
11
11
|
AsyncIterator,
|
|
12
12
|
Callable,
|
|
13
|
-
Coroutine,
|
|
14
13
|
Dict,
|
|
15
14
|
Iterator,
|
|
16
15
|
List,
|
|
@@ -59,15 +58,28 @@ from agno.run.cancel import (
|
|
|
59
58
|
)
|
|
60
59
|
from agno.run.messages import RunMessages
|
|
61
60
|
from agno.run.team import TeamRunEvent, TeamRunInput, TeamRunOutput, TeamRunOutputEvent
|
|
62
|
-
from agno.session import SessionSummaryManager, TeamSession
|
|
61
|
+
from agno.session import SessionSummaryManager, TeamSession, WorkflowSession
|
|
63
62
|
from agno.tools import Toolkit
|
|
64
63
|
from agno.tools.function import Function
|
|
64
|
+
from agno.utils.agent import (
|
|
65
|
+
await_for_background_tasks,
|
|
66
|
+
await_for_background_tasks_stream,
|
|
67
|
+
collect_joint_audios,
|
|
68
|
+
collect_joint_files,
|
|
69
|
+
collect_joint_images,
|
|
70
|
+
collect_joint_videos,
|
|
71
|
+
scrub_history_messages_from_run_output,
|
|
72
|
+
scrub_media_from_run_output,
|
|
73
|
+
scrub_tool_results_from_run_output,
|
|
74
|
+
wait_for_background_tasks,
|
|
75
|
+
wait_for_background_tasks_stream,
|
|
76
|
+
)
|
|
65
77
|
from agno.utils.common import is_typed_dict, validate_typed_dict
|
|
66
78
|
from agno.utils.events import (
|
|
67
|
-
create_team_memory_update_completed_event,
|
|
68
|
-
create_team_memory_update_started_event,
|
|
69
79
|
create_team_parser_model_response_completed_event,
|
|
70
80
|
create_team_parser_model_response_started_event,
|
|
81
|
+
create_team_post_hook_completed_event,
|
|
82
|
+
create_team_post_hook_started_event,
|
|
71
83
|
create_team_pre_hook_completed_event,
|
|
72
84
|
create_team_pre_hook_started_event,
|
|
73
85
|
create_team_reasoning_completed_event,
|
|
@@ -75,11 +87,15 @@ from agno.utils.events import (
|
|
|
75
87
|
create_team_reasoning_step_event,
|
|
76
88
|
create_team_run_cancelled_event,
|
|
77
89
|
create_team_run_completed_event,
|
|
90
|
+
create_team_run_content_completed_event,
|
|
78
91
|
create_team_run_error_event,
|
|
79
92
|
create_team_run_output_content_event,
|
|
80
93
|
create_team_run_started_event,
|
|
94
|
+
create_team_session_summary_completed_event,
|
|
95
|
+
create_team_session_summary_started_event,
|
|
81
96
|
create_team_tool_call_completed_event,
|
|
82
97
|
create_team_tool_call_started_event,
|
|
98
|
+
handle_event,
|
|
83
99
|
)
|
|
84
100
|
from agno.utils.hooks import filter_hook_args, normalize_hooks
|
|
85
101
|
from agno.utils.knowledge import get_agentic_or_user_search_filters
|
|
@@ -95,7 +111,7 @@ from agno.utils.log import (
|
|
|
95
111
|
use_team_logger,
|
|
96
112
|
)
|
|
97
113
|
from agno.utils.merge_dict import merge_dictionaries
|
|
98
|
-
from agno.utils.message import get_text_from_message
|
|
114
|
+
from agno.utils.message import filter_tool_calls, get_text_from_message
|
|
99
115
|
from agno.utils.print_response.team import (
|
|
100
116
|
aprint_response,
|
|
101
117
|
aprint_response_stream,
|
|
@@ -131,15 +147,22 @@ class Team:
|
|
|
131
147
|
model: Optional[Model] = None
|
|
132
148
|
|
|
133
149
|
# --- Team settings ---
|
|
134
|
-
# Name of the team
|
|
135
|
-
name: Optional[str] = None
|
|
136
150
|
# Team UUID (autogenerated if not set)
|
|
137
151
|
id: Optional[str] = None
|
|
138
|
-
#
|
|
139
|
-
|
|
152
|
+
# Name of the team
|
|
153
|
+
name: Optional[str] = None
|
|
140
154
|
# If this team is part of a team itself, this is the role of the team
|
|
141
155
|
role: Optional[str] = None
|
|
142
156
|
|
|
157
|
+
# --- If this Team is part of a team itself ---
|
|
158
|
+
# If this team is part of a team itself, this is the ID of the parent team. This is set automatically.
|
|
159
|
+
parent_team_id: Optional[str] = None
|
|
160
|
+
|
|
161
|
+
# --- If this Team is part of a workflow ---
|
|
162
|
+
# Optional workflow ID. Indicates this team is part of a workflow. This is set automatically.
|
|
163
|
+
workflow_id: Optional[str] = None
|
|
164
|
+
|
|
165
|
+
# --- Team execution settings ---
|
|
143
166
|
# If True, the team leader won't process responses from the members and instead will return them directly
|
|
144
167
|
# Should not be used in combination with delegate_task_to_all_members
|
|
145
168
|
respond_directly: bool = False
|
|
@@ -148,10 +171,6 @@ class Team:
|
|
|
148
171
|
# Set to false if you want to send the run input directly to the member agents
|
|
149
172
|
determine_input_for_members: bool = True
|
|
150
173
|
|
|
151
|
-
# --- If this Team is part of a workflow ---
|
|
152
|
-
# Optional workflow ID. Indicates this team is part of a workflow.
|
|
153
|
-
workflow_id: Optional[str] = None
|
|
154
|
-
|
|
155
174
|
# --- User settings ---
|
|
156
175
|
# Default user ID for this team
|
|
157
176
|
user_id: Optional[str] = None
|
|
@@ -170,13 +189,22 @@ class Team:
|
|
|
170
189
|
# If True, cache the current Team session in memory for faster access
|
|
171
190
|
cache_session: bool = False
|
|
172
191
|
|
|
173
|
-
#
|
|
192
|
+
# Add this flag to control if the workflow should send the team history to the members. This means sending the team-level history to the members, not the agent-level history.
|
|
193
|
+
add_team_history_to_members: bool = False
|
|
194
|
+
# Number of historical runs to include in the messages sent to the members
|
|
195
|
+
num_team_history_runs: int = 3
|
|
196
|
+
# If True, send all member interactions (request/response) during the current run to members that have been delegated a task to
|
|
197
|
+
share_member_interactions: bool = False
|
|
198
|
+
|
|
199
|
+
# If True, adds a tool to allow searching through previous sessions
|
|
174
200
|
search_session_history: Optional[bool] = False
|
|
175
201
|
# Number of past sessions to include in the search
|
|
176
202
|
num_history_sessions: Optional[int] = None
|
|
177
203
|
|
|
178
|
-
# If True,
|
|
179
|
-
|
|
204
|
+
# If True, adds a tool to allow the team to read the team history (this is deprecated and will be removed in a future version)
|
|
205
|
+
read_team_history: bool = False
|
|
206
|
+
# If True, adds a tool to allow the team to read the chat history
|
|
207
|
+
read_chat_history: bool = False
|
|
180
208
|
|
|
181
209
|
# --- System message settings ---
|
|
182
210
|
# A description of the Team that is added to the start of the system message.
|
|
@@ -206,6 +234,9 @@ class Team:
|
|
|
206
234
|
# Role for the system message
|
|
207
235
|
system_message_role: str = "system"
|
|
208
236
|
|
|
237
|
+
# If True, resolve the session_state, dependencies, and metadata in the user and system messages
|
|
238
|
+
resolve_in_context: bool = True
|
|
239
|
+
|
|
209
240
|
# --- Extra Messages ---
|
|
210
241
|
# A list of extra messages added after the system message and before the user message.
|
|
211
242
|
# Use these for few-shot learning or to provide additional context to the Model.
|
|
@@ -244,17 +275,12 @@ class Team:
|
|
|
244
275
|
references_format: Literal["json", "yaml"] = "json"
|
|
245
276
|
|
|
246
277
|
# --- Tools ---
|
|
247
|
-
# If True, send all previous member interactions to members
|
|
248
|
-
share_member_interactions: bool = False
|
|
249
278
|
# If True, add a tool to get information about the team members
|
|
250
279
|
get_member_information_tool: bool = False
|
|
251
280
|
# Add a tool to search the knowledge base (aka Agentic RAG)
|
|
252
281
|
# Only added if knowledge is provided.
|
|
253
282
|
search_knowledge: bool = True
|
|
254
283
|
|
|
255
|
-
# If True, read the team history
|
|
256
|
-
read_team_history: bool = False
|
|
257
|
-
|
|
258
284
|
# If False, media (images, videos, audio, files) is only available to tools and not sent to the LLM
|
|
259
285
|
send_media_to_model: bool = True
|
|
260
286
|
# If True, store media in run output
|
|
@@ -327,6 +353,8 @@ class Team:
|
|
|
327
353
|
add_history_to_context: bool = False
|
|
328
354
|
# Number of historical runs to include in the messages
|
|
329
355
|
num_history_runs: int = 3
|
|
356
|
+
# Maximum number of tool calls to include from history (None = no limit)
|
|
357
|
+
max_tool_calls_from_history: Optional[int] = None
|
|
330
358
|
|
|
331
359
|
# --- Team Storage ---
|
|
332
360
|
# Metadata stored with this team
|
|
@@ -342,8 +370,10 @@ class Team:
|
|
|
342
370
|
# --- Team Streaming ---
|
|
343
371
|
# Stream the response from the Team
|
|
344
372
|
stream: Optional[bool] = None
|
|
345
|
-
# Stream the intermediate steps from the
|
|
346
|
-
|
|
373
|
+
# Stream the intermediate steps from the Agent
|
|
374
|
+
stream_events: Optional[bool] = None
|
|
375
|
+
# [Deprecated] Stream the intermediate steps from the Agent
|
|
376
|
+
stream_intermediate_steps: Optional[bool] = None
|
|
347
377
|
# Stream the member events from the Team
|
|
348
378
|
stream_member_events: bool = True
|
|
349
379
|
|
|
@@ -393,6 +423,8 @@ class Team:
|
|
|
393
423
|
overwrite_db_session_state: bool = False,
|
|
394
424
|
resolve_in_context: bool = True,
|
|
395
425
|
cache_session: bool = False,
|
|
426
|
+
add_team_history_to_members: bool = False,
|
|
427
|
+
num_team_history_runs: int = 3,
|
|
396
428
|
search_session_history: Optional[bool] = False,
|
|
397
429
|
num_history_sessions: Optional[int] = None,
|
|
398
430
|
description: Optional[str] = None,
|
|
@@ -421,10 +453,13 @@ class Team:
|
|
|
421
453
|
get_member_information_tool: bool = False,
|
|
422
454
|
search_knowledge: bool = True,
|
|
423
455
|
read_team_history: bool = False,
|
|
456
|
+
read_chat_history: bool = False,
|
|
424
457
|
store_media: bool = True,
|
|
425
458
|
store_tool_messages: bool = True,
|
|
426
459
|
store_history_messages: bool = True,
|
|
427
460
|
send_media_to_model: bool = True,
|
|
461
|
+
add_history_to_context: bool = False,
|
|
462
|
+
num_history_runs: int = 3,
|
|
428
463
|
tools: Optional[List[Union[Toolkit, Callable, Function, Dict]]] = None,
|
|
429
464
|
tool_call_limit: Optional[int] = None,
|
|
430
465
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
@@ -447,8 +482,7 @@ class Team:
|
|
|
447
482
|
enable_session_summaries: bool = False,
|
|
448
483
|
session_summary_manager: Optional[SessionSummaryManager] = None,
|
|
449
484
|
add_session_summary_to_context: Optional[bool] = None,
|
|
450
|
-
|
|
451
|
-
num_history_runs: int = 3,
|
|
485
|
+
max_tool_calls_from_history: Optional[int] = None,
|
|
452
486
|
metadata: Optional[Dict[str, Any]] = None,
|
|
453
487
|
reasoning: bool = False,
|
|
454
488
|
reasoning_model: Optional[Model] = None,
|
|
@@ -456,7 +490,8 @@ class Team:
|
|
|
456
490
|
reasoning_min_steps: int = 1,
|
|
457
491
|
reasoning_max_steps: int = 10,
|
|
458
492
|
stream: Optional[bool] = None,
|
|
459
|
-
|
|
493
|
+
stream_events: Optional[bool] = None,
|
|
494
|
+
stream_intermediate_steps: Optional[bool] = None,
|
|
460
495
|
store_events: bool = False,
|
|
461
496
|
events_to_skip: Optional[List[Union[RunEvent, TeamRunEvent]]] = None,
|
|
462
497
|
store_member_responses: bool = False,
|
|
@@ -490,6 +525,10 @@ class Team:
|
|
|
490
525
|
self.resolve_in_context = resolve_in_context
|
|
491
526
|
self.cache_session = cache_session
|
|
492
527
|
|
|
528
|
+
self.add_history_to_context = add_history_to_context
|
|
529
|
+
self.num_history_runs = num_history_runs
|
|
530
|
+
self.add_team_history_to_members = add_team_history_to_members
|
|
531
|
+
self.num_team_history_runs = num_team_history_runs
|
|
493
532
|
self.search_session_history = search_session_history
|
|
494
533
|
self.num_history_sessions = num_history_sessions
|
|
495
534
|
|
|
@@ -521,7 +560,7 @@ class Team:
|
|
|
521
560
|
self.share_member_interactions = share_member_interactions
|
|
522
561
|
self.get_member_information_tool = get_member_information_tool
|
|
523
562
|
self.search_knowledge = search_knowledge
|
|
524
|
-
self.
|
|
563
|
+
self.read_chat_history = read_chat_history or read_team_history
|
|
525
564
|
|
|
526
565
|
self.store_media = store_media
|
|
527
566
|
self.store_tool_messages = store_tool_messages
|
|
@@ -557,13 +596,9 @@ class Team:
|
|
|
557
596
|
self.add_session_summary_to_context = add_session_summary_to_context
|
|
558
597
|
self.add_history_to_context = add_history_to_context
|
|
559
598
|
self.num_history_runs = num_history_runs
|
|
599
|
+
self.max_tool_calls_from_history = max_tool_calls_from_history
|
|
560
600
|
self.metadata = metadata
|
|
561
601
|
|
|
562
|
-
if add_history_to_context and not db:
|
|
563
|
-
log_warning(
|
|
564
|
-
"add_history_to_context is True, but no database has been assigned to the agent. History will not be added to the context."
|
|
565
|
-
)
|
|
566
|
-
|
|
567
602
|
self.reasoning = reasoning
|
|
568
603
|
self.reasoning_model = reasoning_model
|
|
569
604
|
self.reasoning_agent = reasoning_agent
|
|
@@ -571,7 +606,7 @@ class Team:
|
|
|
571
606
|
self.reasoning_max_steps = reasoning_max_steps
|
|
572
607
|
|
|
573
608
|
self.stream = stream
|
|
574
|
-
self.
|
|
609
|
+
self.stream_events = stream_events or stream_intermediate_steps
|
|
575
610
|
self.store_events = store_events
|
|
576
611
|
self.store_member_responses = store_member_responses
|
|
577
612
|
|
|
@@ -620,6 +655,22 @@ class Team:
|
|
|
620
655
|
|
|
621
656
|
self._hooks_normalised = False
|
|
622
657
|
|
|
658
|
+
# Lazy-initialized shared thread pool executor for background tasks (memory, cultural knowledge, etc.)
|
|
659
|
+
self._background_executor: Optional[Any] = None
|
|
660
|
+
|
|
661
|
+
@property
|
|
662
|
+
def background_executor(self) -> Any:
|
|
663
|
+
"""Lazy initialization of shared thread pool executor for background tasks.
|
|
664
|
+
|
|
665
|
+
Handles both memory creation and cultural knowledge updates concurrently.
|
|
666
|
+
Initialized only on first use (runtime, not instantiation) and reused across runs.
|
|
667
|
+
"""
|
|
668
|
+
if self._background_executor is None:
|
|
669
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
670
|
+
|
|
671
|
+
self._background_executor = ThreadPoolExecutor(max_workers=3, thread_name_prefix="agno-bg")
|
|
672
|
+
return self._background_executor
|
|
673
|
+
|
|
623
674
|
@property
|
|
624
675
|
def should_parse_structured_output(self) -> bool:
|
|
625
676
|
return self.output_schema is not None and self.parse_response and self.parser_model is None
|
|
@@ -759,11 +810,11 @@ class Team:
|
|
|
759
810
|
|
|
760
811
|
def _initialize_session(
|
|
761
812
|
self,
|
|
762
|
-
run_id: str,
|
|
763
|
-
user_id: Optional[str] = None,
|
|
764
813
|
session_id: Optional[str] = None,
|
|
765
|
-
|
|
766
|
-
) -> Tuple[str, Optional[str]
|
|
814
|
+
user_id: Optional[str] = None,
|
|
815
|
+
) -> Tuple[str, Optional[str]]:
|
|
816
|
+
"""Initialize the session for the team."""
|
|
817
|
+
|
|
767
818
|
if session_id is None:
|
|
768
819
|
if self.session_id:
|
|
769
820
|
session_id = self.session_id
|
|
@@ -775,30 +826,26 @@ class Team:
|
|
|
775
826
|
log_debug(f"Session ID: {session_id}", center=True)
|
|
776
827
|
|
|
777
828
|
# Use the default user_id when necessary
|
|
778
|
-
if user_id is None:
|
|
829
|
+
if user_id is None or user_id == "":
|
|
779
830
|
user_id = self.user_id
|
|
780
831
|
|
|
781
|
-
|
|
782
|
-
if session_state is None:
|
|
783
|
-
session_state = self.session_state or {}
|
|
784
|
-
else:
|
|
785
|
-
# If run session_state is provided, merge agent defaults under it
|
|
786
|
-
# This ensures run state takes precedence over agent defaults
|
|
787
|
-
if self.session_state:
|
|
788
|
-
from agno.utils.merge_dict import merge_dictionaries
|
|
789
|
-
|
|
790
|
-
base_state = self.session_state.copy()
|
|
791
|
-
merge_dictionaries(base_state, session_state)
|
|
792
|
-
session_state.clear()
|
|
793
|
-
session_state.update(base_state)
|
|
832
|
+
return session_id, user_id
|
|
794
833
|
|
|
795
|
-
|
|
834
|
+
def _initialize_session_state(
|
|
835
|
+
self,
|
|
836
|
+
session_state: Dict[str, Any],
|
|
837
|
+
user_id: Optional[str] = None,
|
|
838
|
+
session_id: Optional[str] = None,
|
|
839
|
+
run_id: Optional[str] = None,
|
|
840
|
+
) -> Dict[str, Any]:
|
|
841
|
+
"""Initialize the session state for the team."""
|
|
842
|
+
if user_id:
|
|
796
843
|
session_state["current_user_id"] = user_id
|
|
797
844
|
if session_id is not None:
|
|
798
845
|
session_state["current_session_id"] = session_id
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
return
|
|
846
|
+
if run_id is not None:
|
|
847
|
+
session_state["current_run_id"] = run_id
|
|
848
|
+
return session_state
|
|
802
849
|
|
|
803
850
|
def _has_async_db(self) -> bool:
|
|
804
851
|
"""Return True if the db the team is equipped with is an Async implementation"""
|
|
@@ -810,7 +857,7 @@ class Team:
|
|
|
810
857
|
|
|
811
858
|
if self.delegate_task_to_all_members and self.respond_directly:
|
|
812
859
|
log_warning(
|
|
813
|
-
"delegate_task_to_all_members and respond_directly are both enabled. The task will be delegated to all members."
|
|
860
|
+
"`delegate_task_to_all_members` and `respond_directly` are both enabled. The task will be delegated to all members, but `respond_directly` will be disabled."
|
|
814
861
|
)
|
|
815
862
|
self.respond_directly = False
|
|
816
863
|
|
|
@@ -887,11 +934,13 @@ class Team:
|
|
|
887
934
|
all_args.update(kwargs)
|
|
888
935
|
|
|
889
936
|
for i, hook in enumerate(hooks):
|
|
890
|
-
yield
|
|
937
|
+
yield handle_event( # type: ignore
|
|
891
938
|
run_response=run_response,
|
|
892
939
|
event=create_team_pre_hook_started_event(
|
|
893
940
|
from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
|
|
894
941
|
),
|
|
942
|
+
events_to_skip=self.events_to_skip,
|
|
943
|
+
store_events=self.store_events,
|
|
895
944
|
)
|
|
896
945
|
try:
|
|
897
946
|
# Filter arguments to only include those that the hook accepts
|
|
@@ -899,11 +948,13 @@ class Team:
|
|
|
899
948
|
|
|
900
949
|
hook(**filtered_args)
|
|
901
950
|
|
|
902
|
-
yield
|
|
951
|
+
yield handle_event( # type: ignore
|
|
903
952
|
run_response=run_response,
|
|
904
953
|
event=create_team_pre_hook_completed_event(
|
|
905
954
|
from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
|
|
906
955
|
),
|
|
956
|
+
events_to_skip=self.events_to_skip,
|
|
957
|
+
store_events=self.store_events,
|
|
907
958
|
)
|
|
908
959
|
|
|
909
960
|
except (InputCheckError, OutputCheckError) as e:
|
|
@@ -949,11 +1000,13 @@ class Team:
|
|
|
949
1000
|
all_args.update(kwargs)
|
|
950
1001
|
|
|
951
1002
|
for i, hook in enumerate(hooks):
|
|
952
|
-
yield
|
|
1003
|
+
yield handle_event( # type: ignore
|
|
953
1004
|
run_response=run_response,
|
|
954
1005
|
event=create_team_pre_hook_started_event(
|
|
955
1006
|
from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
|
|
956
1007
|
),
|
|
1008
|
+
events_to_skip=self.events_to_skip,
|
|
1009
|
+
store_events=self.store_events,
|
|
957
1010
|
)
|
|
958
1011
|
try:
|
|
959
1012
|
# Filter arguments to only include those that the hook accepts
|
|
@@ -965,11 +1018,13 @@ class Team:
|
|
|
965
1018
|
# Synchronous function
|
|
966
1019
|
hook(**filtered_args)
|
|
967
1020
|
|
|
968
|
-
yield
|
|
1021
|
+
yield handle_event( # type: ignore
|
|
969
1022
|
run_response=run_response,
|
|
970
1023
|
event=create_team_pre_hook_completed_event(
|
|
971
1024
|
from_run_response=run_response, run_input=run_input, pre_hook_name=hook.__name__
|
|
972
1025
|
),
|
|
1026
|
+
events_to_skip=self.events_to_skip,
|
|
1027
|
+
store_events=self.store_events,
|
|
973
1028
|
)
|
|
974
1029
|
|
|
975
1030
|
except (InputCheckError, OutputCheckError) as e:
|
|
@@ -995,7 +1050,7 @@ class Team:
|
|
|
995
1050
|
user_id: Optional[str] = None,
|
|
996
1051
|
debug_mode: Optional[bool] = None,
|
|
997
1052
|
**kwargs: Any,
|
|
998
|
-
) ->
|
|
1053
|
+
) -> Iterator[TeamRunOutputEvent]:
|
|
999
1054
|
"""Execute multiple post-hook functions in succession."""
|
|
1000
1055
|
if hooks is None:
|
|
1001
1056
|
return
|
|
@@ -1014,12 +1069,31 @@ class Team:
|
|
|
1014
1069
|
all_args.update(kwargs)
|
|
1015
1070
|
|
|
1016
1071
|
for i, hook in enumerate(hooks):
|
|
1072
|
+
yield handle_event( # type: ignore
|
|
1073
|
+
run_response=run_output,
|
|
1074
|
+
event=create_team_post_hook_started_event( # type: ignore
|
|
1075
|
+
from_run_response=run_output,
|
|
1076
|
+
post_hook_name=hook.__name__,
|
|
1077
|
+
),
|
|
1078
|
+
events_to_skip=self.events_to_skip,
|
|
1079
|
+
store_events=self.store_events,
|
|
1080
|
+
)
|
|
1017
1081
|
try:
|
|
1018
1082
|
# Filter arguments to only include those that the hook accepts
|
|
1019
1083
|
filtered_args = filter_hook_args(hook, all_args)
|
|
1020
1084
|
|
|
1021
1085
|
hook(**filtered_args)
|
|
1022
1086
|
|
|
1087
|
+
yield handle_event( # type: ignore
|
|
1088
|
+
run_response=run_output,
|
|
1089
|
+
event=create_team_post_hook_completed_event( # type: ignore
|
|
1090
|
+
from_run_response=run_output,
|
|
1091
|
+
post_hook_name=hook.__name__,
|
|
1092
|
+
),
|
|
1093
|
+
events_to_skip=self.events_to_skip,
|
|
1094
|
+
store_events=self.store_events,
|
|
1095
|
+
)
|
|
1096
|
+
|
|
1023
1097
|
except (InputCheckError, OutputCheckError) as e:
|
|
1024
1098
|
raise e
|
|
1025
1099
|
except Exception as e:
|
|
@@ -1037,7 +1111,7 @@ class Team:
|
|
|
1037
1111
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1038
1112
|
debug_mode: Optional[bool] = None,
|
|
1039
1113
|
**kwargs: Any,
|
|
1040
|
-
) ->
|
|
1114
|
+
) -> AsyncIterator[TeamRunOutputEvent]:
|
|
1041
1115
|
"""Execute multiple post-hook functions in succession (async version)."""
|
|
1042
1116
|
if hooks is None:
|
|
1043
1117
|
return
|
|
@@ -1056,6 +1130,15 @@ class Team:
|
|
|
1056
1130
|
all_args.update(kwargs)
|
|
1057
1131
|
|
|
1058
1132
|
for i, hook in enumerate(hooks):
|
|
1133
|
+
yield handle_event( # type: ignore
|
|
1134
|
+
run_response=run_output,
|
|
1135
|
+
event=create_team_post_hook_started_event( # type: ignore
|
|
1136
|
+
from_run_response=run_output,
|
|
1137
|
+
post_hook_name=hook.__name__,
|
|
1138
|
+
),
|
|
1139
|
+
events_to_skip=self.events_to_skip,
|
|
1140
|
+
store_events=self.store_events,
|
|
1141
|
+
)
|
|
1059
1142
|
try:
|
|
1060
1143
|
# Filter arguments to only include those that the hook accepts
|
|
1061
1144
|
filtered_args = filter_hook_args(hook, all_args)
|
|
@@ -1065,6 +1148,15 @@ class Team:
|
|
|
1065
1148
|
else:
|
|
1066
1149
|
hook(**filtered_args)
|
|
1067
1150
|
|
|
1151
|
+
yield handle_event( # type: ignore
|
|
1152
|
+
run_response=run_output,
|
|
1153
|
+
event=create_team_post_hook_completed_event( # type: ignore
|
|
1154
|
+
from_run_response=run_output,
|
|
1155
|
+
post_hook_name=hook.__name__,
|
|
1156
|
+
),
|
|
1157
|
+
events_to_skip=self.events_to_skip,
|
|
1158
|
+
store_events=self.store_events,
|
|
1159
|
+
)
|
|
1068
1160
|
except (InputCheckError, OutputCheckError) as e:
|
|
1069
1161
|
raise e
|
|
1070
1162
|
except Exception as e:
|
|
@@ -1091,15 +1183,18 @@ class Team:
|
|
|
1091
1183
|
|
|
1092
1184
|
Steps:
|
|
1093
1185
|
1. Execute pre-hooks
|
|
1094
|
-
2.
|
|
1095
|
-
3.
|
|
1096
|
-
4.
|
|
1097
|
-
5.
|
|
1098
|
-
6.
|
|
1099
|
-
7.
|
|
1100
|
-
8.
|
|
1101
|
-
9.
|
|
1102
|
-
10.
|
|
1186
|
+
2. Determine tools for model
|
|
1187
|
+
3. Prepare run messages
|
|
1188
|
+
4. Start memory creation in background thread
|
|
1189
|
+
5. Reason about the task if reasoning is enabled
|
|
1190
|
+
6. Get a response from the model
|
|
1191
|
+
7. Update TeamRunOutput with the model response
|
|
1192
|
+
8. Store media if enabled
|
|
1193
|
+
9. Convert response to structured format
|
|
1194
|
+
10. Execute post-hooks
|
|
1195
|
+
11. Wait for background memory creation
|
|
1196
|
+
12. Create session summary
|
|
1197
|
+
13. Cleanup and store (scrub, stop timer, add to session, calculate metrics, save session)
|
|
1103
1198
|
"""
|
|
1104
1199
|
|
|
1105
1200
|
# Register run for cancellation tracking
|
|
@@ -1125,6 +1220,7 @@ class Team:
|
|
|
1125
1220
|
# Consume the generator without yielding
|
|
1126
1221
|
deque(pre_hook_iterator, maxlen=0)
|
|
1127
1222
|
|
|
1223
|
+
# 2. Determine tools for model
|
|
1128
1224
|
# Initialize team run context
|
|
1129
1225
|
team_run_context: Dict[str, Any] = {}
|
|
1130
1226
|
|
|
@@ -1150,7 +1246,7 @@ class Team:
|
|
|
1150
1246
|
metadata=metadata,
|
|
1151
1247
|
)
|
|
1152
1248
|
|
|
1153
|
-
#
|
|
1249
|
+
# 3. Prepare run messages
|
|
1154
1250
|
run_messages: RunMessages = self._get_run_messages(
|
|
1155
1251
|
run_response=run_response,
|
|
1156
1252
|
session=session,
|
|
@@ -1174,95 +1270,112 @@ class Team:
|
|
|
1174
1270
|
|
|
1175
1271
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
1176
1272
|
|
|
1177
|
-
#
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1273
|
+
# 4. Start memory creation in background thread
|
|
1274
|
+
memory_future = None
|
|
1275
|
+
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
1276
|
+
log_debug("Starting memory creation in background thread.")
|
|
1277
|
+
memory_future = self.background_executor.submit(
|
|
1278
|
+
self._make_memories, run_messages=run_messages, user_id=user_id
|
|
1279
|
+
)
|
|
1182
1280
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
model_response: ModelResponse = self.model.response(
|
|
1186
|
-
messages=run_messages.messages,
|
|
1187
|
-
response_format=response_format,
|
|
1188
|
-
tools=self._tools_for_model,
|
|
1189
|
-
functions=self._functions_for_model,
|
|
1190
|
-
tool_choice=self.tool_choice,
|
|
1191
|
-
tool_call_limit=self.tool_call_limit,
|
|
1192
|
-
send_media_to_model=self.send_media_to_model,
|
|
1193
|
-
)
|
|
1281
|
+
try:
|
|
1282
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1194
1283
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1284
|
+
# 5. Reason about the task if reasoning is enabled
|
|
1285
|
+
self._handle_reasoning(run_response=run_response, run_messages=run_messages)
|
|
1197
1286
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1287
|
+
# Check for cancellation before model call
|
|
1288
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1200
1289
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1290
|
+
# 6. Get the model response for the team leader
|
|
1291
|
+
self.model = cast(Model, self.model)
|
|
1292
|
+
model_response: ModelResponse = self.model.response(
|
|
1293
|
+
messages=run_messages.messages,
|
|
1294
|
+
response_format=response_format,
|
|
1295
|
+
tools=self._tools_for_model,
|
|
1296
|
+
functions=self._functions_for_model,
|
|
1297
|
+
tool_choice=self.tool_choice,
|
|
1298
|
+
tool_call_limit=self.tool_call_limit,
|
|
1299
|
+
send_media_to_model=self.send_media_to_model,
|
|
1300
|
+
)
|
|
1203
1301
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1302
|
+
# Check for cancellation after model call
|
|
1303
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1206
1304
|
|
|
1207
|
-
|
|
1208
|
-
self.
|
|
1209
|
-
else:
|
|
1210
|
-
self._scrub_media_from_run_output(run_response)
|
|
1305
|
+
# If an output model is provided, generate output using the output model
|
|
1306
|
+
self._parse_response_with_output_model(model_response, run_messages)
|
|
1211
1307
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1308
|
+
# If a parser model is provided, structure the response separately
|
|
1309
|
+
self._parse_response_with_parser_model(model_response, run_messages)
|
|
1214
1310
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
hooks=self.post_hooks, # type: ignore
|
|
1219
|
-
run_output=run_response,
|
|
1220
|
-
session=session,
|
|
1221
|
-
session_state=session_state,
|
|
1222
|
-
dependencies=dependencies,
|
|
1223
|
-
metadata=metadata,
|
|
1224
|
-
user_id=user_id,
|
|
1225
|
-
debug_mode=debug_mode,
|
|
1226
|
-
**kwargs,
|
|
1311
|
+
# 7. Update TeamRunOutput with the model response
|
|
1312
|
+
self._update_run_response(
|
|
1313
|
+
model_response=model_response, run_response=run_response, run_messages=run_messages
|
|
1227
1314
|
)
|
|
1228
1315
|
|
|
1229
|
-
|
|
1316
|
+
# 8. Store media if enabled
|
|
1317
|
+
if self.store_media:
|
|
1318
|
+
self._store_media(run_response, model_response)
|
|
1230
1319
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
run_response.metrics.stop_timer()
|
|
1320
|
+
# 9. Convert response to structured format
|
|
1321
|
+
self._convert_response_to_structured_format(run_response=run_response)
|
|
1234
1322
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1323
|
+
# 10. Execute post-hooks after output is generated but before response is returned
|
|
1324
|
+
if self.post_hooks is not None:
|
|
1325
|
+
iterator = self._execute_post_hooks(
|
|
1326
|
+
hooks=self.post_hooks, # type: ignore
|
|
1327
|
+
run_output=run_response,
|
|
1328
|
+
session=session,
|
|
1329
|
+
session_state=session_state,
|
|
1330
|
+
dependencies=dependencies,
|
|
1331
|
+
metadata=metadata,
|
|
1332
|
+
user_id=user_id,
|
|
1333
|
+
debug_mode=debug_mode,
|
|
1334
|
+
**kwargs,
|
|
1335
|
+
)
|
|
1336
|
+
deque(iterator, maxlen=0)
|
|
1337
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1237
1338
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1339
|
+
# 11. Wait for background memory creation
|
|
1340
|
+
wait_for_background_tasks(memory_future=memory_future)
|
|
1240
1341
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1342
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1343
|
+
|
|
1344
|
+
# 12. Create session summary
|
|
1345
|
+
if self.session_summary_manager is not None:
|
|
1346
|
+
# Upsert the RunOutput to Team Session before creating the session summary
|
|
1347
|
+
session.upsert_run(run_response=run_response)
|
|
1348
|
+
try:
|
|
1349
|
+
self.session_summary_manager.create_session_summary(session=session)
|
|
1350
|
+
except Exception as e:
|
|
1351
|
+
log_warning(f"Error in session summary creation: {str(e)}")
|
|
1352
|
+
|
|
1353
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1249
1354
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
session.upsert_run(run_response=run_response)
|
|
1355
|
+
# Set the run status to completed
|
|
1356
|
+
run_response.status = RunStatus.completed
|
|
1253
1357
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1358
|
+
# 13. Cleanup and store the run response
|
|
1359
|
+
self._cleanup_and_store(run_response=run_response, session=session)
|
|
1256
1360
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1361
|
+
# Log Team Telemetry
|
|
1362
|
+
self._log_team_telemetry(session_id=session.session_id, run_id=run_response.run_id)
|
|
1363
|
+
|
|
1364
|
+
log_debug(f"Team Run End: {run_response.run_id}", center=True, symbol="*")
|
|
1259
1365
|
|
|
1260
|
-
|
|
1366
|
+
return run_response
|
|
1261
1367
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1368
|
+
except RunCancelledException as e:
|
|
1369
|
+
# Handle run cancellation during streaming
|
|
1370
|
+
log_info(f"Team run {run_response.run_id} was cancelled")
|
|
1371
|
+
run_response.status = RunStatus.cancelled
|
|
1372
|
+
run_response.content = str(e)
|
|
1264
1373
|
|
|
1265
|
-
|
|
1374
|
+
# Add the RunOutput to Team Session even when cancelled
|
|
1375
|
+
self._cleanup_and_store(run_response=run_response, session=session)
|
|
1376
|
+
return run_response
|
|
1377
|
+
finally:
|
|
1378
|
+
cleanup_run(run_response.run_id) # type: ignore
|
|
1266
1379
|
|
|
1267
1380
|
def _run_stream(
|
|
1268
1381
|
self,
|
|
@@ -1277,7 +1390,7 @@ class Team:
|
|
|
1277
1390
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1278
1391
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
1279
1392
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
1280
|
-
|
|
1393
|
+
stream_events: bool = False,
|
|
1281
1394
|
yield_run_response: bool = False,
|
|
1282
1395
|
debug_mode: Optional[bool] = None,
|
|
1283
1396
|
**kwargs: Any,
|
|
@@ -1286,14 +1399,15 @@ class Team:
|
|
|
1286
1399
|
|
|
1287
1400
|
Steps:
|
|
1288
1401
|
1. Execute pre-hooks
|
|
1289
|
-
2.
|
|
1290
|
-
3.
|
|
1291
|
-
4.
|
|
1292
|
-
5.
|
|
1293
|
-
6.
|
|
1294
|
-
7.
|
|
1295
|
-
8.
|
|
1296
|
-
9.
|
|
1402
|
+
2. Determine tools for model
|
|
1403
|
+
3. Prepare run messages
|
|
1404
|
+
4. Start memory creation in background thread
|
|
1405
|
+
5. Reason about the task if reasoning is enabled
|
|
1406
|
+
6. Get a response from the model
|
|
1407
|
+
7. Parse response with parser model if provided
|
|
1408
|
+
8. Wait for background memory creation
|
|
1409
|
+
9. Create session summary
|
|
1410
|
+
10. Cleanup and store (scrub, add to session, calculate metrics, save session)
|
|
1297
1411
|
"""
|
|
1298
1412
|
# Register run for cancellation tracking
|
|
1299
1413
|
register_run(run_response.run_id) # type: ignore
|
|
@@ -1318,6 +1432,7 @@ class Team:
|
|
|
1318
1432
|
for pre_hook_event in pre_hook_iterator:
|
|
1319
1433
|
yield pre_hook_event
|
|
1320
1434
|
|
|
1435
|
+
# 2. Determine tools for model
|
|
1321
1436
|
# Initialize team run context
|
|
1322
1437
|
team_run_context: Dict[str, Any] = {}
|
|
1323
1438
|
|
|
@@ -1343,7 +1458,7 @@ class Team:
|
|
|
1343
1458
|
metadata=metadata,
|
|
1344
1459
|
)
|
|
1345
1460
|
|
|
1346
|
-
#
|
|
1461
|
+
# 3. Prepare run messages
|
|
1347
1462
|
run_messages: RunMessages = self._get_run_messages(
|
|
1348
1463
|
run_response=run_response,
|
|
1349
1464
|
session=session,
|
|
@@ -1367,28 +1482,44 @@ class Team:
|
|
|
1367
1482
|
|
|
1368
1483
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
1369
1484
|
|
|
1485
|
+
# 4. Start memory creation in background thread
|
|
1486
|
+
memory_future = None
|
|
1487
|
+
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
1488
|
+
log_debug("Starting memory creation in background thread.")
|
|
1489
|
+
memory_future = self.background_executor.submit(
|
|
1490
|
+
self._make_memories, run_messages=run_messages, user_id=user_id
|
|
1491
|
+
)
|
|
1492
|
+
|
|
1370
1493
|
try:
|
|
1371
1494
|
# Start the Run by yielding a RunStarted event
|
|
1372
|
-
if
|
|
1373
|
-
yield
|
|
1495
|
+
if stream_events:
|
|
1496
|
+
yield handle_event( # type: ignore
|
|
1497
|
+
create_team_run_started_event(run_response),
|
|
1498
|
+
run_response,
|
|
1499
|
+
events_to_skip=self.events_to_skip,
|
|
1500
|
+
store_events=self.store_events,
|
|
1501
|
+
)
|
|
1502
|
+
|
|
1503
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1374
1504
|
|
|
1375
|
-
#
|
|
1505
|
+
# 5. Reason about the task if reasoning is enabled
|
|
1376
1506
|
yield from self._handle_reasoning_stream(
|
|
1377
1507
|
run_response=run_response,
|
|
1378
1508
|
run_messages=run_messages,
|
|
1509
|
+
stream_events=stream_events,
|
|
1379
1510
|
)
|
|
1380
1511
|
|
|
1381
1512
|
# Check for cancellation before model processing
|
|
1382
1513
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1383
1514
|
|
|
1384
|
-
#
|
|
1515
|
+
# 6. Get a response from the model
|
|
1385
1516
|
if self.output_model is None:
|
|
1386
1517
|
for event in self._handle_model_response_stream(
|
|
1387
1518
|
session=session,
|
|
1388
1519
|
run_response=run_response,
|
|
1389
1520
|
run_messages=run_messages,
|
|
1390
1521
|
response_format=response_format,
|
|
1391
|
-
|
|
1522
|
+
stream_events=stream_events,
|
|
1392
1523
|
):
|
|
1393
1524
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1394
1525
|
yield event
|
|
@@ -1398,13 +1529,13 @@ class Team:
|
|
|
1398
1529
|
run_response=run_response,
|
|
1399
1530
|
run_messages=run_messages,
|
|
1400
1531
|
response_format=response_format,
|
|
1401
|
-
|
|
1532
|
+
stream_events=stream_events,
|
|
1402
1533
|
):
|
|
1403
1534
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1404
1535
|
from agno.run.team import IntermediateRunContentEvent, RunContentEvent
|
|
1405
1536
|
|
|
1406
1537
|
if isinstance(event, RunContentEvent):
|
|
1407
|
-
if
|
|
1538
|
+
if stream_events:
|
|
1408
1539
|
yield IntermediateRunContentEvent(
|
|
1409
1540
|
content=event.content,
|
|
1410
1541
|
content_type=event.content_type,
|
|
@@ -1416,7 +1547,7 @@ class Team:
|
|
|
1416
1547
|
session=session,
|
|
1417
1548
|
run_response=run_response,
|
|
1418
1549
|
run_messages=run_messages,
|
|
1419
|
-
|
|
1550
|
+
stream_events=stream_events,
|
|
1420
1551
|
):
|
|
1421
1552
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1422
1553
|
yield event
|
|
@@ -1424,14 +1555,22 @@ class Team:
|
|
|
1424
1555
|
# Check for cancellation after model processing
|
|
1425
1556
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1426
1557
|
|
|
1427
|
-
#
|
|
1558
|
+
# 7. Parse response with parser model if provided
|
|
1428
1559
|
yield from self._parse_response_with_parser_model_stream(
|
|
1429
|
-
session=session, run_response=run_response,
|
|
1560
|
+
session=session, run_response=run_response, stream_events=stream_events
|
|
1430
1561
|
)
|
|
1431
1562
|
|
|
1563
|
+
# Yield RunContentCompletedEvent
|
|
1564
|
+
if stream_events:
|
|
1565
|
+
yield handle_event( # type: ignore
|
|
1566
|
+
create_team_run_content_completed_event(from_run_response=run_response),
|
|
1567
|
+
run_response,
|
|
1568
|
+
events_to_skip=self.events_to_skip,
|
|
1569
|
+
store_events=self.store_events,
|
|
1570
|
+
)
|
|
1432
1571
|
# Execute post-hooks after output is generated but before response is returned
|
|
1433
1572
|
if self.post_hooks is not None:
|
|
1434
|
-
self._execute_post_hooks(
|
|
1573
|
+
yield from self._execute_post_hooks(
|
|
1435
1574
|
hooks=self.post_hooks, # type: ignore
|
|
1436
1575
|
run_output=run_response,
|
|
1437
1576
|
session_state=session_state,
|
|
@@ -1442,42 +1581,62 @@ class Team:
|
|
|
1442
1581
|
debug_mode=debug_mode,
|
|
1443
1582
|
**kwargs,
|
|
1444
1583
|
)
|
|
1584
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1445
1585
|
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
if run_response.metrics:
|
|
1449
|
-
run_response.metrics.stop_timer()
|
|
1450
|
-
|
|
1451
|
-
# 5. Add the run to Team Session
|
|
1452
|
-
session.upsert_run(run_response=run_response)
|
|
1453
|
-
|
|
1454
|
-
# 6. Update Team Memory
|
|
1455
|
-
yield from self._make_memories_and_summaries(
|
|
1586
|
+
# 8. Wait for background memory creation
|
|
1587
|
+
yield from wait_for_background_tasks_stream(
|
|
1456
1588
|
run_response=run_response,
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1589
|
+
memory_future=memory_future,
|
|
1590
|
+
stream_events=stream_events,
|
|
1591
|
+
events_to_skip=self.events_to_skip, # type: ignore
|
|
1592
|
+
store_events=self.store_events,
|
|
1460
1593
|
)
|
|
1461
1594
|
|
|
1462
|
-
#
|
|
1463
|
-
|
|
1595
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1596
|
+
# 9. Create session summary
|
|
1597
|
+
if self.session_summary_manager is not None:
|
|
1598
|
+
# Upsert the RunOutput to Team Session before creating the session summary
|
|
1599
|
+
session.upsert_run(run_response=run_response)
|
|
1600
|
+
|
|
1601
|
+
if stream_events:
|
|
1602
|
+
yield handle_event( # type: ignore
|
|
1603
|
+
create_team_session_summary_started_event(from_run_response=run_response),
|
|
1604
|
+
run_response,
|
|
1605
|
+
events_to_skip=self.events_to_skip,
|
|
1606
|
+
store_events=self.store_events,
|
|
1607
|
+
)
|
|
1608
|
+
try:
|
|
1609
|
+
self.session_summary_manager.create_session_summary(session=session)
|
|
1610
|
+
except Exception as e:
|
|
1611
|
+
log_warning(f"Error in session summary creation: {str(e)}")
|
|
1612
|
+
if stream_events:
|
|
1613
|
+
yield handle_event( # type: ignore
|
|
1614
|
+
create_team_session_summary_completed_event(
|
|
1615
|
+
from_run_response=run_response, session_summary=session.summary
|
|
1616
|
+
),
|
|
1617
|
+
run_response,
|
|
1618
|
+
events_to_skip=self.events_to_skip,
|
|
1619
|
+
store_events=self.store_events,
|
|
1620
|
+
)
|
|
1621
|
+
|
|
1622
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1623
|
+
# Create the run completed event
|
|
1624
|
+
completed_event = handle_event(
|
|
1464
1625
|
create_team_run_completed_event(
|
|
1465
1626
|
from_run_response=run_response,
|
|
1466
1627
|
),
|
|
1467
1628
|
run_response,
|
|
1629
|
+
events_to_skip=self.events_to_skip,
|
|
1630
|
+
store_events=self.store_events,
|
|
1468
1631
|
)
|
|
1469
1632
|
|
|
1470
|
-
#
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
# 9. Scrub the stored run based on storage flags
|
|
1474
|
-
if self._scrub_run_output_for_storage(run_response):
|
|
1475
|
-
session.upsert_run(run_response=run_response)
|
|
1633
|
+
# Set the run status to completed
|
|
1634
|
+
run_response.status = RunStatus.completed
|
|
1476
1635
|
|
|
1477
|
-
# 10.
|
|
1478
|
-
self.
|
|
1636
|
+
# 10. Cleanup and store the run response
|
|
1637
|
+
self._cleanup_and_store(run_response=run_response, session=session)
|
|
1479
1638
|
|
|
1480
|
-
if
|
|
1639
|
+
if stream_events:
|
|
1481
1640
|
yield completed_event
|
|
1482
1641
|
|
|
1483
1642
|
if yield_run_response:
|
|
@@ -1495,14 +1654,15 @@ class Team:
|
|
|
1495
1654
|
run_response.content = str(e)
|
|
1496
1655
|
|
|
1497
1656
|
# Yield the cancellation event
|
|
1498
|
-
yield
|
|
1657
|
+
yield handle_event( # type: ignore
|
|
1499
1658
|
create_team_run_cancelled_event(from_run_response=run_response, reason=str(e)),
|
|
1500
1659
|
run_response,
|
|
1660
|
+
events_to_skip=self.events_to_skip,
|
|
1661
|
+
store_events=self.store_events,
|
|
1501
1662
|
)
|
|
1502
1663
|
|
|
1503
1664
|
# Add the RunOutput to Team Session even when cancelled
|
|
1504
|
-
|
|
1505
|
-
self.save_session(session=session)
|
|
1665
|
+
self._cleanup_and_store(run_response=run_response, session=session)
|
|
1506
1666
|
finally:
|
|
1507
1667
|
# Always clean up the run tracking
|
|
1508
1668
|
cleanup_run(run_response.run_id) # type: ignore
|
|
@@ -1513,6 +1673,7 @@ class Team:
|
|
|
1513
1673
|
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
1514
1674
|
*,
|
|
1515
1675
|
stream: Literal[False] = False,
|
|
1676
|
+
stream_events: Optional[bool] = None,
|
|
1516
1677
|
stream_intermediate_steps: Optional[bool] = None,
|
|
1517
1678
|
session_id: Optional[str] = None,
|
|
1518
1679
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -1538,6 +1699,7 @@ class Team:
|
|
|
1538
1699
|
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
1539
1700
|
*,
|
|
1540
1701
|
stream: Literal[True] = True,
|
|
1702
|
+
stream_events: Optional[bool] = None,
|
|
1541
1703
|
stream_intermediate_steps: Optional[bool] = None,
|
|
1542
1704
|
session_id: Optional[str] = None,
|
|
1543
1705
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -1563,6 +1725,7 @@ class Team:
|
|
|
1563
1725
|
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
1564
1726
|
*,
|
|
1565
1727
|
stream: Optional[bool] = None,
|
|
1728
|
+
stream_events: Optional[bool] = None,
|
|
1566
1729
|
stream_intermediate_steps: Optional[bool] = None,
|
|
1567
1730
|
session_id: Optional[str] = None,
|
|
1568
1731
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -1586,6 +1749,14 @@ class Team:
|
|
|
1586
1749
|
if self._has_async_db():
|
|
1587
1750
|
raise Exception("run() is not supported with an async DB. Please use arun() instead.")
|
|
1588
1751
|
|
|
1752
|
+
# Initialize Team
|
|
1753
|
+
self.initialize_team(debug_mode=debug_mode)
|
|
1754
|
+
|
|
1755
|
+
if (add_history_to_context or self.add_history_to_context) and not self.db and not self.parent_team_id:
|
|
1756
|
+
log_warning(
|
|
1757
|
+
"add_history_to_context is True, but no database has been assigned to the team. History will not be added to the context."
|
|
1758
|
+
)
|
|
1759
|
+
|
|
1589
1760
|
# Create a run_id for this specific run
|
|
1590
1761
|
run_id = str(uuid4())
|
|
1591
1762
|
|
|
@@ -1600,12 +1771,7 @@ class Team:
|
|
|
1600
1771
|
self.post_hooks = normalize_hooks(self.post_hooks)
|
|
1601
1772
|
self._hooks_normalised = True
|
|
1602
1773
|
|
|
1603
|
-
session_id, user_id
|
|
1604
|
-
run_id=run_id, session_id=session_id, user_id=user_id, session_state=session_state
|
|
1605
|
-
)
|
|
1606
|
-
|
|
1607
|
-
# Initialize Team
|
|
1608
|
-
self.initialize_team(debug_mode=debug_mode)
|
|
1774
|
+
session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
|
|
1609
1775
|
|
|
1610
1776
|
image_artifacts, video_artifacts, audio_artifacts, file_artifacts = self._validate_media_object_id(
|
|
1611
1777
|
images=images, videos=videos, audios=audio, files=files
|
|
@@ -1624,6 +1790,10 @@ class Team:
|
|
|
1624
1790
|
team_session = self._read_or_create_session(session_id=session_id, user_id=user_id)
|
|
1625
1791
|
self._update_metadata(session=team_session)
|
|
1626
1792
|
|
|
1793
|
+
# Initialize session state
|
|
1794
|
+
session_state = self._initialize_session_state(
|
|
1795
|
+
session_state=session_state or {}, user_id=user_id, session_id=session_id, run_id=run_id
|
|
1796
|
+
)
|
|
1627
1797
|
# Update session state from DB
|
|
1628
1798
|
session_state = self._load_session_state(session=team_session, session_state=session_state)
|
|
1629
1799
|
|
|
@@ -1656,17 +1826,18 @@ class Team:
|
|
|
1656
1826
|
if stream is None:
|
|
1657
1827
|
stream = False if self.stream is None else self.stream
|
|
1658
1828
|
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
False if self.stream_intermediate_steps is None else self.stream_intermediate_steps
|
|
1662
|
-
)
|
|
1829
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
1830
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
1663
1831
|
|
|
1664
|
-
# Can't
|
|
1832
|
+
# Can't stream events if streaming is disabled
|
|
1665
1833
|
if stream is False:
|
|
1666
|
-
|
|
1834
|
+
stream_events = False
|
|
1835
|
+
|
|
1836
|
+
if stream_events is None:
|
|
1837
|
+
stream_events = False if self.stream_events is None else self.stream_events
|
|
1667
1838
|
|
|
1668
1839
|
self.stream = self.stream or stream
|
|
1669
|
-
self.
|
|
1840
|
+
self.stream_events = self.stream_events or stream_events
|
|
1670
1841
|
|
|
1671
1842
|
# Configure the model for runs
|
|
1672
1843
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = (
|
|
@@ -1722,7 +1893,7 @@ class Team:
|
|
|
1722
1893
|
metadata=metadata,
|
|
1723
1894
|
dependencies=run_dependencies,
|
|
1724
1895
|
response_format=response_format,
|
|
1725
|
-
|
|
1896
|
+
stream_events=stream_events,
|
|
1726
1897
|
yield_run_response=yield_run_response,
|
|
1727
1898
|
debug_mode=debug_mode,
|
|
1728
1899
|
**kwargs,
|
|
@@ -1761,17 +1932,6 @@ class Team:
|
|
|
1761
1932
|
else:
|
|
1762
1933
|
delay = self.delay_between_retries
|
|
1763
1934
|
time.sleep(delay)
|
|
1764
|
-
except RunCancelledException as e:
|
|
1765
|
-
# Handle run cancellation
|
|
1766
|
-
log_info(f"Team run {run_response.run_id} was cancelled")
|
|
1767
|
-
run_response.content = str(e)
|
|
1768
|
-
run_response.status = RunStatus.cancelled
|
|
1769
|
-
|
|
1770
|
-
# Add the RunOutput to Team Session even when cancelled
|
|
1771
|
-
team_session.upsert_run(run_response=run_response)
|
|
1772
|
-
self.save_session(session=team_session)
|
|
1773
|
-
|
|
1774
|
-
return run_response
|
|
1775
1935
|
except KeyboardInterrupt:
|
|
1776
1936
|
run_response.content = "Operation cancelled by user"
|
|
1777
1937
|
run_response.status = RunStatus.cancelled
|
|
@@ -1812,10 +1972,6 @@ class Team:
|
|
|
1812
1972
|
add_history_to_context: Optional[bool] = None,
|
|
1813
1973
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
1814
1974
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1815
|
-
audio: Optional[Sequence[Audio]] = None,
|
|
1816
|
-
images: Optional[Sequence[Image]] = None,
|
|
1817
|
-
videos: Optional[Sequence[Video]] = None,
|
|
1818
|
-
files: Optional[Sequence[File]] = None,
|
|
1819
1975
|
debug_mode: Optional[bool] = None,
|
|
1820
1976
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
1821
1977
|
**kwargs: Any,
|
|
@@ -1828,16 +1984,16 @@ class Team:
|
|
|
1828
1984
|
3. Execute pre-hooks
|
|
1829
1985
|
4. Determine tools for model
|
|
1830
1986
|
5. Prepare run messages
|
|
1831
|
-
6.
|
|
1832
|
-
7.
|
|
1833
|
-
8.
|
|
1834
|
-
9.
|
|
1835
|
-
10.
|
|
1836
|
-
11.
|
|
1837
|
-
12.
|
|
1838
|
-
13.
|
|
1839
|
-
14.
|
|
1840
|
-
15.
|
|
1987
|
+
6. Start memory creation in background task
|
|
1988
|
+
7. Reason about the task if reasoning is enabled
|
|
1989
|
+
8. Get a response from the Model
|
|
1990
|
+
9. Update TeamRunOutput with the model response
|
|
1991
|
+
10. Store media if enabled
|
|
1992
|
+
11. Convert response to structured format
|
|
1993
|
+
12. Execute post-hooks
|
|
1994
|
+
13. Wait for background memory creation
|
|
1995
|
+
14. Create session summary
|
|
1996
|
+
15. Cleanup and store (scrub, add to session, calculate metrics, save session)
|
|
1841
1997
|
"""
|
|
1842
1998
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
1843
1999
|
|
|
@@ -1854,6 +2010,11 @@ class Team:
|
|
|
1854
2010
|
|
|
1855
2011
|
# 2. Update metadata and session state
|
|
1856
2012
|
self._update_metadata(session=team_session)
|
|
2013
|
+
# Initialize session state
|
|
2014
|
+
session_state = self._initialize_session_state(
|
|
2015
|
+
session_state=session_state or {}, user_id=user_id, session_id=session_id, run_id=run_response.run_id
|
|
2016
|
+
)
|
|
2017
|
+
# Update session state from DB
|
|
1857
2018
|
session_state = self._load_session_state(session=team_session, session_state=session_state) # type: ignore
|
|
1858
2019
|
|
|
1859
2020
|
run_input = cast(TeamRunInput, run_response.input)
|
|
@@ -1909,10 +2070,10 @@ class Team:
|
|
|
1909
2070
|
session_state=session_state,
|
|
1910
2071
|
user_id=user_id,
|
|
1911
2072
|
input_message=run_input.input_content,
|
|
1912
|
-
audio=
|
|
1913
|
-
images=images,
|
|
1914
|
-
videos=videos,
|
|
1915
|
-
files=files,
|
|
2073
|
+
audio=run_input.audios,
|
|
2074
|
+
images=run_input.images,
|
|
2075
|
+
videos=run_input.videos,
|
|
2076
|
+
files=run_input.files,
|
|
1916
2077
|
knowledge_filters=knowledge_filters,
|
|
1917
2078
|
add_history_to_context=add_history_to_context,
|
|
1918
2079
|
dependencies=dependencies,
|
|
@@ -1921,98 +2082,122 @@ class Team:
|
|
|
1921
2082
|
**kwargs,
|
|
1922
2083
|
)
|
|
1923
2084
|
|
|
2085
|
+
self.model = cast(Model, self.model)
|
|
2086
|
+
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2087
|
+
|
|
2088
|
+
# 6. Start memory creation in background task
|
|
2089
|
+
import asyncio
|
|
2090
|
+
|
|
2091
|
+
memory_task = None
|
|
2092
|
+
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
2093
|
+
log_debug("Starting memory creation in background task.")
|
|
2094
|
+
memory_task = asyncio.create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
2095
|
+
|
|
1924
2096
|
# Register run for cancellation tracking
|
|
1925
2097
|
register_run(run_response.run_id) # type: ignore
|
|
1926
2098
|
|
|
1927
|
-
|
|
1928
|
-
|
|
2099
|
+
try:
|
|
2100
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2101
|
+
# 7. Reason about the task if reasoning is enabled
|
|
2102
|
+
await self._ahandle_reasoning(run_response=run_response, run_messages=run_messages)
|
|
1929
2103
|
|
|
1930
|
-
|
|
1931
|
-
|
|
2104
|
+
# Check for cancellation before model call
|
|
2105
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1932
2106
|
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
2107
|
+
# 8. Get the model response for the team leader
|
|
2108
|
+
model_response = await self.model.aresponse(
|
|
2109
|
+
messages=run_messages.messages,
|
|
2110
|
+
tools=self._tools_for_model,
|
|
2111
|
+
functions=self._functions_for_model,
|
|
2112
|
+
tool_choice=self.tool_choice,
|
|
2113
|
+
tool_call_limit=self.tool_call_limit,
|
|
2114
|
+
response_format=response_format,
|
|
2115
|
+
send_media_to_model=self.send_media_to_model,
|
|
2116
|
+
) # type: ignore
|
|
2117
|
+
|
|
2118
|
+
# Check for cancellation after model call
|
|
2119
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1945
2120
|
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
# If a parser model is provided, structure the response separately
|
|
1949
|
-
await self._aparse_response_with_parser_model(model_response=model_response, run_messages=run_messages)
|
|
2121
|
+
# If an output model is provided, generate output using the output model
|
|
2122
|
+
await self._agenerate_response_with_output_model(model_response=model_response, run_messages=run_messages)
|
|
1950
2123
|
|
|
1951
|
-
|
|
1952
|
-
|
|
2124
|
+
# If a parser model is provided, structure the response separately
|
|
2125
|
+
await self._aparse_response_with_parser_model(model_response=model_response, run_messages=run_messages)
|
|
1953
2126
|
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
self._scrub_media_from_run_output(run_response)
|
|
2127
|
+
# 9. Update TeamRunOutput with the model response
|
|
2128
|
+
self._update_run_response(
|
|
2129
|
+
model_response=model_response, run_response=run_response, run_messages=run_messages
|
|
2130
|
+
)
|
|
1959
2131
|
|
|
1960
|
-
|
|
1961
|
-
|
|
2132
|
+
# 10. Store media if enabled
|
|
2133
|
+
if self.store_media:
|
|
2134
|
+
self._store_media(run_response, model_response)
|
|
1962
2135
|
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
await self._aexecute_post_hooks(
|
|
1966
|
-
hooks=self.post_hooks, # type: ignore
|
|
1967
|
-
run_output=run_response,
|
|
1968
|
-
session=team_session,
|
|
1969
|
-
user_id=user_id,
|
|
1970
|
-
debug_mode=debug_mode,
|
|
1971
|
-
session_state=session_state,
|
|
1972
|
-
dependencies=dependencies,
|
|
1973
|
-
metadata=metadata,
|
|
1974
|
-
**kwargs,
|
|
1975
|
-
)
|
|
2136
|
+
# 11. Convert response to structured format
|
|
2137
|
+
self._convert_response_to_structured_format(run_response=run_response)
|
|
1976
2138
|
|
|
1977
|
-
|
|
2139
|
+
# 12. Execute post-hooks after output is generated but before response is returned
|
|
2140
|
+
if self.post_hooks is not None:
|
|
2141
|
+
async for _ in self._aexecute_post_hooks(
|
|
2142
|
+
hooks=self.post_hooks, # type: ignore
|
|
2143
|
+
run_output=run_response,
|
|
2144
|
+
session=team_session,
|
|
2145
|
+
session_state=session_state,
|
|
2146
|
+
dependencies=dependencies,
|
|
2147
|
+
metadata=metadata,
|
|
2148
|
+
user_id=user_id,
|
|
2149
|
+
debug_mode=debug_mode,
|
|
2150
|
+
**kwargs,
|
|
2151
|
+
):
|
|
2152
|
+
pass
|
|
1978
2153
|
|
|
1979
|
-
|
|
1980
|
-
if run_response.metrics:
|
|
1981
|
-
run_response.metrics.stop_timer()
|
|
2154
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1982
2155
|
|
|
1983
|
-
|
|
1984
|
-
|
|
2156
|
+
# 13. Wait for background memory creation
|
|
2157
|
+
await await_for_background_tasks(memory_task=memory_task)
|
|
1985
2158
|
|
|
1986
|
-
|
|
1987
|
-
|
|
2159
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2160
|
+
# 14. Create session summary
|
|
2161
|
+
if self.session_summary_manager is not None:
|
|
2162
|
+
# Upsert the RunOutput to Team Session before creating the session summary
|
|
2163
|
+
team_session.upsert_run(run_response=run_response)
|
|
2164
|
+
try:
|
|
2165
|
+
await self.session_summary_manager.acreate_session_summary(session=team_session)
|
|
2166
|
+
except Exception as e:
|
|
2167
|
+
log_warning(f"Error in session summary creation: {str(e)}")
|
|
1988
2168
|
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
run_response=run_response,
|
|
1992
|
-
session=team_session,
|
|
1993
|
-
run_messages=run_messages,
|
|
1994
|
-
user_id=user_id,
|
|
1995
|
-
):
|
|
1996
|
-
pass
|
|
2169
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2170
|
+
run_response.status = RunStatus.completed
|
|
1997
2171
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
team_session.upsert_run(run_response=run_response)
|
|
2172
|
+
# 15. Cleanup and store the run response and session
|
|
2173
|
+
await self._acleanup_and_store(run_response=run_response, session=team_session)
|
|
2001
2174
|
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
await self.asave_session(session=team_session)
|
|
2005
|
-
else:
|
|
2006
|
-
self.save_session(session=team_session)
|
|
2175
|
+
# Log Team Telemetry
|
|
2176
|
+
await self._alog_team_telemetry(session_id=team_session.session_id, run_id=run_response.run_id)
|
|
2007
2177
|
|
|
2008
|
-
|
|
2009
|
-
await self._alog_team_telemetry(session_id=team_session.session_id, run_id=run_response.run_id)
|
|
2178
|
+
log_debug(f"Team Run End: {run_response.run_id}", center=True, symbol="*")
|
|
2010
2179
|
|
|
2011
|
-
|
|
2180
|
+
return run_response
|
|
2181
|
+
except RunCancelledException as e:
|
|
2182
|
+
# Handle run cancellation
|
|
2183
|
+
log_info(f"Run {run_response.run_id} was cancelled")
|
|
2184
|
+
run_response.content = str(e)
|
|
2185
|
+
run_response.status = RunStatus.cancelled
|
|
2012
2186
|
|
|
2013
|
-
|
|
2187
|
+
# Cleanup and store the run response and session
|
|
2188
|
+
await self._acleanup_and_store(run_response=run_response, session=team_session)
|
|
2014
2189
|
|
|
2015
|
-
|
|
2190
|
+
return run_response
|
|
2191
|
+
finally:
|
|
2192
|
+
# Cancel the memory task if it's still running
|
|
2193
|
+
if memory_task is not None and not memory_task.done():
|
|
2194
|
+
memory_task.cancel()
|
|
2195
|
+
try:
|
|
2196
|
+
await memory_task
|
|
2197
|
+
except asyncio.CancelledError:
|
|
2198
|
+
pass
|
|
2199
|
+
# Always clean up the run tracking
|
|
2200
|
+
cleanup_run(run_response.run_id) # type: ignore
|
|
2016
2201
|
|
|
2017
2202
|
async def _arun_stream(
|
|
2018
2203
|
self,
|
|
@@ -2021,6 +2206,7 @@ class Team:
|
|
|
2021
2206
|
session_state: Optional[Dict[str, Any]] = None,
|
|
2022
2207
|
user_id: Optional[str] = None,
|
|
2023
2208
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2209
|
+
stream_events: bool = False,
|
|
2024
2210
|
stream_intermediate_steps: bool = False,
|
|
2025
2211
|
yield_run_response: bool = False,
|
|
2026
2212
|
add_dependencies_to_context: Optional[bool] = None,
|
|
@@ -2028,10 +2214,6 @@ class Team:
|
|
|
2028
2214
|
add_history_to_context: Optional[bool] = None,
|
|
2029
2215
|
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
2030
2216
|
metadata: Optional[Dict[str, Any]] = None,
|
|
2031
|
-
audio: Optional[Sequence[Audio]] = None,
|
|
2032
|
-
images: Optional[Sequence[Image]] = None,
|
|
2033
|
-
videos: Optional[Sequence[Video]] = None,
|
|
2034
|
-
files: Optional[Sequence[File]] = None,
|
|
2035
2217
|
debug_mode: Optional[bool] = None,
|
|
2036
2218
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
2037
2219
|
**kwargs: Any,
|
|
@@ -2045,15 +2227,13 @@ class Team:
|
|
|
2045
2227
|
4. Execute pre-hooks
|
|
2046
2228
|
5. Determine tools for model
|
|
2047
2229
|
6. Prepare run messages
|
|
2048
|
-
7.
|
|
2049
|
-
8. Reason about the task
|
|
2230
|
+
7. Start memory creation in background task
|
|
2231
|
+
8. Reason about the task if reasoning is enabled
|
|
2050
2232
|
9. Get a response from the model
|
|
2051
|
-
10.
|
|
2052
|
-
11.
|
|
2053
|
-
12.
|
|
2054
|
-
13.
|
|
2055
|
-
14. Scrub the stored run if needed
|
|
2056
|
-
15. Save session to storage
|
|
2233
|
+
10. Parse response with parser model if provided
|
|
2234
|
+
11. Wait for background memory creation
|
|
2235
|
+
12. Create session summary
|
|
2236
|
+
13. Cleanup and store (scrub, add to session, calculate metrics, save session)
|
|
2057
2237
|
"""
|
|
2058
2238
|
|
|
2059
2239
|
# 1. Resolve dependencies
|
|
@@ -2068,6 +2248,11 @@ class Team:
|
|
|
2068
2248
|
|
|
2069
2249
|
# 3. Update metadata and session state
|
|
2070
2250
|
self._update_metadata(session=team_session)
|
|
2251
|
+
# Initialize session state
|
|
2252
|
+
session_state = self._initialize_session_state(
|
|
2253
|
+
session_state=session_state or {}, user_id=user_id, session_id=session_id, run_id=run_response.run_id
|
|
2254
|
+
)
|
|
2255
|
+
# Update session state from DB
|
|
2071
2256
|
session_state = self._load_session_state(session=team_session, session_state=session_state) # type: ignore
|
|
2072
2257
|
|
|
2073
2258
|
# 4. Execute pre-hooks
|
|
@@ -2102,10 +2287,10 @@ class Team:
|
|
|
2102
2287
|
async_mode=True,
|
|
2103
2288
|
knowledge_filters=knowledge_filters,
|
|
2104
2289
|
input_message=run_input.input_content,
|
|
2105
|
-
images=images,
|
|
2106
|
-
videos=videos,
|
|
2107
|
-
audio=
|
|
2108
|
-
files=files,
|
|
2290
|
+
images=run_input.images,
|
|
2291
|
+
videos=run_input.videos,
|
|
2292
|
+
audio=run_input.audios,
|
|
2293
|
+
files=run_input.files,
|
|
2109
2294
|
debug_mode=debug_mode,
|
|
2110
2295
|
add_history_to_context=add_history_to_context,
|
|
2111
2296
|
dependencies=dependencies,
|
|
@@ -2119,10 +2304,10 @@ class Team:
|
|
|
2119
2304
|
session_state=session_state,
|
|
2120
2305
|
user_id=user_id,
|
|
2121
2306
|
input_message=run_input.input_content,
|
|
2122
|
-
audio=
|
|
2123
|
-
images=images,
|
|
2124
|
-
videos=videos,
|
|
2125
|
-
files=files,
|
|
2307
|
+
audio=run_input.audios,
|
|
2308
|
+
images=run_input.images,
|
|
2309
|
+
videos=run_input.videos,
|
|
2310
|
+
files=run_input.files,
|
|
2126
2311
|
knowledge_filters=knowledge_filters,
|
|
2127
2312
|
add_history_to_context=add_history_to_context,
|
|
2128
2313
|
dependencies=dependencies,
|
|
@@ -2134,16 +2319,36 @@ class Team:
|
|
|
2134
2319
|
|
|
2135
2320
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2136
2321
|
|
|
2322
|
+
# 7. Start memory creation in background task
|
|
2323
|
+
import asyncio
|
|
2324
|
+
|
|
2325
|
+
memory_task = None
|
|
2326
|
+
if run_messages.user_message is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
2327
|
+
log_debug("Starting memory creation in background task.")
|
|
2328
|
+
memory_task = asyncio.create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
2329
|
+
|
|
2137
2330
|
# Register run for cancellation tracking
|
|
2138
2331
|
register_run(run_response.run_id) # type: ignore
|
|
2139
2332
|
|
|
2140
2333
|
try:
|
|
2141
|
-
#
|
|
2142
|
-
|
|
2143
|
-
yield self._handle_event(create_team_run_started_event(from_run_response=run_response), run_response)
|
|
2334
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
2335
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
2144
2336
|
|
|
2145
|
-
#
|
|
2146
|
-
|
|
2337
|
+
# Yield the run started event
|
|
2338
|
+
if stream_events:
|
|
2339
|
+
yield handle_event( # type: ignore
|
|
2340
|
+
create_team_run_started_event(from_run_response=run_response),
|
|
2341
|
+
run_response,
|
|
2342
|
+
events_to_skip=self.events_to_skip,
|
|
2343
|
+
store_events=self.store_events,
|
|
2344
|
+
)
|
|
2345
|
+
|
|
2346
|
+
# 8. Reason about the task if reasoning is enabled
|
|
2347
|
+
async for item in self._ahandle_reasoning_stream(
|
|
2348
|
+
run_response=run_response,
|
|
2349
|
+
run_messages=run_messages,
|
|
2350
|
+
stream_events=stream_events,
|
|
2351
|
+
):
|
|
2147
2352
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2148
2353
|
yield item
|
|
2149
2354
|
|
|
@@ -2157,7 +2362,7 @@ class Team:
|
|
|
2157
2362
|
run_response=run_response,
|
|
2158
2363
|
run_messages=run_messages,
|
|
2159
2364
|
response_format=response_format,
|
|
2160
|
-
|
|
2365
|
+
stream_events=stream_events,
|
|
2161
2366
|
):
|
|
2162
2367
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2163
2368
|
yield event
|
|
@@ -2167,13 +2372,13 @@ class Team:
|
|
|
2167
2372
|
run_response=run_response,
|
|
2168
2373
|
run_messages=run_messages,
|
|
2169
2374
|
response_format=response_format,
|
|
2170
|
-
|
|
2375
|
+
stream_events=stream_events,
|
|
2171
2376
|
):
|
|
2172
2377
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2173
2378
|
from agno.run.team import IntermediateRunContentEvent, RunContentEvent
|
|
2174
2379
|
|
|
2175
2380
|
if isinstance(event, RunContentEvent):
|
|
2176
|
-
if
|
|
2381
|
+
if stream_events:
|
|
2177
2382
|
yield IntermediateRunContentEvent(
|
|
2178
2383
|
content=event.content,
|
|
2179
2384
|
content_type=event.content_type,
|
|
@@ -2185,7 +2390,7 @@ class Team:
|
|
|
2185
2390
|
session=team_session,
|
|
2186
2391
|
run_response=run_response,
|
|
2187
2392
|
run_messages=run_messages,
|
|
2188
|
-
|
|
2393
|
+
stream_events=stream_events,
|
|
2189
2394
|
):
|
|
2190
2395
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2191
2396
|
yield event
|
|
@@ -2193,15 +2398,24 @@ class Team:
|
|
|
2193
2398
|
# Check for cancellation after model processing
|
|
2194
2399
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2195
2400
|
|
|
2196
|
-
#
|
|
2401
|
+
# 10. Parse response with parser model if provided
|
|
2197
2402
|
async for event in self._aparse_response_with_parser_model_stream(
|
|
2198
|
-
session=team_session, run_response=run_response,
|
|
2403
|
+
session=team_session, run_response=run_response, stream_events=stream_events
|
|
2199
2404
|
):
|
|
2200
2405
|
yield event
|
|
2201
2406
|
|
|
2407
|
+
# Yield RunContentCompletedEvent
|
|
2408
|
+
if stream_events:
|
|
2409
|
+
yield handle_event( # type: ignore
|
|
2410
|
+
create_team_run_content_completed_event(from_run_response=run_response),
|
|
2411
|
+
run_response,
|
|
2412
|
+
events_to_skip=self.events_to_skip,
|
|
2413
|
+
store_events=self.store_events,
|
|
2414
|
+
)
|
|
2415
|
+
|
|
2202
2416
|
# Execute post-hooks after output is generated but before response is returned
|
|
2203
2417
|
if self.post_hooks is not None:
|
|
2204
|
-
|
|
2418
|
+
async for event in self._aexecute_post_hooks(
|
|
2205
2419
|
hooks=self.post_hooks, # type: ignore
|
|
2206
2420
|
run_output=run_response,
|
|
2207
2421
|
session_state=session_state,
|
|
@@ -2211,45 +2425,65 @@ class Team:
|
|
|
2211
2425
|
user_id=user_id,
|
|
2212
2426
|
debug_mode=debug_mode,
|
|
2213
2427
|
**kwargs,
|
|
2214
|
-
)
|
|
2215
|
-
|
|
2216
|
-
# Set the run duration
|
|
2217
|
-
if run_response.metrics:
|
|
2218
|
-
run_response.metrics.stop_timer()
|
|
2219
|
-
|
|
2220
|
-
run_response.status = RunStatus.completed
|
|
2221
|
-
|
|
2222
|
-
# 10. Add the run to memory
|
|
2223
|
-
team_session.upsert_run(run_response=run_response)
|
|
2428
|
+
):
|
|
2429
|
+
yield event
|
|
2224
2430
|
|
|
2225
|
-
#
|
|
2226
|
-
|
|
2431
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2432
|
+
# 11. Wait for background memory creation
|
|
2433
|
+
async for event in await_for_background_tasks_stream(
|
|
2227
2434
|
run_response=run_response,
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2435
|
+
memory_task=memory_task,
|
|
2436
|
+
stream_events=stream_events,
|
|
2437
|
+
events_to_skip=self.events_to_skip, # type: ignore
|
|
2438
|
+
store_events=self.store_events,
|
|
2231
2439
|
):
|
|
2232
2440
|
yield event
|
|
2233
2441
|
|
|
2234
|
-
#
|
|
2235
|
-
|
|
2442
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2443
|
+
|
|
2444
|
+
# 12. Create session summary
|
|
2445
|
+
if self.session_summary_manager is not None:
|
|
2446
|
+
# Upsert the RunOutput to Team Session before creating the session summary
|
|
2447
|
+
team_session.upsert_run(run_response=run_response)
|
|
2236
2448
|
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2449
|
+
if stream_events:
|
|
2450
|
+
yield handle_event( # type: ignore
|
|
2451
|
+
create_team_session_summary_started_event(from_run_response=run_response),
|
|
2452
|
+
run_response,
|
|
2453
|
+
events_to_skip=self.events_to_skip,
|
|
2454
|
+
store_events=self.store_events,
|
|
2455
|
+
)
|
|
2456
|
+
try:
|
|
2457
|
+
await self.session_summary_manager.acreate_session_summary(session=team_session)
|
|
2458
|
+
except Exception as e:
|
|
2459
|
+
log_warning(f"Error in session summary creation: {str(e)}")
|
|
2460
|
+
if stream_events:
|
|
2461
|
+
yield handle_event( # type: ignore
|
|
2462
|
+
create_team_session_summary_completed_event(
|
|
2463
|
+
from_run_response=run_response, session_summary=team_session.summary
|
|
2464
|
+
),
|
|
2465
|
+
run_response,
|
|
2466
|
+
events_to_skip=self.events_to_skip,
|
|
2467
|
+
store_events=self.store_events,
|
|
2468
|
+
)
|
|
2469
|
+
|
|
2470
|
+
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2471
|
+
|
|
2472
|
+
# Create the run completed event
|
|
2473
|
+
completed_event = handle_event(
|
|
2474
|
+
create_team_run_completed_event(from_run_response=run_response),
|
|
2475
|
+
run_response,
|
|
2476
|
+
events_to_skip=self.events_to_skip,
|
|
2477
|
+
store_events=self.store_events,
|
|
2240
2478
|
)
|
|
2241
2479
|
|
|
2242
|
-
#
|
|
2243
|
-
|
|
2244
|
-
team_session.upsert_run(run_response=run_response)
|
|
2480
|
+
# Set the run status to completed
|
|
2481
|
+
run_response.status = RunStatus.completed
|
|
2245
2482
|
|
|
2246
|
-
#
|
|
2247
|
-
|
|
2248
|
-
await self.asave_session(session=team_session)
|
|
2249
|
-
else:
|
|
2250
|
-
self.save_session(session=team_session)
|
|
2483
|
+
# 13. Cleanup and store the run response and session
|
|
2484
|
+
await self._acleanup_and_store(run_response=run_response, session=team_session)
|
|
2251
2485
|
|
|
2252
|
-
if
|
|
2486
|
+
if stream_events:
|
|
2253
2487
|
yield completed_event
|
|
2254
2488
|
|
|
2255
2489
|
if yield_run_response:
|
|
@@ -2267,18 +2501,24 @@ class Team:
|
|
|
2267
2501
|
run_response.content = str(e)
|
|
2268
2502
|
|
|
2269
2503
|
# Yield the cancellation event
|
|
2270
|
-
yield
|
|
2504
|
+
yield handle_event( # type: ignore
|
|
2271
2505
|
create_team_run_cancelled_event(from_run_response=run_response, reason=str(e)),
|
|
2272
2506
|
run_response,
|
|
2507
|
+
events_to_skip=self.events_to_skip,
|
|
2508
|
+
store_events=self.store_events,
|
|
2273
2509
|
)
|
|
2274
2510
|
|
|
2275
|
-
#
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
await self.asave_session(session=team_session)
|
|
2279
|
-
else:
|
|
2280
|
-
self.save_session(session=team_session)
|
|
2511
|
+
# Cleanup and store the run response and session
|
|
2512
|
+
await self._acleanup_and_store(run_response=run_response, session=team_session)
|
|
2513
|
+
|
|
2281
2514
|
finally:
|
|
2515
|
+
# Cancel the memory task if it's still running
|
|
2516
|
+
if memory_task is not None and not memory_task.done():
|
|
2517
|
+
memory_task.cancel()
|
|
2518
|
+
try:
|
|
2519
|
+
await memory_task
|
|
2520
|
+
except asyncio.CancelledError:
|
|
2521
|
+
pass
|
|
2282
2522
|
# Always clean up the run tracking
|
|
2283
2523
|
cleanup_run(run_response.run_id) # type: ignore
|
|
2284
2524
|
|
|
@@ -2288,6 +2528,7 @@ class Team:
|
|
|
2288
2528
|
input: Union[str, List, Dict, Message, BaseModel],
|
|
2289
2529
|
*,
|
|
2290
2530
|
stream: Literal[False] = False,
|
|
2531
|
+
stream_events: Optional[bool] = None,
|
|
2291
2532
|
stream_intermediate_steps: Optional[bool] = None,
|
|
2292
2533
|
session_id: Optional[str] = None,
|
|
2293
2534
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -2313,6 +2554,7 @@ class Team:
|
|
|
2313
2554
|
input: Union[str, List, Dict, Message, BaseModel],
|
|
2314
2555
|
*,
|
|
2315
2556
|
stream: Literal[True] = True,
|
|
2557
|
+
stream_events: Optional[bool] = None,
|
|
2316
2558
|
stream_intermediate_steps: Optional[bool] = None,
|
|
2317
2559
|
session_id: Optional[str] = None,
|
|
2318
2560
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -2338,6 +2580,7 @@ class Team:
|
|
|
2338
2580
|
input: Union[str, List, Dict, Message, BaseModel],
|
|
2339
2581
|
*,
|
|
2340
2582
|
stream: Optional[bool] = None,
|
|
2583
|
+
stream_events: Optional[bool] = None,
|
|
2341
2584
|
stream_intermediate_steps: Optional[bool] = None,
|
|
2342
2585
|
session_id: Optional[str] = None,
|
|
2343
2586
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -2359,6 +2602,11 @@ class Team:
|
|
|
2359
2602
|
) -> Union[TeamRunOutput, AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent]]]:
|
|
2360
2603
|
"""Run the Team asynchronously and return the response."""
|
|
2361
2604
|
|
|
2605
|
+
if (add_history_to_context or self.add_history_to_context) and not self.db and not self.parent_team_id:
|
|
2606
|
+
log_warning(
|
|
2607
|
+
"add_history_to_context is True, but no database has been assigned to the team. History will not be added to the context."
|
|
2608
|
+
)
|
|
2609
|
+
|
|
2362
2610
|
# Create a run_id for this specific run
|
|
2363
2611
|
run_id = str(uuid4())
|
|
2364
2612
|
|
|
@@ -2373,9 +2621,7 @@ class Team:
|
|
|
2373
2621
|
self.post_hooks = normalize_hooks(self.post_hooks, async_mode=True)
|
|
2374
2622
|
self._hooks_normalised = True
|
|
2375
2623
|
|
|
2376
|
-
session_id, user_id
|
|
2377
|
-
run_id=run_id, session_id=session_id, user_id=user_id, session_state=session_state
|
|
2378
|
-
)
|
|
2624
|
+
session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
|
|
2379
2625
|
|
|
2380
2626
|
# Initialize Team
|
|
2381
2627
|
self.initialize_team(debug_mode=debug_mode)
|
|
@@ -2409,17 +2655,18 @@ class Team:
|
|
|
2409
2655
|
if stream is None:
|
|
2410
2656
|
stream = False if self.stream is None else self.stream
|
|
2411
2657
|
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
False if self.stream_intermediate_steps is None else self.stream_intermediate_steps
|
|
2415
|
-
)
|
|
2658
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
2659
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
2416
2660
|
|
|
2417
|
-
# Can't
|
|
2661
|
+
# Can't stream events if streaming is disabled
|
|
2418
2662
|
if stream is False:
|
|
2419
|
-
|
|
2663
|
+
stream_events = False
|
|
2664
|
+
|
|
2665
|
+
if stream_events is None:
|
|
2666
|
+
stream_events = False if self.stream_events is None else self.stream_events
|
|
2420
2667
|
|
|
2421
2668
|
self.stream = self.stream or stream
|
|
2422
|
-
self.
|
|
2669
|
+
self.stream_events = self.stream_events or stream_events
|
|
2423
2670
|
|
|
2424
2671
|
# Configure the model for runs
|
|
2425
2672
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = (
|
|
@@ -2480,7 +2727,7 @@ class Team:
|
|
|
2480
2727
|
metadata=metadata,
|
|
2481
2728
|
response_format=response_format,
|
|
2482
2729
|
dependencies=run_dependencies,
|
|
2483
|
-
|
|
2730
|
+
stream_events=stream_events,
|
|
2484
2731
|
yield_run_response=yield_run_response,
|
|
2485
2732
|
debug_mode=debug_mode,
|
|
2486
2733
|
**kwargs,
|
|
@@ -2493,10 +2740,6 @@ class Team:
|
|
|
2493
2740
|
session_id=session_id,
|
|
2494
2741
|
session_state=session_state,
|
|
2495
2742
|
user_id=user_id,
|
|
2496
|
-
audio=audio,
|
|
2497
|
-
images=images,
|
|
2498
|
-
videos=videos,
|
|
2499
|
-
files=files,
|
|
2500
2743
|
knowledge_filters=effective_filters,
|
|
2501
2744
|
add_history_to_context=add_history,
|
|
2502
2745
|
add_dependencies_to_context=add_dependencies,
|
|
@@ -2631,7 +2874,7 @@ class Team:
|
|
|
2631
2874
|
run_response: TeamRunOutput,
|
|
2632
2875
|
run_messages: RunMessages,
|
|
2633
2876
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2634
|
-
|
|
2877
|
+
stream_events: bool = False,
|
|
2635
2878
|
) -> Iterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
2636
2879
|
self.model = cast(Model, self.model)
|
|
2637
2880
|
|
|
@@ -2662,7 +2905,7 @@ class Team:
|
|
|
2662
2905
|
full_model_response=full_model_response,
|
|
2663
2906
|
model_response_event=model_response_event,
|
|
2664
2907
|
reasoning_state=reasoning_state,
|
|
2665
|
-
|
|
2908
|
+
stream_events=stream_events,
|
|
2666
2909
|
parse_structured_output=self.should_parse_structured_output,
|
|
2667
2910
|
)
|
|
2668
2911
|
|
|
@@ -2678,20 +2921,22 @@ class Team:
|
|
|
2678
2921
|
if full_model_response.provider_data is not None:
|
|
2679
2922
|
run_response.model_provider_data = full_model_response.provider_data
|
|
2680
2923
|
|
|
2681
|
-
if
|
|
2924
|
+
if stream_events and reasoning_state["reasoning_started"]:
|
|
2682
2925
|
all_reasoning_steps: List[ReasoningStep] = []
|
|
2683
2926
|
if run_response.reasoning_steps:
|
|
2684
2927
|
all_reasoning_steps = cast(List[ReasoningStep], run_response.reasoning_steps)
|
|
2685
2928
|
|
|
2686
2929
|
if all_reasoning_steps:
|
|
2687
2930
|
add_reasoning_metrics_to_metadata(run_response, reasoning_state["reasoning_time_taken"])
|
|
2688
|
-
yield
|
|
2931
|
+
yield handle_event( # type: ignore
|
|
2689
2932
|
create_team_reasoning_completed_event(
|
|
2690
2933
|
from_run_response=run_response,
|
|
2691
2934
|
content=ReasoningSteps(reasoning_steps=all_reasoning_steps),
|
|
2692
2935
|
content_type=ReasoningSteps.__name__,
|
|
2693
2936
|
),
|
|
2694
2937
|
run_response,
|
|
2938
|
+
events_to_skip=self.events_to_skip,
|
|
2939
|
+
store_events=self.store_events,
|
|
2695
2940
|
)
|
|
2696
2941
|
|
|
2697
2942
|
# Build a list of messages that should be added to the RunOutput
|
|
@@ -2711,7 +2956,7 @@ class Team:
|
|
|
2711
2956
|
run_response: TeamRunOutput,
|
|
2712
2957
|
run_messages: RunMessages,
|
|
2713
2958
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
2714
|
-
|
|
2959
|
+
stream_events: bool = False,
|
|
2715
2960
|
) -> AsyncIterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
2716
2961
|
self.model = cast(Model, self.model)
|
|
2717
2962
|
|
|
@@ -2743,7 +2988,7 @@ class Team:
|
|
|
2743
2988
|
full_model_response=full_model_response,
|
|
2744
2989
|
model_response_event=model_response_event,
|
|
2745
2990
|
reasoning_state=reasoning_state,
|
|
2746
|
-
|
|
2991
|
+
stream_events=stream_events,
|
|
2747
2992
|
parse_structured_output=self.should_parse_structured_output,
|
|
2748
2993
|
):
|
|
2749
2994
|
yield event
|
|
@@ -2772,20 +3017,22 @@ class Team:
|
|
|
2772
3017
|
# Update the TeamRunOutput metrics
|
|
2773
3018
|
run_response.metrics = self._calculate_metrics(messages_for_run_response)
|
|
2774
3019
|
|
|
2775
|
-
if
|
|
3020
|
+
if stream_events and reasoning_state["reasoning_started"]:
|
|
2776
3021
|
all_reasoning_steps: List[ReasoningStep] = []
|
|
2777
3022
|
if run_response.reasoning_steps:
|
|
2778
3023
|
all_reasoning_steps = cast(List[ReasoningStep], run_response.reasoning_steps)
|
|
2779
3024
|
|
|
2780
3025
|
if all_reasoning_steps:
|
|
2781
3026
|
add_reasoning_metrics_to_metadata(run_response, reasoning_state["reasoning_time_taken"])
|
|
2782
|
-
yield
|
|
3027
|
+
yield handle_event( # type: ignore
|
|
2783
3028
|
create_team_reasoning_completed_event(
|
|
2784
3029
|
from_run_response=run_response,
|
|
2785
3030
|
content=ReasoningSteps(reasoning_steps=all_reasoning_steps),
|
|
2786
3031
|
content_type=ReasoningSteps.__name__,
|
|
2787
3032
|
),
|
|
2788
3033
|
run_response,
|
|
3034
|
+
events_to_skip=self.events_to_skip,
|
|
3035
|
+
store_events=self.store_events,
|
|
2789
3036
|
)
|
|
2790
3037
|
|
|
2791
3038
|
def _handle_model_response_chunk(
|
|
@@ -2795,7 +3042,7 @@ class Team:
|
|
|
2795
3042
|
full_model_response: ModelResponse,
|
|
2796
3043
|
model_response_event: Union[ModelResponse, TeamRunOutputEvent, RunOutputEvent],
|
|
2797
3044
|
reasoning_state: Optional[Dict[str, Any]] = None,
|
|
2798
|
-
|
|
3045
|
+
stream_events: bool = False,
|
|
2799
3046
|
parse_structured_output: bool = False,
|
|
2800
3047
|
) -> Iterator[Union[TeamRunOutputEvent, RunOutputEvent]]:
|
|
2801
3048
|
if isinstance(model_response_event, tuple(get_args(RunOutputEvent))) or isinstance(
|
|
@@ -2812,7 +3059,12 @@ class Team:
|
|
|
2812
3059
|
if not model_response_event.run_id: # type: ignore
|
|
2813
3060
|
model_response_event.run_id = run_response.run_id # type: ignore
|
|
2814
3061
|
# We just bubble the event up
|
|
2815
|
-
yield
|
|
3062
|
+
yield handle_event( # type: ignore
|
|
3063
|
+
model_response_event, # type: ignore
|
|
3064
|
+
run_response,
|
|
3065
|
+
events_to_skip=self.events_to_skip,
|
|
3066
|
+
store_events=self.store_events,
|
|
3067
|
+
) # type: ignore
|
|
2816
3068
|
else:
|
|
2817
3069
|
# Don't yield anything
|
|
2818
3070
|
return
|
|
@@ -2918,7 +3170,7 @@ class Team:
|
|
|
2918
3170
|
# Only yield the chunk
|
|
2919
3171
|
if should_yield:
|
|
2920
3172
|
if content_type == "str":
|
|
2921
|
-
yield
|
|
3173
|
+
yield handle_event( # type: ignore
|
|
2922
3174
|
create_team_run_output_content_event(
|
|
2923
3175
|
from_run_response=run_response,
|
|
2924
3176
|
content=model_response_event.content,
|
|
@@ -2930,15 +3182,19 @@ class Team:
|
|
|
2930
3182
|
image=model_response_event.images[-1] if model_response_event.images else None,
|
|
2931
3183
|
),
|
|
2932
3184
|
run_response,
|
|
3185
|
+
events_to_skip=self.events_to_skip,
|
|
3186
|
+
store_events=self.store_events,
|
|
2933
3187
|
)
|
|
2934
3188
|
else:
|
|
2935
|
-
yield
|
|
3189
|
+
yield handle_event( # type: ignore
|
|
2936
3190
|
create_team_run_output_content_event(
|
|
2937
3191
|
from_run_response=run_response,
|
|
2938
3192
|
content=full_model_response.content,
|
|
2939
3193
|
content_type=content_type,
|
|
2940
3194
|
),
|
|
2941
3195
|
run_response,
|
|
3196
|
+
events_to_skip=self.events_to_skip,
|
|
3197
|
+
store_events=self.store_events,
|
|
2942
3198
|
)
|
|
2943
3199
|
|
|
2944
3200
|
# If the model response is a tool_call_started, add the tool call to the run_response
|
|
@@ -2953,12 +3209,14 @@ class Team:
|
|
|
2953
3209
|
run_response.tools.extend(tool_executions_list)
|
|
2954
3210
|
|
|
2955
3211
|
for tool in tool_executions_list:
|
|
2956
|
-
yield
|
|
3212
|
+
yield handle_event( # type: ignore
|
|
2957
3213
|
create_team_tool_call_started_event(
|
|
2958
3214
|
from_run_response=run_response,
|
|
2959
3215
|
tool=tool,
|
|
2960
3216
|
),
|
|
2961
3217
|
run_response,
|
|
3218
|
+
events_to_skip=self.events_to_skip,
|
|
3219
|
+
store_events=self.store_events,
|
|
2962
3220
|
)
|
|
2963
3221
|
|
|
2964
3222
|
# If the model response is a tool_call_completed, update the existing tool call in the run_response
|
|
@@ -3016,33 +3274,39 @@ class Team:
|
|
|
3016
3274
|
"reasoning_time_taken"
|
|
3017
3275
|
] + float(metrics.duration)
|
|
3018
3276
|
|
|
3019
|
-
yield
|
|
3277
|
+
yield handle_event( # type: ignore
|
|
3020
3278
|
create_team_tool_call_completed_event(
|
|
3021
3279
|
from_run_response=run_response,
|
|
3022
3280
|
tool=tool_call,
|
|
3023
3281
|
content=model_response_event.content,
|
|
3024
3282
|
),
|
|
3025
3283
|
run_response,
|
|
3284
|
+
events_to_skip=self.events_to_skip,
|
|
3285
|
+
store_events=self.store_events,
|
|
3026
3286
|
)
|
|
3027
3287
|
|
|
3028
|
-
if
|
|
3288
|
+
if stream_events:
|
|
3029
3289
|
if reasoning_step is not None:
|
|
3030
3290
|
if reasoning_state is not None and not reasoning_state["reasoning_started"]:
|
|
3031
|
-
yield
|
|
3291
|
+
yield handle_event( # type: ignore
|
|
3032
3292
|
create_team_reasoning_started_event(
|
|
3033
3293
|
from_run_response=run_response,
|
|
3034
3294
|
),
|
|
3035
3295
|
run_response,
|
|
3296
|
+
events_to_skip=self.events_to_skip,
|
|
3297
|
+
store_events=self.store_events,
|
|
3036
3298
|
)
|
|
3037
3299
|
reasoning_state["reasoning_started"] = True
|
|
3038
3300
|
|
|
3039
|
-
yield
|
|
3301
|
+
yield handle_event( # type: ignore
|
|
3040
3302
|
create_team_reasoning_step_event(
|
|
3041
3303
|
from_run_response=run_response,
|
|
3042
3304
|
reasoning_step=reasoning_step,
|
|
3043
3305
|
reasoning_content=run_response.reasoning_content or "",
|
|
3044
3306
|
),
|
|
3045
3307
|
run_response,
|
|
3308
|
+
events_to_skip=self.events_to_skip,
|
|
3309
|
+
store_events=self.store_events,
|
|
3046
3310
|
)
|
|
3047
3311
|
|
|
3048
3312
|
def _convert_response_to_structured_format(self, run_response: Union[TeamRunOutput, RunOutput, ModelResponse]):
|
|
@@ -3083,97 +3347,71 @@ class Team:
|
|
|
3083
3347
|
else:
|
|
3084
3348
|
log_warning("Something went wrong. Member run response content is not a string")
|
|
3085
3349
|
|
|
3086
|
-
def
|
|
3087
|
-
|
|
3088
|
-
run_response
|
|
3089
|
-
run_messages: RunMessages,
|
|
3090
|
-
session: TeamSession,
|
|
3091
|
-
user_id: Optional[str] = None,
|
|
3092
|
-
) -> Iterator[TeamRunOutputEvent]:
|
|
3093
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
3350
|
+
def _cleanup_and_store(self, run_response: TeamRunOutput, session: TeamSession) -> None:
|
|
3351
|
+
# Scrub the stored run based on storage flags
|
|
3352
|
+
self._scrub_run_output_for_storage(run_response)
|
|
3094
3353
|
|
|
3095
|
-
#
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
user_message_str = (
|
|
3099
|
-
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
3100
|
-
)
|
|
3101
|
-
# Create user memories
|
|
3102
|
-
if user_message_str is not None and self.memory_manager is not None and not self.enable_agentic_memory:
|
|
3103
|
-
futures.append(
|
|
3104
|
-
executor.submit(
|
|
3105
|
-
self.memory_manager.create_user_memories,
|
|
3106
|
-
message=user_message_str,
|
|
3107
|
-
user_id=user_id,
|
|
3108
|
-
team_id=self.id,
|
|
3109
|
-
)
|
|
3110
|
-
)
|
|
3354
|
+
# Stop the timer for the Run duration
|
|
3355
|
+
if run_response.metrics:
|
|
3356
|
+
run_response.metrics.stop_timer()
|
|
3111
3357
|
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
log_debug("Creating session summary.")
|
|
3115
|
-
futures.append(
|
|
3116
|
-
executor.submit(
|
|
3117
|
-
self.session_summary_manager.create_session_summary, # type: ignore
|
|
3118
|
-
session=session,
|
|
3119
|
-
)
|
|
3120
|
-
)
|
|
3358
|
+
# Add RunOutput to Agent Session
|
|
3359
|
+
session.upsert_run(run_response=run_response)
|
|
3121
3360
|
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
yield self._handle_event(
|
|
3125
|
-
create_team_memory_update_started_event(from_run_response=run_response), run_response
|
|
3126
|
-
)
|
|
3361
|
+
# Calculate session metrics
|
|
3362
|
+
self._update_session_metrics(session=session)
|
|
3127
3363
|
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3364
|
+
# Save session to memory
|
|
3365
|
+
self.save_session(session=session)
|
|
3366
|
+
|
|
3367
|
+
async def _acleanup_and_store(self, run_response: TeamRunOutput, session: TeamSession) -> None:
|
|
3368
|
+
# Scrub the stored run based on storage flags
|
|
3369
|
+
self._scrub_run_output_for_storage(run_response)
|
|
3370
|
+
|
|
3371
|
+
# Stop the timer for the Run duration
|
|
3372
|
+
if run_response.metrics:
|
|
3373
|
+
run_response.metrics.stop_timer()
|
|
3374
|
+
|
|
3375
|
+
# Add RunOutput to Agent Session
|
|
3376
|
+
session.upsert_run(run_response=run_response)
|
|
3377
|
+
|
|
3378
|
+
# Calculate session metrics
|
|
3379
|
+
self._update_session_metrics(session=session)
|
|
3134
3380
|
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
create_team_memory_update_completed_event(from_run_response=run_response),
|
|
3138
|
-
run_response,
|
|
3139
|
-
)
|
|
3381
|
+
# Save session to memory
|
|
3382
|
+
self.save_session(session=session)
|
|
3140
3383
|
|
|
3141
|
-
|
|
3384
|
+
def _make_memories(
|
|
3142
3385
|
self,
|
|
3143
|
-
run_response: TeamRunOutput,
|
|
3144
3386
|
run_messages: RunMessages,
|
|
3145
|
-
session: TeamSession,
|
|
3146
3387
|
user_id: Optional[str] = None,
|
|
3147
|
-
)
|
|
3148
|
-
tasks: List[Coroutine] = []
|
|
3149
|
-
|
|
3388
|
+
):
|
|
3150
3389
|
user_message_str = (
|
|
3151
3390
|
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
3152
3391
|
)
|
|
3153
|
-
if user_message_str is not None and self.memory_manager is not None
|
|
3154
|
-
|
|
3155
|
-
|
|
3392
|
+
if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
|
|
3393
|
+
log_debug("Creating user memories.")
|
|
3394
|
+
self.memory_manager.create_user_memories(
|
|
3395
|
+
message=user_message_str,
|
|
3396
|
+
user_id=user_id,
|
|
3397
|
+
team_id=self.id,
|
|
3156
3398
|
)
|
|
3157
3399
|
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
if self.stream_intermediate_steps:
|
|
3174
|
-
yield self._handle_event(
|
|
3175
|
-
create_team_memory_update_completed_event(from_run_response=run_response), run_response
|
|
3176
|
-
)
|
|
3400
|
+
async def _amake_memories(
|
|
3401
|
+
self,
|
|
3402
|
+
run_messages: RunMessages,
|
|
3403
|
+
user_id: Optional[str] = None,
|
|
3404
|
+
):
|
|
3405
|
+
user_message_str = (
|
|
3406
|
+
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
3407
|
+
)
|
|
3408
|
+
if user_message_str is not None and user_message_str.strip() != "" and self.memory_manager is not None:
|
|
3409
|
+
log_debug("Creating user memories.")
|
|
3410
|
+
await self.memory_manager.acreate_user_memories(
|
|
3411
|
+
message=user_message_str,
|
|
3412
|
+
user_id=user_id,
|
|
3413
|
+
team_id=self.id,
|
|
3414
|
+
)
|
|
3177
3415
|
|
|
3178
3416
|
def _get_response_format(self, model: Optional[Model] = None) -> Optional[Union[Dict, Type[BaseModel]]]:
|
|
3179
3417
|
model = cast(Model, model or self.model)
|
|
@@ -3269,14 +3507,20 @@ class Team:
|
|
|
3269
3507
|
log_warning("A response model is required to parse the response with a parser model")
|
|
3270
3508
|
|
|
3271
3509
|
def _parse_response_with_parser_model_stream(
|
|
3272
|
-
self,
|
|
3510
|
+
self,
|
|
3511
|
+
session: TeamSession,
|
|
3512
|
+
run_response: TeamRunOutput,
|
|
3513
|
+
stream_events: bool = False,
|
|
3273
3514
|
):
|
|
3274
3515
|
"""Parse the model response using the parser model"""
|
|
3275
3516
|
if self.parser_model is not None:
|
|
3276
3517
|
if self.output_schema is not None:
|
|
3277
|
-
if
|
|
3278
|
-
yield
|
|
3279
|
-
create_team_parser_model_response_started_event(run_response),
|
|
3518
|
+
if stream_events:
|
|
3519
|
+
yield handle_event( # type: ignore
|
|
3520
|
+
create_team_parser_model_response_started_event(run_response),
|
|
3521
|
+
run_response,
|
|
3522
|
+
events_to_skip=self.events_to_skip,
|
|
3523
|
+
store_events=self.store_events,
|
|
3280
3524
|
)
|
|
3281
3525
|
|
|
3282
3526
|
parser_model_response = ModelResponse(content="")
|
|
@@ -3295,7 +3539,7 @@ class Team:
|
|
|
3295
3539
|
full_model_response=parser_model_response,
|
|
3296
3540
|
model_response_event=model_response_event,
|
|
3297
3541
|
parse_structured_output=True,
|
|
3298
|
-
|
|
3542
|
+
stream_events=stream_events,
|
|
3299
3543
|
)
|
|
3300
3544
|
|
|
3301
3545
|
run_response.content = parser_model_response.content
|
|
@@ -3311,23 +3555,29 @@ class Team:
|
|
|
3311
3555
|
else:
|
|
3312
3556
|
log_warning("Unable to parse response with parser model")
|
|
3313
3557
|
|
|
3314
|
-
if
|
|
3315
|
-
yield
|
|
3316
|
-
create_team_parser_model_response_completed_event(run_response),
|
|
3558
|
+
if stream_events:
|
|
3559
|
+
yield handle_event( # type: ignore
|
|
3560
|
+
create_team_parser_model_response_completed_event(run_response),
|
|
3561
|
+
run_response,
|
|
3562
|
+
events_to_skip=self.events_to_skip,
|
|
3563
|
+
store_events=self.store_events,
|
|
3317
3564
|
)
|
|
3318
3565
|
|
|
3319
3566
|
else:
|
|
3320
3567
|
log_warning("A response model is required to parse the response with a parser model")
|
|
3321
3568
|
|
|
3322
3569
|
async def _aparse_response_with_parser_model_stream(
|
|
3323
|
-
self, session: TeamSession, run_response: TeamRunOutput,
|
|
3570
|
+
self, session: TeamSession, run_response: TeamRunOutput, stream_events: bool = False
|
|
3324
3571
|
):
|
|
3325
3572
|
"""Parse the model response using the parser model stream."""
|
|
3326
3573
|
if self.parser_model is not None:
|
|
3327
3574
|
if self.output_schema is not None:
|
|
3328
|
-
if
|
|
3329
|
-
yield
|
|
3330
|
-
create_team_parser_model_response_started_event(run_response),
|
|
3575
|
+
if stream_events:
|
|
3576
|
+
yield handle_event( # type: ignore
|
|
3577
|
+
create_team_parser_model_response_started_event(run_response),
|
|
3578
|
+
run_response,
|
|
3579
|
+
events_to_skip=self.events_to_skip,
|
|
3580
|
+
store_events=self.store_events,
|
|
3331
3581
|
)
|
|
3332
3582
|
|
|
3333
3583
|
parser_model_response = ModelResponse(content="")
|
|
@@ -3347,7 +3597,7 @@ class Team:
|
|
|
3347
3597
|
full_model_response=parser_model_response,
|
|
3348
3598
|
model_response_event=model_response_event,
|
|
3349
3599
|
parse_structured_output=True,
|
|
3350
|
-
|
|
3600
|
+
stream_events=stream_events,
|
|
3351
3601
|
):
|
|
3352
3602
|
yield event
|
|
3353
3603
|
|
|
@@ -3364,9 +3614,12 @@ class Team:
|
|
|
3364
3614
|
else:
|
|
3365
3615
|
log_warning("Unable to parse response with parser model")
|
|
3366
3616
|
|
|
3367
|
-
if
|
|
3368
|
-
yield
|
|
3369
|
-
create_team_parser_model_response_completed_event(run_response),
|
|
3617
|
+
if stream_events:
|
|
3618
|
+
yield handle_event( # type: ignore
|
|
3619
|
+
create_team_parser_model_response_completed_event(run_response),
|
|
3620
|
+
run_response,
|
|
3621
|
+
events_to_skip=self.events_to_skip,
|
|
3622
|
+
store_events=self.store_events,
|
|
3370
3623
|
)
|
|
3371
3624
|
else:
|
|
3372
3625
|
log_warning("A response model is required to parse the response with a parser model")
|
|
@@ -3385,7 +3638,7 @@ class Team:
|
|
|
3385
3638
|
session: TeamSession,
|
|
3386
3639
|
run_response: TeamRunOutput,
|
|
3387
3640
|
run_messages: RunMessages,
|
|
3388
|
-
|
|
3641
|
+
stream_events: bool = False,
|
|
3389
3642
|
):
|
|
3390
3643
|
"""Parse the model response using the output model stream."""
|
|
3391
3644
|
from agno.utils.events import (
|
|
@@ -3396,8 +3649,13 @@ class Team:
|
|
|
3396
3649
|
if self.output_model is None:
|
|
3397
3650
|
return
|
|
3398
3651
|
|
|
3399
|
-
if
|
|
3400
|
-
yield
|
|
3652
|
+
if stream_events:
|
|
3653
|
+
yield handle_event( # type: ignore
|
|
3654
|
+
create_team_output_model_response_started_event(run_response),
|
|
3655
|
+
run_response,
|
|
3656
|
+
events_to_skip=self.events_to_skip,
|
|
3657
|
+
store_events=self.store_events,
|
|
3658
|
+
)
|
|
3401
3659
|
|
|
3402
3660
|
messages_for_output_model = self._get_messages_for_output_model(run_messages.messages)
|
|
3403
3661
|
model_response = ModelResponse(content="")
|
|
@@ -3413,8 +3671,13 @@ class Team:
|
|
|
3413
3671
|
# Update the TeamRunResponse content
|
|
3414
3672
|
run_response.content = model_response.content
|
|
3415
3673
|
|
|
3416
|
-
if
|
|
3417
|
-
yield
|
|
3674
|
+
if stream_events:
|
|
3675
|
+
yield handle_event( # type: ignore
|
|
3676
|
+
create_team_output_model_response_completed_event(run_response),
|
|
3677
|
+
run_response,
|
|
3678
|
+
events_to_skip=self.events_to_skip,
|
|
3679
|
+
store_events=self.store_events,
|
|
3680
|
+
)
|
|
3418
3681
|
|
|
3419
3682
|
# Build a list of messages that should be added to the RunResponse
|
|
3420
3683
|
messages_for_run_response = [m for m in run_messages.messages if m.add_to_agent_memory]
|
|
@@ -3439,7 +3702,7 @@ class Team:
|
|
|
3439
3702
|
session: TeamSession,
|
|
3440
3703
|
run_response: TeamRunOutput,
|
|
3441
3704
|
run_messages: RunMessages,
|
|
3442
|
-
|
|
3705
|
+
stream_events: bool = False,
|
|
3443
3706
|
):
|
|
3444
3707
|
"""Parse the model response using the output model stream."""
|
|
3445
3708
|
from agno.utils.events import (
|
|
@@ -3450,8 +3713,13 @@ class Team:
|
|
|
3450
3713
|
if self.output_model is None:
|
|
3451
3714
|
return
|
|
3452
3715
|
|
|
3453
|
-
if
|
|
3454
|
-
yield
|
|
3716
|
+
if stream_events:
|
|
3717
|
+
yield handle_event( # type: ignore
|
|
3718
|
+
create_team_output_model_response_started_event(run_response),
|
|
3719
|
+
run_response,
|
|
3720
|
+
events_to_skip=self.events_to_skip,
|
|
3721
|
+
store_events=self.store_events,
|
|
3722
|
+
)
|
|
3455
3723
|
|
|
3456
3724
|
messages_for_output_model = self._get_messages_for_output_model(run_messages.messages)
|
|
3457
3725
|
model_response = ModelResponse(content="")
|
|
@@ -3468,8 +3736,13 @@ class Team:
|
|
|
3468
3736
|
# Update the TeamRunResponse content
|
|
3469
3737
|
run_response.content = model_response.content
|
|
3470
3738
|
|
|
3471
|
-
if
|
|
3472
|
-
yield
|
|
3739
|
+
if stream_events:
|
|
3740
|
+
yield handle_event( # type: ignore
|
|
3741
|
+
create_team_output_model_response_completed_event(run_response),
|
|
3742
|
+
run_response,
|
|
3743
|
+
events_to_skip=self.events_to_skip,
|
|
3744
|
+
store_events=self.store_events,
|
|
3745
|
+
)
|
|
3473
3746
|
|
|
3474
3747
|
# Build a list of messages that should be added to the RunResponse
|
|
3475
3748
|
messages_for_run_response = [m for m in run_messages.messages if m.add_to_agent_memory]
|
|
@@ -3500,6 +3773,7 @@ class Team:
|
|
|
3500
3773
|
input: Union[List, Dict, str, Message, BaseModel, List[Message]],
|
|
3501
3774
|
*,
|
|
3502
3775
|
stream: Optional[bool] = None,
|
|
3776
|
+
stream_events: Optional[bool] = None,
|
|
3503
3777
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3504
3778
|
session_id: Optional[str] = None,
|
|
3505
3779
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -3540,8 +3814,15 @@ class Team:
|
|
|
3540
3814
|
if stream is None:
|
|
3541
3815
|
stream = self.stream or False
|
|
3542
3816
|
|
|
3543
|
-
|
|
3544
|
-
|
|
3817
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
3818
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
3819
|
+
|
|
3820
|
+
# Can't stream events if streaming is disabled
|
|
3821
|
+
if stream is False:
|
|
3822
|
+
stream_events = False
|
|
3823
|
+
|
|
3824
|
+
if stream_events is None:
|
|
3825
|
+
stream_events = False if self.stream_events is None else self.stream_events
|
|
3545
3826
|
|
|
3546
3827
|
if stream:
|
|
3547
3828
|
print_response_stream(
|
|
@@ -3560,7 +3841,7 @@ class Team:
|
|
|
3560
3841
|
videos=videos,
|
|
3561
3842
|
files=files,
|
|
3562
3843
|
markdown=markdown,
|
|
3563
|
-
|
|
3844
|
+
stream_events=stream_events,
|
|
3564
3845
|
knowledge_filters=knowledge_filters,
|
|
3565
3846
|
add_history_to_context=add_history_to_context,
|
|
3566
3847
|
dependencies=dependencies,
|
|
@@ -3602,6 +3883,7 @@ class Team:
|
|
|
3602
3883
|
input: Union[List, Dict, str, Message, BaseModel, List[Message]],
|
|
3603
3884
|
*,
|
|
3604
3885
|
stream: Optional[bool] = None,
|
|
3886
|
+
stream_events: Optional[bool] = None,
|
|
3605
3887
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3606
3888
|
session_id: Optional[str] = None,
|
|
3607
3889
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -3637,8 +3919,15 @@ class Team:
|
|
|
3637
3919
|
if stream is None:
|
|
3638
3920
|
stream = self.stream or False
|
|
3639
3921
|
|
|
3640
|
-
|
|
3641
|
-
|
|
3922
|
+
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
3923
|
+
stream_events = stream_events or stream_intermediate_steps
|
|
3924
|
+
|
|
3925
|
+
# Can't stream events if streaming is disabled
|
|
3926
|
+
if stream is False:
|
|
3927
|
+
stream_events = False
|
|
3928
|
+
|
|
3929
|
+
if stream_events is None:
|
|
3930
|
+
stream_events = False if self.stream_events is None else self.stream_events
|
|
3642
3931
|
|
|
3643
3932
|
if stream:
|
|
3644
3933
|
await aprint_response_stream(
|
|
@@ -3657,7 +3946,7 @@ class Team:
|
|
|
3657
3946
|
videos=videos,
|
|
3658
3947
|
files=files,
|
|
3659
3948
|
markdown=markdown,
|
|
3660
|
-
|
|
3949
|
+
stream_events=stream_events,
|
|
3661
3950
|
knowledge_filters=knowledge_filters,
|
|
3662
3951
|
add_history_to_context=add_history_to_context,
|
|
3663
3952
|
dependencies=dependencies,
|
|
@@ -3704,88 +3993,6 @@ class Team:
|
|
|
3704
3993
|
return member.name or entity_id
|
|
3705
3994
|
return entity_id
|
|
3706
3995
|
|
|
3707
|
-
def _scrub_media_from_run_output(self, run_response: TeamRunOutput) -> None:
|
|
3708
|
-
"""
|
|
3709
|
-
Completely remove all media from RunOutput when store_media=False.
|
|
3710
|
-
This includes media in input, output artifacts, and all messages.
|
|
3711
|
-
"""
|
|
3712
|
-
# 1. Scrub RunInput media
|
|
3713
|
-
if run_response.input is not None:
|
|
3714
|
-
run_response.input.images = []
|
|
3715
|
-
run_response.input.videos = []
|
|
3716
|
-
run_response.input.audios = []
|
|
3717
|
-
run_response.input.files = []
|
|
3718
|
-
|
|
3719
|
-
# 3. Scrub media from all messages
|
|
3720
|
-
if run_response.messages:
|
|
3721
|
-
for message in run_response.messages:
|
|
3722
|
-
self._scrub_media_from_message(message)
|
|
3723
|
-
|
|
3724
|
-
# 4. Scrub media from additional_input messages if any
|
|
3725
|
-
if run_response.additional_input:
|
|
3726
|
-
for message in run_response.additional_input:
|
|
3727
|
-
self._scrub_media_from_message(message)
|
|
3728
|
-
|
|
3729
|
-
# 5. Scrub media from reasoning_messages if any
|
|
3730
|
-
if run_response.reasoning_messages:
|
|
3731
|
-
for message in run_response.reasoning_messages:
|
|
3732
|
-
self._scrub_media_from_message(message)
|
|
3733
|
-
|
|
3734
|
-
def _scrub_media_from_message(self, message: Message) -> None:
|
|
3735
|
-
"""Remove all media from a Message object."""
|
|
3736
|
-
# Input media
|
|
3737
|
-
message.images = None
|
|
3738
|
-
message.videos = None
|
|
3739
|
-
message.audio = None
|
|
3740
|
-
message.files = None
|
|
3741
|
-
|
|
3742
|
-
# Output media
|
|
3743
|
-
message.audio_output = None
|
|
3744
|
-
message.image_output = None
|
|
3745
|
-
message.video_output = None
|
|
3746
|
-
|
|
3747
|
-
def _scrub_tool_results_from_run_output(self, run_response: TeamRunOutput) -> None:
|
|
3748
|
-
"""
|
|
3749
|
-
Remove all tool-related data from RunOutput when store_tool_messages=False.
|
|
3750
|
-
This removes both the tool call and its corresponding result to maintain API consistency.
|
|
3751
|
-
"""
|
|
3752
|
-
if not run_response.messages:
|
|
3753
|
-
return
|
|
3754
|
-
|
|
3755
|
-
# Step 1: Collect all tool_call_ids from tool result messages
|
|
3756
|
-
tool_call_ids_to_remove = set()
|
|
3757
|
-
for message in run_response.messages:
|
|
3758
|
-
if message.role == "tool" and message.tool_call_id:
|
|
3759
|
-
tool_call_ids_to_remove.add(message.tool_call_id)
|
|
3760
|
-
|
|
3761
|
-
# Step 2: Remove tool result messages (role="tool")
|
|
3762
|
-
run_response.messages = [msg for msg in run_response.messages if msg.role != "tool"]
|
|
3763
|
-
|
|
3764
|
-
# Step 3: Remove assistant messages that made those tool calls
|
|
3765
|
-
filtered_messages = []
|
|
3766
|
-
for message in run_response.messages:
|
|
3767
|
-
# Check if this assistant message made any of the tool calls we're removing
|
|
3768
|
-
should_remove = False
|
|
3769
|
-
if message.role == "assistant" and message.tool_calls:
|
|
3770
|
-
for tool_call in message.tool_calls:
|
|
3771
|
-
if tool_call.get("id") in tool_call_ids_to_remove:
|
|
3772
|
-
should_remove = True
|
|
3773
|
-
break
|
|
3774
|
-
|
|
3775
|
-
if not should_remove:
|
|
3776
|
-
filtered_messages.append(message)
|
|
3777
|
-
|
|
3778
|
-
run_response.messages = filtered_messages
|
|
3779
|
-
|
|
3780
|
-
def _scrub_history_messages_from_run_output(self, run_response: TeamRunOutput) -> None:
|
|
3781
|
-
"""
|
|
3782
|
-
Remove all history messages from TeamRunOutput when store_history_messages=False.
|
|
3783
|
-
This removes messages that were loaded from the team's memory.
|
|
3784
|
-
"""
|
|
3785
|
-
# Remove messages with from_history=True
|
|
3786
|
-
if run_response.messages:
|
|
3787
|
-
run_response.messages = [msg for msg in run_response.messages if not msg.from_history]
|
|
3788
|
-
|
|
3789
3996
|
def _scrub_run_output_for_storage(self, run_response: TeamRunOutput) -> bool:
|
|
3790
3997
|
"""
|
|
3791
3998
|
Scrub run output based on storage flags before persisting to database.
|
|
@@ -3794,15 +4001,15 @@ class Team:
|
|
|
3794
4001
|
scrubbed = False
|
|
3795
4002
|
|
|
3796
4003
|
if not self.store_media:
|
|
3797
|
-
|
|
4004
|
+
scrub_media_from_run_output(run_response)
|
|
3798
4005
|
scrubbed = True
|
|
3799
4006
|
|
|
3800
4007
|
if not self.store_tool_messages:
|
|
3801
|
-
|
|
4008
|
+
scrub_tool_results_from_run_output(run_response)
|
|
3802
4009
|
scrubbed = True
|
|
3803
4010
|
|
|
3804
4011
|
if not self.store_history_messages:
|
|
3805
|
-
|
|
4012
|
+
scrub_history_messages_from_run_output(run_response)
|
|
3806
4013
|
scrubbed = True
|
|
3807
4014
|
|
|
3808
4015
|
return scrubbed
|
|
@@ -3959,32 +4166,42 @@ class Team:
|
|
|
3959
4166
|
# Helpers
|
|
3960
4167
|
###########################################################################
|
|
3961
4168
|
|
|
3962
|
-
def _handle_reasoning(self, run_response: TeamRunOutput, run_messages: RunMessages)
|
|
4169
|
+
def _handle_reasoning(self, run_response: TeamRunOutput, run_messages: RunMessages):
|
|
3963
4170
|
if self.reasoning or self.reasoning_model is not None:
|
|
3964
|
-
reasoning_generator = self._reason(
|
|
4171
|
+
reasoning_generator = self._reason(
|
|
4172
|
+
run_response=run_response, run_messages=run_messages, stream_events=False
|
|
4173
|
+
)
|
|
3965
4174
|
|
|
3966
4175
|
# Consume the generator without yielding
|
|
3967
4176
|
deque(reasoning_generator, maxlen=0)
|
|
3968
4177
|
|
|
3969
4178
|
def _handle_reasoning_stream(
|
|
3970
|
-
self, run_response: TeamRunOutput, run_messages: RunMessages
|
|
4179
|
+
self, run_response: TeamRunOutput, run_messages: RunMessages, stream_events: bool
|
|
3971
4180
|
) -> Iterator[TeamRunOutputEvent]:
|
|
3972
4181
|
if self.reasoning or self.reasoning_model is not None:
|
|
3973
|
-
reasoning_generator = self._reason(
|
|
4182
|
+
reasoning_generator = self._reason(
|
|
4183
|
+
run_response=run_response,
|
|
4184
|
+
run_messages=run_messages,
|
|
4185
|
+
stream_events=stream_events,
|
|
4186
|
+
)
|
|
3974
4187
|
yield from reasoning_generator
|
|
3975
4188
|
|
|
3976
4189
|
async def _ahandle_reasoning(self, run_response: TeamRunOutput, run_messages: RunMessages) -> None:
|
|
3977
4190
|
if self.reasoning or self.reasoning_model is not None:
|
|
3978
|
-
reason_generator = self._areason(run_response=run_response, run_messages=run_messages)
|
|
4191
|
+
reason_generator = self._areason(run_response=run_response, run_messages=run_messages, stream_events=False)
|
|
3979
4192
|
# Consume the generator without yielding
|
|
3980
4193
|
async for _ in reason_generator:
|
|
3981
4194
|
pass
|
|
3982
4195
|
|
|
3983
4196
|
async def _ahandle_reasoning_stream(
|
|
3984
|
-
self, run_response: TeamRunOutput, run_messages: RunMessages
|
|
4197
|
+
self, run_response: TeamRunOutput, run_messages: RunMessages, stream_events: bool
|
|
3985
4198
|
) -> AsyncIterator[TeamRunOutputEvent]:
|
|
3986
4199
|
if self.reasoning or self.reasoning_model is not None:
|
|
3987
|
-
reason_generator = self._areason(
|
|
4200
|
+
reason_generator = self._areason(
|
|
4201
|
+
run_response=run_response,
|
|
4202
|
+
run_messages=run_messages,
|
|
4203
|
+
stream_events=stream_events,
|
|
4204
|
+
)
|
|
3988
4205
|
async for item in reason_generator:
|
|
3989
4206
|
yield item
|
|
3990
4207
|
|
|
@@ -4062,9 +4279,15 @@ class Team:
|
|
|
4062
4279
|
self,
|
|
4063
4280
|
run_response: TeamRunOutput,
|
|
4064
4281
|
run_messages: RunMessages,
|
|
4282
|
+
stream_events: bool,
|
|
4065
4283
|
) -> Iterator[TeamRunOutputEvent]:
|
|
4066
|
-
if
|
|
4067
|
-
yield
|
|
4284
|
+
if stream_events:
|
|
4285
|
+
yield handle_event( # type: ignore
|
|
4286
|
+
create_team_reasoning_started_event(from_run_response=run_response),
|
|
4287
|
+
run_response,
|
|
4288
|
+
events_to_skip=self.events_to_skip,
|
|
4289
|
+
store_events=self.store_events,
|
|
4290
|
+
)
|
|
4068
4291
|
|
|
4069
4292
|
use_default_reasoning = False
|
|
4070
4293
|
|
|
@@ -4185,14 +4408,16 @@ class Team:
|
|
|
4185
4408
|
reasoning_steps=[ReasoningStep(result=reasoning_message.content)],
|
|
4186
4409
|
reasoning_agent_messages=[reasoning_message],
|
|
4187
4410
|
)
|
|
4188
|
-
if
|
|
4189
|
-
yield
|
|
4411
|
+
if stream_events:
|
|
4412
|
+
yield handle_event( # type: ignore
|
|
4190
4413
|
create_team_reasoning_completed_event(
|
|
4191
4414
|
from_run_response=run_response,
|
|
4192
4415
|
content=ReasoningSteps(reasoning_steps=[ReasoningStep(result=reasoning_message.content)]),
|
|
4193
4416
|
content_type=ReasoningSteps.__name__,
|
|
4194
4417
|
),
|
|
4195
4418
|
run_response,
|
|
4419
|
+
events_to_skip=self.events_to_skip,
|
|
4420
|
+
store_events=self.store_events,
|
|
4196
4421
|
)
|
|
4197
4422
|
else:
|
|
4198
4423
|
log_warning(
|
|
@@ -4270,19 +4495,21 @@ class Team:
|
|
|
4270
4495
|
reasoning_steps: List[ReasoningStep] = reasoning_agent_response.content.reasoning_steps
|
|
4271
4496
|
all_reasoning_steps.extend(reasoning_steps)
|
|
4272
4497
|
# Yield reasoning steps
|
|
4273
|
-
if
|
|
4498
|
+
if stream_events:
|
|
4274
4499
|
for reasoning_step in reasoning_steps:
|
|
4275
4500
|
updated_reasoning_content = self._format_reasoning_step_content(
|
|
4276
4501
|
run_response, reasoning_step
|
|
4277
4502
|
)
|
|
4278
4503
|
|
|
4279
|
-
yield
|
|
4504
|
+
yield handle_event( # type: ignore
|
|
4280
4505
|
create_team_reasoning_step_event(
|
|
4281
4506
|
from_run_response=run_response,
|
|
4282
4507
|
reasoning_step=reasoning_step,
|
|
4283
4508
|
reasoning_content=updated_reasoning_content,
|
|
4284
4509
|
),
|
|
4285
4510
|
run_response,
|
|
4511
|
+
events_to_skip=self.events_to_skip,
|
|
4512
|
+
store_events=self.store_events,
|
|
4286
4513
|
)
|
|
4287
4514
|
|
|
4288
4515
|
# Find the index of the first assistant message
|
|
@@ -4318,23 +4545,31 @@ class Team:
|
|
|
4318
4545
|
)
|
|
4319
4546
|
|
|
4320
4547
|
# Yield the final reasoning completed event
|
|
4321
|
-
if
|
|
4322
|
-
yield
|
|
4548
|
+
if stream_events:
|
|
4549
|
+
yield handle_event( # type: ignore
|
|
4323
4550
|
create_team_reasoning_completed_event(
|
|
4324
4551
|
from_run_response=run_response,
|
|
4325
4552
|
content=ReasoningSteps(reasoning_steps=all_reasoning_steps),
|
|
4326
4553
|
content_type=ReasoningSteps.__name__,
|
|
4327
4554
|
),
|
|
4328
4555
|
run_response,
|
|
4556
|
+
events_to_skip=self.events_to_skip,
|
|
4557
|
+
store_events=self.store_events,
|
|
4329
4558
|
)
|
|
4330
4559
|
|
|
4331
4560
|
async def _areason(
|
|
4332
4561
|
self,
|
|
4333
4562
|
run_response: TeamRunOutput,
|
|
4334
4563
|
run_messages: RunMessages,
|
|
4564
|
+
stream_events: bool,
|
|
4335
4565
|
) -> AsyncIterator[TeamRunOutputEvent]:
|
|
4336
|
-
if
|
|
4337
|
-
yield
|
|
4566
|
+
if stream_events:
|
|
4567
|
+
yield handle_event( # type: ignore
|
|
4568
|
+
create_team_reasoning_started_event(from_run_response=run_response),
|
|
4569
|
+
run_response,
|
|
4570
|
+
events_to_skip=self.events_to_skip,
|
|
4571
|
+
store_events=self.store_events,
|
|
4572
|
+
)
|
|
4338
4573
|
|
|
4339
4574
|
use_default_reasoning = False
|
|
4340
4575
|
|
|
@@ -4454,14 +4689,16 @@ class Team:
|
|
|
4454
4689
|
reasoning_steps=[ReasoningStep(result=reasoning_message.content)],
|
|
4455
4690
|
reasoning_agent_messages=[reasoning_message],
|
|
4456
4691
|
)
|
|
4457
|
-
if
|
|
4458
|
-
yield
|
|
4692
|
+
if stream_events:
|
|
4693
|
+
yield handle_event( # type: ignore
|
|
4459
4694
|
create_team_reasoning_completed_event(
|
|
4460
4695
|
from_run_response=run_response,
|
|
4461
4696
|
content=ReasoningSteps(reasoning_steps=[ReasoningStep(result=reasoning_message.content)]),
|
|
4462
4697
|
content_type=ReasoningSteps.__name__,
|
|
4463
4698
|
),
|
|
4464
4699
|
run_response,
|
|
4700
|
+
events_to_skip=self.events_to_skip,
|
|
4701
|
+
store_events=self.store_events,
|
|
4465
4702
|
)
|
|
4466
4703
|
else:
|
|
4467
4704
|
log_warning(
|
|
@@ -4538,19 +4775,21 @@ class Team:
|
|
|
4538
4775
|
reasoning_steps: List[ReasoningStep] = reasoning_agent_response.content.reasoning_steps
|
|
4539
4776
|
all_reasoning_steps.extend(reasoning_steps)
|
|
4540
4777
|
# Yield reasoning steps
|
|
4541
|
-
if
|
|
4778
|
+
if stream_events:
|
|
4542
4779
|
for reasoning_step in reasoning_steps:
|
|
4543
4780
|
updated_reasoning_content = self._format_reasoning_step_content(
|
|
4544
4781
|
run_response, reasoning_step
|
|
4545
4782
|
)
|
|
4546
4783
|
|
|
4547
|
-
yield
|
|
4784
|
+
yield handle_event( # type: ignore
|
|
4548
4785
|
create_team_reasoning_step_event(
|
|
4549
4786
|
from_run_response=run_response,
|
|
4550
4787
|
reasoning_step=reasoning_step,
|
|
4551
4788
|
reasoning_content=updated_reasoning_content,
|
|
4552
4789
|
),
|
|
4553
4790
|
run_response,
|
|
4791
|
+
events_to_skip=self.events_to_skip,
|
|
4792
|
+
store_events=self.store_events,
|
|
4554
4793
|
)
|
|
4555
4794
|
|
|
4556
4795
|
# Find the index of the first assistant message
|
|
@@ -4586,14 +4825,16 @@ class Team:
|
|
|
4586
4825
|
)
|
|
4587
4826
|
|
|
4588
4827
|
# Yield the final reasoning completed event
|
|
4589
|
-
if
|
|
4590
|
-
yield
|
|
4828
|
+
if stream_events:
|
|
4829
|
+
yield handle_event( # type: ignore # type: ignore
|
|
4591
4830
|
create_team_reasoning_completed_event(
|
|
4592
4831
|
from_run_response=run_response,
|
|
4593
4832
|
content=ReasoningSteps(reasoning_steps=all_reasoning_steps),
|
|
4594
4833
|
content_type=ReasoningSteps.__name__,
|
|
4595
4834
|
),
|
|
4596
4835
|
run_response,
|
|
4836
|
+
events_to_skip=self.events_to_skip,
|
|
4837
|
+
store_events=self.store_events,
|
|
4597
4838
|
)
|
|
4598
4839
|
|
|
4599
4840
|
def _resolve_run_dependencies(self, dependencies: Optional[Dict[str, Any]] = None) -> None:
|
|
@@ -4641,137 +4882,6 @@ class Team:
|
|
|
4641
4882
|
except Exception as e:
|
|
4642
4883
|
log_warning(f"Failed to resolve context for '{key}': {e}")
|
|
4643
4884
|
|
|
4644
|
-
def _collect_joint_images(
|
|
4645
|
-
self,
|
|
4646
|
-
run_input: Optional[TeamRunInput] = None,
|
|
4647
|
-
session: Optional[TeamSession] = None,
|
|
4648
|
-
) -> Optional[Sequence[Image]]:
|
|
4649
|
-
"""Collect images from input, session history, and current run response."""
|
|
4650
|
-
joint_images: List[Image] = []
|
|
4651
|
-
|
|
4652
|
-
# 1. Add images from current input
|
|
4653
|
-
if run_input and run_input.images:
|
|
4654
|
-
joint_images.extend(run_input.images)
|
|
4655
|
-
log_debug(f"Added {len(run_input.images)} input images to joint list")
|
|
4656
|
-
|
|
4657
|
-
# 2. Add images from session history (from both input and generated sources)
|
|
4658
|
-
try:
|
|
4659
|
-
if session and session.runs:
|
|
4660
|
-
for historical_run in session.runs:
|
|
4661
|
-
# Add generated images from previous runs
|
|
4662
|
-
if historical_run.images:
|
|
4663
|
-
joint_images.extend(historical_run.images)
|
|
4664
|
-
log_debug(
|
|
4665
|
-
f"Added {len(historical_run.images)} generated images from historical run {historical_run.run_id}"
|
|
4666
|
-
)
|
|
4667
|
-
|
|
4668
|
-
# Add input images from previous runs
|
|
4669
|
-
if historical_run.input and historical_run.input.images:
|
|
4670
|
-
joint_images.extend(historical_run.input.images)
|
|
4671
|
-
log_debug(
|
|
4672
|
-
f"Added {len(historical_run.input.images)} input images from historical run {historical_run.run_id}"
|
|
4673
|
-
)
|
|
4674
|
-
except Exception as e:
|
|
4675
|
-
log_debug(f"Could not access session history for images: {e}")
|
|
4676
|
-
|
|
4677
|
-
if joint_images:
|
|
4678
|
-
log_debug(f"Images Available to Model: {len(joint_images)} images")
|
|
4679
|
-
return joint_images if joint_images else None
|
|
4680
|
-
|
|
4681
|
-
def _collect_joint_videos(
|
|
4682
|
-
self,
|
|
4683
|
-
run_input: Optional[TeamRunInput] = None,
|
|
4684
|
-
session: Optional[TeamSession] = None,
|
|
4685
|
-
) -> Optional[Sequence[Video]]:
|
|
4686
|
-
"""Collect videos from input, session history, and current run response."""
|
|
4687
|
-
joint_videos: List[Video] = []
|
|
4688
|
-
|
|
4689
|
-
# 1. Add videos from current input
|
|
4690
|
-
if run_input and run_input.videos:
|
|
4691
|
-
joint_videos.extend(run_input.videos)
|
|
4692
|
-
log_debug(f"Added {len(run_input.videos)} input videos to joint list")
|
|
4693
|
-
|
|
4694
|
-
# 2. Add videos from session history (from both input and generated sources)
|
|
4695
|
-
try:
|
|
4696
|
-
if session and session.runs:
|
|
4697
|
-
for historical_run in session.runs:
|
|
4698
|
-
# Add generated videos from previous runs
|
|
4699
|
-
if historical_run.videos:
|
|
4700
|
-
joint_videos.extend(historical_run.videos)
|
|
4701
|
-
log_debug(
|
|
4702
|
-
f"Added {len(historical_run.videos)} generated videos from historical run {historical_run.run_id}"
|
|
4703
|
-
)
|
|
4704
|
-
|
|
4705
|
-
# Add input videos from previous runs
|
|
4706
|
-
if historical_run.input and historical_run.input.videos:
|
|
4707
|
-
joint_videos.extend(historical_run.input.videos)
|
|
4708
|
-
log_debug(
|
|
4709
|
-
f"Added {len(historical_run.input.videos)} input videos from historical run {historical_run.run_id}"
|
|
4710
|
-
)
|
|
4711
|
-
except Exception as e:
|
|
4712
|
-
log_debug(f"Could not access session history for videos: {e}")
|
|
4713
|
-
|
|
4714
|
-
if joint_videos:
|
|
4715
|
-
log_debug(f"Videos Available to Model: {len(joint_videos)} videos")
|
|
4716
|
-
return joint_videos if joint_videos else None
|
|
4717
|
-
|
|
4718
|
-
def _collect_joint_audios(
|
|
4719
|
-
self,
|
|
4720
|
-
run_input: Optional[TeamRunInput] = None,
|
|
4721
|
-
session: Optional[TeamSession] = None,
|
|
4722
|
-
) -> Optional[Sequence[Audio]]:
|
|
4723
|
-
"""Collect audios from input, session history, and current run response."""
|
|
4724
|
-
joint_audios: List[Audio] = []
|
|
4725
|
-
|
|
4726
|
-
# 1. Add audios from current input
|
|
4727
|
-
if run_input and run_input.audios:
|
|
4728
|
-
joint_audios.extend(run_input.audios)
|
|
4729
|
-
log_debug(f"Added {len(run_input.audios)} input audios to joint list")
|
|
4730
|
-
|
|
4731
|
-
# 2. Add audios from session history (from both input and generated sources)
|
|
4732
|
-
try:
|
|
4733
|
-
if session and session.runs:
|
|
4734
|
-
for historical_run in session.runs:
|
|
4735
|
-
# Add generated audios from previous runs
|
|
4736
|
-
if historical_run.audio:
|
|
4737
|
-
joint_audios.extend(historical_run.audio)
|
|
4738
|
-
log_debug(
|
|
4739
|
-
f"Added {len(historical_run.audio)} generated audios from historical run {historical_run.run_id}"
|
|
4740
|
-
)
|
|
4741
|
-
|
|
4742
|
-
# Add input audios from previous runs
|
|
4743
|
-
if historical_run.input and historical_run.input.audios:
|
|
4744
|
-
joint_audios.extend(historical_run.input.audios)
|
|
4745
|
-
log_debug(
|
|
4746
|
-
f"Added {len(historical_run.input.audios)} input audios from historical run {historical_run.run_id}"
|
|
4747
|
-
)
|
|
4748
|
-
except Exception as e:
|
|
4749
|
-
log_debug(f"Could not access session history for audios: {e}")
|
|
4750
|
-
|
|
4751
|
-
if joint_audios:
|
|
4752
|
-
log_debug(f"Audios Available to Model: {len(joint_audios)} audios")
|
|
4753
|
-
return joint_audios if joint_audios else None
|
|
4754
|
-
|
|
4755
|
-
def _collect_joint_files(
|
|
4756
|
-
self,
|
|
4757
|
-
run_input: Optional[TeamRunInput] = None,
|
|
4758
|
-
) -> Optional[Sequence[File]]:
|
|
4759
|
-
"""Collect files from input and session history."""
|
|
4760
|
-
from agno.utils.log import log_debug
|
|
4761
|
-
|
|
4762
|
-
joint_files: List[File] = []
|
|
4763
|
-
|
|
4764
|
-
# 1. Add files from current input
|
|
4765
|
-
if run_input and run_input.files:
|
|
4766
|
-
joint_files.extend(run_input.files)
|
|
4767
|
-
|
|
4768
|
-
# TODO: Files aren't stored in session history yet and dont have a FileArtifact
|
|
4769
|
-
|
|
4770
|
-
if joint_files:
|
|
4771
|
-
log_debug(f"Files Available to Model: {len(joint_files)} files")
|
|
4772
|
-
|
|
4773
|
-
return joint_files if joint_files else None
|
|
4774
|
-
|
|
4775
4885
|
def determine_tools_for_model(
|
|
4776
4886
|
self,
|
|
4777
4887
|
model: Model,
|
|
@@ -4802,14 +4912,14 @@ class Team:
|
|
|
4802
4912
|
for tool in self.tools:
|
|
4803
4913
|
_tools.append(tool)
|
|
4804
4914
|
|
|
4805
|
-
if self.
|
|
4806
|
-
_tools.append(self.
|
|
4915
|
+
if self.read_chat_history:
|
|
4916
|
+
_tools.append(self._get_chat_history_function(session=session, async_mode=async_mode))
|
|
4807
4917
|
|
|
4808
4918
|
if self.memory_manager is not None and self.enable_agentic_memory:
|
|
4809
4919
|
_tools.append(self._get_update_user_memory_function(user_id=user_id, async_mode=async_mode))
|
|
4810
4920
|
|
|
4811
4921
|
if self.enable_agentic_state:
|
|
4812
|
-
_tools.append(self.
|
|
4922
|
+
_tools.append(Function(name="update_session_state", entrypoint=self._update_session_state_tool))
|
|
4813
4923
|
|
|
4814
4924
|
if self.search_session_history:
|
|
4815
4925
|
_tools.append(
|
|
@@ -4848,7 +4958,7 @@ class Team:
|
|
|
4848
4958
|
|
|
4849
4959
|
if self.members:
|
|
4850
4960
|
# Get the user message if we are using the input directly
|
|
4851
|
-
|
|
4961
|
+
user_message_content = None
|
|
4852
4962
|
if self.determine_input_for_members is False:
|
|
4853
4963
|
user_message = self._get_user_message(
|
|
4854
4964
|
run_response=run_response,
|
|
@@ -4863,16 +4973,17 @@ class Team:
|
|
|
4863
4973
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
4864
4974
|
metadata=metadata,
|
|
4865
4975
|
)
|
|
4976
|
+
user_message_content = user_message.content if user_message is not None else None
|
|
4866
4977
|
|
|
4867
4978
|
delegate_task_func = self._get_delegate_task_function(
|
|
4868
4979
|
run_response=run_response,
|
|
4869
4980
|
session=session,
|
|
4870
4981
|
session_state=session_state,
|
|
4871
4982
|
team_run_context=team_run_context,
|
|
4872
|
-
input=
|
|
4983
|
+
input=user_message_content,
|
|
4873
4984
|
user_id=user_id,
|
|
4874
4985
|
stream=self.stream or False,
|
|
4875
|
-
|
|
4986
|
+
stream_events=self.stream_events or False,
|
|
4876
4987
|
async_mode=async_mode,
|
|
4877
4988
|
images=images, # type: ignore
|
|
4878
4989
|
videos=videos, # type: ignore
|
|
@@ -4983,10 +5094,10 @@ class Team:
|
|
|
4983
5094
|
|
|
4984
5095
|
if needs_media:
|
|
4985
5096
|
# Only collect media if functions actually need them
|
|
4986
|
-
joint_images =
|
|
4987
|
-
joint_files =
|
|
4988
|
-
joint_audios =
|
|
4989
|
-
joint_videos =
|
|
5097
|
+
joint_images = collect_joint_images(run_response.input, session) # type: ignore
|
|
5098
|
+
joint_files = collect_joint_files(run_response.input) # type: ignore
|
|
5099
|
+
joint_audios = collect_joint_audios(run_response.input, session) # type: ignore
|
|
5100
|
+
joint_videos = collect_joint_videos(run_response.input, session) # type: ignore
|
|
4990
5101
|
|
|
4991
5102
|
for func in self._functions_for_model.values():
|
|
4992
5103
|
func._images = joint_images
|
|
@@ -5183,12 +5294,11 @@ class Team:
|
|
|
5183
5294
|
"- You cannot use a member tool directly. You can only delegate tasks to members.\n"
|
|
5184
5295
|
"- When you delegate a task to another member, make sure to include:\n"
|
|
5185
5296
|
" - 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.\n"
|
|
5186
|
-
" -
|
|
5187
|
-
" - expected_output (str): The expected output.\n"
|
|
5297
|
+
" - task (str): A clear description of the task. Determine the best way to describe the task to the member.\n"
|
|
5188
5298
|
"- You can delegate tasks to multiple members at once.\n"
|
|
5189
5299
|
"- You must always analyze the responses from members before responding to the user.\n"
|
|
5190
5300
|
"- After analyzing the responses from the members, if you feel the task has been completed, you can stop and respond to the user.\n"
|
|
5191
|
-
"- If you are
|
|
5301
|
+
"- If you are NOT satisfied with the responses from the members, you should re-assign the task to a different member.\n"
|
|
5192
5302
|
"- For simple greetings, thanks, or questions about the team itself, you should respond directly.\n"
|
|
5193
5303
|
"- For all work requests, tasks, or questions requiring expertise, route to appropriate team members.\n"
|
|
5194
5304
|
)
|
|
@@ -5477,8 +5587,7 @@ class Team:
|
|
|
5477
5587
|
"- You cannot use a member tool directly. You can only delegate tasks to members.\n"
|
|
5478
5588
|
"- When you delegate a task to another member, make sure to include:\n"
|
|
5479
5589
|
" - 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.\n"
|
|
5480
|
-
" -
|
|
5481
|
-
" - expected_output (str): The expected output.\n"
|
|
5590
|
+
" - task (str): A clear description of the task.\n"
|
|
5482
5591
|
"- You can delegate tasks to multiple members at once.\n"
|
|
5483
5592
|
"- You must always analyze the responses from members before responding to the user.\n"
|
|
5484
5593
|
"- After analyzing the responses from the members, if you feel the task has been completed, you can stop and respond to the user.\n"
|
|
@@ -5727,13 +5836,16 @@ class Team:
|
|
|
5727
5836
|
for _msg in history_copy:
|
|
5728
5837
|
_msg.from_history = True
|
|
5729
5838
|
|
|
5839
|
+
# Filter tool calls from history messages
|
|
5840
|
+
if self.max_tool_calls_from_history is not None:
|
|
5841
|
+
filter_tool_calls(history_copy, self.max_tool_calls_from_history)
|
|
5842
|
+
|
|
5730
5843
|
log_debug(f"Adding {len(history_copy)} messages from history")
|
|
5731
5844
|
|
|
5732
5845
|
# Extend the messages with the history
|
|
5733
5846
|
run_messages.messages += history_copy
|
|
5734
5847
|
|
|
5735
5848
|
# 5. Add user message to run_messages (message second as per Dirk's requirement)
|
|
5736
|
-
user_message: Optional[Message] = None
|
|
5737
5849
|
# 5.1 Build user message if message is None, str or list
|
|
5738
5850
|
user_message = self._get_user_message(
|
|
5739
5851
|
run_response=run_response,
|
|
@@ -5855,13 +5967,16 @@ class Team:
|
|
|
5855
5967
|
for _msg in history_copy:
|
|
5856
5968
|
_msg.from_history = True
|
|
5857
5969
|
|
|
5970
|
+
# Filter tool calls from history messages
|
|
5971
|
+
if self.max_tool_calls_from_history is not None:
|
|
5972
|
+
filter_tool_calls(history_copy, self.max_tool_calls_from_history)
|
|
5973
|
+
|
|
5858
5974
|
log_debug(f"Adding {len(history_copy)} messages from history")
|
|
5859
5975
|
|
|
5860
5976
|
# Extend the messages with the history
|
|
5861
5977
|
run_messages.messages += history_copy
|
|
5862
5978
|
|
|
5863
5979
|
# 5. Add user message to run_messages (message second as per Dirk's requirement)
|
|
5864
|
-
user_message: Optional[Message] = None
|
|
5865
5980
|
# 5.1 Build user message if message is None, str or list
|
|
5866
5981
|
user_message = self._get_user_message(
|
|
5867
5982
|
run_response=run_response,
|
|
@@ -6305,10 +6420,15 @@ class Team:
|
|
|
6305
6420
|
"""Get information about the members of the team, including their IDs, names, and roles."""
|
|
6306
6421
|
return self.get_members_system_message_content(indent=0)
|
|
6307
6422
|
|
|
6308
|
-
def
|
|
6309
|
-
def
|
|
6423
|
+
def _get_chat_history_function(self, session: TeamSession, async_mode: bool = False):
|
|
6424
|
+
def get_chat_history(num_chats: Optional[int] = None) -> str:
|
|
6310
6425
|
"""
|
|
6311
|
-
Use this function to get the team chat history.
|
|
6426
|
+
Use this function to get the team chat history in reverse chronological order.
|
|
6427
|
+
Leave the num_chats parameter blank to get the entire chat history.
|
|
6428
|
+
Example:
|
|
6429
|
+
- To get the last chat, use num_chats=1
|
|
6430
|
+
- To get the last 5 chats, use num_chats=5
|
|
6431
|
+
- To get all chats, leave num_chats blank
|
|
6312
6432
|
|
|
6313
6433
|
Args:
|
|
6314
6434
|
num_chats: The number of chats to return.
|
|
@@ -6317,12 +6437,42 @@ class Team:
|
|
|
6317
6437
|
|
|
6318
6438
|
Returns:
|
|
6319
6439
|
str: A JSON string containing a list of dictionaries representing the team chat history.
|
|
6440
|
+
"""
|
|
6441
|
+
import json
|
|
6442
|
+
|
|
6443
|
+
history: List[Dict[str, Any]] = []
|
|
6444
|
+
|
|
6445
|
+
all_chats = session.get_messages_from_last_n_runs(
|
|
6446
|
+
team_id=self.id,
|
|
6447
|
+
)
|
|
6448
|
+
|
|
6449
|
+
if len(all_chats) == 0:
|
|
6450
|
+
return ""
|
|
6451
|
+
|
|
6452
|
+
for chat in all_chats[::-1]: # type: ignore
|
|
6453
|
+
history.insert(0, chat.to_dict()) # type: ignore
|
|
6454
|
+
|
|
6455
|
+
if num_chats is not None:
|
|
6456
|
+
history = history[:num_chats]
|
|
6457
|
+
|
|
6458
|
+
return json.dumps(history)
|
|
6320
6459
|
|
|
6460
|
+
async def aget_chat_history(num_chats: Optional[int] = None) -> str:
|
|
6461
|
+
"""
|
|
6462
|
+
Use this function to get the team chat history in reverse chronological order.
|
|
6463
|
+
Leave the num_chats parameter blank to get the entire chat history.
|
|
6321
6464
|
Example:
|
|
6322
6465
|
- To get the last chat, use num_chats=1
|
|
6323
6466
|
- To get the last 5 chats, use num_chats=5
|
|
6324
|
-
- To get all chats,
|
|
6325
|
-
|
|
6467
|
+
- To get all chats, leave num_chats blank
|
|
6468
|
+
|
|
6469
|
+
Args:
|
|
6470
|
+
num_chats: The number of chats to return.
|
|
6471
|
+
Each chat contains 2 messages. One from the team and one from the user.
|
|
6472
|
+
Default: None
|
|
6473
|
+
|
|
6474
|
+
Returns:
|
|
6475
|
+
str: A JSON string containing a list of dictionaries representing the team chat history.
|
|
6326
6476
|
"""
|
|
6327
6477
|
import json
|
|
6328
6478
|
|
|
@@ -6343,9 +6493,13 @@ class Team:
|
|
|
6343
6493
|
|
|
6344
6494
|
return json.dumps(history)
|
|
6345
6495
|
|
|
6346
|
-
|
|
6496
|
+
if async_mode:
|
|
6497
|
+
get_chat_history_func = aget_chat_history
|
|
6498
|
+
else:
|
|
6499
|
+
get_chat_history_func = get_chat_history # type: ignore
|
|
6500
|
+
return Function.from_callable(get_chat_history_func, name="get_chat_history")
|
|
6347
6501
|
|
|
6348
|
-
def
|
|
6502
|
+
def _update_session_state_tool(self, session_state, session_state_updates: dict) -> str:
|
|
6349
6503
|
"""
|
|
6350
6504
|
Update the shared session state. Provide any updates as a dictionary of key-value pairs.
|
|
6351
6505
|
Example:
|
|
@@ -6361,7 +6515,7 @@ class Team:
|
|
|
6361
6515
|
|
|
6362
6516
|
def _get_previous_sessions_messages_function(
|
|
6363
6517
|
self, num_history_sessions: Optional[int] = 2, user_id: Optional[str] = None
|
|
6364
|
-
)
|
|
6518
|
+
):
|
|
6365
6519
|
"""Factory function to create a get_previous_session_messages function.
|
|
6366
6520
|
|
|
6367
6521
|
Args:
|
|
@@ -6477,9 +6631,9 @@ class Team:
|
|
|
6477
6631
|
return json.dumps([msg.to_dict() for msg in all_messages]) if all_messages else "No history found"
|
|
6478
6632
|
|
|
6479
6633
|
if self._has_async_db():
|
|
6480
|
-
return aget_previous_session_messages
|
|
6634
|
+
return Function.from_callable(aget_previous_session_messages, name="get_previous_session_messages")
|
|
6481
6635
|
else:
|
|
6482
|
-
return get_previous_session_messages
|
|
6636
|
+
return Function.from_callable(get_previous_session_messages, name="get_previous_session_messages")
|
|
6483
6637
|
|
|
6484
6638
|
def _get_history_for_member_agent(self, session: TeamSession, member_agent: Union[Agent, "Team"]) -> List[Message]:
|
|
6485
6639
|
from copy import deepcopy
|
|
@@ -6514,7 +6668,12 @@ class Team:
|
|
|
6514
6668
|
return []
|
|
6515
6669
|
|
|
6516
6670
|
def _determine_team_member_interactions(
|
|
6517
|
-
self,
|
|
6671
|
+
self,
|
|
6672
|
+
team_run_context: Dict[str, Any],
|
|
6673
|
+
images: List[Image],
|
|
6674
|
+
videos: List[Video],
|
|
6675
|
+
audio: List[Audio],
|
|
6676
|
+
files: List[File],
|
|
6518
6677
|
) -> Optional[str]:
|
|
6519
6678
|
team_member_interactions_str = None
|
|
6520
6679
|
if self.share_member_interactions:
|
|
@@ -6525,6 +6684,8 @@ class Team:
|
|
|
6525
6684
|
videos.extend(context_videos)
|
|
6526
6685
|
if context_audio := self._get_team_run_context_audio(team_run_context=team_run_context): # type: ignore
|
|
6527
6686
|
audio.extend(context_audio)
|
|
6687
|
+
if context_files := self._get_team_run_context_files(team_run_context=team_run_context): # type: ignore
|
|
6688
|
+
files.extend(context_files)
|
|
6528
6689
|
return team_member_interactions_str
|
|
6529
6690
|
|
|
6530
6691
|
def _find_member_by_id(self, member_id: str) -> Optional[Tuple[int, Union[Agent, "Team"]]]:
|
|
@@ -6562,9 +6723,9 @@ class Team:
|
|
|
6562
6723
|
team_run_context: Dict[str, Any],
|
|
6563
6724
|
user_id: Optional[str] = None,
|
|
6564
6725
|
stream: bool = False,
|
|
6565
|
-
|
|
6726
|
+
stream_events: bool = False,
|
|
6566
6727
|
async_mode: bool = False,
|
|
6567
|
-
input: Optional[
|
|
6728
|
+
input: Optional[str] = None, # Used for determine_input_for_members=False
|
|
6568
6729
|
images: Optional[List[Image]] = None,
|
|
6569
6730
|
videos: Optional[List[Video]] = None,
|
|
6570
6731
|
audio: Optional[List[Audio]] = None,
|
|
@@ -6586,54 +6747,54 @@ class Team:
|
|
|
6586
6747
|
if not files:
|
|
6587
6748
|
files = []
|
|
6588
6749
|
|
|
6589
|
-
def _setup_delegate_task_to_member(
|
|
6590
|
-
member_agent: Union[Agent, "Team"], task_description: str, expected_output: Optional[str] = None
|
|
6591
|
-
):
|
|
6750
|
+
def _setup_delegate_task_to_member(member_agent: Union[Agent, "Team"], task_description: str):
|
|
6592
6751
|
# 1. Initialize the member agent
|
|
6593
6752
|
self._initialize_member(member_agent)
|
|
6594
6753
|
|
|
6595
|
-
# 2.
|
|
6754
|
+
# 2. Handle respond_directly nuances
|
|
6755
|
+
if self.respond_directly:
|
|
6756
|
+
# Since we return the response directly from the member agent, we need to set the output schema from the team down.
|
|
6757
|
+
if not member_agent.output_schema and self.output_schema:
|
|
6758
|
+
member_agent.output_schema = self.output_schema
|
|
6759
|
+
|
|
6760
|
+
# If the member will produce structured output, we need to parse the response
|
|
6761
|
+
if member_agent.output_schema is not None:
|
|
6762
|
+
self._member_response_model = member_agent.output_schema
|
|
6763
|
+
|
|
6764
|
+
# 3. Handle enable_agentic_knowledge_filters on the member agent
|
|
6765
|
+
if self.enable_agentic_knowledge_filters and not member_agent.enable_agentic_knowledge_filters:
|
|
6766
|
+
member_agent.enable_agentic_knowledge_filters = self.enable_agentic_knowledge_filters
|
|
6767
|
+
|
|
6768
|
+
# 4. Determine team context to send
|
|
6596
6769
|
team_member_interactions_str = self._determine_team_member_interactions(
|
|
6597
|
-
team_run_context, images, videos, audio
|
|
6770
|
+
team_run_context, images=images, videos=videos, audio=audio, files=files
|
|
6598
6771
|
)
|
|
6599
6772
|
|
|
6600
|
-
|
|
6773
|
+
# 5. Get the team history
|
|
6774
|
+
team_history_str = None
|
|
6775
|
+
if self.add_team_history_to_members and session:
|
|
6776
|
+
team_history_str = session.get_team_history_context(num_runs=self.num_team_history_runs)
|
|
6601
6777
|
|
|
6602
|
-
#
|
|
6778
|
+
# 6. Create the member agent task or use the input directly
|
|
6603
6779
|
if self.determine_input_for_members is False:
|
|
6604
6780
|
member_agent_task = input # type: ignore
|
|
6605
6781
|
else:
|
|
6606
|
-
|
|
6607
|
-
if member_agent.expected_output is not None:
|
|
6608
|
-
expected_output = None
|
|
6782
|
+
member_agent_task = task_description
|
|
6609
6783
|
|
|
6784
|
+
if team_history_str or team_member_interactions_str:
|
|
6610
6785
|
member_agent_task = format_member_agent_task( # type: ignore
|
|
6611
|
-
task_description
|
|
6786
|
+
task_description=member_agent_task or "",
|
|
6787
|
+
team_member_interactions_str=team_member_interactions_str,
|
|
6788
|
+
team_history_str=team_history_str,
|
|
6612
6789
|
)
|
|
6613
6790
|
|
|
6614
|
-
#
|
|
6791
|
+
# 7. Add member-level history for the member if enabled (because we won't load the session for the member, so history won't be loaded automatically)
|
|
6615
6792
|
history = None
|
|
6616
|
-
if member_agent.add_history_to_context
|
|
6793
|
+
if member_agent.add_history_to_context:
|
|
6617
6794
|
history = self._get_history_for_member_agent(session, member_agent)
|
|
6618
6795
|
if history:
|
|
6619
6796
|
if isinstance(member_agent_task, str):
|
|
6620
6797
|
history.append(Message(role="user", content=member_agent_task))
|
|
6621
|
-
else:
|
|
6622
|
-
history.append(member_agent_task)
|
|
6623
|
-
|
|
6624
|
-
# 5. Handle respond_directly
|
|
6625
|
-
if self.respond_directly:
|
|
6626
|
-
# Since we return the response directly from the member agent, we need to set the output schema from the team down.
|
|
6627
|
-
if not member_agent.output_schema and self.output_schema:
|
|
6628
|
-
member_agent.output_schema = self.output_schema
|
|
6629
|
-
|
|
6630
|
-
# If the member will produce structured output, we need to parse the response
|
|
6631
|
-
if member_agent.output_schema is not None:
|
|
6632
|
-
self._member_response_model = member_agent.output_schema
|
|
6633
|
-
|
|
6634
|
-
# 6. Handle enable_agentic_knowledge_filters on the member agent
|
|
6635
|
-
if self.enable_agentic_knowledge_filters and not member_agent.enable_agentic_knowledge_filters:
|
|
6636
|
-
member_agent.enable_agentic_knowledge_filters = self.enable_agentic_knowledge_filters
|
|
6637
6798
|
|
|
6638
6799
|
return member_agent_task, history
|
|
6639
6800
|
|
|
@@ -6692,28 +6853,28 @@ class Team:
|
|
|
6692
6853
|
self._update_team_media(member_agent_run_response) # type: ignore
|
|
6693
6854
|
|
|
6694
6855
|
def delegate_task_to_member(
|
|
6695
|
-
member_id: str,
|
|
6856
|
+
member_id: str, task: str
|
|
6696
6857
|
) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
6697
6858
|
"""Use this function to delegate a task to the selected team member.
|
|
6698
6859
|
You must provide a clear and concise description of the task the member should achieve AND the expected output.
|
|
6699
6860
|
|
|
6700
6861
|
Args:
|
|
6701
6862
|
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.
|
|
6702
|
-
|
|
6703
|
-
expected_output (str, optional): The expected output from the member (optional).
|
|
6863
|
+
task (str): A clear and concise description of the task the member should achieve.
|
|
6704
6864
|
Returns:
|
|
6705
6865
|
str: The result of the delegated task.
|
|
6706
6866
|
"""
|
|
6707
6867
|
|
|
6708
6868
|
# Find the member agent using the helper function
|
|
6709
6869
|
result = self._find_member_by_id(member_id)
|
|
6710
|
-
history = None
|
|
6711
6870
|
if result is None:
|
|
6712
6871
|
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)}"
|
|
6713
6872
|
return
|
|
6714
6873
|
|
|
6715
6874
|
_, member_agent = result
|
|
6716
|
-
member_agent_task, history = _setup_delegate_task_to_member(
|
|
6875
|
+
member_agent_task, history = _setup_delegate_task_to_member(
|
|
6876
|
+
member_agent=member_agent, task_description=task
|
|
6877
|
+
)
|
|
6717
6878
|
|
|
6718
6879
|
# Make sure for the member agent, we are using the agent logger
|
|
6719
6880
|
use_agent_logger()
|
|
@@ -6731,7 +6892,7 @@ class Team:
|
|
|
6731
6892
|
audio=audio,
|
|
6732
6893
|
files=files,
|
|
6733
6894
|
stream=True,
|
|
6734
|
-
|
|
6895
|
+
stream_events=stream_events,
|
|
6735
6896
|
debug_mode=debug_mode,
|
|
6736
6897
|
dependencies=dependencies,
|
|
6737
6898
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
@@ -6818,28 +6979,28 @@ class Team:
|
|
|
6818
6979
|
)
|
|
6819
6980
|
|
|
6820
6981
|
async def adelegate_task_to_member(
|
|
6821
|
-
member_id: str,
|
|
6982
|
+
member_id: str, task: str
|
|
6822
6983
|
) -> AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
6823
6984
|
"""Use this function to delegate a task to the selected team member.
|
|
6824
6985
|
You must provide a clear and concise description of the task the member should achieve AND the expected output.
|
|
6825
6986
|
|
|
6826
6987
|
Args:
|
|
6827
6988
|
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.
|
|
6828
|
-
|
|
6829
|
-
expected_output (str, optional): The expected output from the member (optional).
|
|
6989
|
+
task (str): A clear and concise description of the task the member should achieve.
|
|
6830
6990
|
Returns:
|
|
6831
6991
|
str: The result of the delegated task.
|
|
6832
6992
|
"""
|
|
6833
6993
|
|
|
6834
6994
|
# Find the member agent using the helper function
|
|
6835
6995
|
result = self._find_member_by_id(member_id)
|
|
6836
|
-
history = None
|
|
6837
6996
|
if result is None:
|
|
6838
6997
|
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)}"
|
|
6839
6998
|
return
|
|
6840
6999
|
|
|
6841
7000
|
_, member_agent = result
|
|
6842
|
-
member_agent_task, history = _setup_delegate_task_to_member(
|
|
7001
|
+
member_agent_task, history = _setup_delegate_task_to_member(
|
|
7002
|
+
member_agent=member_agent, task_description=task
|
|
7003
|
+
)
|
|
6843
7004
|
|
|
6844
7005
|
# Make sure for the member agent, we are using the agent logger
|
|
6845
7006
|
use_agent_logger()
|
|
@@ -6857,7 +7018,7 @@ class Team:
|
|
|
6857
7018
|
audio=audio,
|
|
6858
7019
|
files=files,
|
|
6859
7020
|
stream=True,
|
|
6860
|
-
|
|
7021
|
+
stream_events=stream_events,
|
|
6861
7022
|
debug_mode=debug_mode,
|
|
6862
7023
|
dependencies=dependencies,
|
|
6863
7024
|
add_dependencies_to_context=add_dependencies_to_context,
|
|
@@ -6940,16 +7101,13 @@ class Team:
|
|
|
6940
7101
|
)
|
|
6941
7102
|
|
|
6942
7103
|
# When the task should be delegated to all members
|
|
6943
|
-
def delegate_task_to_members(
|
|
6944
|
-
task_description: str, expected_output: Optional[str] = None
|
|
6945
|
-
) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
7104
|
+
def delegate_task_to_members(task: str) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
6946
7105
|
"""
|
|
6947
7106
|
Use this function to delegate a task to all the member agents and return a response.
|
|
6948
7107
|
You must provide a clear and concise description of the task the member should achieve AND the expected output.
|
|
6949
7108
|
|
|
6950
7109
|
Args:
|
|
6951
|
-
|
|
6952
|
-
expected_output (str, optional): The expected output from the member agents (optional).
|
|
7110
|
+
task (str): A clear and concise description of the task to send to member agents.
|
|
6953
7111
|
Returns:
|
|
6954
7112
|
str: The result of the delegated task.
|
|
6955
7113
|
"""
|
|
@@ -6957,7 +7115,7 @@ class Team:
|
|
|
6957
7115
|
# Run all the members sequentially
|
|
6958
7116
|
for _, member_agent in enumerate(self.members):
|
|
6959
7117
|
member_agent_task, history = _setup_delegate_task_to_member(
|
|
6960
|
-
member_agent, task_description
|
|
7118
|
+
member_agent=member_agent, task_description=task
|
|
6961
7119
|
)
|
|
6962
7120
|
|
|
6963
7121
|
member_session_state_copy = copy(session_state)
|
|
@@ -6973,7 +7131,7 @@ class Team:
|
|
|
6973
7131
|
audio=audio,
|
|
6974
7132
|
files=files,
|
|
6975
7133
|
stream=True,
|
|
6976
|
-
|
|
7134
|
+
stream_events=stream_events,
|
|
6977
7135
|
knowledge_filters=knowledge_filters
|
|
6978
7136
|
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
6979
7137
|
else None,
|
|
@@ -7055,15 +7213,12 @@ class Team:
|
|
|
7055
7213
|
use_team_logger()
|
|
7056
7214
|
|
|
7057
7215
|
# When the task should be delegated to all members
|
|
7058
|
-
async def adelegate_task_to_members(
|
|
7059
|
-
task_description: str, expected_output: Optional[str] = None
|
|
7060
|
-
) -> AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
7216
|
+
async def adelegate_task_to_members(task: str) -> AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent, str]]:
|
|
7061
7217
|
"""Use this function to delegate a task to all the member agents and return a response.
|
|
7062
|
-
You must provide a clear and concise description of the task to send to member agents
|
|
7218
|
+
You must provide a clear and concise description of the task to send to member agents.
|
|
7063
7219
|
|
|
7064
7220
|
Args:
|
|
7065
|
-
|
|
7066
|
-
expected_output (str, optional): The expected output from the member agents (optional).
|
|
7221
|
+
task (str): A clear and concise description of the task to send to member agents.
|
|
7067
7222
|
Returns:
|
|
7068
7223
|
str: The result of the delegated task.
|
|
7069
7224
|
"""
|
|
@@ -7075,8 +7230,8 @@ class Team:
|
|
|
7075
7230
|
|
|
7076
7231
|
async def stream_member(agent: Union[Agent, "Team"]) -> None:
|
|
7077
7232
|
member_agent_task, history = _setup_delegate_task_to_member(
|
|
7078
|
-
agent, task_description
|
|
7079
|
-
)
|
|
7233
|
+
member_agent=agent, task_description=task
|
|
7234
|
+
) # type: ignore
|
|
7080
7235
|
member_session_state_copy = copy(session_state)
|
|
7081
7236
|
|
|
7082
7237
|
member_stream = agent.arun( # type: ignore
|
|
@@ -7089,7 +7244,7 @@ class Team:
|
|
|
7089
7244
|
audio=audio,
|
|
7090
7245
|
files=files,
|
|
7091
7246
|
stream=True,
|
|
7092
|
-
|
|
7247
|
+
stream_events=stream_events,
|
|
7093
7248
|
debug_mode=debug_mode,
|
|
7094
7249
|
knowledge_filters=knowledge_filters
|
|
7095
7250
|
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
@@ -7150,7 +7305,7 @@ class Team:
|
|
|
7150
7305
|
for member_agent_index, member_agent in enumerate(self.members):
|
|
7151
7306
|
current_agent = member_agent
|
|
7152
7307
|
member_agent_task, history = _setup_delegate_task_to_member(
|
|
7153
|
-
current_agent, task_description
|
|
7308
|
+
member_agent=current_agent, task_description=task
|
|
7154
7309
|
)
|
|
7155
7310
|
|
|
7156
7311
|
async def run_member_agent(agent=current_agent) -> str:
|
|
@@ -7166,7 +7321,7 @@ class Team:
|
|
|
7166
7321
|
audio=audio,
|
|
7167
7322
|
files=files,
|
|
7168
7323
|
stream=False,
|
|
7169
|
-
|
|
7324
|
+
stream_events=stream_events,
|
|
7170
7325
|
debug_mode=debug_mode,
|
|
7171
7326
|
knowledge_filters=knowledge_filters
|
|
7172
7327
|
if not member_agent.knowledge_filters and member_agent.knowledge
|
|
@@ -7240,24 +7395,28 @@ class Team:
|
|
|
7240
7395
|
###########################################################################
|
|
7241
7396
|
# Session Management
|
|
7242
7397
|
###########################################################################
|
|
7243
|
-
def _read_session(
|
|
7398
|
+
def _read_session(
|
|
7399
|
+
self, session_id: str, session_type: SessionType = SessionType.TEAM
|
|
7400
|
+
) -> Optional[Union[TeamSession, WorkflowSession]]:
|
|
7244
7401
|
"""Get a Session from the database."""
|
|
7245
7402
|
try:
|
|
7246
7403
|
if not self.db:
|
|
7247
7404
|
raise ValueError("Db not initialized")
|
|
7248
|
-
session = self.db.get_session(session_id=session_id, session_type=
|
|
7405
|
+
session = self.db.get_session(session_id=session_id, session_type=session_type)
|
|
7249
7406
|
return session # type: ignore
|
|
7250
7407
|
except Exception as e:
|
|
7251
7408
|
log_warning(f"Error getting session from db: {e}")
|
|
7252
7409
|
return None
|
|
7253
7410
|
|
|
7254
|
-
async def _aread_session(
|
|
7411
|
+
async def _aread_session(
|
|
7412
|
+
self, session_id: str, session_type: SessionType = SessionType.TEAM
|
|
7413
|
+
) -> Optional[Union[TeamSession, WorkflowSession]]:
|
|
7255
7414
|
"""Get a Session from the database."""
|
|
7256
7415
|
try:
|
|
7257
7416
|
if not self.db:
|
|
7258
7417
|
raise ValueError("Db not initialized")
|
|
7259
7418
|
self.db = cast(AsyncBaseDb, self.db)
|
|
7260
|
-
session = await self.db.get_session(session_id=session_id, session_type=
|
|
7419
|
+
session = await self.db.get_session(session_id=session_id, session_type=session_type)
|
|
7261
7420
|
return session # type: ignore
|
|
7262
7421
|
except Exception as e:
|
|
7263
7422
|
log_warning(f"Error getting session from db: {e}")
|
|
@@ -7358,12 +7517,17 @@ class Team:
|
|
|
7358
7517
|
# Create new session if none found
|
|
7359
7518
|
if team_session is None:
|
|
7360
7519
|
log_debug(f"Creating new TeamSession: {session_id}")
|
|
7520
|
+
session_data = {}
|
|
7521
|
+
if self.session_state is not None:
|
|
7522
|
+
from copy import deepcopy
|
|
7523
|
+
|
|
7524
|
+
session_data["session_state"] = deepcopy(self.session_state)
|
|
7361
7525
|
team_session = TeamSession(
|
|
7362
7526
|
session_id=session_id,
|
|
7363
7527
|
team_id=self.id,
|
|
7364
7528
|
user_id=user_id,
|
|
7365
7529
|
team_data=self._get_team_data(),
|
|
7366
|
-
session_data=
|
|
7530
|
+
session_data=session_data,
|
|
7367
7531
|
metadata=self.metadata,
|
|
7368
7532
|
created_at=int(time()),
|
|
7369
7533
|
)
|
|
@@ -7439,7 +7603,48 @@ class Team:
|
|
|
7439
7603
|
|
|
7440
7604
|
# Load and return the session from the database
|
|
7441
7605
|
if self.db is not None:
|
|
7442
|
-
|
|
7606
|
+
loaded_session = None
|
|
7607
|
+
# We have a standalone team, so we are loading a TeamSession
|
|
7608
|
+
if self.workflow_id is None:
|
|
7609
|
+
loaded_session = cast(TeamSession, self._read_session(session_id=session_id_to_load)) # type: ignore
|
|
7610
|
+
# We have a workflow team, so we are loading a WorkflowSession
|
|
7611
|
+
else:
|
|
7612
|
+
loaded_session = cast(WorkflowSession, self._read_session(session_id=session_id_to_load)) # type: ignore
|
|
7613
|
+
|
|
7614
|
+
# Cache the session if relevant
|
|
7615
|
+
if loaded_session is not None and self.cache_session:
|
|
7616
|
+
self._agent_session = loaded_session
|
|
7617
|
+
|
|
7618
|
+
return loaded_session
|
|
7619
|
+
|
|
7620
|
+
log_debug(f"TeamSession {session_id_to_load} not found in db")
|
|
7621
|
+
return None
|
|
7622
|
+
|
|
7623
|
+
async def aget_session(
|
|
7624
|
+
self,
|
|
7625
|
+
session_id: Optional[str] = None,
|
|
7626
|
+
) -> Optional[TeamSession]:
|
|
7627
|
+
"""Load an TeamSession from database.
|
|
7628
|
+
|
|
7629
|
+
Args:
|
|
7630
|
+
session_id: The session_id to load from storage.
|
|
7631
|
+
|
|
7632
|
+
Returns:
|
|
7633
|
+
TeamSession: The TeamSession loaded from the database or created if it does not exist.
|
|
7634
|
+
"""
|
|
7635
|
+
if not session_id and not self.session_id:
|
|
7636
|
+
return None
|
|
7637
|
+
|
|
7638
|
+
session_id_to_load = session_id or self.session_id
|
|
7639
|
+
|
|
7640
|
+
# If there is a cached session, return it
|
|
7641
|
+
if self.cache_session and hasattr(self, "_team_session") and self._team_session is not None:
|
|
7642
|
+
if self._team_session.session_id == session_id_to_load:
|
|
7643
|
+
return self._team_session
|
|
7644
|
+
|
|
7645
|
+
# Load and return the session from the database
|
|
7646
|
+
if self.db is not None:
|
|
7647
|
+
team_session = cast(TeamSession, await self._aread_session(session_id=session_id_to_load)) # type: ignore
|
|
7443
7648
|
|
|
7444
7649
|
# Cache the session if relevant
|
|
7445
7650
|
if team_session is not None and self.cache_session:
|
|
@@ -7478,7 +7683,17 @@ class Team:
|
|
|
7478
7683
|
session.session_data["session_state"].pop("current_session_id", None) # type: ignore
|
|
7479
7684
|
session.session_data["session_state"].pop("current_user_id", None) # type: ignore
|
|
7480
7685
|
session.session_data["session_state"].pop("current_run_id", None) # type: ignore
|
|
7481
|
-
|
|
7686
|
+
|
|
7687
|
+
# scrub the member responses if not storing them
|
|
7688
|
+
if not self.store_member_responses and session.runs is not None:
|
|
7689
|
+
for run in session.runs:
|
|
7690
|
+
if hasattr(run, "member_responses"):
|
|
7691
|
+
run.member_responses = []
|
|
7692
|
+
|
|
7693
|
+
if self._has_async_db():
|
|
7694
|
+
await self._aupsert_session(session=session)
|
|
7695
|
+
else:
|
|
7696
|
+
self._upsert_session(session=session)
|
|
7482
7697
|
log_debug(f"Created or updated TeamSession record: {session.session_id}")
|
|
7483
7698
|
|
|
7484
7699
|
def _load_session_state(self, session: TeamSession, session_state: Dict[str, Any]) -> Dict[str, Any]:
|
|
@@ -7608,6 +7823,60 @@ class Team:
|
|
|
7608
7823
|
raise Exception("Session not found")
|
|
7609
7824
|
return session.session_data.get("session_state", {}) if session.session_data is not None else {}
|
|
7610
7825
|
|
|
7826
|
+
def update_session_state(self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None) -> str:
|
|
7827
|
+
"""
|
|
7828
|
+
Update the session state for the given session ID and user ID.
|
|
7829
|
+
Args:
|
|
7830
|
+
session_state_updates: The updates to apply to the session state. Should be a dictionary of key-value pairs.
|
|
7831
|
+
session_id: The session ID to update. If not provided, the current cached session ID is used.
|
|
7832
|
+
Returns:
|
|
7833
|
+
dict: The updated session state.
|
|
7834
|
+
"""
|
|
7835
|
+
session_id = session_id or self.session_id
|
|
7836
|
+
if session_id is None:
|
|
7837
|
+
raise Exception("Session ID is not set")
|
|
7838
|
+
session = self.get_session(session_id=session_id) # type: ignore
|
|
7839
|
+
if session is None:
|
|
7840
|
+
raise Exception("Session not found")
|
|
7841
|
+
|
|
7842
|
+
if session.session_data is not None and "session_state" not in session.session_data:
|
|
7843
|
+
session.session_data["session_state"] = {}
|
|
7844
|
+
|
|
7845
|
+
for key, value in session_state_updates.items():
|
|
7846
|
+
session.session_data["session_state"][key] = value # type: ignore
|
|
7847
|
+
|
|
7848
|
+
self.save_session(session=session)
|
|
7849
|
+
|
|
7850
|
+
return session.session_data["session_state"] # type: ignore
|
|
7851
|
+
|
|
7852
|
+
async def aupdate_session_state(
|
|
7853
|
+
self, session_state_updates: Dict[str, Any], session_id: Optional[str] = None
|
|
7854
|
+
) -> str:
|
|
7855
|
+
"""
|
|
7856
|
+
Update the session state for the given session ID and user ID.
|
|
7857
|
+
Args:
|
|
7858
|
+
session_state_updates: The updates to apply to the session state. Should be a dictionary of key-value pairs.
|
|
7859
|
+
session_id: The session ID to update. If not provided, the current cached session ID is used.
|
|
7860
|
+
Returns:
|
|
7861
|
+
dict: The updated session state.
|
|
7862
|
+
"""
|
|
7863
|
+
session_id = session_id or self.session_id
|
|
7864
|
+
if session_id is None:
|
|
7865
|
+
raise Exception("Session ID is not set")
|
|
7866
|
+
session = await self.aget_session(session_id=session_id) # type: ignore
|
|
7867
|
+
if session is None:
|
|
7868
|
+
raise Exception("Session not found")
|
|
7869
|
+
|
|
7870
|
+
if session.session_data is not None and "session_state" not in session.session_data:
|
|
7871
|
+
session.session_data["session_state"] = {}
|
|
7872
|
+
|
|
7873
|
+
for key, value in session_state_updates.items():
|
|
7874
|
+
session.session_data["session_state"][key] = value # type: ignore
|
|
7875
|
+
|
|
7876
|
+
await self.asave_session(session=session)
|
|
7877
|
+
|
|
7878
|
+
return session.session_data["session_state"] # type: ignore
|
|
7879
|
+
|
|
7611
7880
|
def get_session_metrics(self, session_id: Optional[str] = None) -> Optional[Metrics]:
|
|
7612
7881
|
"""Get the session metrics for the given session ID and user ID."""
|
|
7613
7882
|
session_id = session_id or self.session_id
|
|
@@ -7708,7 +7977,9 @@ class Team:
|
|
|
7708
7977
|
return ""
|
|
7709
7978
|
team_member_interactions_str = ""
|
|
7710
7979
|
if "member_responses" in team_run_context:
|
|
7711
|
-
team_member_interactions_str +=
|
|
7980
|
+
team_member_interactions_str += (
|
|
7981
|
+
"<member_interaction_context>\nSee below interactions wit other team members.\n"
|
|
7982
|
+
)
|
|
7712
7983
|
|
|
7713
7984
|
for interaction in team_run_context["member_responses"]:
|
|
7714
7985
|
response_dict = interaction["run_response"].to_dict()
|
|
@@ -7721,7 +7992,7 @@ class Team:
|
|
|
7721
7992
|
team_member_interactions_str += f"Task: {interaction['task']}\n"
|
|
7722
7993
|
team_member_interactions_str += f"Response: {response_content}\n"
|
|
7723
7994
|
team_member_interactions_str += "\n"
|
|
7724
|
-
team_member_interactions_str += "</
|
|
7995
|
+
team_member_interactions_str += "</member_interaction_context>\n"
|
|
7725
7996
|
return team_member_interactions_str
|
|
7726
7997
|
|
|
7727
7998
|
def _get_team_run_context_images(self, team_run_context: Dict[str, Any]) -> List[Image]:
|
|
@@ -7754,6 +8025,16 @@ class Team:
|
|
|
7754
8025
|
audio.extend(interaction["run_response"].audio)
|
|
7755
8026
|
return audio
|
|
7756
8027
|
|
|
8028
|
+
def _get_team_run_context_files(self, team_run_context: Dict[str, Any]) -> List[File]:
|
|
8029
|
+
if not team_run_context:
|
|
8030
|
+
return []
|
|
8031
|
+
files = []
|
|
8032
|
+
if "member_responses" in team_run_context:
|
|
8033
|
+
for interaction in team_run_context["member_responses"]:
|
|
8034
|
+
if interaction["run_response"].files:
|
|
8035
|
+
files.extend(interaction["run_response"].files)
|
|
8036
|
+
return files
|
|
8037
|
+
|
|
7757
8038
|
###########################################################################
|
|
7758
8039
|
# Handle images, videos and audio
|
|
7759
8040
|
###########################################################################
|