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/os/utils.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from datetime import datetime, timezone
|
|
2
3
|
from typing import Any, Callable, Dict, List, Optional, Set, Type, Union
|
|
3
4
|
|
|
4
|
-
from fastapi import FastAPI, HTTPException, UploadFile
|
|
5
|
+
from fastapi import FastAPI, HTTPException, Request, UploadFile
|
|
5
6
|
from fastapi.routing import APIRoute, APIRouter
|
|
6
7
|
from pydantic import BaseModel, create_model
|
|
7
8
|
from starlette.middleware.cors import CORSMiddleware
|
|
@@ -13,13 +14,149 @@ from agno.media import Audio, Image, Video
|
|
|
13
14
|
from agno.media import File as FileMedia
|
|
14
15
|
from agno.models.message import Message
|
|
15
16
|
from agno.os.config import AgentOSConfig
|
|
17
|
+
from agno.run.agent import RunOutputEvent
|
|
18
|
+
from agno.run.team import TeamRunOutputEvent
|
|
19
|
+
from agno.run.workflow import WorkflowRunOutputEvent
|
|
16
20
|
from agno.team.team import Team
|
|
17
21
|
from agno.tools import Toolkit
|
|
18
22
|
from agno.tools.function import Function
|
|
19
|
-
from agno.utils.log import logger
|
|
23
|
+
from agno.utils.log import log_warning, logger
|
|
20
24
|
from agno.workflow.workflow import Workflow
|
|
21
25
|
|
|
22
26
|
|
|
27
|
+
async def get_request_kwargs(request: Request, endpoint_func: Callable) -> Dict[str, Any]:
|
|
28
|
+
"""Given a Request and an endpoint function, return a dictionary with all extra form data fields.
|
|
29
|
+
Args:
|
|
30
|
+
request: The FastAPI Request object
|
|
31
|
+
endpoint_func: The function exposing the endpoint that received the request
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
A dictionary of kwargs
|
|
35
|
+
"""
|
|
36
|
+
import inspect
|
|
37
|
+
|
|
38
|
+
form_data = await request.form()
|
|
39
|
+
sig = inspect.signature(endpoint_func)
|
|
40
|
+
known_fields = set(sig.parameters.keys())
|
|
41
|
+
kwargs: Dict[str, Any] = {key: value for key, value in form_data.items() if key not in known_fields}
|
|
42
|
+
|
|
43
|
+
# Handle JSON parameters. They are passed as strings and need to be deserialized.
|
|
44
|
+
if session_state := kwargs.get("session_state"):
|
|
45
|
+
try:
|
|
46
|
+
if isinstance(session_state, str):
|
|
47
|
+
session_state_dict = json.loads(session_state) # type: ignore
|
|
48
|
+
kwargs["session_state"] = session_state_dict
|
|
49
|
+
except json.JSONDecodeError:
|
|
50
|
+
kwargs.pop("session_state")
|
|
51
|
+
log_warning(f"Invalid session_state parameter couldn't be loaded: {session_state}")
|
|
52
|
+
|
|
53
|
+
if dependencies := kwargs.get("dependencies"):
|
|
54
|
+
try:
|
|
55
|
+
if isinstance(dependencies, str):
|
|
56
|
+
dependencies_dict = json.loads(dependencies) # type: ignore
|
|
57
|
+
kwargs["dependencies"] = dependencies_dict
|
|
58
|
+
except json.JSONDecodeError:
|
|
59
|
+
kwargs.pop("dependencies")
|
|
60
|
+
log_warning(f"Invalid dependencies parameter couldn't be loaded: {dependencies}")
|
|
61
|
+
|
|
62
|
+
if metadata := kwargs.get("metadata"):
|
|
63
|
+
try:
|
|
64
|
+
if isinstance(metadata, str):
|
|
65
|
+
metadata_dict = json.loads(metadata) # type: ignore
|
|
66
|
+
kwargs["metadata"] = metadata_dict
|
|
67
|
+
except json.JSONDecodeError:
|
|
68
|
+
kwargs.pop("metadata")
|
|
69
|
+
log_warning(f"Invalid metadata parameter couldn't be loaded: {metadata}")
|
|
70
|
+
|
|
71
|
+
if knowledge_filters := kwargs.get("knowledge_filters"):
|
|
72
|
+
try:
|
|
73
|
+
if isinstance(knowledge_filters, str):
|
|
74
|
+
knowledge_filters_dict = json.loads(knowledge_filters) # type: ignore
|
|
75
|
+
|
|
76
|
+
# Try to deserialize FilterExpr objects
|
|
77
|
+
from agno.filters import from_dict
|
|
78
|
+
|
|
79
|
+
# Check if it's a single FilterExpr dict or a list of FilterExpr dicts
|
|
80
|
+
if isinstance(knowledge_filters_dict, dict) and "op" in knowledge_filters_dict:
|
|
81
|
+
# Single FilterExpr - convert to list format
|
|
82
|
+
kwargs["knowledge_filters"] = [from_dict(knowledge_filters_dict)]
|
|
83
|
+
elif isinstance(knowledge_filters_dict, list):
|
|
84
|
+
# List of FilterExprs or mixed content
|
|
85
|
+
deserialized = []
|
|
86
|
+
for item in knowledge_filters_dict:
|
|
87
|
+
if isinstance(item, dict) and "op" in item:
|
|
88
|
+
deserialized.append(from_dict(item))
|
|
89
|
+
else:
|
|
90
|
+
# Keep non-FilterExpr items as-is
|
|
91
|
+
deserialized.append(item)
|
|
92
|
+
kwargs["knowledge_filters"] = deserialized
|
|
93
|
+
else:
|
|
94
|
+
# Regular dict filter
|
|
95
|
+
kwargs["knowledge_filters"] = knowledge_filters_dict
|
|
96
|
+
except json.JSONDecodeError:
|
|
97
|
+
kwargs.pop("knowledge_filters")
|
|
98
|
+
log_warning(f"Invalid knowledge_filters parameter couldn't be loaded: {knowledge_filters}")
|
|
99
|
+
except ValueError as e:
|
|
100
|
+
# Filter deserialization failed
|
|
101
|
+
kwargs.pop("knowledge_filters")
|
|
102
|
+
log_warning(f"Invalid FilterExpr in knowledge_filters: {e}")
|
|
103
|
+
|
|
104
|
+
# Handle output_schema - convert JSON schema to dynamic Pydantic model
|
|
105
|
+
if output_schema := kwargs.get("output_schema"):
|
|
106
|
+
try:
|
|
107
|
+
if isinstance(output_schema, str):
|
|
108
|
+
from agno.os.utils import json_schema_to_pydantic_model
|
|
109
|
+
|
|
110
|
+
schema_dict = json.loads(output_schema)
|
|
111
|
+
dynamic_model = json_schema_to_pydantic_model(schema_dict)
|
|
112
|
+
kwargs["output_schema"] = dynamic_model
|
|
113
|
+
except json.JSONDecodeError:
|
|
114
|
+
kwargs.pop("output_schema")
|
|
115
|
+
log_warning(f"Invalid output_schema JSON: {output_schema}")
|
|
116
|
+
except Exception as e:
|
|
117
|
+
kwargs.pop("output_schema")
|
|
118
|
+
log_warning(f"Failed to create output_schema model: {e}")
|
|
119
|
+
|
|
120
|
+
# Parse boolean and null values
|
|
121
|
+
for key, value in kwargs.items():
|
|
122
|
+
if isinstance(value, str) and value.lower() in ["true", "false"]:
|
|
123
|
+
kwargs[key] = value.lower() == "true"
|
|
124
|
+
elif isinstance(value, str) and value.lower() in ["null", "none"]:
|
|
125
|
+
kwargs[key] = None
|
|
126
|
+
|
|
127
|
+
return kwargs
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def format_sse_event(event: Union[RunOutputEvent, TeamRunOutputEvent, WorkflowRunOutputEvent]) -> str:
|
|
131
|
+
"""Parse JSON data into SSE-compliant format.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
event_dict: Dictionary containing the event data
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
SSE-formatted response:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
event: EventName
|
|
141
|
+
data: { ... }
|
|
142
|
+
|
|
143
|
+
event: AnotherEventName
|
|
144
|
+
data: { ... }
|
|
145
|
+
```
|
|
146
|
+
"""
|
|
147
|
+
try:
|
|
148
|
+
# Parse the JSON to extract the event type
|
|
149
|
+
event_type = event.event or "message"
|
|
150
|
+
|
|
151
|
+
# Serialize to valid JSON with double quotes and no newlines
|
|
152
|
+
clean_json = event.to_json(separators=(",", ":"), indent=None)
|
|
153
|
+
|
|
154
|
+
return f"event: {event_type}\ndata: {clean_json}\n\n"
|
|
155
|
+
except json.JSONDecodeError:
|
|
156
|
+
clean_json = event.to_json(separators=(",", ":"), indent=None)
|
|
157
|
+
return f"event: message\ndata: {clean_json}\n\n"
|
|
158
|
+
|
|
159
|
+
|
|
23
160
|
async def get_db(
|
|
24
161
|
dbs: dict[str, list[Union[BaseDb, AsyncBaseDb]]], db_id: Optional[str] = None, table: Optional[str] = None
|
|
25
162
|
) -> Union[BaseDb, AsyncBaseDb]:
|