agno 2.2.13__py3-none-any.whl → 2.3.1__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 (92) hide show
  1. agno/agent/agent.py +197 -110
  2. agno/api/api.py +2 -0
  3. agno/db/base.py +26 -0
  4. agno/db/dynamo/dynamo.py +8 -0
  5. agno/db/dynamo/schemas.py +1 -0
  6. agno/db/firestore/firestore.py +8 -0
  7. agno/db/firestore/schemas.py +1 -0
  8. agno/db/gcs_json/gcs_json_db.py +8 -0
  9. agno/db/in_memory/in_memory_db.py +8 -1
  10. agno/db/json/json_db.py +8 -0
  11. agno/db/migrations/manager.py +199 -0
  12. agno/db/migrations/versions/__init__.py +0 -0
  13. agno/db/migrations/versions/v2_3_0.py +938 -0
  14. agno/db/mongo/async_mongo.py +16 -6
  15. agno/db/mongo/mongo.py +11 -0
  16. agno/db/mongo/schemas.py +3 -0
  17. agno/db/mongo/utils.py +17 -0
  18. agno/db/mysql/mysql.py +76 -3
  19. agno/db/mysql/schemas.py +20 -10
  20. agno/db/postgres/async_postgres.py +99 -25
  21. agno/db/postgres/postgres.py +75 -6
  22. agno/db/postgres/schemas.py +30 -20
  23. agno/db/redis/redis.py +15 -2
  24. agno/db/redis/schemas.py +4 -0
  25. agno/db/schemas/memory.py +13 -0
  26. agno/db/singlestore/schemas.py +11 -0
  27. agno/db/singlestore/singlestore.py +79 -5
  28. agno/db/sqlite/async_sqlite.py +97 -19
  29. agno/db/sqlite/schemas.py +10 -0
  30. agno/db/sqlite/sqlite.py +79 -2
  31. agno/db/surrealdb/surrealdb.py +8 -0
  32. agno/knowledge/chunking/semantic.py +7 -2
  33. agno/knowledge/embedder/nebius.py +1 -1
  34. agno/knowledge/knowledge.py +57 -86
  35. agno/knowledge/reader/csv_reader.py +7 -9
  36. agno/knowledge/reader/docx_reader.py +5 -5
  37. agno/knowledge/reader/field_labeled_csv_reader.py +16 -18
  38. agno/knowledge/reader/json_reader.py +5 -4
  39. agno/knowledge/reader/markdown_reader.py +8 -8
  40. agno/knowledge/reader/pdf_reader.py +11 -11
  41. agno/knowledge/reader/pptx_reader.py +5 -5
  42. agno/knowledge/reader/s3_reader.py +3 -3
  43. agno/knowledge/reader/text_reader.py +8 -8
  44. agno/knowledge/reader/web_search_reader.py +1 -48
  45. agno/knowledge/reader/website_reader.py +10 -10
  46. agno/models/anthropic/claude.py +319 -28
  47. agno/models/aws/claude.py +32 -0
  48. agno/models/azure/openai_chat.py +19 -10
  49. agno/models/base.py +612 -545
  50. agno/models/cerebras/cerebras.py +8 -11
  51. agno/models/cohere/chat.py +27 -1
  52. agno/models/google/gemini.py +39 -7
  53. agno/models/groq/groq.py +25 -11
  54. agno/models/meta/llama.py +20 -9
  55. agno/models/meta/llama_openai.py +3 -19
  56. agno/models/nebius/nebius.py +4 -4
  57. agno/models/openai/chat.py +30 -14
  58. agno/models/openai/responses.py +10 -13
  59. agno/models/response.py +1 -0
  60. agno/models/vertexai/claude.py +26 -0
  61. agno/os/app.py +8 -19
  62. agno/os/router.py +54 -0
  63. agno/os/routers/knowledge/knowledge.py +2 -2
  64. agno/os/schema.py +2 -2
  65. agno/session/agent.py +57 -92
  66. agno/session/summary.py +1 -1
  67. agno/session/team.py +62 -112
  68. agno/session/workflow.py +353 -57
  69. agno/team/team.py +227 -125
  70. agno/tools/models/nebius.py +5 -5
  71. agno/tools/models_labs.py +20 -10
  72. agno/tools/nano_banana.py +151 -0
  73. agno/tools/yfinance.py +12 -11
  74. agno/utils/http.py +111 -0
  75. agno/utils/media.py +11 -0
  76. agno/utils/models/claude.py +8 -0
  77. agno/utils/print_response/agent.py +33 -12
  78. agno/utils/print_response/team.py +22 -12
  79. agno/vectordb/couchbase/couchbase.py +6 -2
  80. agno/workflow/condition.py +13 -0
  81. agno/workflow/loop.py +13 -0
  82. agno/workflow/parallel.py +13 -0
  83. agno/workflow/router.py +13 -0
  84. agno/workflow/step.py +120 -20
  85. agno/workflow/steps.py +13 -0
  86. agno/workflow/workflow.py +76 -63
  87. {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/METADATA +6 -2
  88. {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/RECORD +91 -88
  89. agno/tools/googlesearch.py +0 -98
  90. {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/WHEEL +0 -0
  91. {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/licenses/LICENSE +0 -0
  92. {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/top_level.txt +0 -0
agno/db/dynamo/dynamo.py CHANGED
@@ -182,6 +182,14 @@ class DynamoDb(BaseDb):
182
182
 
183
183
  return table_name
184
184
 
185
+ def get_latest_schema_version(self):
186
+ """Get the latest version of the database schema."""
187
+ pass
188
+
189
+ def upsert_schema_version(self, version: str) -> None:
190
+ """Upsert the schema version into the database."""
191
+ pass
192
+
185
193
  # --- Sessions ---
186
194
 
187
195
  def delete_session(self, session_id: Optional[str] = None) -> bool:
agno/db/dynamo/schemas.py CHANGED
@@ -74,6 +74,7 @@ USER_MEMORY_TABLE_SCHEMA = {
74
74
  {"AttributeName": "agent_id", "AttributeType": "S"},
75
75
  {"AttributeName": "team_id", "AttributeType": "S"},
76
76
  {"AttributeName": "workflow_id", "AttributeType": "S"},
77
+ {"AttributeName": "created_at", "AttributeType": "S"},
77
78
  {"AttributeName": "updated_at", "AttributeType": "S"},
78
79
  ],
79
80
  "GlobalSecondaryIndexes": [
@@ -237,6 +237,14 @@ class FirestoreDb(BaseDb):
237
237
  log_error(f"Error deleting session: {e}")
238
238
  raise e
239
239
 
240
+ def get_latest_schema_version(self):
241
+ """Get the latest version of the database schema."""
242
+ pass
243
+
244
+ def upsert_schema_version(self, version: str) -> None:
245
+ """Upsert the schema version into the database."""
246
+ pass
247
+
240
248
  def delete_sessions(self, session_ids: List[str]) -> None:
241
249
  """Delete multiple sessions from the database.
242
250
 
@@ -67,6 +67,7 @@ USER_MEMORY_COLLECTION_SCHEMA = [
67
67
  {"key": "agent_id"},
68
68
  {"key": "team_id"},
69
69
  {"key": "topics"},
70
+ {"key": "created_at"},
70
71
  {"key": "updated_at"},
71
72
  # Composite indexes for memory queries
72
73
  {"key": [("user_id", "ASCENDING"), ("agent_id", "ASCENDING")], "collection_group": False},
@@ -142,6 +142,14 @@ class GcsJsonDb(BaseDb):
142
142
  log_error(f"Error writing to the {blob_name} JSON file in GCS: {e}")
143
143
  return
144
144
 
145
+ def get_latest_schema_version(self):
146
+ """Get the latest version of the database schema."""
147
+ pass
148
+
149
+ def upsert_schema_version(self, version: str) -> None:
150
+ """Upsert the schema version into the database."""
151
+ pass
152
+
145
153
  # -- Session methods --
146
154
 
147
155
  def delete_session(self, session_id: str) -> bool:
@@ -38,8 +38,15 @@ class InMemoryDb(BaseDb):
38
38
  """In-memory implementation, always returns True."""
39
39
  return True
40
40
 
41
- # -- Session methods --
41
+ def get_latest_schema_version(self):
42
+ """Get the latest version of the database schema."""
43
+ pass
44
+
45
+ def upsert_schema_version(self, version: str) -> None:
46
+ """Upsert the schema version into the database."""
47
+ pass
42
48
 
49
+ # -- Session methods --
43
50
  def delete_session(self, session_id: str) -> bool:
44
51
  """Delete a session from in-memory storage.
45
52
 
agno/db/json/json_db.py CHANGED
@@ -124,6 +124,14 @@ class JsonDb(BaseDb):
124
124
  log_error(f"Error writing to the {file_path} JSON file: {e}")
125
125
  raise e
126
126
 
127
+ def get_latest_schema_version(self):
128
+ """Get the latest version of the database schema."""
129
+ pass
130
+
131
+ def upsert_schema_version(self, version: str) -> None:
132
+ """Upsert the schema version into the database."""
133
+ pass
134
+
127
135
  # -- Session methods --
128
136
 
129
137
  def delete_session(self, session_id: str) -> bool:
@@ -0,0 +1,199 @@
1
+ import importlib
2
+ from typing import Optional, Union
3
+
4
+ from packaging import version as packaging_version
5
+ from packaging.version import Version
6
+
7
+ from agno.db.base import AsyncBaseDb, BaseDb
8
+ from agno.utils.log import log_error, log_info, log_warning
9
+
10
+
11
+ class MigrationManager:
12
+ """Manager class to handle database migrations"""
13
+
14
+ available_versions: list[tuple[str, Version]] = [
15
+ ("v2_0_0", packaging_version.parse("2.0.0")),
16
+ ("v2_3_0", packaging_version.parse("2.3.0")),
17
+ ]
18
+
19
+ def __init__(self, db: Union[AsyncBaseDb, BaseDb]):
20
+ self.db = db
21
+
22
+ @property
23
+ def latest_schema_version(self) -> Version:
24
+ return self.available_versions[-1][1]
25
+
26
+ async def up(self, target_version: Optional[str] = None, table_type: Optional[str] = None):
27
+ """Handle executing an up migration.
28
+
29
+ Args:
30
+ target_version: The version to migrate to, e.g. "v3.0.0". If not provided, the latest available version will be used.
31
+ table_type: The type of table to migrate. If not provided, all table types will be considered.
32
+ """
33
+
34
+ # If not target version is provided, use the latest available version
35
+ if not target_version:
36
+ _target_version = self.latest_schema_version
37
+ log_info(
38
+ f"No target version provided. Will migrate to the latest available version: {str(_target_version)}"
39
+ )
40
+ else:
41
+ _target_version = packaging_version.parse(target_version)
42
+
43
+ # Select tables to migrate
44
+ if table_type:
45
+ if table_type not in ["memory", "session", "metrics", "eval", "knowledge", "culture"]:
46
+ log_warning(
47
+ f"Invalid table type: {table_type}. Use one of: memory, session, metrics, eval, knowledge, culture"
48
+ )
49
+ return
50
+ tables = [(table_type, getattr(self.db, f"{table_type}_table_name"))]
51
+ else:
52
+ tables = [
53
+ ("memories", self.db.memory_table_name),
54
+ ("sessions", self.db.session_table_name),
55
+ ("metrics", self.db.metrics_table_name),
56
+ ("evals", self.db.eval_table_name),
57
+ ("knowledge", self.db.knowledge_table_name),
58
+ ("culture", self.db.culture_table_name),
59
+ ]
60
+
61
+ # Handle migrations for each table separately (extend in future if needed):
62
+ for table_type, table_name in tables:
63
+ if isinstance(self.db, AsyncBaseDb):
64
+ current_version = packaging_version.parse(await self.db.get_latest_schema_version(table_name))
65
+ else:
66
+ current_version = packaging_version.parse(self.db.get_latest_schema_version(table_name))
67
+
68
+ if current_version is None:
69
+ log_warning(f"Skipping up migration: No version found for table {table_name}.")
70
+ continue
71
+
72
+ # If the target version is less or equal to the current version, no migrations needed
73
+ if _target_version <= current_version:
74
+ log_warning(
75
+ f"Skipping up migration: the version of table '{table_name}' ({current_version}) is less or equal to the target version ({_target_version})."
76
+ )
77
+ continue
78
+
79
+ log_info(
80
+ f"Starting database migration for table {table_name}. Current version: {current_version}. Target version: {_target_version}."
81
+ )
82
+
83
+ # Find files after the current version
84
+ latest_version = None
85
+ migration_executed = False
86
+ for version, normalised_version in self.available_versions:
87
+ if normalised_version > current_version:
88
+ if target_version and normalised_version > _target_version:
89
+ break
90
+
91
+ log_info(f"Applying migration {normalised_version} on {table_name}")
92
+ migration_executed = await self._up_migration(version, table_type, table_name)
93
+ if migration_executed:
94
+ log_info(f"Successfully applied migration {normalised_version} on table {table_name}")
95
+ else:
96
+ log_info(f"Skipping application of migration {normalised_version} on table {table_name}")
97
+
98
+ latest_version = normalised_version.public
99
+
100
+ if migration_executed and latest_version:
101
+ log_info(f"Storing version {latest_version} in database for table {table_name}")
102
+ if isinstance(self.db, AsyncBaseDb):
103
+ await self.db.upsert_schema_version(table_name, latest_version)
104
+ else:
105
+ self.db.upsert_schema_version(table_name, latest_version)
106
+ log_info(f"Successfully stored version {latest_version} in database for table {table_name}")
107
+ log_info("----------------------------------------------------------")
108
+
109
+ async def _up_migration(self, version: str, table_type: str, table_name: str) -> bool:
110
+ """Run the database-specific logic to handle an up migration.
111
+
112
+ Args:
113
+ version: The version to migrate to, e.g. "v3.0.0"
114
+ """
115
+ migration_module = importlib.import_module(f"agno.db.migrations.versions.{version}")
116
+
117
+ try:
118
+ if isinstance(self.db, AsyncBaseDb):
119
+ return await migration_module.async_up(self.db, table_type, table_name)
120
+ else:
121
+ return migration_module.up(self.db, table_type, table_name)
122
+ except Exception as e:
123
+ log_error(f"Error running migration to version {version}: {e}")
124
+ raise
125
+
126
+ async def down(self, target_version: str, table_type: Optional[str] = None):
127
+ """Handle executing a down migration.
128
+
129
+ Args:
130
+ target_version: The version to migrate to. e.g. "v2.3.0"
131
+ table_type: The type of table to migrate. If not provided, all table types will be considered.
132
+ """
133
+ _target_version = packaging_version.parse(target_version)
134
+
135
+ # Select tables to migrate
136
+ if table_type:
137
+ if table_type not in ["memory", "session", "metrics", "eval", "knowledge", "culture"]:
138
+ log_warning(
139
+ f"Invalid table type: {table_type}. Use one of: memory, session, metrics, eval, knowledge, culture"
140
+ )
141
+ return
142
+ tables = [(table_type, getattr(self.db, f"{table_type}_table_name"))]
143
+ else:
144
+ tables = [
145
+ ("memories", self.db.memory_table_name),
146
+ ("sessions", self.db.session_table_name),
147
+ ("metrics", self.db.metrics_table_name),
148
+ ("evals", self.db.eval_table_name),
149
+ ("knowledge", self.db.knowledge_table_name),
150
+ ("culture", self.db.culture_table_name),
151
+ ]
152
+
153
+ for table_type, table_name in tables:
154
+ if isinstance(self.db, AsyncBaseDb):
155
+ current_version = packaging_version.parse(await self.db.get_latest_schema_version(table_name))
156
+ else:
157
+ current_version = packaging_version.parse(self.db.get_latest_schema_version(table_name))
158
+
159
+ if _target_version >= current_version:
160
+ log_warning(
161
+ f"Skipping down migration: the version of table '{table_name}' ({current_version}) is less or equal to the target version ({_target_version})."
162
+ )
163
+ continue
164
+
165
+ migration_executed = False
166
+ # Run down migration for all versions between target and current (include down of current version)
167
+ # Apply down migrations in reverse order to ensure dependencies are met
168
+ for version, normalised_version in reversed(self.available_versions):
169
+ if normalised_version > _target_version:
170
+ log_info(f"Reverting migration {normalised_version} on table {table_name}")
171
+ migration_executed = await self._down_migration(version, table_type, table_name)
172
+ if migration_executed:
173
+ log_info(f"Successfully reverted migration {normalised_version} on table {table_name}")
174
+ else:
175
+ log_info(f"Skipping revert of migration {normalised_version} on table {table_name}")
176
+
177
+ if migration_executed:
178
+ log_info(f"Storing version {_target_version} in database for table {table_name}")
179
+ if isinstance(self.db, AsyncBaseDb):
180
+ await self.db.upsert_schema_version(table_name, _target_version.public)
181
+ else:
182
+ self.db.upsert_schema_version(table_name, _target_version.public)
183
+ log_info(f"Successfully stored version {_target_version} in database for table {table_name}")
184
+
185
+ async def _down_migration(self, version: str, table_type: str, table_name: str) -> bool:
186
+ """Run the database-specific logic to handle a down migration.
187
+
188
+ Args:
189
+ version: The version to migrate to, e.g. "v3.0.0"
190
+ """
191
+ migration_module = importlib.import_module(f"agno.db.migrations.versions.{version}")
192
+ try:
193
+ if isinstance(self.db, AsyncBaseDb):
194
+ return await migration_module.async_down(self.db, table_type, table_name)
195
+ else:
196
+ return migration_module.down(self.db, table_type, table_name)
197
+ except Exception as e:
198
+ log_error(f"Error running migration to version {version}: {e}")
199
+ raise
File without changes