agno 2.3.22__py3-none-any.whl → 2.3.24__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 +28 -1
- agno/agent/remote.py +1 -1
- agno/db/mongo/mongo.py +9 -1
- agno/db/mysql/async_mysql.py +5 -7
- agno/db/mysql/mysql.py +5 -7
- agno/db/mysql/schemas.py +39 -21
- agno/db/postgres/async_postgres.py +10 -2
- agno/db/postgres/postgres.py +5 -7
- agno/db/postgres/schemas.py +39 -21
- agno/db/singlestore/schemas.py +41 -21
- agno/db/singlestore/singlestore.py +14 -3
- agno/db/sqlite/async_sqlite.py +7 -2
- agno/db/sqlite/schemas.py +36 -21
- agno/db/sqlite/sqlite.py +3 -7
- agno/knowledge/chunking/markdown.py +94 -8
- agno/knowledge/chunking/semantic.py +2 -2
- agno/knowledge/knowledge.py +215 -207
- agno/models/base.py +32 -8
- agno/models/google/gemini.py +27 -4
- agno/os/routers/agents/router.py +1 -1
- agno/os/routers/evals/evals.py +2 -2
- agno/os/routers/knowledge/knowledge.py +21 -5
- agno/os/routers/knowledge/schemas.py +1 -1
- agno/os/routers/memory/memory.py +4 -4
- agno/os/routers/session/session.py +2 -2
- agno/os/routers/teams/router.py +2 -2
- agno/os/routers/traces/traces.py +3 -3
- agno/os/routers/workflows/router.py +1 -1
- agno/os/schema.py +1 -1
- agno/os/utils.py +1 -1
- agno/remote/base.py +1 -1
- agno/team/remote.py +1 -1
- agno/team/team.py +24 -4
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +150 -13
- agno/tools/crawl4ai.py +3 -0
- agno/tools/file.py +14 -13
- agno/tools/function.py +15 -2
- agno/tools/mcp/mcp.py +1 -0
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/python.py +14 -6
- agno/tools/toolkit.py +122 -23
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/chromadb.py +1 -1
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +1 -1
- agno/vectordb/milvus/milvus.py +1 -1
- agno/vectordb/mongodb/mongodb.py +13 -3
- agno/vectordb/pgvector/pgvector.py +1 -1
- agno/vectordb/pineconedb/pineconedb.py +2 -2
- agno/vectordb/qdrant/qdrant.py +1 -1
- agno/vectordb/redis/redisdb.py +2 -2
- agno/vectordb/singlestore/singlestore.py +1 -1
- agno/vectordb/surrealdb/surrealdb.py +2 -2
- agno/vectordb/weaviate/weaviate.py +1 -1
- agno/workflow/remote.py +1 -1
- agno/workflow/workflow.py +14 -0
- {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/METADATA +1 -1
- {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/RECORD +62 -62
- {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/WHEEL +0 -0
- {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/top_level.txt +0 -0
agno/models/base.py
CHANGED
|
@@ -1016,6 +1016,8 @@ class Model(ABC):
|
|
|
1016
1016
|
model_response.extra.update(provider_response.extra)
|
|
1017
1017
|
if provider_response.provider_data is not None:
|
|
1018
1018
|
model_response.provider_data = provider_response.provider_data
|
|
1019
|
+
if provider_response.response_usage is not None:
|
|
1020
|
+
model_response.response_usage = provider_response.response_usage
|
|
1019
1021
|
|
|
1020
1022
|
async def _aprocess_model_response(
|
|
1021
1023
|
self,
|
|
@@ -1073,6 +1075,8 @@ class Model(ABC):
|
|
|
1073
1075
|
model_response.extra.update(provider_response.extra)
|
|
1074
1076
|
if provider_response.provider_data is not None:
|
|
1075
1077
|
model_response.provider_data = provider_response.provider_data
|
|
1078
|
+
if provider_response.response_usage is not None:
|
|
1079
|
+
model_response.response_usage = provider_response.response_usage
|
|
1076
1080
|
|
|
1077
1081
|
def _populate_assistant_message(
|
|
1078
1082
|
self,
|
|
@@ -2026,10 +2030,20 @@ class Model(ABC):
|
|
|
2026
2030
|
user_input_schema = []
|
|
2027
2031
|
for input_field in fc.arguments.get("user_input_fields", []):
|
|
2028
2032
|
field_type = input_field.get("field_type")
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
+
if isinstance(field_type, str):
|
|
2034
|
+
type_mapping = {
|
|
2035
|
+
"str": str,
|
|
2036
|
+
"int": int,
|
|
2037
|
+
"float": float,
|
|
2038
|
+
"bool": bool,
|
|
2039
|
+
"list": list,
|
|
2040
|
+
"dict": dict,
|
|
2041
|
+
}
|
|
2042
|
+
python_type = type_mapping.get(field_type, str)
|
|
2043
|
+
elif isinstance(field_type, type):
|
|
2044
|
+
python_type = field_type
|
|
2045
|
+
else:
|
|
2046
|
+
python_type = str
|
|
2033
2047
|
user_input_schema.append(
|
|
2034
2048
|
UserInputField(
|
|
2035
2049
|
name=input_field.get("field_name"),
|
|
@@ -2181,10 +2195,20 @@ class Model(ABC):
|
|
|
2181
2195
|
user_input_schema = []
|
|
2182
2196
|
for input_field in fc.arguments.get("user_input_fields", []):
|
|
2183
2197
|
field_type = input_field.get("field_type")
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2198
|
+
if isinstance(field_type, str):
|
|
2199
|
+
type_mapping = {
|
|
2200
|
+
"str": str,
|
|
2201
|
+
"int": int,
|
|
2202
|
+
"float": float,
|
|
2203
|
+
"bool": bool,
|
|
2204
|
+
"list": list,
|
|
2205
|
+
"dict": dict,
|
|
2206
|
+
}
|
|
2207
|
+
python_type = type_mapping.get(field_type, str)
|
|
2208
|
+
elif isinstance(field_type, type):
|
|
2209
|
+
python_type = field_type
|
|
2210
|
+
else:
|
|
2211
|
+
python_type = str
|
|
2188
2212
|
user_input_schema.append(
|
|
2189
2213
|
UserInputField(
|
|
2190
2214
|
name=input_field.get("field_name"),
|
agno/models/google/gemini.py
CHANGED
|
@@ -466,7 +466,12 @@ class Gemini(Model):
|
|
|
466
466
|
|
|
467
467
|
except (ClientError, ServerError) as e:
|
|
468
468
|
log_error(f"Error from Gemini API: {e}")
|
|
469
|
-
error_message = str(e
|
|
469
|
+
error_message = str(e)
|
|
470
|
+
if hasattr(e, "response"):
|
|
471
|
+
if hasattr(e.response, "text"):
|
|
472
|
+
error_message = e.response.text
|
|
473
|
+
else:
|
|
474
|
+
error_message = str(e.response)
|
|
470
475
|
raise ModelProviderError(
|
|
471
476
|
message=error_message,
|
|
472
477
|
status_code=e.code if hasattr(e, "code") and e.code is not None else 502,
|
|
@@ -518,8 +523,14 @@ class Gemini(Model):
|
|
|
518
523
|
|
|
519
524
|
except (ClientError, ServerError) as e:
|
|
520
525
|
log_error(f"Error from Gemini API: {e}")
|
|
526
|
+
error_message = str(e)
|
|
527
|
+
if hasattr(e, "response"):
|
|
528
|
+
if hasattr(e.response, "text"):
|
|
529
|
+
error_message = e.response.text
|
|
530
|
+
else:
|
|
531
|
+
error_message = str(e.response)
|
|
521
532
|
raise ModelProviderError(
|
|
522
|
-
message=
|
|
533
|
+
message=error_message,
|
|
523
534
|
status_code=e.code if hasattr(e, "code") and e.code is not None else 502,
|
|
524
535
|
model_name=self.name,
|
|
525
536
|
model_id=self.id,
|
|
@@ -574,8 +585,14 @@ class Gemini(Model):
|
|
|
574
585
|
|
|
575
586
|
except (ClientError, ServerError) as e:
|
|
576
587
|
log_error(f"Error from Gemini API: {e}")
|
|
588
|
+
error_message = str(e)
|
|
589
|
+
if hasattr(e, "response"):
|
|
590
|
+
if hasattr(e.response, "text"):
|
|
591
|
+
error_message = e.response.text
|
|
592
|
+
else:
|
|
593
|
+
error_message = str(e.response)
|
|
577
594
|
raise ModelProviderError(
|
|
578
|
-
message=
|
|
595
|
+
message=error_message,
|
|
579
596
|
status_code=e.code if hasattr(e, "code") and e.code is not None else 502,
|
|
580
597
|
model_name=self.name,
|
|
581
598
|
model_id=self.id,
|
|
@@ -628,8 +645,14 @@ class Gemini(Model):
|
|
|
628
645
|
|
|
629
646
|
except (ClientError, ServerError) as e:
|
|
630
647
|
log_error(f"Error from Gemini API: {e}")
|
|
648
|
+
error_message = str(e)
|
|
649
|
+
if hasattr(e, "response"):
|
|
650
|
+
if hasattr(e.response, "text"):
|
|
651
|
+
error_message = e.response.text
|
|
652
|
+
else:
|
|
653
|
+
error_message = str(e.response)
|
|
631
654
|
raise ModelProviderError(
|
|
632
|
-
message=
|
|
655
|
+
message=error_message,
|
|
633
656
|
status_code=e.code if hasattr(e, "code") and e.code is not None else 502,
|
|
634
657
|
model_name=self.name,
|
|
635
658
|
model_id=self.id,
|
agno/os/routers/agents/router.py
CHANGED
|
@@ -409,7 +409,7 @@ def get_agent_router(
|
|
|
409
409
|
if agent is None:
|
|
410
410
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
411
411
|
|
|
412
|
-
cancelled = agent.
|
|
412
|
+
cancelled = await agent.acancel_run(run_id=run_id)
|
|
413
413
|
if not cancelled:
|
|
414
414
|
raise HTTPException(status_code=500, detail="Failed to cancel run - run not found or already completed")
|
|
415
415
|
|
agno/os/routers/evals/evals.py
CHANGED
|
@@ -118,8 +118,8 @@ def attach_routes(
|
|
|
118
118
|
model_id: Optional[str] = Query(default=None, description="Model ID"),
|
|
119
119
|
filter_type: Optional[EvalFilterType] = Query(default=None, description="Filter type", alias="type"),
|
|
120
120
|
eval_types: Optional[List[EvalType]] = Depends(parse_eval_types_filter),
|
|
121
|
-
limit: Optional[int] = Query(default=20, description="Number of eval runs to return"),
|
|
122
|
-
page: Optional[int] = Query(default=1, description="Page number"),
|
|
121
|
+
limit: Optional[int] = Query(default=20, description="Number of eval runs to return", ge=1),
|
|
122
|
+
page: Optional[int] = Query(default=1, description="Page number", ge=0),
|
|
123
123
|
sort_by: Optional[str] = Query(default="created_at", description="Field to sort by"),
|
|
124
124
|
sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
|
|
125
125
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
@@ -5,6 +5,7 @@ from typing import Any, Dict, List, Optional, Union
|
|
|
5
5
|
|
|
6
6
|
from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, Path, Query, Request, UploadFile
|
|
7
7
|
|
|
8
|
+
from agno.db.base import AsyncBaseDb
|
|
8
9
|
from agno.knowledge.content import Content, FileData
|
|
9
10
|
from agno.knowledge.knowledge import Knowledge
|
|
10
11
|
from agno.knowledge.reader import ReaderFactory
|
|
@@ -36,7 +37,7 @@ from agno.os.schema import (
|
|
|
36
37
|
from agno.os.settings import AgnoAPISettings
|
|
37
38
|
from agno.os.utils import get_knowledge_instance_by_db_id
|
|
38
39
|
from agno.remote.base import RemoteKnowledge
|
|
39
|
-
from agno.utils.log import log_debug, log_info
|
|
40
|
+
from agno.utils.log import log_debug, log_error, log_info
|
|
40
41
|
from agno.utils.string import generate_id
|
|
41
42
|
|
|
42
43
|
logger = logging.getLogger(__name__)
|
|
@@ -297,7 +298,17 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Union[Knowledge,
|
|
|
297
298
|
else:
|
|
298
299
|
raise HTTPException(status_code=400, detail=f"Invalid reader_id: {update_data.reader_id}")
|
|
299
300
|
|
|
300
|
-
|
|
301
|
+
# Use async patch method if contents_db is an AsyncBaseDb, otherwise use sync patch method
|
|
302
|
+
updated_content_dict = None
|
|
303
|
+
try:
|
|
304
|
+
if knowledge.contents_db is not None and isinstance(knowledge.contents_db, AsyncBaseDb):
|
|
305
|
+
updated_content_dict = await knowledge.apatch_content(content)
|
|
306
|
+
else:
|
|
307
|
+
updated_content_dict = knowledge.patch_content(content)
|
|
308
|
+
except Exception as e:
|
|
309
|
+
log_error(f"Error updating content: {str(e)}")
|
|
310
|
+
raise HTTPException(status_code=500, detail=f"Error updating content: {str(e)}")
|
|
311
|
+
|
|
301
312
|
if not updated_content_dict:
|
|
302
313
|
raise HTTPException(status_code=404, detail=f"Content not found: {content_id}")
|
|
303
314
|
|
|
@@ -344,8 +355,8 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Union[Knowledge,
|
|
|
344
355
|
)
|
|
345
356
|
async def get_content(
|
|
346
357
|
request: Request,
|
|
347
|
-
limit: Optional[int] = Query(default=20, description="Number of content entries to return"),
|
|
348
|
-
page: Optional[int] = Query(default=1, description="Page number"),
|
|
358
|
+
limit: Optional[int] = Query(default=20, description="Number of content entries to return", ge=1),
|
|
359
|
+
page: Optional[int] = Query(default=1, description="Page number", ge=0),
|
|
349
360
|
sort_by: Optional[str] = Query(default="created_at", description="Field to sort by"),
|
|
350
361
|
sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
|
|
351
362
|
db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
|
|
@@ -1090,7 +1101,12 @@ async def process_content(
|
|
|
1090
1101
|
|
|
1091
1102
|
content.status = KnowledgeContentStatus.FAILED
|
|
1092
1103
|
content.status_message = str(e)
|
|
1093
|
-
|
|
1104
|
+
# Use async patch method if contents_db is an AsyncBaseDb, otherwise use sync patch method
|
|
1105
|
+
if knowledge.contents_db is not None and isinstance(knowledge.contents_db, AsyncBaseDb):
|
|
1106
|
+
await knowledge.apatch_content(content)
|
|
1107
|
+
else:
|
|
1108
|
+
knowledge.patch_content(content)
|
|
1109
|
+
|
|
1094
1110
|
except Exception:
|
|
1095
1111
|
# Swallow any secondary errors to avoid crashing the background task
|
|
1096
1112
|
pass
|
|
@@ -156,7 +156,7 @@ class VectorSearchRequestSchema(BaseModel):
|
|
|
156
156
|
class Meta(BaseModel):
|
|
157
157
|
"""Inline metadata schema for pagination."""
|
|
158
158
|
|
|
159
|
-
limit: int = Field(20, description="Number of results per page", ge=1
|
|
159
|
+
limit: int = Field(20, description="Number of results per page", ge=1)
|
|
160
160
|
page: int = Field(1, description="Page number", ge=1)
|
|
161
161
|
|
|
162
162
|
query: str = Field(..., description="The search query text")
|
agno/os/routers/memory/memory.py
CHANGED
|
@@ -256,8 +256,8 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
256
256
|
team_id: Optional[str] = Query(default=None, description="Filter memories by team ID"),
|
|
257
257
|
topics: Optional[List[str]] = Depends(parse_topics),
|
|
258
258
|
search_content: Optional[str] = Query(default=None, description="Fuzzy search within memory content"),
|
|
259
|
-
limit: Optional[int] = Query(default=20, description="Number of memories to return per page"),
|
|
260
|
-
page: Optional[int] = Query(default=1, description="Page number for pagination"),
|
|
259
|
+
limit: Optional[int] = Query(default=20, description="Number of memories to return per page", ge=1),
|
|
260
|
+
page: Optional[int] = Query(default=1, description="Page number for pagination", ge=0),
|
|
261
261
|
sort_by: Optional[str] = Query(default="updated_at", description="Field to sort memories by"),
|
|
262
262
|
sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
|
|
263
263
|
db_id: Optional[str] = Query(default=None, description="Database ID to query memories from"),
|
|
@@ -558,8 +558,8 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
558
558
|
)
|
|
559
559
|
async def get_user_memory_stats(
|
|
560
560
|
request: Request,
|
|
561
|
-
limit: Optional[int] = Query(default=20, description="Number of user statistics to return per page"),
|
|
562
|
-
page: Optional[int] = Query(default=1, description="Page number for pagination"),
|
|
561
|
+
limit: Optional[int] = Query(default=20, description="Number of user statistics to return per page", ge=1),
|
|
562
|
+
page: Optional[int] = Query(default=1, description="Page number for pagination", ge=0),
|
|
563
563
|
db_id: Optional[str] = Query(default=None, description="Database ID to query statistics from"),
|
|
564
564
|
table: Optional[str] = Query(default=None, description="Table to query statistics from"),
|
|
565
565
|
) -> PaginatedResponse[UserStatsSchema]:
|
|
@@ -107,8 +107,8 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
107
107
|
),
|
|
108
108
|
user_id: Optional[str] = Query(default=None, description="Filter sessions by user ID"),
|
|
109
109
|
session_name: Optional[str] = Query(default=None, description="Filter sessions by name (partial match)"),
|
|
110
|
-
limit: Optional[int] = Query(default=20, description="Number of sessions to return per page"),
|
|
111
|
-
page: Optional[int] = Query(default=1, description="Page number for pagination"),
|
|
110
|
+
limit: Optional[int] = Query(default=20, description="Number of sessions to return per page", ge=1),
|
|
111
|
+
page: Optional[int] = Query(default=1, description="Page number for pagination", ge=0),
|
|
112
112
|
sort_by: Optional[str] = Query(default="created_at", description="Field to sort sessions by"),
|
|
113
113
|
sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
|
|
114
114
|
db_id: Optional[str] = Query(default=None, description="Database ID to query sessions from"),
|
agno/os/routers/teams/router.py
CHANGED
|
@@ -95,7 +95,7 @@ async def team_response_streamer(
|
|
|
95
95
|
)
|
|
96
96
|
yield format_sse_event(error_response)
|
|
97
97
|
|
|
98
|
-
except
|
|
98
|
+
except BaseException as e:
|
|
99
99
|
import traceback
|
|
100
100
|
|
|
101
101
|
traceback.print_exc()
|
|
@@ -325,7 +325,7 @@ def get_team_router(
|
|
|
325
325
|
if team is None:
|
|
326
326
|
raise HTTPException(status_code=404, detail="Team not found")
|
|
327
327
|
|
|
328
|
-
cancelled = team.
|
|
328
|
+
cancelled = await team.acancel_run(run_id=run_id)
|
|
329
329
|
if not cancelled:
|
|
330
330
|
raise HTTPException(status_code=500, detail="Failed to cancel run - run not found or already completed")
|
|
331
331
|
|
agno/os/routers/traces/traces.py
CHANGED
|
@@ -126,8 +126,8 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
126
126
|
default=None,
|
|
127
127
|
description="Filter traces ending before this time (ISO 8601 format with timezone, e.g., '2025-11-19T11:00:00Z' or '2025-11-19T16:30:00+05:30'). Times are converted to UTC for comparison.",
|
|
128
128
|
),
|
|
129
|
-
page: int = Query(default=1, description="Page number (1-indexed)", ge=
|
|
130
|
-
limit: int = Query(default=20, description="Number of traces per page", ge=1
|
|
129
|
+
page: int = Query(default=1, description="Page number (1-indexed)", ge=0),
|
|
130
|
+
limit: int = Query(default=20, description="Number of traces per page", ge=1),
|
|
131
131
|
db_id: Optional[str] = Query(default=None, description="Database ID to query traces from"),
|
|
132
132
|
):
|
|
133
133
|
"""Get list of traces with optional filters and pagination"""
|
|
@@ -455,7 +455,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBase
|
|
|
455
455
|
description="Filter sessions with traces created before this time (ISO 8601 format with timezone, e.g., '2025-11-19T11:00:00Z' or '2025-11-19T16:30:00+05:30'). Times are converted to UTC for comparison.",
|
|
456
456
|
),
|
|
457
457
|
page: int = Query(default=1, description="Page number (1-indexed)", ge=1),
|
|
458
|
-
limit: int = Query(default=20, description="Number of sessions per page", ge=1
|
|
458
|
+
limit: int = Query(default=20, description="Number of sessions per page", ge=1),
|
|
459
459
|
db_id: Optional[str] = Query(default=None, description="Database ID to query statistics from"),
|
|
460
460
|
):
|
|
461
461
|
"""Get trace statistics grouped by session"""
|
|
@@ -721,7 +721,7 @@ def get_workflow_router(
|
|
|
721
721
|
if workflow is None:
|
|
722
722
|
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
723
723
|
|
|
724
|
-
cancelled = workflow.
|
|
724
|
+
cancelled = await workflow.acancel_run(run_id=run_id)
|
|
725
725
|
if not cancelled:
|
|
726
726
|
raise HTTPException(status_code=500, detail="Failed to cancel run - run not found or already completed")
|
|
727
727
|
|
agno/os/schema.py
CHANGED
|
@@ -549,7 +549,7 @@ class SortOrder(str, Enum):
|
|
|
549
549
|
|
|
550
550
|
class PaginationInfo(BaseModel):
|
|
551
551
|
page: int = Field(0, description="Current page number (0-indexed)", ge=0)
|
|
552
|
-
limit: int = Field(20, description="Number of items per page", ge=1
|
|
552
|
+
limit: int = Field(20, description="Number of items per page", ge=1)
|
|
553
553
|
total_pages: int = Field(0, description="Total number of pages", ge=0)
|
|
554
554
|
total_count: int = Field(0, description="Total count of items", ge=0)
|
|
555
555
|
search_time_ms: float = Field(0, description="Search execution time in milliseconds", ge=0)
|
agno/os/utils.py
CHANGED
agno/remote/base.py
CHANGED
|
@@ -577,5 +577,5 @@ class BaseRemote:
|
|
|
577
577
|
raise NotImplementedError("acontinue_run method must be implemented by the subclass")
|
|
578
578
|
|
|
579
579
|
@abstractmethod
|
|
580
|
-
async def
|
|
580
|
+
async def acancel_run(self, run_id: str) -> bool:
|
|
581
581
|
raise NotImplementedError("cancel_run method must be implemented by the subclass")
|
agno/team/remote.py
CHANGED
|
@@ -425,7 +425,7 @@ class RemoteTeam(BaseRemote):
|
|
|
425
425
|
)
|
|
426
426
|
return map_task_result_to_team_run_output(task_result, team_id=self.team_id, user_id=user_id)
|
|
427
427
|
|
|
428
|
-
async def
|
|
428
|
+
async def acancel_run(self, run_id: str, auth_token: Optional[str] = None) -> bool:
|
|
429
429
|
"""Cancel a running team execution.
|
|
430
430
|
|
|
431
431
|
Args:
|
agno/team/team.py
CHANGED
|
@@ -56,6 +56,9 @@ from agno.models.utils import get_model
|
|
|
56
56
|
from agno.reasoning.step import NextAction, ReasoningStep, ReasoningSteps
|
|
57
57
|
from agno.run import RunContext, RunStatus
|
|
58
58
|
from agno.run.agent import RunEvent, RunOutput, RunOutputEvent
|
|
59
|
+
from agno.run.cancel import (
|
|
60
|
+
acancel_run as acancel_run_global,
|
|
61
|
+
)
|
|
59
62
|
from agno.run.cancel import (
|
|
60
63
|
acleanup_run,
|
|
61
64
|
araise_if_cancelled,
|
|
@@ -1011,6 +1014,18 @@ class Team:
|
|
|
1011
1014
|
"""
|
|
1012
1015
|
return cancel_run_global(run_id)
|
|
1013
1016
|
|
|
1017
|
+
@staticmethod
|
|
1018
|
+
async def acancel_run(run_id: str) -> bool:
|
|
1019
|
+
"""Cancel a running team execution.
|
|
1020
|
+
|
|
1021
|
+
Args:
|
|
1022
|
+
run_id (str): The run_id to cancel.
|
|
1023
|
+
|
|
1024
|
+
Returns:
|
|
1025
|
+
bool: True if the run was found and marked for cancellation, False otherwise.
|
|
1026
|
+
"""
|
|
1027
|
+
return await acancel_run_global(run_id)
|
|
1028
|
+
|
|
1014
1029
|
async def _connect_mcp_tools(self) -> None:
|
|
1015
1030
|
"""Connect the MCP tools to the agent."""
|
|
1016
1031
|
if self.tools is not None:
|
|
@@ -1554,6 +1569,7 @@ class Team:
|
|
|
1554
1569
|
tools=_tools,
|
|
1555
1570
|
tool_choice=self.tool_choice,
|
|
1556
1571
|
tool_call_limit=self.tool_call_limit,
|
|
1572
|
+
run_response=run_response,
|
|
1557
1573
|
send_media_to_model=self.send_media_to_model,
|
|
1558
1574
|
compression_manager=self.compression_manager if self.compress_tool_results else None,
|
|
1559
1575
|
)
|
|
@@ -2652,6 +2668,8 @@ class Team:
|
|
|
2652
2668
|
"""
|
|
2653
2669
|
log_debug(f"Team Run Start: {run_response.run_id}", center=True)
|
|
2654
2670
|
|
|
2671
|
+
await aregister_run(run_context.run_id)
|
|
2672
|
+
|
|
2655
2673
|
memory_task = None
|
|
2656
2674
|
|
|
2657
2675
|
try:
|
|
@@ -3375,6 +3393,7 @@ class Team:
|
|
|
3375
3393
|
tool_choice=self.tool_choice,
|
|
3376
3394
|
tool_call_limit=self.tool_call_limit,
|
|
3377
3395
|
stream_model_response=stream_model_response,
|
|
3396
|
+
run_response=run_response,
|
|
3378
3397
|
send_media_to_model=self.send_media_to_model,
|
|
3379
3398
|
compression_manager=self.compression_manager if self.compress_tool_results else None,
|
|
3380
3399
|
):
|
|
@@ -5367,7 +5386,8 @@ class Team:
|
|
|
5367
5386
|
|
|
5368
5387
|
elif isinstance(tool, Toolkit):
|
|
5369
5388
|
# For each function in the toolkit and process entrypoint
|
|
5370
|
-
|
|
5389
|
+
toolkit_functions = tool.get_async_functions() if async_mode else tool.get_functions()
|
|
5390
|
+
for name, _func in toolkit_functions.items():
|
|
5371
5391
|
if name in _function_names:
|
|
5372
5392
|
continue
|
|
5373
5393
|
_function_names.append(name)
|
|
@@ -8429,7 +8449,7 @@ class Team:
|
|
|
8429
8449
|
gen_session_name_prompt = "Team Conversation\n"
|
|
8430
8450
|
|
|
8431
8451
|
# Get team session messages for generating the name
|
|
8432
|
-
messages_for_generating_session_name =
|
|
8452
|
+
messages_for_generating_session_name = session.get_messages()
|
|
8433
8453
|
|
|
8434
8454
|
for message in messages_for_generating_session_name:
|
|
8435
8455
|
gen_session_name_prompt += f"{message.role.upper()}: {message.content}\n"
|
|
@@ -8979,7 +8999,7 @@ class Team:
|
|
|
8979
8999
|
log_warning("No valid filters remain after validation. Search will proceed without filters.")
|
|
8980
9000
|
|
|
8981
9001
|
if invalid_keys == [] and valid_filters == {}:
|
|
8982
|
-
|
|
9002
|
+
log_debug("No valid filters provided. Search will proceed without filters.")
|
|
8983
9003
|
filters = None
|
|
8984
9004
|
|
|
8985
9005
|
if self.knowledge_retriever is not None and callable(self.knowledge_retriever):
|
|
@@ -9055,7 +9075,7 @@ class Team:
|
|
|
9055
9075
|
log_warning("No valid filters remain after validation. Search will proceed without filters.")
|
|
9056
9076
|
|
|
9057
9077
|
if invalid_keys == [] and valid_filters == {}:
|
|
9058
|
-
|
|
9078
|
+
log_debug("No valid filters provided. Search will proceed without filters.")
|
|
9059
9079
|
filters = None
|
|
9060
9080
|
|
|
9061
9081
|
if self.knowledge_retriever is not None and callable(self.knowledge_retriever):
|
agno/tools/brandfetch.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Brandfetch API toolkit for retrieving brand data and searching brands.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import warnings
|
|
5
6
|
from os import getenv
|
|
6
|
-
from typing import Any, Optional
|
|
7
|
+
from typing import Any, List, Optional
|
|
7
8
|
|
|
8
9
|
try:
|
|
9
10
|
import httpx
|
|
@@ -31,8 +32,6 @@ class BrandfetchTools(Toolkit):
|
|
|
31
32
|
all: bool - if True, will use all tools
|
|
32
33
|
enable_search_by_identifier: bool - if True, will use search by identifier
|
|
33
34
|
enable_search_by_brand: bool - if True, will use search by brand
|
|
34
|
-
enable_asearch_by_identifier: bool - if True, will use async search by identifier
|
|
35
|
-
enable_asearch_by_brand: bool - if True, will use async search by brand
|
|
36
35
|
"""
|
|
37
36
|
|
|
38
37
|
def __init__(
|
|
@@ -44,9 +43,18 @@ class BrandfetchTools(Toolkit):
|
|
|
44
43
|
enable_search_by_identifier: bool = True,
|
|
45
44
|
enable_search_by_brand: bool = False,
|
|
46
45
|
all: bool = False,
|
|
47
|
-
async_tools: bool = False,
|
|
46
|
+
async_tools: bool = False, # Deprecated
|
|
48
47
|
**kwargs,
|
|
49
48
|
):
|
|
49
|
+
# Handle deprecated async_tools parameter
|
|
50
|
+
if async_tools:
|
|
51
|
+
warnings.warn(
|
|
52
|
+
"The 'async_tools' parameter is deprecated and will be removed in a future version. "
|
|
53
|
+
"Async tools are now automatically used when calling agent.arun() or agent.aprint_response().",
|
|
54
|
+
DeprecationWarning,
|
|
55
|
+
stacklevel=2,
|
|
56
|
+
)
|
|
57
|
+
|
|
50
58
|
self.api_key = api_key or getenv("BRANDFETCH_API_KEY")
|
|
51
59
|
self.client_id = client_id or getenv("BRANDFETCH_CLIENT_ID")
|
|
52
60
|
self.base_url = base_url
|
|
@@ -54,20 +62,21 @@ class BrandfetchTools(Toolkit):
|
|
|
54
62
|
self.search_url = f"{self.base_url}/search"
|
|
55
63
|
self.brand_url = f"{self.base_url}/brands"
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
#
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
# Build tools lists
|
|
66
|
+
# sync tools: used by agent.run() and agent.print_response()
|
|
67
|
+
# async tools: used by agent.arun() and agent.aprint_response()
|
|
68
|
+
tools: List[Any] = []
|
|
69
|
+
async_tools_list: List[tuple] = []
|
|
70
|
+
|
|
71
|
+
if all or enable_search_by_identifier:
|
|
72
|
+
tools.append(self.search_by_identifier)
|
|
73
|
+
async_tools_list.append((self.asearch_by_identifier, "search_by_identifier"))
|
|
74
|
+
if all or enable_search_by_brand:
|
|
75
|
+
tools.append(self.search_by_brand)
|
|
76
|
+
async_tools_list.append((self.asearch_by_brand, "search_by_brand"))
|
|
77
|
+
|
|
69
78
|
name = kwargs.pop("name", "brandfetch_tools")
|
|
70
|
-
super().__init__(name=name, tools=tools, **kwargs)
|
|
79
|
+
super().__init__(name=name, tools=tools, async_tools=async_tools_list, **kwargs)
|
|
71
80
|
|
|
72
81
|
async def asearch_by_identifier(self, identifier: str) -> dict[str, Any]:
|
|
73
82
|
"""
|