agno 2.3.4__py3-none-any.whl → 2.3.6__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 +184 -45
- agno/culture/manager.py +2 -2
- agno/db/base.py +330 -8
- agno/db/dynamo/dynamo.py +722 -2
- agno/db/dynamo/schemas.py +127 -0
- agno/db/firestore/firestore.py +573 -1
- agno/db/firestore/schemas.py +40 -0
- agno/db/gcs_json/gcs_json_db.py +446 -1
- agno/db/in_memory/in_memory_db.py +143 -1
- agno/db/json/json_db.py +438 -1
- agno/db/mongo/async_mongo.py +522 -0
- agno/db/mongo/mongo.py +523 -1
- agno/db/mongo/schemas.py +29 -0
- agno/db/mysql/mysql.py +536 -3
- agno/db/mysql/schemas.py +38 -0
- agno/db/postgres/async_postgres.py +553 -15
- agno/db/postgres/postgres.py +544 -5
- agno/db/postgres/schemas.py +38 -0
- agno/db/redis/redis.py +468 -1
- agno/db/redis/schemas.py +32 -0
- agno/db/singlestore/schemas.py +38 -0
- agno/db/singlestore/singlestore.py +523 -1
- agno/db/sqlite/async_sqlite.py +549 -10
- agno/db/sqlite/schemas.py +38 -0
- agno/db/sqlite/sqlite.py +540 -9
- agno/db/sqlite/utils.py +6 -8
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +548 -1
- agno/eval/accuracy.py +18 -8
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/exceptions.py +11 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +1 -1
- agno/knowledge/chunking/semantic.py +2 -2
- agno/models/aimlapi/aimlapi.py +2 -3
- agno/models/anthropic/claude.py +18 -13
- agno/models/aws/bedrock.py +3 -4
- agno/models/aws/claude.py +5 -1
- agno/models/azure/ai_foundry.py +2 -2
- agno/models/azure/openai_chat.py +8 -0
- agno/models/cerebras/cerebras.py +62 -11
- agno/models/cerebras/cerebras_openai.py +2 -3
- agno/models/cohere/chat.py +1 -5
- agno/models/cometapi/cometapi.py +2 -3
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +2 -3
- agno/models/deepseek/deepseek.py +2 -3
- agno/models/fireworks/fireworks.py +2 -3
- agno/models/google/gemini.py +9 -7
- agno/models/groq/groq.py +2 -3
- agno/models/huggingface/huggingface.py +1 -5
- agno/models/ibm/watsonx.py +1 -5
- agno/models/internlm/internlm.py +2 -3
- agno/models/langdb/langdb.py +6 -4
- agno/models/litellm/chat.py +2 -2
- agno/models/litellm/litellm_openai.py +2 -3
- agno/models/meta/llama.py +1 -5
- agno/models/meta/llama_openai.py +4 -5
- agno/models/mistral/mistral.py +1 -5
- agno/models/nebius/nebius.py +2 -3
- agno/models/nvidia/nvidia.py +4 -5
- agno/models/openai/chat.py +14 -3
- agno/models/openai/responses.py +14 -3
- agno/models/openrouter/openrouter.py +4 -5
- agno/models/perplexity/perplexity.py +2 -3
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +4 -5
- agno/models/response.py +2 -1
- agno/models/sambanova/sambanova.py +4 -5
- agno/models/siliconflow/siliconflow.py +3 -4
- agno/models/together/together.py +4 -5
- agno/models/vercel/v0.py +4 -5
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +4 -5
- agno/os/app.py +104 -0
- agno/os/config.py +13 -0
- agno/os/interfaces/whatsapp/router.py +0 -1
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/mcp.py +1 -0
- agno/os/router.py +31 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/schema.py +12 -2
- agno/os/utils.py +57 -0
- agno/run/agent.py +1 -0
- agno/run/base.py +17 -0
- agno/run/team.py +4 -0
- agno/table.py +10 -0
- agno/team/team.py +221 -69
- agno/tools/function.py +10 -8
- agno/tools/google_drive.py +4 -3
- agno/tools/nano_banana.py +1 -1
- agno/tools/spotify.py +922 -0
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +6 -6
- agno/utils/hooks.py +56 -1
- agno/utils/mcp.py +1 -1
- agno/vectordb/qdrant/qdrant.py +22 -22
- agno/workflow/condition.py +8 -0
- agno/workflow/loop.py +8 -0
- agno/workflow/parallel.py +8 -0
- agno/workflow/router.py +8 -0
- agno/workflow/step.py +20 -0
- agno/workflow/steps.py +8 -0
- agno/workflow/workflow.py +88 -19
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/METADATA +38 -33
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/RECORD +116 -105
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/WHEEL +0 -0
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/top_level.txt +0 -0
agno/team/team.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import contextlib
|
|
3
5
|
import json
|
|
@@ -76,8 +78,8 @@ from agno.utils.agent import (
|
|
|
76
78
|
aget_session_state_util,
|
|
77
79
|
aset_session_name_util,
|
|
78
80
|
aupdate_session_state_util,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
await_for_open_threads,
|
|
82
|
+
await_for_thread_tasks_stream,
|
|
81
83
|
collect_joint_audios,
|
|
82
84
|
collect_joint_files,
|
|
83
85
|
collect_joint_images,
|
|
@@ -96,8 +98,8 @@ from agno.utils.agent import (
|
|
|
96
98
|
store_media_util,
|
|
97
99
|
update_session_state_util,
|
|
98
100
|
validate_media_object_id,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
wait_for_open_threads,
|
|
102
|
+
wait_for_thread_tasks_stream,
|
|
101
103
|
)
|
|
102
104
|
from agno.utils.common import is_typed_dict, validate_typed_dict
|
|
103
105
|
from agno.utils.events import (
|
|
@@ -122,7 +124,7 @@ from agno.utils.events import (
|
|
|
122
124
|
create_team_tool_call_started_event,
|
|
123
125
|
handle_event,
|
|
124
126
|
)
|
|
125
|
-
from agno.utils.hooks import filter_hook_args, normalize_hooks
|
|
127
|
+
from agno.utils.hooks import copy_args_for_background, filter_hook_args, normalize_hooks, should_run_hook_in_background
|
|
126
128
|
from agno.utils.knowledge import get_agentic_or_user_search_filters
|
|
127
129
|
from agno.utils.log import (
|
|
128
130
|
log_debug,
|
|
@@ -344,6 +346,8 @@ class Team:
|
|
|
344
346
|
pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
|
|
345
347
|
# Functions called after output is generated but before the response is returned
|
|
346
348
|
post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
|
|
349
|
+
# If True, run hooks as FastAPI background tasks (non-blocking). Set by AgentOS.
|
|
350
|
+
_run_hooks_in_background: Optional[bool] = None
|
|
347
351
|
|
|
348
352
|
# --- Structured output ---
|
|
349
353
|
# Input schema for validating input
|
|
@@ -636,7 +640,7 @@ class Team:
|
|
|
636
640
|
self.tool_call_limit = tool_call_limit
|
|
637
641
|
self.tool_hooks = tool_hooks
|
|
638
642
|
|
|
639
|
-
# Initialize hooks
|
|
643
|
+
# Initialize hooks
|
|
640
644
|
self.pre_hooks = pre_hooks
|
|
641
645
|
self.post_hooks = post_hooks
|
|
642
646
|
|
|
@@ -752,8 +756,13 @@ class Team:
|
|
|
752
756
|
self.id = generate_id_from_name(self.name)
|
|
753
757
|
|
|
754
758
|
def _set_debug(self, debug_mode: Optional[bool] = None) -> None:
|
|
759
|
+
# Get the debug level from the environment variable or the default debug level
|
|
760
|
+
debug_level: Literal[1, 2] = (
|
|
761
|
+
cast(Literal[1, 2], int(env)) if (env := getenv("AGNO_DEBUG_LEVEL")) in ("1", "2") else self.debug_level
|
|
762
|
+
)
|
|
763
|
+
# If the default debug mode is set, or passed on run, or via environment variable, set the debug mode to True
|
|
755
764
|
if self.debug_mode or debug_mode or getenv("AGNO_DEBUG", "false").lower() == "true":
|
|
756
|
-
set_log_level_to_debug(source_type="team", level=
|
|
765
|
+
set_log_level_to_debug(source_type="team", level=debug_level)
|
|
757
766
|
else:
|
|
758
767
|
set_log_level_to_info(source_type="team")
|
|
759
768
|
|
|
@@ -837,6 +846,26 @@ class Team:
|
|
|
837
846
|
for sub_member in member.members:
|
|
838
847
|
member._initialize_member(sub_member, debug_mode=debug_mode)
|
|
839
848
|
|
|
849
|
+
def propagate_run_hooks_in_background(self, run_in_background: bool = True) -> None:
|
|
850
|
+
"""
|
|
851
|
+
Propagate _run_hooks_in_background setting to this team and all nested members recursively.
|
|
852
|
+
|
|
853
|
+
This method sets _run_hooks_in_background on the team and all its members (agents and nested teams).
|
|
854
|
+
For nested teams, it recursively propagates the setting to their members as well.
|
|
855
|
+
|
|
856
|
+
Args:
|
|
857
|
+
run_in_background: Whether hooks should run in background. Defaults to True.
|
|
858
|
+
"""
|
|
859
|
+
self._run_hooks_in_background = run_in_background
|
|
860
|
+
|
|
861
|
+
for member in self.members:
|
|
862
|
+
if hasattr(member, "_run_hooks_in_background"):
|
|
863
|
+
member._run_hooks_in_background = run_in_background
|
|
864
|
+
|
|
865
|
+
# If it's a nested team, recursively propagate to its members
|
|
866
|
+
if isinstance(member, Team):
|
|
867
|
+
member.propagate_run_hooks_in_background(run_in_background)
|
|
868
|
+
|
|
840
869
|
def _set_default_model(self) -> None:
|
|
841
870
|
# Set the default model
|
|
842
871
|
if self.model is None:
|
|
@@ -1037,13 +1066,14 @@ class Team:
|
|
|
1037
1066
|
user_id: Optional[str] = None,
|
|
1038
1067
|
debug_mode: Optional[bool] = None,
|
|
1039
1068
|
stream_events: bool = False,
|
|
1069
|
+
background_tasks: Optional[Any] = None,
|
|
1040
1070
|
**kwargs: Any,
|
|
1041
1071
|
) -> Iterator[TeamRunOutputEvent]:
|
|
1042
1072
|
"""Execute multiple pre-hook functions in succession."""
|
|
1043
1073
|
if hooks is None:
|
|
1044
1074
|
return
|
|
1045
1075
|
|
|
1046
|
-
# Prepare
|
|
1076
|
+
# Prepare arguments for hooks
|
|
1047
1077
|
all_args = {
|
|
1048
1078
|
"run_input": run_input,
|
|
1049
1079
|
"run_context": run_context,
|
|
@@ -1055,9 +1085,32 @@ class Team:
|
|
|
1055
1085
|
"dependencies": run_context.dependencies,
|
|
1056
1086
|
"debug_mode": debug_mode or self.debug_mode,
|
|
1057
1087
|
}
|
|
1088
|
+
|
|
1089
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
1090
|
+
# Note: Pre-hooks running in background may not be able to modify run_input
|
|
1091
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
1092
|
+
# Schedule ALL pre_hooks as background tasks
|
|
1093
|
+
# Copy args to prevent race conditions
|
|
1094
|
+
bg_args = copy_args_for_background(all_args)
|
|
1095
|
+
for hook in hooks:
|
|
1096
|
+
# Filter arguments to only include those that the hook accepts
|
|
1097
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1098
|
+
|
|
1099
|
+
# Add to background tasks
|
|
1100
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1101
|
+
return
|
|
1102
|
+
|
|
1058
1103
|
all_args.update(kwargs)
|
|
1059
1104
|
|
|
1060
1105
|
for i, hook in enumerate(hooks):
|
|
1106
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
1107
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
1108
|
+
# Copy args to prevent race conditions
|
|
1109
|
+
bg_args = copy_args_for_background(all_args)
|
|
1110
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1111
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1112
|
+
continue
|
|
1113
|
+
|
|
1061
1114
|
if stream_events:
|
|
1062
1115
|
yield handle_event( # type: ignore
|
|
1063
1116
|
run_response=run_response,
|
|
@@ -1105,13 +1158,14 @@ class Team:
|
|
|
1105
1158
|
user_id: Optional[str] = None,
|
|
1106
1159
|
debug_mode: Optional[bool] = None,
|
|
1107
1160
|
stream_events: bool = False,
|
|
1161
|
+
background_tasks: Optional[Any] = None,
|
|
1108
1162
|
**kwargs: Any,
|
|
1109
1163
|
) -> AsyncIterator[TeamRunOutputEvent]:
|
|
1110
1164
|
"""Execute multiple pre-hook functions in succession (async version)."""
|
|
1111
1165
|
if hooks is None:
|
|
1112
1166
|
return
|
|
1113
1167
|
|
|
1114
|
-
# Prepare
|
|
1168
|
+
# Prepare arguments for hooks
|
|
1115
1169
|
all_args = {
|
|
1116
1170
|
"run_input": run_input,
|
|
1117
1171
|
"run_context": run_context,
|
|
@@ -1123,9 +1177,32 @@ class Team:
|
|
|
1123
1177
|
"metadata": run_context.metadata,
|
|
1124
1178
|
"debug_mode": debug_mode or self.debug_mode,
|
|
1125
1179
|
}
|
|
1180
|
+
|
|
1181
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
1182
|
+
# Note: Pre-hooks running in background may not be able to modify run_input
|
|
1183
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
1184
|
+
# Schedule ALL pre_hooks as background tasks
|
|
1185
|
+
# Copy args to prevent race conditions
|
|
1186
|
+
bg_args = copy_args_for_background(all_args)
|
|
1187
|
+
for hook in hooks:
|
|
1188
|
+
# Filter arguments to only include those that the hook accepts
|
|
1189
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1190
|
+
|
|
1191
|
+
# Add to background tasks (both sync and async hooks supported)
|
|
1192
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1193
|
+
return
|
|
1194
|
+
|
|
1126
1195
|
all_args.update(kwargs)
|
|
1127
1196
|
|
|
1128
1197
|
for i, hook in enumerate(hooks):
|
|
1198
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
1199
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
1200
|
+
# Copy args to prevent race conditions
|
|
1201
|
+
bg_args = copy_args_for_background(all_args)
|
|
1202
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1203
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1204
|
+
continue
|
|
1205
|
+
|
|
1129
1206
|
if stream_events:
|
|
1130
1207
|
yield handle_event( # type: ignore
|
|
1131
1208
|
run_response=run_response,
|
|
@@ -1178,13 +1255,14 @@ class Team:
|
|
|
1178
1255
|
user_id: Optional[str] = None,
|
|
1179
1256
|
debug_mode: Optional[bool] = None,
|
|
1180
1257
|
stream_events: bool = False,
|
|
1258
|
+
background_tasks: Optional[Any] = None,
|
|
1181
1259
|
**kwargs: Any,
|
|
1182
1260
|
) -> Iterator[TeamRunOutputEvent]:
|
|
1183
1261
|
"""Execute multiple post-hook functions in succession."""
|
|
1184
1262
|
if hooks is None:
|
|
1185
1263
|
return
|
|
1186
1264
|
|
|
1187
|
-
# Prepare
|
|
1265
|
+
# Prepare arguments for hooks
|
|
1188
1266
|
all_args = {
|
|
1189
1267
|
"run_output": run_output,
|
|
1190
1268
|
"run_context": run_context,
|
|
@@ -1196,9 +1274,31 @@ class Team:
|
|
|
1196
1274
|
"metadata": run_context.metadata,
|
|
1197
1275
|
"debug_mode": debug_mode or self.debug_mode,
|
|
1198
1276
|
}
|
|
1277
|
+
|
|
1278
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
1279
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
1280
|
+
# Schedule ALL post_hooks as background tasks
|
|
1281
|
+
# Copy args to prevent race conditions
|
|
1282
|
+
bg_args = copy_args_for_background(all_args)
|
|
1283
|
+
for hook in hooks:
|
|
1284
|
+
# Filter arguments to only include those that the hook accepts
|
|
1285
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1286
|
+
|
|
1287
|
+
# Add to background tasks
|
|
1288
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1289
|
+
return
|
|
1290
|
+
|
|
1199
1291
|
all_args.update(kwargs)
|
|
1200
1292
|
|
|
1201
1293
|
for i, hook in enumerate(hooks):
|
|
1294
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
1295
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
1296
|
+
# Copy args to prevent race conditions
|
|
1297
|
+
bg_args = copy_args_for_background(all_args)
|
|
1298
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1299
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1300
|
+
continue
|
|
1301
|
+
|
|
1202
1302
|
if stream_events:
|
|
1203
1303
|
yield handle_event( # type: ignore
|
|
1204
1304
|
run_response=run_output,
|
|
@@ -1241,13 +1341,14 @@ class Team:
|
|
|
1241
1341
|
user_id: Optional[str] = None,
|
|
1242
1342
|
debug_mode: Optional[bool] = None,
|
|
1243
1343
|
stream_events: bool = False,
|
|
1344
|
+
background_tasks: Optional[Any] = None,
|
|
1244
1345
|
**kwargs: Any,
|
|
1245
1346
|
) -> AsyncIterator[TeamRunOutputEvent]:
|
|
1246
1347
|
"""Execute multiple post-hook functions in succession (async version)."""
|
|
1247
1348
|
if hooks is None:
|
|
1248
1349
|
return
|
|
1249
1350
|
|
|
1250
|
-
# Prepare
|
|
1351
|
+
# Prepare arguments for hooks
|
|
1251
1352
|
all_args = {
|
|
1252
1353
|
"run_output": run_output,
|
|
1253
1354
|
"run_context": run_context,
|
|
@@ -1259,9 +1360,31 @@ class Team:
|
|
|
1259
1360
|
"metadata": run_context.metadata,
|
|
1260
1361
|
"debug_mode": debug_mode or self.debug_mode,
|
|
1261
1362
|
}
|
|
1363
|
+
|
|
1364
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
1365
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
1366
|
+
# Schedule ALL post_hooks as background tasks
|
|
1367
|
+
# Copy args to prevent race conditions
|
|
1368
|
+
bg_args = copy_args_for_background(all_args)
|
|
1369
|
+
for hook in hooks:
|
|
1370
|
+
# Filter arguments to only include those that the hook accepts
|
|
1371
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1372
|
+
|
|
1373
|
+
# Add to background tasks (both sync and async hooks supported)
|
|
1374
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1375
|
+
return
|
|
1376
|
+
|
|
1262
1377
|
all_args.update(kwargs)
|
|
1263
1378
|
|
|
1264
1379
|
for i, hook in enumerate(hooks):
|
|
1380
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
1381
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
1382
|
+
# Copy args to prevent race conditions
|
|
1383
|
+
bg_args = copy_args_for_background(all_args)
|
|
1384
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
1385
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
1386
|
+
continue
|
|
1387
|
+
|
|
1265
1388
|
if stream_events:
|
|
1266
1389
|
yield handle_event( # type: ignore
|
|
1267
1390
|
run_response=run_output,
|
|
@@ -1310,6 +1433,7 @@ class Team:
|
|
|
1310
1433
|
add_session_state_to_context: Optional[bool] = None,
|
|
1311
1434
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
1312
1435
|
debug_mode: Optional[bool] = None,
|
|
1436
|
+
background_tasks: Optional[Any] = None,
|
|
1313
1437
|
**kwargs: Any,
|
|
1314
1438
|
) -> TeamRunOutput:
|
|
1315
1439
|
"""Run the Team and return the response.
|
|
@@ -1330,9 +1454,6 @@ class Team:
|
|
|
1330
1454
|
13. Cleanup and store (scrub, stop timer, add to session, calculate metrics, save session)
|
|
1331
1455
|
"""
|
|
1332
1456
|
|
|
1333
|
-
# Register run for cancellation tracking
|
|
1334
|
-
register_run(run_response.run_id) # type: ignore
|
|
1335
|
-
|
|
1336
1457
|
# 1. Execute pre-hooks
|
|
1337
1458
|
run_input = cast(TeamRunInput, run_response.input)
|
|
1338
1459
|
self.model = cast(Model, self.model)
|
|
@@ -1346,6 +1467,7 @@ class Team:
|
|
|
1346
1467
|
session=session,
|
|
1347
1468
|
user_id=user_id,
|
|
1348
1469
|
debug_mode=debug_mode,
|
|
1470
|
+
background_tasks=background_tasks,
|
|
1349
1471
|
**kwargs,
|
|
1350
1472
|
)
|
|
1351
1473
|
# Consume the generator without yielding
|
|
@@ -1458,13 +1580,14 @@ class Team:
|
|
|
1458
1580
|
session=session,
|
|
1459
1581
|
user_id=user_id,
|
|
1460
1582
|
debug_mode=debug_mode,
|
|
1583
|
+
background_tasks=background_tasks,
|
|
1461
1584
|
**kwargs,
|
|
1462
1585
|
)
|
|
1463
1586
|
deque(iterator, maxlen=0)
|
|
1464
1587
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1465
1588
|
|
|
1466
1589
|
# 11. Wait for background memory creation
|
|
1467
|
-
|
|
1590
|
+
wait_for_open_threads(memory_future=memory_future)
|
|
1468
1591
|
|
|
1469
1592
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1470
1593
|
|
|
@@ -1517,6 +1640,7 @@ class Team:
|
|
|
1517
1640
|
stream_events: bool = False,
|
|
1518
1641
|
yield_run_output: bool = False,
|
|
1519
1642
|
debug_mode: Optional[bool] = None,
|
|
1643
|
+
background_tasks: Optional[Any] = None,
|
|
1520
1644
|
**kwargs: Any,
|
|
1521
1645
|
) -> Iterator[Union[TeamRunOutputEvent, RunOutputEvent, TeamRunOutput]]:
|
|
1522
1646
|
"""Run the Team and return the response iterator.
|
|
@@ -1533,8 +1657,6 @@ class Team:
|
|
|
1533
1657
|
9. Create session summary
|
|
1534
1658
|
10. Cleanup and store (scrub, add to session, calculate metrics, save session)
|
|
1535
1659
|
"""
|
|
1536
|
-
# Register run for cancellation tracking
|
|
1537
|
-
register_run(run_response.run_id) # type: ignore
|
|
1538
1660
|
|
|
1539
1661
|
# 1. Execute pre-hooks
|
|
1540
1662
|
run_input = cast(TeamRunInput, run_response.input)
|
|
@@ -1550,6 +1672,7 @@ class Team:
|
|
|
1550
1672
|
user_id=user_id,
|
|
1551
1673
|
debug_mode=debug_mode,
|
|
1552
1674
|
stream_events=stream_events,
|
|
1675
|
+
background_tasks=background_tasks,
|
|
1553
1676
|
**kwargs,
|
|
1554
1677
|
)
|
|
1555
1678
|
for pre_hook_event in pre_hook_iterator:
|
|
@@ -1702,12 +1825,13 @@ class Team:
|
|
|
1702
1825
|
user_id=user_id,
|
|
1703
1826
|
debug_mode=debug_mode,
|
|
1704
1827
|
stream_events=stream_events,
|
|
1828
|
+
background_tasks=background_tasks,
|
|
1705
1829
|
**kwargs,
|
|
1706
1830
|
)
|
|
1707
1831
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1708
1832
|
|
|
1709
1833
|
# 8. Wait for background memory creation
|
|
1710
|
-
yield from
|
|
1834
|
+
yield from wait_for_thread_tasks_stream(
|
|
1711
1835
|
run_response=run_response,
|
|
1712
1836
|
memory_future=memory_future,
|
|
1713
1837
|
stream_events=stream_events,
|
|
@@ -1879,6 +2003,10 @@ class Team:
|
|
|
1879
2003
|
if self._has_async_db():
|
|
1880
2004
|
raise Exception("run() is not supported with an async DB. Please use arun() instead.")
|
|
1881
2005
|
|
|
2006
|
+
# Create a run_id for this specific run and register immediately for cancellation tracking
|
|
2007
|
+
run_id = str(uuid4())
|
|
2008
|
+
register_run(run_id)
|
|
2009
|
+
|
|
1882
2010
|
# Initialize Team
|
|
1883
2011
|
self.initialize_team(debug_mode=debug_mode)
|
|
1884
2012
|
|
|
@@ -1894,8 +2022,11 @@ class Team:
|
|
|
1894
2022
|
stacklevel=2,
|
|
1895
2023
|
)
|
|
1896
2024
|
|
|
1897
|
-
|
|
1898
|
-
|
|
2025
|
+
background_tasks = kwargs.pop("background_tasks", None)
|
|
2026
|
+
if background_tasks is not None:
|
|
2027
|
+
from fastapi import BackgroundTasks
|
|
2028
|
+
|
|
2029
|
+
background_tasks: BackgroundTasks = background_tasks # type: ignore
|
|
1899
2030
|
|
|
1900
2031
|
# Validate input against input_schema if provided
|
|
1901
2032
|
validated_input = self._validate_input(input)
|
|
@@ -1929,7 +2060,10 @@ class Team:
|
|
|
1929
2060
|
|
|
1930
2061
|
# Initialize session state
|
|
1931
2062
|
session_state = self._initialize_session_state(
|
|
1932
|
-
session_state=session_state
|
|
2063
|
+
session_state=session_state if session_state is not None else {},
|
|
2064
|
+
user_id=user_id,
|
|
2065
|
+
session_id=session_id,
|
|
2066
|
+
run_id=run_id,
|
|
1933
2067
|
)
|
|
1934
2068
|
# Update session state from DB
|
|
1935
2069
|
session_state = self._load_session_state(session=team_session, session_state=session_state)
|
|
@@ -2051,6 +2185,7 @@ class Team:
|
|
|
2051
2185
|
stream_events=stream_events,
|
|
2052
2186
|
yield_run_output=yield_run_output,
|
|
2053
2187
|
debug_mode=debug_mode,
|
|
2188
|
+
background_tasks=background_tasks,
|
|
2054
2189
|
**kwargs,
|
|
2055
2190
|
)
|
|
2056
2191
|
|
|
@@ -2066,6 +2201,7 @@ class Team:
|
|
|
2066
2201
|
add_session_state_to_context=add_session_state,
|
|
2067
2202
|
response_format=response_format,
|
|
2068
2203
|
debug_mode=debug_mode,
|
|
2204
|
+
background_tasks=background_tasks,
|
|
2069
2205
|
**kwargs,
|
|
2070
2206
|
)
|
|
2071
2207
|
|
|
@@ -2123,6 +2259,7 @@ class Team:
|
|
|
2123
2259
|
add_session_state_to_context: Optional[bool] = None,
|
|
2124
2260
|
add_history_to_context: Optional[bool] = None,
|
|
2125
2261
|
debug_mode: Optional[bool] = None,
|
|
2262
|
+
background_tasks: Optional[Any] = None,
|
|
2126
2263
|
**kwargs: Any,
|
|
2127
2264
|
) -> TeamRunOutput:
|
|
2128
2265
|
"""Run the Team and return the response.
|
|
@@ -2146,8 +2283,6 @@ class Team:
|
|
|
2146
2283
|
"""
|
|
2147
2284
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2148
2285
|
|
|
2149
|
-
register_run(run_response.run_id) # type: ignore
|
|
2150
|
-
|
|
2151
2286
|
if run_context.dependencies is not None:
|
|
2152
2287
|
await self._aresolve_run_dependencies(run_context=run_context)
|
|
2153
2288
|
|
|
@@ -2161,7 +2296,7 @@ class Team:
|
|
|
2161
2296
|
self._update_metadata(session=team_session)
|
|
2162
2297
|
# Initialize session state
|
|
2163
2298
|
run_context.session_state = self._initialize_session_state(
|
|
2164
|
-
session_state=run_context.session_state
|
|
2299
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
2165
2300
|
user_id=user_id,
|
|
2166
2301
|
session_id=session_id,
|
|
2167
2302
|
run_id=run_response.run_id,
|
|
@@ -2184,6 +2319,7 @@ class Team:
|
|
|
2184
2319
|
session=team_session,
|
|
2185
2320
|
user_id=user_id,
|
|
2186
2321
|
debug_mode=debug_mode,
|
|
2322
|
+
background_tasks=background_tasks,
|
|
2187
2323
|
**kwargs,
|
|
2188
2324
|
)
|
|
2189
2325
|
|
|
@@ -2241,9 +2377,6 @@ class Team:
|
|
|
2241
2377
|
log_debug("Starting memory creation in background task.")
|
|
2242
2378
|
memory_task = asyncio.create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
2243
2379
|
|
|
2244
|
-
# Register run for cancellation tracking
|
|
2245
|
-
register_run(run_response.run_id) # type: ignore
|
|
2246
|
-
|
|
2247
2380
|
try:
|
|
2248
2381
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2249
2382
|
# 7. Reason about the task if reasoning is enabled
|
|
@@ -2299,6 +2432,7 @@ class Team:
|
|
|
2299
2432
|
session=team_session,
|
|
2300
2433
|
user_id=user_id,
|
|
2301
2434
|
debug_mode=debug_mode,
|
|
2435
|
+
background_tasks=background_tasks,
|
|
2302
2436
|
**kwargs,
|
|
2303
2437
|
):
|
|
2304
2438
|
pass
|
|
@@ -2306,7 +2440,7 @@ class Team:
|
|
|
2306
2440
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2307
2441
|
|
|
2308
2442
|
# 13. Wait for background memory creation
|
|
2309
|
-
await
|
|
2443
|
+
await await_for_open_threads(memory_task=memory_task)
|
|
2310
2444
|
|
|
2311
2445
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2312
2446
|
# 14. Create session summary
|
|
@@ -2367,6 +2501,7 @@ class Team:
|
|
|
2367
2501
|
add_session_state_to_context: Optional[bool] = None,
|
|
2368
2502
|
add_history_to_context: Optional[bool] = None,
|
|
2369
2503
|
debug_mode: Optional[bool] = None,
|
|
2504
|
+
background_tasks: Optional[Any] = None,
|
|
2370
2505
|
**kwargs: Any,
|
|
2371
2506
|
) -> AsyncIterator[Union[TeamRunOutputEvent, RunOutputEvent, TeamRunOutput]]:
|
|
2372
2507
|
"""Run the Team and return the response.
|
|
@@ -2401,7 +2536,7 @@ class Team:
|
|
|
2401
2536
|
self._update_metadata(session=team_session)
|
|
2402
2537
|
# Initialize session state
|
|
2403
2538
|
run_context.session_state = self._initialize_session_state(
|
|
2404
|
-
session_state=run_context.session_state
|
|
2539
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
2405
2540
|
user_id=user_id,
|
|
2406
2541
|
session_id=session_id,
|
|
2407
2542
|
run_id=run_response.run_id,
|
|
@@ -2425,6 +2560,7 @@ class Team:
|
|
|
2425
2560
|
user_id=user_id,
|
|
2426
2561
|
debug_mode=debug_mode,
|
|
2427
2562
|
stream_events=stream_events,
|
|
2563
|
+
background_tasks=background_tasks,
|
|
2428
2564
|
**kwargs,
|
|
2429
2565
|
)
|
|
2430
2566
|
async for pre_hook_event in pre_hook_iterator:
|
|
@@ -2477,9 +2613,6 @@ class Team:
|
|
|
2477
2613
|
log_debug("Starting memory creation in background task.")
|
|
2478
2614
|
memory_task = asyncio.create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
2479
2615
|
|
|
2480
|
-
# Register run for cancellation tracking
|
|
2481
|
-
register_run(run_response.run_id) # type: ignore
|
|
2482
|
-
|
|
2483
2616
|
try:
|
|
2484
2617
|
# Considering both stream_events and stream_intermediate_steps (deprecated)
|
|
2485
2618
|
stream_events = stream_events or stream_intermediate_steps
|
|
@@ -2579,13 +2712,14 @@ class Team:
|
|
|
2579
2712
|
user_id=user_id,
|
|
2580
2713
|
debug_mode=debug_mode,
|
|
2581
2714
|
stream_events=stream_events,
|
|
2715
|
+
background_tasks=background_tasks,
|
|
2582
2716
|
**kwargs,
|
|
2583
2717
|
):
|
|
2584
2718
|
yield event
|
|
2585
2719
|
|
|
2586
2720
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2587
2721
|
# 11. Wait for background memory creation
|
|
2588
|
-
async for event in
|
|
2722
|
+
async for event in await_for_thread_tasks_stream(
|
|
2589
2723
|
run_response=run_response,
|
|
2590
2724
|
memory_task=memory_task,
|
|
2591
2725
|
stream_events=stream_events,
|
|
@@ -2767,6 +2901,10 @@ class Team:
|
|
|
2767
2901
|
) -> Union[TeamRunOutput, AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent]]]:
|
|
2768
2902
|
"""Run the Team asynchronously and return the response."""
|
|
2769
2903
|
|
|
2904
|
+
# Create a run_id for this specific run and register immediately for cancellation tracking
|
|
2905
|
+
run_id = str(uuid4())
|
|
2906
|
+
register_run(run_id)
|
|
2907
|
+
|
|
2770
2908
|
if (add_history_to_context or self.add_history_to_context) and not self.db and not self.parent_team_id:
|
|
2771
2909
|
log_warning(
|
|
2772
2910
|
"add_history_to_context is True, but no database has been assigned to the team. History will not be added to the context."
|
|
@@ -2779,8 +2917,11 @@ class Team:
|
|
|
2779
2917
|
stacklevel=2,
|
|
2780
2918
|
)
|
|
2781
2919
|
|
|
2782
|
-
|
|
2783
|
-
|
|
2920
|
+
background_tasks = kwargs.pop("background_tasks", None)
|
|
2921
|
+
if background_tasks is not None:
|
|
2922
|
+
from fastapi import BackgroundTasks
|
|
2923
|
+
|
|
2924
|
+
background_tasks: BackgroundTasks = background_tasks # type: ignore
|
|
2784
2925
|
|
|
2785
2926
|
# Validate input against input_schema if provided
|
|
2786
2927
|
validated_input = self._validate_input(input)
|
|
@@ -2927,6 +3068,7 @@ class Team:
|
|
|
2927
3068
|
stream_events=stream_events,
|
|
2928
3069
|
yield_run_output=yield_run_output,
|
|
2929
3070
|
debug_mode=debug_mode,
|
|
3071
|
+
background_tasks=background_tasks,
|
|
2930
3072
|
**kwargs,
|
|
2931
3073
|
)
|
|
2932
3074
|
return response_iterator # type: ignore
|
|
@@ -2942,6 +3084,7 @@ class Team:
|
|
|
2942
3084
|
add_session_state_to_context=add_session_state,
|
|
2943
3085
|
response_format=response_format,
|
|
2944
3086
|
debug_mode=debug_mode,
|
|
3087
|
+
background_tasks=background_tasks,
|
|
2945
3088
|
**kwargs,
|
|
2946
3089
|
)
|
|
2947
3090
|
|
|
@@ -3047,7 +3190,9 @@ class Team:
|
|
|
3047
3190
|
run_response.messages = messages_for_run_response
|
|
3048
3191
|
|
|
3049
3192
|
# Update the TeamRunOutput metrics
|
|
3050
|
-
run_response.metrics = self._calculate_metrics(
|
|
3193
|
+
run_response.metrics = self._calculate_metrics(
|
|
3194
|
+
messages_for_run_response, current_run_metrics=run_response.metrics
|
|
3195
|
+
)
|
|
3051
3196
|
|
|
3052
3197
|
if model_response.tool_executions:
|
|
3053
3198
|
for tool_call in model_response.tool_executions:
|
|
@@ -3141,7 +3286,9 @@ class Team:
|
|
|
3141
3286
|
# Update the TeamRunOutput messages
|
|
3142
3287
|
run_response.messages = messages_for_run_response
|
|
3143
3288
|
# Update the TeamRunOutput metrics
|
|
3144
|
-
run_response.metrics = self._calculate_metrics(
|
|
3289
|
+
run_response.metrics = self._calculate_metrics(
|
|
3290
|
+
messages_for_run_response, current_run_metrics=run_response.metrics
|
|
3291
|
+
)
|
|
3145
3292
|
|
|
3146
3293
|
# Update the run_response audio if streaming
|
|
3147
3294
|
if full_model_response.audio is not None:
|
|
@@ -3225,7 +3372,9 @@ class Team:
|
|
|
3225
3372
|
# Update the TeamRunOutput messages
|
|
3226
3373
|
run_response.messages = messages_for_run_response
|
|
3227
3374
|
# Update the TeamRunOutput metrics
|
|
3228
|
-
run_response.metrics = self._calculate_metrics(
|
|
3375
|
+
run_response.metrics = self._calculate_metrics(
|
|
3376
|
+
messages_for_run_response, current_run_metrics=run_response.metrics
|
|
3377
|
+
)
|
|
3229
3378
|
|
|
3230
3379
|
if stream_events and reasoning_state["reasoning_started"]:
|
|
3231
3380
|
all_reasoning_steps: List[ReasoningStep] = []
|
|
@@ -3600,7 +3749,7 @@ class Team:
|
|
|
3600
3749
|
session.upsert_run(run_response=run_response)
|
|
3601
3750
|
|
|
3602
3751
|
# Calculate session metrics
|
|
3603
|
-
self._update_session_metrics(session=session)
|
|
3752
|
+
self._update_session_metrics(session=session, run_response=run_response)
|
|
3604
3753
|
|
|
3605
3754
|
# Save session to memory
|
|
3606
3755
|
self.save_session(session=session)
|
|
@@ -3617,7 +3766,7 @@ class Team:
|
|
|
3617
3766
|
session.upsert_run(run_response=run_response)
|
|
3618
3767
|
|
|
3619
3768
|
# Calculate session metrics
|
|
3620
|
-
self._update_session_metrics(session=session)
|
|
3769
|
+
self._update_session_metrics(session=session, run_response=run_response)
|
|
3621
3770
|
|
|
3622
3771
|
# Save session to memory
|
|
3623
3772
|
await self.asave_session(session=session)
|
|
@@ -3957,7 +4106,9 @@ class Team:
|
|
|
3957
4106
|
# Update the RunResponse messages
|
|
3958
4107
|
run_response.messages = messages_for_run_response
|
|
3959
4108
|
# Update the RunResponse metrics
|
|
3960
|
-
run_response.metrics = self._calculate_metrics(
|
|
4109
|
+
run_response.metrics = self._calculate_metrics(
|
|
4110
|
+
messages_for_run_response, current_run_metrics=run_response.metrics
|
|
4111
|
+
)
|
|
3961
4112
|
|
|
3962
4113
|
async def _agenerate_response_with_output_model(
|
|
3963
4114
|
self, model_response: ModelResponse, run_messages: RunMessages
|
|
@@ -4022,7 +4173,9 @@ class Team:
|
|
|
4022
4173
|
# Update the RunResponse messages
|
|
4023
4174
|
run_response.messages = messages_for_run_response
|
|
4024
4175
|
# Update the RunResponse metrics
|
|
4025
|
-
run_response.metrics = self._calculate_metrics(
|
|
4176
|
+
run_response.metrics = self._calculate_metrics(
|
|
4177
|
+
messages_for_run_response, current_run_metrics=run_response.metrics
|
|
4178
|
+
)
|
|
4026
4179
|
|
|
4027
4180
|
def _handle_event(
|
|
4028
4181
|
self,
|
|
@@ -4458,42 +4611,41 @@ class Team:
|
|
|
4458
4611
|
async for item in reason_generator:
|
|
4459
4612
|
yield item
|
|
4460
4613
|
|
|
4461
|
-
def
|
|
4462
|
-
|
|
4463
|
-
session_metrics = Metrics()
|
|
4464
|
-
assistant_message_role = self.model.assistant_message_role if self.model is not None else "assistant"
|
|
4465
|
-
|
|
4466
|
-
# Get metrics of the team leader's messages
|
|
4467
|
-
for m in messages:
|
|
4468
|
-
if m.role == assistant_message_role and m.metrics is not None:
|
|
4469
|
-
session_metrics += m.metrics
|
|
4470
|
-
|
|
4471
|
-
return session_metrics
|
|
4472
|
-
|
|
4473
|
-
def _calculate_metrics(self, messages: List[Message]) -> Metrics:
|
|
4474
|
-
metrics = Metrics()
|
|
4614
|
+
def _calculate_metrics(self, messages: List[Message], current_run_metrics: Optional[Metrics] = None) -> Metrics:
|
|
4615
|
+
metrics = current_run_metrics or Metrics()
|
|
4475
4616
|
assistant_message_role = self.model.assistant_message_role if self.model is not None else "assistant"
|
|
4476
4617
|
|
|
4477
4618
|
for m in messages:
|
|
4478
4619
|
if m.role == assistant_message_role and m.metrics is not None and m.from_history is False:
|
|
4479
4620
|
metrics += m.metrics
|
|
4480
4621
|
|
|
4481
|
-
|
|
4622
|
+
# If the run metrics were already initialized, keep the time related metrics
|
|
4623
|
+
if current_run_metrics is not None:
|
|
4624
|
+
metrics.timer = current_run_metrics.timer
|
|
4625
|
+
metrics.duration = current_run_metrics.duration
|
|
4626
|
+
metrics.time_to_first_token = current_run_metrics.time_to_first_token
|
|
4482
4627
|
|
|
4483
|
-
|
|
4484
|
-
"""Calculate session metrics"""
|
|
4628
|
+
return metrics
|
|
4485
4629
|
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4630
|
+
def _get_session_metrics(self, session: TeamSession) -> Metrics:
|
|
4631
|
+
# Get the session_metrics from the database
|
|
4632
|
+
if session.session_data is not None and "session_metrics" in session.session_data:
|
|
4633
|
+
session_metrics_from_db = session.session_data.get("session_metrics")
|
|
4634
|
+
if session_metrics_from_db is not None:
|
|
4635
|
+
if isinstance(session_metrics_from_db, dict):
|
|
4636
|
+
return Metrics(**session_metrics_from_db)
|
|
4637
|
+
elif isinstance(session_metrics_from_db, Metrics):
|
|
4638
|
+
return session_metrics_from_db
|
|
4493
4639
|
|
|
4494
|
-
|
|
4495
|
-
session_metrics = self._calculate_session_metrics(session_messages)
|
|
4640
|
+
return Metrics()
|
|
4496
4641
|
|
|
4642
|
+
def _update_session_metrics(self, session: TeamSession, run_response: TeamRunOutput):
|
|
4643
|
+
"""Calculate session metrics"""
|
|
4644
|
+
session_metrics = self._get_session_metrics(session=session)
|
|
4645
|
+
# Add the metrics for the current run to the session metrics
|
|
4646
|
+
if run_response.metrics is not None:
|
|
4647
|
+
session_metrics += run_response.metrics
|
|
4648
|
+
session_metrics.time_to_first_token = None
|
|
4497
4649
|
if session.session_data is not None:
|
|
4498
4650
|
session.session_data["session_metrics"] = session_metrics
|
|
4499
4651
|
|
|
@@ -6728,7 +6880,7 @@ class Team:
|
|
|
6728
6880
|
return message
|
|
6729
6881
|
# Should already be resolved and passed from run() method
|
|
6730
6882
|
format_variables = ChainMap(
|
|
6731
|
-
session_state
|
|
6883
|
+
session_state if session_state is not None else {},
|
|
6732
6884
|
dependencies or {},
|
|
6733
6885
|
metadata or {},
|
|
6734
6886
|
{"user_id": user_id} if user_id is not None else {},
|