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.
Files changed (71) hide show
  1. agno/agent/agent.py +391 -335
  2. agno/db/mongo/async_mongo.py +0 -24
  3. agno/db/mongo/mongo.py +0 -16
  4. agno/db/mysql/__init__.py +2 -1
  5. agno/db/mysql/async_mysql.py +2888 -0
  6. agno/db/mysql/mysql.py +17 -27
  7. agno/db/mysql/utils.py +139 -6
  8. agno/db/postgres/async_postgres.py +10 -26
  9. agno/db/postgres/postgres.py +7 -25
  10. agno/db/redis/redis.py +0 -4
  11. agno/db/schemas/evals.py +1 -0
  12. agno/db/singlestore/singlestore.py +5 -12
  13. agno/db/sqlite/async_sqlite.py +2 -26
  14. agno/db/sqlite/sqlite.py +0 -20
  15. agno/eval/__init__.py +10 -0
  16. agno/eval/agent_as_judge.py +860 -0
  17. agno/eval/base.py +29 -0
  18. agno/eval/utils.py +2 -1
  19. agno/exceptions.py +7 -0
  20. agno/knowledge/embedder/openai.py +8 -8
  21. agno/knowledge/knowledge.py +1142 -176
  22. agno/media.py +22 -6
  23. agno/models/aws/claude.py +8 -7
  24. agno/models/base.py +160 -11
  25. agno/models/deepseek/deepseek.py +67 -0
  26. agno/models/google/gemini.py +65 -11
  27. agno/models/google/utils.py +22 -0
  28. agno/models/message.py +2 -0
  29. agno/models/openai/chat.py +4 -0
  30. agno/models/openai/responses.py +3 -2
  31. agno/os/app.py +64 -74
  32. agno/os/interfaces/a2a/router.py +3 -4
  33. agno/os/interfaces/a2a/utils.py +1 -1
  34. agno/os/interfaces/agui/router.py +2 -0
  35. agno/os/middleware/jwt.py +8 -6
  36. agno/os/router.py +3 -1607
  37. agno/os/routers/agents/__init__.py +3 -0
  38. agno/os/routers/agents/router.py +581 -0
  39. agno/os/routers/agents/schema.py +261 -0
  40. agno/os/routers/evals/evals.py +26 -6
  41. agno/os/routers/evals/schemas.py +34 -2
  42. agno/os/routers/evals/utils.py +101 -20
  43. agno/os/routers/knowledge/knowledge.py +1 -1
  44. agno/os/routers/teams/__init__.py +3 -0
  45. agno/os/routers/teams/router.py +496 -0
  46. agno/os/routers/teams/schema.py +257 -0
  47. agno/os/routers/workflows/__init__.py +3 -0
  48. agno/os/routers/workflows/router.py +545 -0
  49. agno/os/routers/workflows/schema.py +75 -0
  50. agno/os/schema.py +1 -559
  51. agno/os/utils.py +139 -2
  52. agno/team/team.py +159 -100
  53. agno/tools/file_generation.py +12 -6
  54. agno/tools/firecrawl.py +15 -7
  55. agno/tools/workflow.py +8 -1
  56. agno/utils/hooks.py +64 -5
  57. agno/utils/http.py +2 -2
  58. agno/utils/media.py +11 -1
  59. agno/utils/print_response/agent.py +8 -0
  60. agno/utils/print_response/team.py +8 -0
  61. agno/vectordb/pgvector/pgvector.py +88 -51
  62. agno/workflow/parallel.py +11 -5
  63. agno/workflow/step.py +17 -5
  64. agno/workflow/types.py +38 -2
  65. agno/workflow/workflow.py +12 -4
  66. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/METADATA +8 -3
  67. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/RECORD +70 -58
  68. agno/tools/memori.py +0 -339
  69. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/WHEEL +0 -0
  70. {agno-2.3.7.dist-info → agno-2.3.9.dist-info}/licenses/LICENSE +0 -0
  71. {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]: