agno 2.3.7__py3-none-any.whl → 2.3.9__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 +391 -335
- agno/db/mongo/async_mongo.py +0 -24
- agno/db/mongo/mongo.py +0 -16
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2888 -0
- agno/db/mysql/mysql.py +17 -27
- agno/db/mysql/utils.py +139 -6
- agno/db/postgres/async_postgres.py +10 -26
- agno/db/postgres/postgres.py +7 -25
- agno/db/redis/redis.py +0 -4
- agno/db/schemas/evals.py +1 -0
- agno/db/singlestore/singlestore.py +5 -12
- agno/db/sqlite/async_sqlite.py +2 -26
- agno/db/sqlite/sqlite.py +0 -20
- agno/eval/__init__.py +10 -0
- agno/eval/agent_as_judge.py +860 -0
- agno/eval/base.py +29 -0
- agno/eval/utils.py +2 -1
- agno/exceptions.py +7 -0
- agno/knowledge/embedder/openai.py +8 -8
- agno/knowledge/knowledge.py +1142 -176
- agno/media.py +22 -6
- agno/models/aws/claude.py +8 -7
- agno/models/base.py +160 -11
- agno/models/deepseek/deepseek.py +67 -0
- agno/models/google/gemini.py +65 -11
- agno/models/google/utils.py +22 -0
- agno/models/message.py +2 -0
- agno/models/openai/chat.py +4 -0
- agno/models/openai/responses.py +3 -2
- agno/os/app.py +64 -74
- agno/os/interfaces/a2a/router.py +3 -4
- agno/os/interfaces/a2a/utils.py +1 -1
- agno/os/interfaces/agui/router.py +2 -0
- agno/os/middleware/jwt.py +8 -6
- agno/os/router.py +3 -1607
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +581 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/evals.py +26 -6
- agno/os/routers/evals/schemas.py +34 -2
- agno/os/routers/evals/utils.py +101 -20
- agno/os/routers/knowledge/knowledge.py +1 -1
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +496 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +545 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +1 -559
- agno/os/utils.py +139 -2
- agno/team/team.py +159 -100
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/workflow.py +8 -1
- agno/utils/hooks.py +64 -5
- agno/utils/http.py +2 -2
- agno/utils/media.py +11 -1
- agno/utils/print_response/agent.py +8 -0
- agno/utils/print_response/team.py +8 -0
- agno/vectordb/pgvector/pgvector.py +88 -51
- agno/workflow/parallel.py +11 -5
- agno/workflow/step.py +17 -5
- agno/workflow/types.py +38 -2
- agno/workflow/workflow.py +12 -4
- {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/METADATA +8 -3
- {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/RECORD +70 -58
- agno/tools/memori.py +0 -339
- {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/WHEEL +0 -0
- {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/top_level.txt +0 -0
agno/team/team.py
CHANGED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import contextlib
|
|
5
5
|
import json
|
|
6
|
+
import time
|
|
6
7
|
import warnings
|
|
7
8
|
from collections import ChainMap, deque
|
|
8
9
|
from copy import copy
|
|
@@ -10,6 +11,7 @@ from dataclasses import dataclass
|
|
|
10
11
|
from os import getenv
|
|
11
12
|
from textwrap import dedent
|
|
12
13
|
from typing import (
|
|
14
|
+
TYPE_CHECKING,
|
|
13
15
|
Any,
|
|
14
16
|
AsyncIterator,
|
|
15
17
|
Callable,
|
|
@@ -31,12 +33,14 @@ from uuid import uuid4
|
|
|
31
33
|
|
|
32
34
|
from pydantic import BaseModel
|
|
33
35
|
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from agno.eval.base import BaseEval
|
|
38
|
+
|
|
34
39
|
from agno.agent import Agent
|
|
35
40
|
from agno.compression.manager import CompressionManager
|
|
36
41
|
from agno.db.base import AsyncBaseDb, BaseDb, SessionType, UserMemory
|
|
37
42
|
from agno.exceptions import (
|
|
38
43
|
InputCheckError,
|
|
39
|
-
ModelProviderError,
|
|
40
44
|
OutputCheckError,
|
|
41
45
|
RunCancelledException,
|
|
42
46
|
)
|
|
@@ -115,7 +119,6 @@ from agno.utils.events import (
|
|
|
115
119
|
create_team_run_cancelled_event,
|
|
116
120
|
create_team_run_completed_event,
|
|
117
121
|
create_team_run_content_completed_event,
|
|
118
|
-
create_team_run_error_event,
|
|
119
122
|
create_team_run_output_content_event,
|
|
120
123
|
create_team_run_started_event,
|
|
121
124
|
create_team_session_summary_completed_event,
|
|
@@ -124,7 +127,13 @@ from agno.utils.events import (
|
|
|
124
127
|
create_team_tool_call_started_event,
|
|
125
128
|
handle_event,
|
|
126
129
|
)
|
|
127
|
-
from agno.utils.hooks import
|
|
130
|
+
from agno.utils.hooks import (
|
|
131
|
+
copy_args_for_background,
|
|
132
|
+
filter_hook_args,
|
|
133
|
+
normalize_post_hooks,
|
|
134
|
+
normalize_pre_hooks,
|
|
135
|
+
should_run_hook_in_background,
|
|
136
|
+
)
|
|
128
137
|
from agno.utils.knowledge import get_agentic_or_user_search_filters
|
|
129
138
|
from agno.utils.log import (
|
|
130
139
|
log_debug,
|
|
@@ -267,6 +276,8 @@ class Team:
|
|
|
267
276
|
system_message: Optional[Union[str, Callable, Message]] = None
|
|
268
277
|
# Role for the system message
|
|
269
278
|
system_message_role: str = "system"
|
|
279
|
+
# Introduction for the team
|
|
280
|
+
introduction: Optional[str] = None
|
|
270
281
|
|
|
271
282
|
# If True, resolve the session_state, dependencies, and metadata in the user and system messages
|
|
272
283
|
resolve_in_context: bool = True
|
|
@@ -343,9 +354,9 @@ class Team:
|
|
|
343
354
|
|
|
344
355
|
# --- Team Hooks ---
|
|
345
356
|
# Functions called right after team session is loaded, before processing starts
|
|
346
|
-
pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
|
|
357
|
+
pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, "BaseEval"]]] = None
|
|
347
358
|
# Functions called after output is generated but before the response is returned
|
|
348
|
-
post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
|
|
359
|
+
post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, "BaseEval"]]] = None
|
|
349
360
|
# If True, run hooks as FastAPI background tasks (non-blocking). Set by AgentOS.
|
|
350
361
|
_run_hooks_in_background: Optional[bool] = None
|
|
351
362
|
|
|
@@ -487,6 +498,7 @@ class Team:
|
|
|
487
498
|
add_member_tools_to_context: bool = False,
|
|
488
499
|
system_message: Optional[Union[str, Callable, Message]] = None,
|
|
489
500
|
system_message_role: str = "system",
|
|
501
|
+
introduction: Optional[str] = None,
|
|
490
502
|
additional_input: Optional[List[Union[str, Dict, BaseModel, Message]]] = None,
|
|
491
503
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
492
504
|
add_dependencies_to_context: bool = False,
|
|
@@ -513,8 +525,8 @@ class Team:
|
|
|
513
525
|
tool_call_limit: Optional[int] = None,
|
|
514
526
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
515
527
|
tool_hooks: Optional[List[Callable]] = None,
|
|
516
|
-
pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None,
|
|
517
|
-
post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None,
|
|
528
|
+
pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, "BaseEval"]]] = None,
|
|
529
|
+
post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, "BaseEval"]]] = None,
|
|
518
530
|
input_schema: Optional[Type[BaseModel]] = None,
|
|
519
531
|
output_schema: Optional[Type[BaseModel]] = None,
|
|
520
532
|
parser_model: Optional[Union[Model, str]] = None,
|
|
@@ -612,6 +624,7 @@ class Team:
|
|
|
612
624
|
self.add_member_tools_to_context = add_member_tools_to_context
|
|
613
625
|
self.system_message = system_message
|
|
614
626
|
self.system_message_role = system_message_role
|
|
627
|
+
self.introduction = introduction
|
|
615
628
|
self.additional_input = additional_input
|
|
616
629
|
|
|
617
630
|
self.dependencies = dependencies
|
|
@@ -1554,7 +1567,12 @@ class Team:
|
|
|
1554
1567
|
|
|
1555
1568
|
# 4. Start memory creation in background thread
|
|
1556
1569
|
memory_future = None
|
|
1557
|
-
if
|
|
1570
|
+
if (
|
|
1571
|
+
run_messages.user_message is not None
|
|
1572
|
+
and self.memory_manager is not None
|
|
1573
|
+
and self.enable_user_memories
|
|
1574
|
+
and not self.enable_agentic_memory
|
|
1575
|
+
):
|
|
1558
1576
|
log_debug("Starting memory creation in background thread.")
|
|
1559
1577
|
memory_future = self.background_executor.submit(
|
|
1560
1578
|
self._make_memories, run_messages=run_messages, user_id=user_id
|
|
@@ -1761,7 +1779,12 @@ class Team:
|
|
|
1761
1779
|
|
|
1762
1780
|
# 4. Start memory creation in background thread
|
|
1763
1781
|
memory_future = None
|
|
1764
|
-
if
|
|
1782
|
+
if (
|
|
1783
|
+
run_messages.user_message is not None
|
|
1784
|
+
and self.memory_manager is not None
|
|
1785
|
+
and self.enable_user_memories
|
|
1786
|
+
and not self.enable_agentic_memory
|
|
1787
|
+
):
|
|
1765
1788
|
log_debug("Starting memory creation in background thread.")
|
|
1766
1789
|
memory_future = self.background_executor.submit(
|
|
1767
1790
|
self._make_memories, run_messages=run_messages, user_id=user_id
|
|
@@ -1963,7 +1986,7 @@ class Team:
|
|
|
1963
1986
|
session_id: Optional[str] = None,
|
|
1964
1987
|
session_state: Optional[Dict[str, Any]] = None,
|
|
1965
1988
|
user_id: Optional[str] = None,
|
|
1966
|
-
|
|
1989
|
+
run_id: Optional[str] = None,
|
|
1967
1990
|
audio: Optional[Sequence[Audio]] = None,
|
|
1968
1991
|
images: Optional[Sequence[Image]] = None,
|
|
1969
1992
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -1991,7 +2014,7 @@ class Team:
|
|
|
1991
2014
|
session_state: Optional[Dict[str, Any]] = None,
|
|
1992
2015
|
run_context: Optional[RunContext] = None,
|
|
1993
2016
|
user_id: Optional[str] = None,
|
|
1994
|
-
|
|
2017
|
+
run_id: Optional[str] = None,
|
|
1995
2018
|
audio: Optional[Sequence[Audio]] = None,
|
|
1996
2019
|
images: Optional[Sequence[Image]] = None,
|
|
1997
2020
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -2019,8 +2042,8 @@ class Team:
|
|
|
2019
2042
|
session_id: Optional[str] = None,
|
|
2020
2043
|
session_state: Optional[Dict[str, Any]] = None,
|
|
2021
2044
|
run_context: Optional[RunContext] = None,
|
|
2045
|
+
run_id: Optional[str] = None,
|
|
2022
2046
|
user_id: Optional[str] = None,
|
|
2023
|
-
retries: Optional[int] = None,
|
|
2024
2047
|
audio: Optional[Sequence[Audio]] = None,
|
|
2025
2048
|
images: Optional[Sequence[Image]] = None,
|
|
2026
2049
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -2041,8 +2064,8 @@ class Team:
|
|
|
2041
2064
|
if self._has_async_db():
|
|
2042
2065
|
raise Exception("run() is not supported with an async DB. Please use arun() instead.")
|
|
2043
2066
|
|
|
2044
|
-
#
|
|
2045
|
-
run_id = str(uuid4())
|
|
2067
|
+
# Set the id for the run and register it immediately for cancellation tracking
|
|
2068
|
+
run_id = run_id or str(uuid4())
|
|
2046
2069
|
register_run(run_id)
|
|
2047
2070
|
|
|
2048
2071
|
# Initialize Team
|
|
@@ -2059,6 +2082,7 @@ class Team:
|
|
|
2059
2082
|
DeprecationWarning,
|
|
2060
2083
|
stacklevel=2,
|
|
2061
2084
|
)
|
|
2085
|
+
yield_run_output = yield_run_output or yield_run_response # For backwards compatibility
|
|
2062
2086
|
|
|
2063
2087
|
background_tasks = kwargs.pop("background_tasks", None)
|
|
2064
2088
|
if background_tasks is not None:
|
|
@@ -2072,9 +2096,9 @@ class Team:
|
|
|
2072
2096
|
# Normalise hook & guardails
|
|
2073
2097
|
if not self._hooks_normalised:
|
|
2074
2098
|
if self.pre_hooks:
|
|
2075
|
-
self.pre_hooks =
|
|
2099
|
+
self.pre_hooks = normalize_pre_hooks(self.pre_hooks) # type: ignore
|
|
2076
2100
|
if self.post_hooks:
|
|
2077
|
-
self.post_hooks =
|
|
2101
|
+
self.post_hooks = normalize_post_hooks(self.post_hooks) # type: ignore
|
|
2078
2102
|
self._hooks_normalised = True
|
|
2079
2103
|
|
|
2080
2104
|
session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
|
|
@@ -2196,18 +2220,11 @@ class Team:
|
|
|
2196
2220
|
run_response.metrics = Metrics()
|
|
2197
2221
|
run_response.metrics.start_timer()
|
|
2198
2222
|
|
|
2199
|
-
#
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
# Run the team
|
|
2203
|
-
last_exception = None
|
|
2204
|
-
num_attempts = retries + 1
|
|
2205
|
-
|
|
2206
|
-
yield_run_output = bool(yield_run_output or yield_run_response) # For backwards compatibility
|
|
2223
|
+
# Set up retry logic
|
|
2224
|
+
num_attempts = self.retries + 1
|
|
2207
2225
|
|
|
2208
2226
|
for attempt in range(num_attempts):
|
|
2209
|
-
|
|
2210
|
-
|
|
2227
|
+
log_debug(f"Retrying Team run {run_id}. Attempt {attempt + 1} of {num_attempts}...")
|
|
2211
2228
|
# Run the team
|
|
2212
2229
|
try:
|
|
2213
2230
|
if stream:
|
|
@@ -2246,18 +2263,6 @@ class Team:
|
|
|
2246
2263
|
except (InputCheckError, OutputCheckError) as e:
|
|
2247
2264
|
log_error(f"Validation failed: {str(e)} | Check: {e.check_trigger}")
|
|
2248
2265
|
raise e
|
|
2249
|
-
except ModelProviderError as e:
|
|
2250
|
-
import time
|
|
2251
|
-
|
|
2252
|
-
log_warning(f"Attempt {attempt + 1}/{num_attempts} failed: {str(e)}")
|
|
2253
|
-
|
|
2254
|
-
last_exception = e
|
|
2255
|
-
if attempt < num_attempts - 1: # Don't sleep on the last attempt
|
|
2256
|
-
if self.exponential_backoff:
|
|
2257
|
-
delay = 2**attempt * self.delay_between_retries
|
|
2258
|
-
else:
|
|
2259
|
-
delay = self.delay_between_retries
|
|
2260
|
-
time.sleep(delay)
|
|
2261
2266
|
except KeyboardInterrupt:
|
|
2262
2267
|
run_response.content = "Operation cancelled by user"
|
|
2263
2268
|
run_response.status = RunStatus.cancelled
|
|
@@ -2270,21 +2275,24 @@ class Team:
|
|
|
2270
2275
|
)
|
|
2271
2276
|
else:
|
|
2272
2277
|
return run_response
|
|
2278
|
+
except Exception as e:
|
|
2279
|
+
# Check if this is the last attempt
|
|
2280
|
+
if attempt < num_attempts - 1:
|
|
2281
|
+
# Calculate delay with exponential backoff if enabled
|
|
2282
|
+
if self.exponential_backoff:
|
|
2283
|
+
delay = self.delay_between_retries * (2**attempt)
|
|
2284
|
+
else:
|
|
2285
|
+
delay = self.delay_between_retries
|
|
2273
2286
|
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
return generator_wrapper(create_team_run_error_event(run_response, error=str(last_exception)))
|
|
2281
|
-
|
|
2282
|
-
raise last_exception
|
|
2283
|
-
else:
|
|
2284
|
-
if stream:
|
|
2285
|
-
return generator_wrapper(create_team_run_error_event(run_response, error=str(last_exception)))
|
|
2287
|
+
log_warning(f"Attempt {attempt + 1}/{num_attempts} failed: {str(e)}. Retrying in {delay}s...")
|
|
2288
|
+
time.sleep(delay)
|
|
2289
|
+
else:
|
|
2290
|
+
# Final attempt failed - re-raise the exception
|
|
2291
|
+
log_error(f"All {num_attempts} attempts failed. Final error: {str(e)}")
|
|
2292
|
+
raise e
|
|
2286
2293
|
|
|
2287
|
-
|
|
2294
|
+
# If we get here, all retries failed
|
|
2295
|
+
raise Exception(f"Failed after {num_attempts} attempts.")
|
|
2288
2296
|
|
|
2289
2297
|
async def _arun(
|
|
2290
2298
|
self,
|
|
@@ -2411,7 +2419,12 @@ class Team:
|
|
|
2411
2419
|
|
|
2412
2420
|
# 6. Start memory creation in background task
|
|
2413
2421
|
memory_task = None
|
|
2414
|
-
if
|
|
2422
|
+
if (
|
|
2423
|
+
run_messages.user_message is not None
|
|
2424
|
+
and self.memory_manager is not None
|
|
2425
|
+
and self.enable_user_memories
|
|
2426
|
+
and not self.enable_agentic_memory
|
|
2427
|
+
):
|
|
2415
2428
|
log_debug("Starting memory creation in background task.")
|
|
2416
2429
|
memory_task = asyncio.create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
2417
2430
|
|
|
@@ -2649,7 +2662,12 @@ class Team:
|
|
|
2649
2662
|
|
|
2650
2663
|
# 7. Start memory creation in background task
|
|
2651
2664
|
memory_task = None
|
|
2652
|
-
if
|
|
2665
|
+
if (
|
|
2666
|
+
run_messages.user_message is not None
|
|
2667
|
+
and self.memory_manager is not None
|
|
2668
|
+
and self.enable_user_memories
|
|
2669
|
+
and not self.enable_agentic_memory
|
|
2670
|
+
):
|
|
2653
2671
|
log_debug("Starting memory creation in background task.")
|
|
2654
2672
|
memory_task = asyncio.create_task(self._amake_memories(run_messages=run_messages, user_id=user_id))
|
|
2655
2673
|
|
|
@@ -2865,9 +2883,9 @@ class Team:
|
|
|
2865
2883
|
stream_intermediate_steps: Optional[bool] = None,
|
|
2866
2884
|
session_id: Optional[str] = None,
|
|
2867
2885
|
session_state: Optional[Dict[str, Any]] = None,
|
|
2886
|
+
run_id: Optional[str] = None,
|
|
2868
2887
|
run_context: Optional[RunContext] = None,
|
|
2869
2888
|
user_id: Optional[str] = None,
|
|
2870
|
-
retries: Optional[int] = None,
|
|
2871
2889
|
audio: Optional[Sequence[Audio]] = None,
|
|
2872
2890
|
images: Optional[Sequence[Image]] = None,
|
|
2873
2891
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -2893,9 +2911,9 @@ class Team:
|
|
|
2893
2911
|
stream_intermediate_steps: Optional[bool] = None,
|
|
2894
2912
|
session_id: Optional[str] = None,
|
|
2895
2913
|
session_state: Optional[Dict[str, Any]] = None,
|
|
2914
|
+
run_id: Optional[str] = None,
|
|
2896
2915
|
run_context: Optional[RunContext] = None,
|
|
2897
2916
|
user_id: Optional[str] = None,
|
|
2898
|
-
retries: Optional[int] = None,
|
|
2899
2917
|
audio: Optional[Sequence[Audio]] = None,
|
|
2900
2918
|
images: Optional[Sequence[Image]] = None,
|
|
2901
2919
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -2922,9 +2940,9 @@ class Team:
|
|
|
2922
2940
|
stream_intermediate_steps: Optional[bool] = None,
|
|
2923
2941
|
session_id: Optional[str] = None,
|
|
2924
2942
|
session_state: Optional[Dict[str, Any]] = None,
|
|
2943
|
+
run_id: Optional[str] = None,
|
|
2925
2944
|
run_context: Optional[RunContext] = None,
|
|
2926
2945
|
user_id: Optional[str] = None,
|
|
2927
|
-
retries: Optional[int] = None,
|
|
2928
2946
|
audio: Optional[Sequence[Audio]] = None,
|
|
2929
2947
|
images: Optional[Sequence[Image]] = None,
|
|
2930
2948
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -2943,8 +2961,8 @@ class Team:
|
|
|
2943
2961
|
) -> Union[TeamRunOutput, AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent]]]:
|
|
2944
2962
|
"""Run the Team asynchronously and return the response."""
|
|
2945
2963
|
|
|
2946
|
-
#
|
|
2947
|
-
run_id = str(uuid4())
|
|
2964
|
+
# Set the id for the run and register it immediately for cancellation tracking
|
|
2965
|
+
run_id = run_id or str(uuid4())
|
|
2948
2966
|
register_run(run_id)
|
|
2949
2967
|
|
|
2950
2968
|
if (add_history_to_context or self.add_history_to_context) and not self.db and not self.parent_team_id:
|
|
@@ -2959,6 +2977,8 @@ class Team:
|
|
|
2959
2977
|
stacklevel=2,
|
|
2960
2978
|
)
|
|
2961
2979
|
|
|
2980
|
+
yield_run_output = yield_run_output or yield_run_response # For backwards compatibility
|
|
2981
|
+
|
|
2962
2982
|
background_tasks = kwargs.pop("background_tasks", None)
|
|
2963
2983
|
if background_tasks is not None:
|
|
2964
2984
|
from fastapi import BackgroundTasks
|
|
@@ -2971,9 +2991,9 @@ class Team:
|
|
|
2971
2991
|
# Normalise hook & guardails
|
|
2972
2992
|
if not self._hooks_normalised:
|
|
2973
2993
|
if self.pre_hooks:
|
|
2974
|
-
self.pre_hooks =
|
|
2994
|
+
self.pre_hooks = normalize_pre_hooks(self.pre_hooks, async_mode=True) # type: ignore
|
|
2975
2995
|
if self.post_hooks:
|
|
2976
|
-
self.post_hooks =
|
|
2996
|
+
self.post_hooks = normalize_post_hooks(self.post_hooks, async_mode=True) # type: ignore
|
|
2977
2997
|
self._hooks_normalised = True
|
|
2978
2998
|
|
|
2979
2999
|
session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
|
|
@@ -3084,20 +3104,16 @@ class Team:
|
|
|
3084
3104
|
run_response.metrics = Metrics()
|
|
3085
3105
|
run_response.metrics.start_timer()
|
|
3086
3106
|
|
|
3087
|
-
# If no retries are set, use the team's default retries
|
|
3088
|
-
retries = retries if retries is not None else self.retries
|
|
3089
|
-
|
|
3090
|
-
# Run the team
|
|
3091
|
-
last_exception = None
|
|
3092
|
-
num_attempts = retries + 1
|
|
3093
|
-
|
|
3094
3107
|
yield_run_output = bool(yield_run_output or yield_run_response) # For backwards compatibility
|
|
3095
3108
|
|
|
3109
|
+
# Resolve retry parameters
|
|
3110
|
+
num_attempts = self.retries + 1
|
|
3111
|
+
|
|
3096
3112
|
for attempt in range(num_attempts):
|
|
3097
3113
|
# Run the team
|
|
3098
3114
|
try:
|
|
3099
3115
|
if stream:
|
|
3100
|
-
|
|
3116
|
+
return self._arun_stream( # type: ignore
|
|
3101
3117
|
input=validated_input,
|
|
3102
3118
|
run_response=run_response,
|
|
3103
3119
|
run_context=run_context,
|
|
@@ -3113,7 +3129,6 @@ class Team:
|
|
|
3113
3129
|
background_tasks=background_tasks,
|
|
3114
3130
|
**kwargs,
|
|
3115
3131
|
)
|
|
3116
|
-
return response_iterator # type: ignore
|
|
3117
3132
|
else:
|
|
3118
3133
|
return self._arun( # type: ignore
|
|
3119
3134
|
input=validated_input,
|
|
@@ -3133,17 +3148,6 @@ class Team:
|
|
|
3133
3148
|
except (InputCheckError, OutputCheckError) as e:
|
|
3134
3149
|
log_error(f"Validation failed: {str(e)} | Check: {e.check_trigger}")
|
|
3135
3150
|
raise e
|
|
3136
|
-
except ModelProviderError as e:
|
|
3137
|
-
log_warning(f"Attempt {attempt + 1}/{num_attempts} failed: {str(e)}")
|
|
3138
|
-
last_exception = e
|
|
3139
|
-
if attempt < num_attempts - 1: # Don't sleep on the last attempt
|
|
3140
|
-
if self.exponential_backoff:
|
|
3141
|
-
delay = 2**attempt * self.delay_between_retries
|
|
3142
|
-
else:
|
|
3143
|
-
delay = self.delay_between_retries
|
|
3144
|
-
import time
|
|
3145
|
-
|
|
3146
|
-
time.sleep(delay)
|
|
3147
3151
|
except KeyboardInterrupt:
|
|
3148
3152
|
run_response.content = "Operation cancelled by user"
|
|
3149
3153
|
run_response.status = RunStatus.cancelled
|
|
@@ -3156,21 +3160,25 @@ class Team:
|
|
|
3156
3160
|
)
|
|
3157
3161
|
else:
|
|
3158
3162
|
return run_response
|
|
3163
|
+
except Exception as e:
|
|
3164
|
+
# Check if this is the last attempt
|
|
3165
|
+
if attempt < num_attempts - 1:
|
|
3166
|
+
# Calculate delay with exponential backoff if enabled
|
|
3167
|
+
if self.exponential_backoff:
|
|
3168
|
+
delay = self.delay_between_retries * (2**attempt)
|
|
3169
|
+
else:
|
|
3170
|
+
delay = self.delay_between_retries
|
|
3159
3171
|
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
raise last_exception
|
|
3169
|
-
else:
|
|
3170
|
-
if stream:
|
|
3171
|
-
return async_generator_wrapper(create_team_run_error_event(run_response, error=str(last_exception)))
|
|
3172
|
+
log_warning(f"Attempt {attempt + 1}/{num_attempts} failed: {str(e)}. Retrying in {delay}s...")
|
|
3173
|
+
time.sleep(delay)
|
|
3174
|
+
continue
|
|
3175
|
+
else:
|
|
3176
|
+
# Final attempt failed - re-raise the exception
|
|
3177
|
+
log_error(f"All {num_attempts} attempts failed. Final error: {str(e)}")
|
|
3178
|
+
raise e
|
|
3172
3179
|
|
|
3173
|
-
|
|
3180
|
+
# If we get here, all retries failed
|
|
3181
|
+
raise Exception(f"Failed after {num_attempts} attempts.")
|
|
3174
3182
|
|
|
3175
3183
|
def _update_run_response(
|
|
3176
3184
|
self,
|
|
@@ -3821,7 +3829,12 @@ class Team:
|
|
|
3821
3829
|
user_message_str = (
|
|
3822
3830
|
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
3823
3831
|
)
|
|
3824
|
-
if
|
|
3832
|
+
if (
|
|
3833
|
+
user_message_str is not None
|
|
3834
|
+
and user_message_str.strip() != ""
|
|
3835
|
+
and self.memory_manager is not None
|
|
3836
|
+
and self.enable_user_memories
|
|
3837
|
+
):
|
|
3825
3838
|
log_debug("Managing user memories")
|
|
3826
3839
|
self.memory_manager.create_user_memories(
|
|
3827
3840
|
message=user_message_str,
|
|
@@ -3837,7 +3850,12 @@ class Team:
|
|
|
3837
3850
|
user_message_str = (
|
|
3838
3851
|
run_messages.user_message.get_content_string() if run_messages.user_message is not None else None
|
|
3839
3852
|
)
|
|
3840
|
-
if
|
|
3853
|
+
if (
|
|
3854
|
+
user_message_str is not None
|
|
3855
|
+
and user_message_str.strip() != ""
|
|
3856
|
+
and self.memory_manager is not None
|
|
3857
|
+
and self.enable_user_memories
|
|
3858
|
+
):
|
|
3841
3859
|
log_debug("Managing user memories")
|
|
3842
3860
|
await self.memory_manager.acreate_user_memories(
|
|
3843
3861
|
message=user_message_str,
|
|
@@ -4244,6 +4262,7 @@ class Team:
|
|
|
4244
4262
|
session_id: Optional[str] = None,
|
|
4245
4263
|
session_state: Optional[Dict[str, Any]] = None,
|
|
4246
4264
|
user_id: Optional[str] = None,
|
|
4265
|
+
run_id: Optional[str] = None,
|
|
4247
4266
|
audio: Optional[Sequence[Audio]] = None,
|
|
4248
4267
|
images: Optional[Sequence[Image]] = None,
|
|
4249
4268
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -4316,6 +4335,7 @@ class Team:
|
|
|
4316
4335
|
session_id=session_id,
|
|
4317
4336
|
session_state=session_state,
|
|
4318
4337
|
user_id=user_id,
|
|
4338
|
+
run_id=run_id,
|
|
4319
4339
|
audio=audio,
|
|
4320
4340
|
images=images,
|
|
4321
4341
|
videos=videos,
|
|
@@ -4344,6 +4364,7 @@ class Team:
|
|
|
4344
4364
|
session_id=session_id,
|
|
4345
4365
|
session_state=session_state,
|
|
4346
4366
|
user_id=user_id,
|
|
4367
|
+
run_id=run_id,
|
|
4347
4368
|
audio=audio,
|
|
4348
4369
|
images=images,
|
|
4349
4370
|
videos=videos,
|
|
@@ -4367,6 +4388,7 @@ class Team:
|
|
|
4367
4388
|
session_id: Optional[str] = None,
|
|
4368
4389
|
session_state: Optional[Dict[str, Any]] = None,
|
|
4369
4390
|
user_id: Optional[str] = None,
|
|
4391
|
+
run_id: Optional[str] = None,
|
|
4370
4392
|
audio: Optional[Sequence[Audio]] = None,
|
|
4371
4393
|
images: Optional[Sequence[Image]] = None,
|
|
4372
4394
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -4434,6 +4456,7 @@ class Team:
|
|
|
4434
4456
|
session_id=session_id,
|
|
4435
4457
|
session_state=session_state,
|
|
4436
4458
|
user_id=user_id,
|
|
4459
|
+
run_id=run_id,
|
|
4437
4460
|
audio=audio,
|
|
4438
4461
|
images=images,
|
|
4439
4462
|
videos=videos,
|
|
@@ -4462,6 +4485,7 @@ class Team:
|
|
|
4462
4485
|
session_id=session_id,
|
|
4463
4486
|
session_state=session_state,
|
|
4464
4487
|
user_id=user_id,
|
|
4488
|
+
run_id=run_id,
|
|
4465
4489
|
audio=audio,
|
|
4466
4490
|
images=images,
|
|
4467
4491
|
videos=videos,
|
|
@@ -8207,6 +8231,20 @@ class Team:
|
|
|
8207
8231
|
metadata=self.metadata,
|
|
8208
8232
|
created_at=int(time()),
|
|
8209
8233
|
)
|
|
8234
|
+
if self.introduction is not None:
|
|
8235
|
+
from uuid import uuid4
|
|
8236
|
+
|
|
8237
|
+
team_session.upsert_run(
|
|
8238
|
+
TeamRunOutput(
|
|
8239
|
+
run_id=str(uuid4()),
|
|
8240
|
+
team_id=self.id,
|
|
8241
|
+
session_id=session_id,
|
|
8242
|
+
user_id=user_id,
|
|
8243
|
+
team_name=self.name,
|
|
8244
|
+
content=self.introduction,
|
|
8245
|
+
messages=[Message(role=self.model.assistant_message_role, content=self.introduction)], # type: ignore
|
|
8246
|
+
)
|
|
8247
|
+
)
|
|
8210
8248
|
|
|
8211
8249
|
# Cache the session if relevant
|
|
8212
8250
|
if team_session is not None and self.cache_session:
|
|
@@ -8239,15 +8277,34 @@ class Team:
|
|
|
8239
8277
|
# Create new session if none found
|
|
8240
8278
|
if team_session is None:
|
|
8241
8279
|
log_debug(f"Creating new TeamSession: {session_id}")
|
|
8280
|
+
session_data = {}
|
|
8281
|
+
if self.session_state is not None:
|
|
8282
|
+
from copy import deepcopy
|
|
8283
|
+
|
|
8284
|
+
session_data["session_state"] = deepcopy(self.session_state)
|
|
8242
8285
|
team_session = TeamSession(
|
|
8243
8286
|
session_id=session_id,
|
|
8244
8287
|
team_id=self.id,
|
|
8245
8288
|
user_id=user_id,
|
|
8246
8289
|
team_data=self._get_team_data(),
|
|
8247
|
-
session_data=
|
|
8290
|
+
session_data=session_data,
|
|
8248
8291
|
metadata=self.metadata,
|
|
8249
8292
|
created_at=int(time()),
|
|
8250
8293
|
)
|
|
8294
|
+
if self.introduction is not None:
|
|
8295
|
+
from uuid import uuid4
|
|
8296
|
+
|
|
8297
|
+
team_session.upsert_run(
|
|
8298
|
+
TeamRunOutput(
|
|
8299
|
+
run_id=str(uuid4()),
|
|
8300
|
+
team_id=self.id,
|
|
8301
|
+
session_id=session_id,
|
|
8302
|
+
user_id=user_id,
|
|
8303
|
+
team_name=self.name,
|
|
8304
|
+
content=self.introduction,
|
|
8305
|
+
messages=[Message(role=self.model.assistant_message_role, content=self.introduction)], # type: ignore
|
|
8306
|
+
)
|
|
8307
|
+
)
|
|
8251
8308
|
|
|
8252
8309
|
# Cache the session if relevant
|
|
8253
8310
|
if team_session is not None and self.cache_session:
|
|
@@ -8897,12 +8954,13 @@ class Team:
|
|
|
8897
8954
|
Optional[List[UserMemory]]: The user memories.
|
|
8898
8955
|
"""
|
|
8899
8956
|
if self.memory_manager is None:
|
|
8900
|
-
|
|
8957
|
+
self._set_memory_manager()
|
|
8958
|
+
|
|
8901
8959
|
user_id = user_id if user_id is not None else self.user_id
|
|
8902
8960
|
if user_id is None:
|
|
8903
8961
|
user_id = "default"
|
|
8904
8962
|
|
|
8905
|
-
return self.memory_manager.get_user_memories(user_id=user_id)
|
|
8963
|
+
return self.memory_manager.get_user_memories(user_id=user_id) # type: ignore
|
|
8906
8964
|
|
|
8907
8965
|
async def aget_user_memories(self, user_id: Optional[str] = None) -> Optional[List[UserMemory]]:
|
|
8908
8966
|
"""Get the user memories for the given user ID.
|
|
@@ -8913,12 +8971,13 @@ class Team:
|
|
|
8913
8971
|
Optional[List[UserMemory]]: The user memories.
|
|
8914
8972
|
"""
|
|
8915
8973
|
if self.memory_manager is None:
|
|
8916
|
-
|
|
8974
|
+
self._set_memory_manager()
|
|
8975
|
+
|
|
8917
8976
|
user_id = user_id if user_id is not None else self.user_id
|
|
8918
8977
|
if user_id is None:
|
|
8919
8978
|
user_id = "default"
|
|
8920
8979
|
|
|
8921
|
-
return await self.memory_manager.aget_user_memories(user_id=user_id)
|
|
8980
|
+
return await self.memory_manager.aget_user_memories(user_id=user_id) # type: ignore
|
|
8922
8981
|
|
|
8923
8982
|
###########################################################################
|
|
8924
8983
|
# Handle reasoning content
|
agno/tools/file_generation.py
CHANGED
|
@@ -108,14 +108,16 @@ class FileGenerationTools(Toolkit):
|
|
|
108
108
|
# Save file to disk (if output_directory is set)
|
|
109
109
|
file_path = self._save_file_to_disk(json_content, filename)
|
|
110
110
|
|
|
111
|
+
content_bytes = json_content.encode("utf-8")
|
|
112
|
+
|
|
111
113
|
# Create FileArtifact
|
|
112
114
|
file_artifact = File(
|
|
113
115
|
id=str(uuid4()),
|
|
114
|
-
content=
|
|
116
|
+
content=content_bytes,
|
|
115
117
|
mime_type="application/json",
|
|
116
118
|
file_type="json",
|
|
117
119
|
filename=filename,
|
|
118
|
-
size=len(
|
|
120
|
+
size=len(content_bytes),
|
|
119
121
|
filepath=file_path if file_path else None,
|
|
120
122
|
)
|
|
121
123
|
|
|
@@ -195,14 +197,16 @@ class FileGenerationTools(Toolkit):
|
|
|
195
197
|
# Save file to disk (if output_directory is set)
|
|
196
198
|
file_path = self._save_file_to_disk(csv_content, filename)
|
|
197
199
|
|
|
200
|
+
content_bytes = csv_content.encode("utf-8")
|
|
201
|
+
|
|
198
202
|
# Create FileArtifact
|
|
199
203
|
file_artifact = File(
|
|
200
204
|
id=str(uuid4()),
|
|
201
|
-
content=
|
|
205
|
+
content=content_bytes,
|
|
202
206
|
mime_type="text/csv",
|
|
203
207
|
file_type="csv",
|
|
204
208
|
filename=filename,
|
|
205
|
-
size=len(
|
|
209
|
+
size=len(content_bytes),
|
|
206
210
|
filepath=file_path if file_path else None,
|
|
207
211
|
)
|
|
208
212
|
|
|
@@ -325,14 +329,16 @@ class FileGenerationTools(Toolkit):
|
|
|
325
329
|
# Save file to disk (if output_directory is set)
|
|
326
330
|
file_path = self._save_file_to_disk(content, filename)
|
|
327
331
|
|
|
332
|
+
content_bytes = content.encode("utf-8")
|
|
333
|
+
|
|
328
334
|
# Create FileArtifact
|
|
329
335
|
file_artifact = File(
|
|
330
336
|
id=str(uuid4()),
|
|
331
|
-
content=
|
|
337
|
+
content=content_bytes,
|
|
332
338
|
mime_type="text/plain",
|
|
333
339
|
file_type="txt",
|
|
334
340
|
filename=filename,
|
|
335
|
-
size=len(
|
|
341
|
+
size=len(content_bytes),
|
|
336
342
|
filepath=file_path if file_path else None,
|
|
337
343
|
)
|
|
338
344
|
|