agno 2.1.9__py3-none-any.whl → 2.2.0__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 (83) hide show
  1. agno/agent/agent.py +2048 -1204
  2. agno/culture/__init__.py +3 -0
  3. agno/culture/manager.py +954 -0
  4. agno/db/async_postgres/async_postgres.py +232 -0
  5. agno/db/async_postgres/schemas.py +15 -0
  6. agno/db/async_postgres/utils.py +58 -0
  7. agno/db/base.py +83 -6
  8. agno/db/dynamo/dynamo.py +162 -0
  9. agno/db/dynamo/schemas.py +44 -0
  10. agno/db/dynamo/utils.py +59 -0
  11. agno/db/firestore/firestore.py +231 -0
  12. agno/db/firestore/schemas.py +10 -0
  13. agno/db/firestore/utils.py +96 -0
  14. agno/db/gcs_json/gcs_json_db.py +190 -0
  15. agno/db/gcs_json/utils.py +58 -0
  16. agno/db/in_memory/in_memory_db.py +118 -0
  17. agno/db/in_memory/utils.py +58 -0
  18. agno/db/json/json_db.py +129 -0
  19. agno/db/json/utils.py +58 -0
  20. agno/db/mongo/mongo.py +222 -0
  21. agno/db/mongo/schemas.py +10 -0
  22. agno/db/mongo/utils.py +59 -0
  23. agno/db/mysql/mysql.py +232 -1
  24. agno/db/mysql/schemas.py +14 -0
  25. agno/db/mysql/utils.py +58 -0
  26. agno/db/postgres/postgres.py +242 -0
  27. agno/db/postgres/schemas.py +15 -0
  28. agno/db/postgres/utils.py +58 -0
  29. agno/db/redis/redis.py +181 -0
  30. agno/db/redis/schemas.py +14 -0
  31. agno/db/redis/utils.py +58 -0
  32. agno/db/schemas/__init__.py +2 -1
  33. agno/db/schemas/culture.py +120 -0
  34. agno/db/singlestore/schemas.py +14 -0
  35. agno/db/singlestore/singlestore.py +231 -0
  36. agno/db/singlestore/utils.py +58 -0
  37. agno/db/sqlite/schemas.py +14 -0
  38. agno/db/sqlite/sqlite.py +274 -7
  39. agno/db/sqlite/utils.py +62 -0
  40. agno/db/surrealdb/models.py +51 -1
  41. agno/db/surrealdb/surrealdb.py +154 -0
  42. agno/db/surrealdb/utils.py +61 -1
  43. agno/knowledge/reader/field_labeled_csv_reader.py +0 -2
  44. agno/memory/manager.py +28 -11
  45. agno/models/anthropic/claude.py +2 -2
  46. agno/models/message.py +0 -1
  47. agno/models/ollama/chat.py +7 -2
  48. agno/os/app.py +29 -7
  49. agno/os/interfaces/a2a/router.py +2 -2
  50. agno/os/interfaces/agui/router.py +2 -2
  51. agno/os/router.py +7 -7
  52. agno/os/routers/evals/schemas.py +31 -31
  53. agno/os/routers/health.py +6 -2
  54. agno/os/routers/knowledge/schemas.py +49 -47
  55. agno/os/routers/memory/schemas.py +16 -16
  56. agno/os/routers/metrics/schemas.py +16 -16
  57. agno/os/routers/session/session.py +382 -7
  58. agno/os/schema.py +254 -231
  59. agno/os/utils.py +1 -1
  60. agno/run/agent.py +49 -1
  61. agno/run/team.py +43 -0
  62. agno/session/summary.py +45 -13
  63. agno/session/team.py +90 -5
  64. agno/team/team.py +1118 -857
  65. agno/tools/gmail.py +59 -14
  66. agno/utils/agent.py +372 -0
  67. agno/utils/events.py +144 -2
  68. agno/utils/print_response/agent.py +10 -6
  69. agno/utils/print_response/team.py +6 -4
  70. agno/utils/print_response/workflow.py +7 -5
  71. agno/utils/team.py +9 -8
  72. agno/workflow/condition.py +17 -9
  73. agno/workflow/loop.py +18 -10
  74. agno/workflow/parallel.py +14 -6
  75. agno/workflow/router.py +17 -9
  76. agno/workflow/step.py +14 -6
  77. agno/workflow/steps.py +14 -6
  78. agno/workflow/workflow.py +245 -122
  79. {agno-2.1.9.dist-info → agno-2.2.0.dist-info}/METADATA +60 -23
  80. {agno-2.1.9.dist-info → agno-2.2.0.dist-info}/RECORD +83 -79
  81. {agno-2.1.9.dist-info → agno-2.2.0.dist-info}/WHEEL +0 -0
  82. {agno-2.1.9.dist-info → agno-2.2.0.dist-info}/licenses/LICENSE +0 -0
  83. {agno-2.1.9.dist-info → agno-2.2.0.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@ from dataclasses import asdict
2
2
  from datetime import datetime, timezone
3
3
  from typing import Any, Dict, List, Optional
4
4
 
5
- from pydantic import BaseModel
5
+ from pydantic import BaseModel, Field
6
6
 
7
7
  from agno.db.schemas.evals import EvalType
8
8
  from agno.eval import AccuracyResult, PerformanceResult, ReliabilityResult
@@ -12,43 +12,43 @@ from agno.eval.reliability import ReliabilityEval
12
12
 
13
13
 
14
14
  class EvalRunInput(BaseModel):
15
- agent_id: Optional[str] = None
16
- team_id: Optional[str] = None
17
-
18
- model_id: Optional[str] = None
19
- model_provider: Optional[str] = None
20
- eval_type: EvalType
21
- input: str
22
- additional_guidelines: Optional[str] = None
23
- additional_context: Optional[str] = None
24
- num_iterations: Optional[int] = 1
25
- name: Optional[str] = None
15
+ agent_id: Optional[str] = Field(None, description="Agent ID to evaluate")
16
+ team_id: Optional[str] = Field(None, description="Team ID to evaluate")
17
+
18
+ model_id: Optional[str] = Field(None, description="Model ID to use for evaluation")
19
+ model_provider: Optional[str] = Field(None, description="Model provider name")
20
+ eval_type: EvalType = Field(..., description="Type of evaluation to run (accuracy, performance, or reliability)")
21
+ input: str = Field(..., description="Input text/query for the evaluation", min_length=1)
22
+ additional_guidelines: Optional[str] = Field(None, description="Additional guidelines for the evaluation")
23
+ additional_context: Optional[str] = Field(None, description="Additional context for the evaluation")
24
+ num_iterations: int = Field(1, description="Number of times to run the evaluation", ge=1, le=100)
25
+ name: Optional[str] = Field(None, description="Name for this evaluation run")
26
26
 
27
27
  # Accuracy eval specific fields
28
- expected_output: Optional[str] = None
28
+ expected_output: Optional[str] = Field(None, description="Expected output for accuracy evaluation")
29
29
 
30
30
  # Performance eval specific fields
31
- warmup_runs: Optional[int] = 0
31
+ warmup_runs: int = Field(0, description="Number of warmup runs before measuring performance", ge=0, le=10)
32
32
 
33
33
  # Reliability eval specific fields
34
- expected_tool_calls: Optional[List[str]] = None
34
+ expected_tool_calls: Optional[List[str]] = Field(None, description="Expected tool calls for reliability evaluation")
35
35
 
36
36
 
37
37
  class EvalSchema(BaseModel):
38
- id: str
39
-
40
- agent_id: Optional[str] = None
41
- model_id: Optional[str] = None
42
- model_provider: Optional[str] = None
43
- team_id: Optional[str] = None
44
- workflow_id: Optional[str] = None
45
- name: Optional[str] = None
46
- evaluated_component_name: Optional[str] = None
47
- eval_type: EvalType
48
- eval_data: Dict[str, Any]
49
- eval_input: Optional[Dict[str, Any]] = None
50
- created_at: Optional[datetime] = None
51
- updated_at: Optional[datetime] = None
38
+ id: str = Field(..., description="Unique identifier for the evaluation run")
39
+
40
+ agent_id: Optional[str] = Field(None, description="Agent ID that was evaluated")
41
+ model_id: Optional[str] = Field(None, description="Model ID used in evaluation")
42
+ model_provider: Optional[str] = Field(None, description="Model provider name")
43
+ team_id: Optional[str] = Field(None, description="Team ID that was evaluated")
44
+ workflow_id: Optional[str] = Field(None, description="Workflow ID that was evaluated")
45
+ name: Optional[str] = Field(None, description="Name of the evaluation run")
46
+ evaluated_component_name: Optional[str] = Field(None, description="Name of the evaluated component")
47
+ eval_type: EvalType = Field(..., description="Type of evaluation (accuracy, performance, or reliability)")
48
+ eval_data: Dict[str, Any] = Field(..., description="Evaluation results and metrics")
49
+ eval_input: Optional[Dict[str, Any]] = Field(None, description="Input parameters used for the evaluation")
50
+ created_at: Optional[datetime] = Field(None, description="Timestamp when evaluation was created")
51
+ updated_at: Optional[datetime] = Field(None, description="Timestamp when evaluation was last updated")
52
52
 
53
53
  @classmethod
54
54
  def from_dict(cls, eval_run: Dict[str, Any]) -> "EvalSchema":
@@ -135,8 +135,8 @@ class EvalSchema(BaseModel):
135
135
 
136
136
 
137
137
  class DeleteEvalRunsRequest(BaseModel):
138
- eval_run_ids: List[str]
138
+ eval_run_ids: List[str] = Field(..., description="List of evaluation run IDs to delete", min_length=1)
139
139
 
140
140
 
141
141
  class UpdateEvalRunRequest(BaseModel):
142
- name: str
142
+ name: str = Field(..., description="New name for the evaluation run", min_length=1, max_length=255)
agno/os/routers/health.py CHANGED
@@ -1,3 +1,5 @@
1
+ from datetime import datetime, timezone
2
+
1
3
  from fastapi import APIRouter
2
4
 
3
5
  from agno.os.schema import HealthResponse
@@ -6,6 +8,8 @@ from agno.os.schema import HealthResponse
6
8
  def get_health_router() -> APIRouter:
7
9
  router = APIRouter(tags=["Health"])
8
10
 
11
+ started_time_stamp = datetime.now(timezone.utc).timestamp()
12
+
9
13
  @router.get(
10
14
  "/health",
11
15
  operation_id="health_check",
@@ -15,11 +19,11 @@ def get_health_router() -> APIRouter:
15
19
  responses={
16
20
  200: {
17
21
  "description": "API is healthy and operational",
18
- "content": {"application/json": {"example": {"status": "ok"}}},
22
+ "content": {"application/json": {"example": {"status": "ok", "instantiated_at": "1760169236.778903"}}},
19
23
  }
20
24
  },
21
25
  )
22
26
  async def health_check() -> HealthResponse:
23
- return HealthResponse(status="ok")
27
+ return HealthResponse(status="ok", instantiated_at=str(started_time_stamp))
24
28
 
25
29
  return router
@@ -16,23 +16,23 @@ class ContentStatus(str, Enum):
16
16
  class ContentStatusResponse(BaseModel):
17
17
  """Response model for content status endpoint."""
18
18
 
19
- status: ContentStatus
20
- status_message: str = ""
19
+ status: ContentStatus = Field(..., description="Current processing status of the content")
20
+ status_message: str = Field("", description="Status message or error details")
21
21
 
22
22
 
23
23
  class ContentResponseSchema(BaseModel):
24
- id: str
25
- name: Optional[str] = None
26
- description: Optional[str] = None
27
- type: Optional[str] = None
28
- size: Optional[str] = None
29
- linked_to: Optional[str] = None
30
- metadata: Optional[dict] = None
31
- access_count: Optional[int] = None
32
- status: Optional[ContentStatus] = None
33
- status_message: Optional[str] = None
34
- created_at: Optional[datetime] = None
35
- updated_at: Optional[datetime] = None
24
+ id: str = Field(..., description="Unique identifier for the content")
25
+ name: Optional[str] = Field(None, description="Name of the content")
26
+ description: Optional[str] = Field(None, description="Description of the content")
27
+ type: Optional[str] = Field(None, description="MIME type of the content")
28
+ size: Optional[str] = Field(None, description="Size of the content in bytes")
29
+ linked_to: Optional[str] = Field(None, description="ID of related content if linked")
30
+ metadata: Optional[dict] = Field(None, description="Additional metadata as key-value pairs")
31
+ access_count: Optional[int] = Field(None, description="Number of times content has been accessed", ge=0)
32
+ status: Optional[ContentStatus] = Field(None, description="Processing status of the content")
33
+ status_message: Optional[str] = Field(None, description="Status message or error details")
34
+ created_at: Optional[datetime] = Field(None, description="Timestamp when content was created")
35
+ updated_at: Optional[datetime] = Field(None, description="Timestamp when content was last updated")
36
36
 
37
37
  @classmethod
38
38
  def from_dict(cls, content: Dict[str, Any]) -> "ContentResponseSchema":
@@ -99,37 +99,39 @@ class ContentUpdateSchema(BaseModel):
99
99
 
100
100
 
101
101
  class ReaderSchema(BaseModel):
102
- id: str
103
- name: Optional[str] = None
104
- description: Optional[str] = None
105
- chunkers: Optional[List[str]] = None
102
+ id: str = Field(..., description="Unique identifier for the reader")
103
+ name: Optional[str] = Field(None, description="Name of the reader")
104
+ description: Optional[str] = Field(None, description="Description of the reader's capabilities")
105
+ chunkers: Optional[List[str]] = Field(None, description="List of supported chunking strategies")
106
106
 
107
107
 
108
108
  class ChunkerSchema(BaseModel):
109
- key: str
110
- name: Optional[str] = None
111
- description: Optional[str] = None
109
+ key: str = Field(..., description="Unique key for the chunker")
110
+ name: Optional[str] = Field(None, description="Name of the chunker")
111
+ description: Optional[str] = Field(None, description="Description of the chunking strategy")
112
112
 
113
113
 
114
114
  class VectorDbSchema(BaseModel):
115
- id: str
116
- name: Optional[str] = None
117
- description: Optional[str] = None
118
- search_types: Optional[List[str]] = None
115
+ id: str = Field(..., description="Unique identifier for the vector database")
116
+ name: Optional[str] = Field(None, description="Name of the vector database")
117
+ description: Optional[str] = Field(None, description="Description of the vector database")
118
+ search_types: Optional[List[str]] = Field(
119
+ None, description="List of supported search types (vector, keyword, hybrid)"
120
+ )
119
121
 
120
122
 
121
123
  class VectorSearchResult(BaseModel):
122
124
  """Schema for search result documents."""
123
125
 
124
- id: str
125
- content: str
126
- name: Optional[str] = None
127
- meta_data: Optional[Dict[str, Any]] = None
128
- usage: Optional[Dict[str, Any]] = None
129
- reranking_score: Optional[float] = None
130
- content_id: Optional[str] = None
131
- content_origin: Optional[str] = None
132
- size: Optional[int] = None
126
+ id: str = Field(..., description="Unique identifier for the search result document")
127
+ content: str = Field(..., description="Content text of the document")
128
+ name: Optional[str] = Field(None, description="Name of the document")
129
+ meta_data: Optional[Dict[str, Any]] = Field(None, description="Metadata associated with the document")
130
+ usage: Optional[Dict[str, Any]] = Field(None, description="Usage statistics (e.g., token counts)")
131
+ reranking_score: Optional[float] = Field(None, description="Reranking score for relevance", ge=0.0, le=1.0)
132
+ content_id: Optional[str] = Field(None, description="ID of the source content")
133
+ content_origin: Optional[str] = Field(None, description="Origin URL or source of the content")
134
+ size: Optional[int] = Field(None, description="Size of the content in bytes", ge=0)
133
135
 
134
136
  @classmethod
135
137
  def from_document(cls, document) -> "VectorSearchResult":
@@ -153,23 +155,23 @@ class VectorSearchRequestSchema(BaseModel):
153
155
  class Meta(BaseModel):
154
156
  """Inline metadata schema for pagination."""
155
157
 
156
- limit: Optional[int] = Field(20, description="Number of results per page", ge=1, le=100)
157
- page: Optional[int] = Field(1, description="Page number", ge=1)
158
+ limit: int = Field(20, description="Number of results per page", ge=1, le=100)
159
+ page: int = Field(1, description="Page number", ge=1)
158
160
 
159
- query: str = Field(..., description="The search query")
160
- db_id: Optional[str] = Field(None, description="The content database id")
161
- vector_db_ids: Optional[List[str]] = Field(None, description="List of vector database ids to search in")
162
- search_type: Optional[str] = Field(None, description="The type of search to perform")
163
- max_results: Optional[int] = Field(None, description="The maximum number of results to return")
164
- filters: Optional[Dict[str, Any]] = Field(None, description="The filters to apply to the search")
161
+ query: str = Field(..., description="The search query text")
162
+ db_id: Optional[str] = Field(None, description="The content database ID to search in")
163
+ vector_db_ids: Optional[List[str]] = Field(None, description="List of vector database IDs to search in")
164
+ search_type: Optional[str] = Field(None, description="The type of search to perform (vector, keyword, hybrid)")
165
+ max_results: Optional[int] = Field(None, description="The maximum number of results to return", ge=1, le=1000)
166
+ filters: Optional[Dict[str, Any]] = Field(None, description="Filters to apply to the search results")
165
167
  meta: Optional[Meta] = Field(
166
168
  None, description="Pagination metadata. Limit and page number to return a subset of results."
167
169
  )
168
170
 
169
171
 
170
172
  class ConfigResponseSchema(BaseModel):
171
- readers: Optional[Dict[str, ReaderSchema]] = None
172
- readersForType: Optional[Dict[str, List[str]]] = None
173
- chunkers: Optional[Dict[str, ChunkerSchema]] = None
174
- filters: Optional[List[str]] = None
175
- vector_dbs: Optional[List[VectorDbSchema]] = None
173
+ readers: Optional[Dict[str, ReaderSchema]] = Field(None, description="Available content readers")
174
+ readersForType: Optional[Dict[str, List[str]]] = Field(None, description="Mapping of content types to reader IDs")
175
+ chunkers: Optional[Dict[str, ChunkerSchema]] = Field(None, description="Available chunking strategies")
176
+ filters: Optional[List[str]] = Field(None, description="Available filter tags")
177
+ vector_dbs: Optional[List[VectorDbSchema]] = Field(None, description="Configured vector databases")
@@ -1,24 +1,24 @@
1
1
  from datetime import datetime, timezone
2
2
  from typing import Any, Dict, List, Optional
3
3
 
4
- from pydantic import BaseModel
4
+ from pydantic import BaseModel, Field
5
5
 
6
6
 
7
7
  class DeleteMemoriesRequest(BaseModel):
8
- memory_ids: List[str]
9
- user_id: Optional[str] = None
8
+ memory_ids: List[str] = Field(..., description="List of memory IDs to delete", min_length=1)
9
+ user_id: Optional[str] = Field(None, description="User ID to filter memories for deletion")
10
10
 
11
11
 
12
12
  class UserMemorySchema(BaseModel):
13
- memory_id: str
14
- memory: str
15
- topics: Optional[List[str]]
13
+ memory_id: str = Field(..., description="Unique identifier for the memory")
14
+ memory: str = Field(..., description="Memory content text", min_length=1)
15
+ topics: Optional[List[str]] = Field(None, description="Topics or tags associated with the memory")
16
16
 
17
- agent_id: Optional[str]
18
- team_id: Optional[str]
19
- user_id: Optional[str]
17
+ agent_id: Optional[str] = Field(None, description="Agent ID associated with this memory")
18
+ team_id: Optional[str] = Field(None, description="Team ID associated with this memory")
19
+ user_id: Optional[str] = Field(None, description="User ID who owns this memory")
20
20
 
21
- updated_at: Optional[datetime]
21
+ updated_at: Optional[datetime] = Field(None, description="Timestamp when memory was last updated")
22
22
 
23
23
  @classmethod
24
24
  def from_dict(cls, memory_dict: Dict[str, Any]) -> "UserMemorySchema":
@@ -36,17 +36,17 @@ class UserMemorySchema(BaseModel):
36
36
  class UserMemoryCreateSchema(BaseModel):
37
37
  """Define the payload expected for creating a new user memory"""
38
38
 
39
- memory: str
40
- user_id: Optional[str] = None
41
- topics: Optional[List[str]] = None
39
+ memory: str = Field(..., description="Memory content text", min_length=1, max_length=5000)
40
+ user_id: Optional[str] = Field(None, description="User ID who owns this memory")
41
+ topics: Optional[List[str]] = Field(None, description="Topics or tags to categorize the memory")
42
42
 
43
43
 
44
44
  class UserStatsSchema(BaseModel):
45
45
  """Schema for user memory statistics"""
46
46
 
47
- user_id: str
48
- total_memories: int
49
- last_memory_updated_at: Optional[datetime] = None
47
+ user_id: str = Field(..., description="User ID")
48
+ total_memories: int = Field(..., description="Total number of memories for this user", ge=0)
49
+ last_memory_updated_at: Optional[datetime] = Field(None, description="Timestamp of the most recent memory update")
50
50
 
51
51
  @classmethod
52
52
  def from_dict(cls, user_stats_dict: Dict[str, Any]) -> "UserStatsSchema":
@@ -1,27 +1,27 @@
1
1
  from datetime import datetime
2
2
  from typing import Any, Dict, List, Optional
3
3
 
4
- from pydantic import BaseModel
4
+ from pydantic import BaseModel, Field
5
5
 
6
6
 
7
7
  class DayAggregatedMetrics(BaseModel):
8
8
  """Aggregated metrics for a given day"""
9
9
 
10
- id: str
10
+ id: str = Field(..., description="Unique identifier for the metrics record")
11
11
 
12
- agent_runs_count: int
13
- agent_sessions_count: int
14
- team_runs_count: int
15
- team_sessions_count: int
16
- workflow_runs_count: int
17
- workflow_sessions_count: int
18
- users_count: int
19
- token_metrics: Dict[str, Any]
20
- model_metrics: List[Dict[str, Any]]
12
+ agent_runs_count: int = Field(..., description="Total number of agent runs", ge=0)
13
+ agent_sessions_count: int = Field(..., description="Total number of agent sessions", ge=0)
14
+ team_runs_count: int = Field(..., description="Total number of team runs", ge=0)
15
+ team_sessions_count: int = Field(..., description="Total number of team sessions", ge=0)
16
+ workflow_runs_count: int = Field(..., description="Total number of workflow runs", ge=0)
17
+ workflow_sessions_count: int = Field(..., description="Total number of workflow sessions", ge=0)
18
+ users_count: int = Field(..., description="Total number of unique users", ge=0)
19
+ token_metrics: Dict[str, Any] = Field(..., description="Token usage metrics (input, output, cached, etc.)")
20
+ model_metrics: List[Dict[str, Any]] = Field(..., description="Metrics grouped by model (model_id, provider, count)")
21
21
 
22
- date: datetime
23
- created_at: int
24
- updated_at: int
22
+ date: datetime = Field(..., description="Date for which these metrics are aggregated")
23
+ created_at: int = Field(..., description="Unix timestamp when metrics were created", ge=0)
24
+ updated_at: int = Field(..., description="Unix timestamp when metrics were last updated", ge=0)
25
25
 
26
26
  @classmethod
27
27
  def from_dict(cls, metrics_dict: Dict[str, Any]) -> "DayAggregatedMetrics":
@@ -43,5 +43,5 @@ class DayAggregatedMetrics(BaseModel):
43
43
 
44
44
 
45
45
  class MetricsResponse(BaseModel):
46
- metrics: List[DayAggregatedMetrics]
47
- updated_at: Optional[datetime]
46
+ metrics: List[DayAggregatedMetrics] = Field(..., description="List of daily aggregated metrics")
47
+ updated_at: Optional[datetime] = Field(None, description="Timestamp of the most recent metrics update")