agno 2.2.7__py3-none-any.whl → 2.2.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 (43) hide show
  1. agno/agent/agent.py +23 -15
  2. agno/db/base.py +23 -0
  3. agno/db/dynamo/dynamo.py +20 -25
  4. agno/db/dynamo/schemas.py +1 -0
  5. agno/db/firestore/firestore.py +11 -0
  6. agno/db/gcs_json/gcs_json_db.py +4 -0
  7. agno/db/in_memory/in_memory_db.py +4 -0
  8. agno/db/json/json_db.py +4 -0
  9. agno/db/mongo/async_mongo.py +27 -0
  10. agno/db/mongo/mongo.py +25 -0
  11. agno/db/mysql/mysql.py +26 -1
  12. agno/db/postgres/async_postgres.py +26 -1
  13. agno/db/postgres/postgres.py +26 -1
  14. agno/db/redis/redis.py +4 -0
  15. agno/db/singlestore/singlestore.py +24 -0
  16. agno/db/sqlite/async_sqlite.py +25 -1
  17. agno/db/sqlite/sqlite.py +25 -1
  18. agno/db/surrealdb/surrealdb.py +13 -1
  19. agno/knowledge/reader/docx_reader.py +0 -1
  20. agno/models/azure/ai_foundry.py +2 -1
  21. agno/models/cerebras/cerebras.py +3 -2
  22. agno/models/openai/chat.py +2 -1
  23. agno/models/openai/responses.py +2 -1
  24. agno/os/app.py +112 -50
  25. agno/os/config.py +1 -0
  26. agno/os/interfaces/agui/router.py +9 -0
  27. agno/os/interfaces/agui/utils.py +49 -3
  28. agno/os/mcp.py +8 -8
  29. agno/os/router.py +27 -9
  30. agno/os/routers/evals/evals.py +12 -7
  31. agno/os/routers/memory/memory.py +18 -10
  32. agno/os/routers/metrics/metrics.py +6 -4
  33. agno/os/routers/session/session.py +21 -11
  34. agno/os/utils.py +57 -11
  35. agno/team/team.py +26 -21
  36. agno/vectordb/__init__.py +1 -2
  37. agno/vectordb/mongodb/__init__.py +7 -1
  38. agno/vectordb/redis/__init__.py +4 -0
  39. {agno-2.2.7.dist-info → agno-2.2.9.dist-info}/METADATA +11 -13
  40. {agno-2.2.7.dist-info → agno-2.2.9.dist-info}/RECORD +43 -43
  41. {agno-2.2.7.dist-info → agno-2.2.9.dist-info}/WHEEL +0 -0
  42. {agno-2.2.7.dist-info → agno-2.2.9.dist-info}/licenses/LICENSE +0 -0
  43. {agno-2.2.7.dist-info → agno-2.2.9.dist-info}/top_level.txt +0 -0
agno/agent/agent.py CHANGED
@@ -1140,7 +1140,7 @@ class Agent:
1140
1140
  add_session_state_to_context: Optional[bool] = None,
1141
1141
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
1142
1142
  stream_events: bool = False,
1143
- yield_run_response: bool = False,
1143
+ yield_run_output: Optional[bool] = None,
1144
1144
  debug_mode: Optional[bool] = None,
1145
1145
  **kwargs: Any,
1146
1146
  ) -> Iterator[Union[RunOutputEvent, RunOutput]]:
@@ -1410,7 +1410,7 @@ class Agent:
1410
1410
  if stream_events:
1411
1411
  yield completed_event # type: ignore
1412
1412
 
1413
- if yield_run_response:
1413
+ if yield_run_output:
1414
1414
  yield run_response
1415
1415
 
1416
1416
  # Log Agent Telemetry
@@ -1491,7 +1491,8 @@ class Agent:
1491
1491
  add_session_state_to_context: Optional[bool] = None,
1492
1492
  dependencies: Optional[Dict[str, Any]] = None,
1493
1493
  metadata: Optional[Dict[str, Any]] = None,
1494
- yield_run_response: bool = False,
1494
+ yield_run_response: bool = False, # To be deprecated: use yield_run_output instead
1495
+ yield_run_output: bool = False,
1495
1496
  debug_mode: Optional[bool] = None,
1496
1497
  **kwargs: Any,
1497
1498
  ) -> Iterator[Union[RunOutputEvent, RunOutput]]: ...
@@ -1517,7 +1518,8 @@ class Agent:
1517
1518
  add_session_state_to_context: Optional[bool] = None,
1518
1519
  dependencies: Optional[Dict[str, Any]] = None,
1519
1520
  metadata: Optional[Dict[str, Any]] = None,
1520
- yield_run_response: bool = False,
1521
+ yield_run_response: Optional[bool] = None, # To be deprecated: use yield_run_output instead
1522
+ yield_run_output: Optional[bool] = None,
1521
1523
  debug_mode: Optional[bool] = None,
1522
1524
  **kwargs: Any,
1523
1525
  ) -> Union[RunOutput, Iterator[Union[RunOutputEvent, RunOutput]]]:
@@ -1655,6 +1657,8 @@ class Agent:
1655
1657
  last_exception = None
1656
1658
  num_attempts = retries + 1
1657
1659
 
1660
+ yield_run_output = yield_run_output or yield_run_response # For backwards compatibility
1661
+
1658
1662
  for attempt in range(num_attempts):
1659
1663
  try:
1660
1664
  if stream:
@@ -1668,7 +1672,7 @@ class Agent:
1668
1672
  add_session_state_to_context=add_session_state,
1669
1673
  response_format=response_format,
1670
1674
  stream_events=stream_events,
1671
- yield_run_response=yield_run_response,
1675
+ yield_run_output=yield_run_output,
1672
1676
  debug_mode=debug_mode,
1673
1677
  **kwargs,
1674
1678
  )
@@ -2009,7 +2013,7 @@ class Agent:
2009
2013
  add_session_state_to_context: Optional[bool] = None,
2010
2014
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
2011
2015
  stream_events: bool = False,
2012
- yield_run_response: Optional[bool] = None,
2016
+ yield_run_output: Optional[bool] = None,
2013
2017
  debug_mode: Optional[bool] = None,
2014
2018
  **kwargs: Any,
2015
2019
  ) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]:
@@ -2307,7 +2311,7 @@ class Agent:
2307
2311
  if stream_events:
2308
2312
  yield completed_event # type: ignore
2309
2313
 
2310
- if yield_run_response:
2314
+ if yield_run_output:
2311
2315
  yield run_response
2312
2316
 
2313
2317
  # Log Agent Telemetry
@@ -2408,7 +2412,8 @@ class Agent:
2408
2412
  add_session_state_to_context: Optional[bool] = None,
2409
2413
  dependencies: Optional[Dict[str, Any]] = None,
2410
2414
  metadata: Optional[Dict[str, Any]] = None,
2411
- yield_run_response: Optional[bool] = None,
2415
+ yield_run_response: Optional[bool] = None, # To be deprecated: use yield_run_output instead
2416
+ yield_run_output: Optional[bool] = None,
2412
2417
  debug_mode: Optional[bool] = None,
2413
2418
  **kwargs: Any,
2414
2419
  ) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]: ...
@@ -2434,7 +2439,8 @@ class Agent:
2434
2439
  add_session_state_to_context: Optional[bool] = None,
2435
2440
  dependencies: Optional[Dict[str, Any]] = None,
2436
2441
  metadata: Optional[Dict[str, Any]] = None,
2437
- yield_run_response: Optional[bool] = None,
2442
+ yield_run_response: Optional[bool] = None, # To be deprecated: use yield_run_output instead
2443
+ yield_run_output: Optional[bool] = None,
2438
2444
  debug_mode: Optional[bool] = None,
2439
2445
  **kwargs: Any,
2440
2446
  ) -> Union[RunOutput, AsyncIterator[RunOutputEvent]]:
@@ -2559,6 +2565,8 @@ class Agent:
2559
2565
  last_exception = None
2560
2566
  num_attempts = retries + 1
2561
2567
 
2568
+ yield_run_output = yield_run_output or yield_run_response # For backwards compatibility
2569
+
2562
2570
  for attempt in range(num_attempts):
2563
2571
  try:
2564
2572
  # Pass the new run_response to _arun
@@ -2569,7 +2577,7 @@ class Agent:
2569
2577
  user_id=user_id,
2570
2578
  response_format=response_format,
2571
2579
  stream_events=stream_events,
2572
- yield_run_response=yield_run_response,
2580
+ yield_run_output=yield_run_output,
2573
2581
  session_id=session_id,
2574
2582
  add_history_to_context=add_history,
2575
2583
  add_dependencies_to_context=add_dependencies,
@@ -3248,7 +3256,7 @@ class Agent:
3248
3256
  dependencies: Optional[Dict[str, Any]] = None,
3249
3257
  metadata: Optional[Dict[str, Any]] = None,
3250
3258
  debug_mode: Optional[bool] = None,
3251
- yield_run_response: bool = False,
3259
+ yield_run_output: bool = False,
3252
3260
  **kwargs,
3253
3261
  ) -> Union[RunOutput, AsyncIterator[Union[RunOutputEvent, RunOutput]]]:
3254
3262
  """Continue a previous run.
@@ -3266,7 +3274,7 @@ class Agent:
3266
3274
  dependencies: The dependencies to use for continuing the run.
3267
3275
  metadata: The metadata to use for continuing the run.
3268
3276
  debug_mode: Whether to enable debug mode.
3269
- yield_run_response: Whether to yield the run response.
3277
+ yield_run_output: Whether to yield the run response.
3270
3278
  (deprecated) stream_intermediate_steps: Whether to stream all steps.
3271
3279
  """
3272
3280
  if run_response is None and run_id is None:
@@ -3351,7 +3359,7 @@ class Agent:
3351
3359
  session_id=session_id,
3352
3360
  response_format=response_format,
3353
3361
  stream_events=stream_events,
3354
- yield_run_response=yield_run_response,
3362
+ yield_run_output=yield_run_output,
3355
3363
  debug_mode=debug_mode,
3356
3364
  **kwargs,
3357
3365
  )
@@ -3620,7 +3628,7 @@ class Agent:
3620
3628
  user_id: Optional[str] = None,
3621
3629
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
3622
3630
  stream_events: bool = False,
3623
- yield_run_response: Optional[bool] = None,
3631
+ yield_run_output: bool = False,
3624
3632
  debug_mode: Optional[bool] = None,
3625
3633
  **kwargs,
3626
3634
  ) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]:
@@ -3860,7 +3868,7 @@ class Agent:
3860
3868
  if stream_events:
3861
3869
  yield completed_event # type: ignore
3862
3870
 
3863
- if yield_run_response:
3871
+ if yield_run_output:
3864
3872
  yield run_response
3865
3873
 
3866
3874
  # Log Agent Telemetry
agno/db/base.py CHANGED
@@ -38,6 +38,14 @@ class BaseDb(ABC):
38
38
  self.eval_table_name = eval_table or "agno_eval_runs"
39
39
  self.knowledge_table_name = knowledge_table or "agno_knowledge"
40
40
 
41
+ @abstractmethod
42
+ def table_exists(self, table_name: str) -> bool:
43
+ raise NotImplementedError
44
+
45
+ def _create_all_tables(self) -> None:
46
+ """Create all tables for this database."""
47
+ pass
48
+
41
49
  # --- Sessions ---
42
50
  @abstractmethod
43
51
  def delete_session(self, session_id: str) -> bool:
@@ -328,6 +336,21 @@ class AsyncBaseDb(ABC):
328
336
  self.knowledge_table_name = knowledge_table or "agno_knowledge"
329
337
  self.culture_table_name = culture_table or "agno_culture"
330
338
 
339
+ @abstractmethod
340
+ async def table_exists(self, table_name: str) -> bool:
341
+ """Check if a table with the given name exists in this database.
342
+
343
+ Default implementation returns True if the table name is configured.
344
+ Subclasses should override this to perform actual existence checks.
345
+
346
+ Args:
347
+ table_name: Name of the table to check
348
+
349
+ Returns:
350
+ bool: True if the table exists, False otherwise
351
+ """
352
+ raise NotImplementedError
353
+
331
354
  # --- Sessions ---
332
355
  @abstractmethod
333
356
  async def delete_session(self, session_id: str) -> bool:
agno/db/dynamo/dynamo.py CHANGED
@@ -112,27 +112,8 @@ class DynamoDb(BaseDb):
112
112
  session = boto3.Session(**session_kwargs)
113
113
  self.client = session.client("dynamodb")
114
114
 
115
- def _create_tables(self):
116
- tables_to_create = [
117
- (self.session_table_name, "sessions"),
118
- (self.memory_table_name, "memories"),
119
- (self.metrics_table_name, "metrics"),
120
- (self.eval_table_name, "evals"),
121
- (self.knowledge_table_name, "knowledge_sources"),
122
- ]
123
-
124
- for table_name, table_type in tables_to_create:
125
- if table_name:
126
- try:
127
- schema = get_table_schema_definition(table_type)
128
- schema["TableName"] = table_name
129
- create_table_if_not_exists(self.client, table_name, schema)
130
-
131
- except Exception as e:
132
- log_error(f"Failed to create table {table_name}: {e}")
133
-
134
- def _table_exists(self, table_name: str) -> bool:
135
- """Check if a DynamoDB table with the given name exists.
115
+ def table_exists(self, table_name: str) -> bool:
116
+ """Check if a DynamoDB table exists.
136
117
 
137
118
  Args:
138
119
  table_name: The name of the table to check
@@ -145,9 +126,23 @@ class DynamoDb(BaseDb):
145
126
  return True
146
127
  except self.client.exceptions.ResourceNotFoundException:
147
128
  return False
148
- except Exception as e:
149
- log_error(f"Error checking if table {table_name} exists: {e}")
150
- return False
129
+
130
+ def _create_all_tables(self):
131
+ """Create all configured DynamoDB tables if they don't exist."""
132
+ tables_to_create = [
133
+ ("sessions", self.session_table_name),
134
+ ("memories", self.memory_table_name),
135
+ ("metrics", self.metrics_table_name),
136
+ ("evals", self.eval_table_name),
137
+ ("knowledge", self.knowledge_table_name),
138
+ ("culture", self.culture_table_name),
139
+ ]
140
+
141
+ for table_type, table_name in tables_to_create:
142
+ if not self.table_exists(table_name):
143
+ schema = get_table_schema_definition(table_type)
144
+ schema["TableName"] = table_name
145
+ create_table_if_not_exists(self.client, table_name, schema)
151
146
 
152
147
  def _get_table(self, table_type: str, create_table_if_not_found: Optional[bool] = True) -> Optional[str]:
153
148
  """
@@ -180,7 +175,7 @@ class DynamoDb(BaseDb):
180
175
  raise ValueError(f"Unknown table type: {table_type}")
181
176
 
182
177
  # Check if table exists, create if it doesn't
183
- if not self._table_exists(table_name) and create_table_if_not_found:
178
+ if not self.table_exists(table_name) and create_table_if_not_found:
184
179
  schema = get_table_schema_definition(table_type)
185
180
  schema["TableName"] = table_name
186
181
  create_table_if_not_exists(self.client, table_name, schema)
agno/db/dynamo/schemas.py CHANGED
@@ -176,6 +176,7 @@ KNOWLEDGE_TABLE_SCHEMA = {
176
176
  "KeySchema": [{"AttributeName": "id", "KeyType": "HASH"}],
177
177
  "AttributeDefinitions": [
178
178
  {"AttributeName": "id", "AttributeType": "S"},
179
+ {"AttributeName": "user_id", "AttributeType": "S"},
179
180
  {"AttributeName": "type", "AttributeType": "S"},
180
181
  {"AttributeName": "status", "AttributeType": "S"},
181
182
  {"AttributeName": "created_at", "AttributeType": "N"},
@@ -89,6 +89,17 @@ class FirestoreDb(BaseDb):
89
89
 
90
90
  # -- DB methods --
91
91
 
92
+ def table_exists(self, table_name: str) -> bool:
93
+ """Check if a collection with the given name exists in the Firestore database.
94
+
95
+ Args:
96
+ table_name: Name of the collection to check
97
+
98
+ Returns:
99
+ bool: True if the collection exists in the database, False otherwise
100
+ """
101
+ return table_name in self.db_client.list_collections()
102
+
92
103
  def _get_collection(self, table_type: str, create_collection_if_not_found: Optional[bool] = True):
93
104
  """Get or create a collection based on table type.
94
105
 
@@ -83,6 +83,10 @@ class GcsJsonDb(BaseDb):
83
83
  self.client = gcs.Client(project=project, credentials=credentials)
84
84
  self.bucket = self.client.bucket(self.bucket_name)
85
85
 
86
+ def table_exists(self, table_name: str) -> bool:
87
+ """JSON implementation, always returns True."""
88
+ return True
89
+
86
90
  def _get_blob_name(self, filename: str) -> str:
87
91
  """Get the full blob name including prefix for a given filename."""
88
92
  return f"{self.prefix}{filename}.json"
@@ -34,6 +34,10 @@ class InMemoryDb(BaseDb):
34
34
  self._knowledge: List[Dict[str, Any]] = []
35
35
  self._cultural_knowledge: List[Dict[str, Any]] = []
36
36
 
37
+ def table_exists(self, table_name: str) -> bool:
38
+ """In-memory implementation, always returns True."""
39
+ return True
40
+
37
41
  # -- Session methods --
38
42
 
39
43
  def delete_session(self, session_id: str) -> bool:
agno/db/json/json_db.py CHANGED
@@ -66,6 +66,10 @@ class JsonDb(BaseDb):
66
66
  # Create the directory where the JSON files will be stored, if it doesn't exist
67
67
  self.db_path = Path(db_path or os.path.join(os.getcwd(), "agno_json_db"))
68
68
 
69
+ def table_exists(self, table_name: str) -> bool:
70
+ """JSON implementation, always returns True."""
71
+ return True
72
+
69
73
  def _read_json_file(self, filename: str, create_table_if_not_found: Optional[bool] = True) -> List[Dict[str, Any]]:
70
74
  """Read data from a JSON file, creating it if it doesn't exist.
71
75
 
@@ -99,6 +99,33 @@ class AsyncMongoDb(AsyncBaseDb):
99
99
  self._database: Optional[AsyncIOMotorDatabase] = None
100
100
  self._event_loop: Optional[asyncio.AbstractEventLoop] = None
101
101
 
102
+ async def table_exists(self, table_name: str) -> bool:
103
+ """Check if a collection with the given name exists in the MongoDB database.
104
+
105
+ Args:
106
+ table_name: Name of the collection to check
107
+
108
+ Returns:
109
+ bool: True if the collection exists in the database, False otherwise
110
+ """
111
+ collection_names = await self.database.list_collection_names()
112
+ return table_name in collection_names
113
+
114
+ async def _create_all_tables(self):
115
+ """Create all configured MongoDB collections if they don't exist."""
116
+ collections_to_create = [
117
+ ("sessions", self.session_table_name),
118
+ ("memories", self.memory_table_name),
119
+ ("metrics", self.metrics_table_name),
120
+ ("evals", self.eval_table_name),
121
+ ("knowledge", self.knowledge_table_name),
122
+ ("culture", self.culture_table_name),
123
+ ]
124
+
125
+ for collection_type, collection_name in collections_to_create:
126
+ if collection_name and not await self.table_exists(collection_name):
127
+ await self._get_collection(collection_type, create_collection_if_not_found=True)
128
+
102
129
  def _ensure_client(self) -> AsyncIOMotorClient:
103
130
  """
104
131
  Ensure the Motor client is valid for the current event loop.
agno/db/mongo/mongo.py CHANGED
@@ -100,6 +100,31 @@ class MongoDb(BaseDb):
100
100
  return self._database
101
101
 
102
102
  # -- DB methods --
103
+ def table_exists(self, table_name: str) -> bool:
104
+ """Check if a collection with the given name exists in the MongoDB database.
105
+
106
+ Args:
107
+ table_name: Name of the collection to check
108
+
109
+ Returns:
110
+ bool: True if the collection exists in the database, False otherwise
111
+ """
112
+ return table_name in self.database.list_collection_names()
113
+
114
+ def _create_all_tables(self):
115
+ """Create all configured MongoDB collections if they don't exist."""
116
+ collections_to_create = [
117
+ ("sessions", self.session_table_name),
118
+ ("memories", self.memory_table_name),
119
+ ("metrics", self.metrics_table_name),
120
+ ("evals", self.eval_table_name),
121
+ ("knowledge", self.knowledge_table_name),
122
+ ("culture", self.culture_table_name),
123
+ ]
124
+
125
+ for collection_type, collection_name in collections_to_create:
126
+ if collection_name and not self.table_exists(collection_name):
127
+ self._get_collection(collection_type, create_collection_if_not_found=True)
103
128
 
104
129
  def _get_collection(
105
130
  self, table_type: str, create_collection_if_not_found: Optional[bool] = True
agno/db/mysql/mysql.py CHANGED
@@ -107,6 +107,18 @@ class MySQLDb(BaseDb):
107
107
  self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
108
108
 
109
109
  # -- DB methods --
110
+ def table_exists(self, table_name: str) -> bool:
111
+ """Check if a table with the given name exists in the MySQL database.
112
+
113
+ Args:
114
+ table_name: Name of the table to check
115
+
116
+ Returns:
117
+ bool: True if the table exists in the database, False otherwise
118
+ """
119
+ with self.Session() as sess:
120
+ return is_table_available(session=sess, table_name=table_name, db_schema=self.db_schema)
121
+
110
122
  def _create_table(self, table_name: str, table_type: str, db_schema: str) -> Table:
111
123
  """
112
124
  Create a table with the appropriate schema based on the table type.
@@ -191,13 +203,26 @@ class MySQLDb(BaseDb):
191
203
  except Exception as e:
192
204
  log_error(f"Error creating index {idx.name}: {e}")
193
205
 
194
- log_info(f"Successfully created table {db_schema}.{table_name}")
206
+ log_debug(f"Successfully created table {db_schema}.{table_name}")
195
207
  return table
196
208
 
197
209
  except Exception as e:
198
210
  log_error(f"Could not create table {db_schema}.{table_name}: {e}")
199
211
  raise
200
212
 
213
+ def _create_all_tables(self):
214
+ """Create all tables for the database."""
215
+ tables_to_create = [
216
+ (self.session_table_name, "sessions"),
217
+ (self.memory_table_name, "memories"),
218
+ (self.metrics_table_name, "metrics"),
219
+ (self.eval_table_name, "evals"),
220
+ (self.knowledge_table_name, "knowledge"),
221
+ ]
222
+
223
+ for table_name, table_type in tables_to_create:
224
+ self._create_table(table_name=table_name, table_type=table_type, db_schema=self.db_schema)
225
+
201
226
  def _get_table(self, table_type: str, create_table_if_not_found: Optional[bool] = False) -> Optional[Table]:
202
227
  if table_type == "sessions":
203
228
  self.session_table = self._get_or_create_table(
@@ -102,6 +102,31 @@ class AsyncPostgresDb(AsyncBaseDb):
102
102
  self.async_session_factory = async_sessionmaker(bind=self.db_engine)
103
103
 
104
104
  # -- DB methods --
105
+ async def table_exists(self, table_name: str) -> bool:
106
+ """Check if a table with the given name exists in the Postgres database.
107
+
108
+ Args:
109
+ table_name: Name of the table to check
110
+
111
+ Returns:
112
+ bool: True if the table exists in the database, False otherwise
113
+ """
114
+ async with self.async_session_factory() as sess:
115
+ return await ais_table_available(session=sess, table_name=table_name, db_schema=self.db_schema)
116
+
117
+ async def _create_all_tables(self):
118
+ """Create all tables for the database."""
119
+ tables_to_create = [
120
+ (self.session_table_name, "sessions"),
121
+ (self.memory_table_name, "memories"),
122
+ (self.metrics_table_name, "metrics"),
123
+ (self.eval_table_name, "evals"),
124
+ (self.knowledge_table_name, "knowledge"),
125
+ ]
126
+
127
+ for table_name, table_type in tables_to_create:
128
+ await self._create_table(table_name=table_name, table_type=table_type, db_schema=self.db_schema)
129
+
105
130
  async def _create_table(self, table_name: str, table_type: str, db_schema: str) -> Table:
106
131
  """
107
132
  Create a table with the appropriate schema based on the table type.
@@ -180,7 +205,7 @@ class AsyncPostgresDb(AsyncBaseDb):
180
205
  except Exception as e:
181
206
  log_error(f"Error creating index {idx.name}: {e}")
182
207
 
183
- log_info(f"Successfully created table {table_name} in schema {db_schema}")
208
+ log_debug(f"Successfully created table {table_name} in schema {db_schema}")
184
209
  return table
185
210
 
186
211
  except Exception as e:
@@ -106,6 +106,31 @@ class PostgresDb(BaseDb):
106
106
  self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
107
107
 
108
108
  # -- DB methods --
109
+ def table_exists(self, table_name: str) -> bool:
110
+ """Check if a table with the given name exists in the Postgres database.
111
+
112
+ Args:
113
+ table_name: Name of the table to check
114
+
115
+ Returns:
116
+ bool: True if the table exists in the database, False otherwise
117
+ """
118
+ with self.Session() as sess:
119
+ return is_table_available(session=sess, table_name=table_name, db_schema=self.db_schema)
120
+
121
+ def _create_all_tables(self):
122
+ """Create all tables for the database."""
123
+ tables_to_create = [
124
+ (self.session_table_name, "sessions"),
125
+ (self.memory_table_name, "memories"),
126
+ (self.metrics_table_name, "metrics"),
127
+ (self.eval_table_name, "evals"),
128
+ (self.knowledge_table_name, "knowledge"),
129
+ ]
130
+
131
+ for table_name, table_type in tables_to_create:
132
+ self._create_table(table_name=table_name, table_type=table_type, db_schema=self.db_schema)
133
+
109
134
  def _create_table(self, table_name: str, table_type: str, db_schema: str) -> Table:
110
135
  """
111
136
  Create a table with the appropriate schema based on the table type.
@@ -184,7 +209,7 @@ class PostgresDb(BaseDb):
184
209
  except Exception as e:
185
210
  log_error(f"Error creating index {idx.name}: {e}")
186
211
 
187
- log_info(f"Successfully created table {table_name} in schema {db_schema}")
212
+ log_debug(f"Successfully created table {table_name} in schema {db_schema}")
188
213
  return table
189
214
 
190
215
  except Exception as e:
agno/db/redis/redis.py CHANGED
@@ -100,6 +100,10 @@ class RedisDb(BaseDb):
100
100
 
101
101
  # -- DB methods --
102
102
 
103
+ def table_exists(self, table_name: str) -> bool:
104
+ """Redis implementation, always returns True."""
105
+ return True
106
+
103
107
  def _get_table_name(self, table_type: str) -> str:
104
108
  """Get the active table name for the given table type."""
105
109
  if table_type == "sessions":
@@ -112,6 +112,17 @@ class SingleStoreDb(BaseDb):
112
112
  self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
113
113
 
114
114
  # -- DB methods --
115
+ def table_exists(self, table_name: str) -> bool:
116
+ """Check if a table with the given name exists in the SingleStore database.
117
+
118
+ Args:
119
+ table_name: Name of the table to check
120
+
121
+ Returns:
122
+ bool: True if the table exists in the database, False otherwise
123
+ """
124
+ with self.Session() as sess:
125
+ return is_table_available(session=sess, table_name=table_name, db_schema=self.db_schema)
115
126
 
116
127
  def _create_table_structure_only(self, table_name: str, table_type: str, db_schema: Optional[str]) -> Table:
117
128
  """
@@ -157,6 +168,19 @@ class SingleStoreDb(BaseDb):
157
168
  log_error(f"Could not create table structure for {table_ref}: {e}")
158
169
  raise
159
170
 
171
+ def _create_all_tables(self):
172
+ """Create all tables for the database."""
173
+ tables_to_create = [
174
+ (self.session_table_name, "sessions"),
175
+ (self.memory_table_name, "memories"),
176
+ (self.metrics_table_name, "metrics"),
177
+ (self.eval_table_name, "evals"),
178
+ (self.knowledge_table_name, "knowledge"),
179
+ ]
180
+
181
+ for table_name, table_type in tables_to_create:
182
+ self._create_table(table_name=table_name, table_type=table_type, db_schema=self.db_schema)
183
+
160
184
  def _create_table(self, table_name: str, table_type: str, db_schema: Optional[str]) -> Table:
161
185
  """
162
186
  Create a table with the appropriate schema based on the table type.
@@ -112,6 +112,30 @@ class AsyncSqliteDb(AsyncBaseDb):
112
112
  self.async_session_factory = async_sessionmaker(bind=self.db_engine, expire_on_commit=False)
113
113
 
114
114
  # -- DB methods --
115
+ async def table_exists(self, table_name: str) -> bool:
116
+ """Check if a table with the given name exists in the SQLite database.
117
+
118
+ Args:
119
+ table_name: Name of the table to check
120
+
121
+ Returns:
122
+ bool: True if the table exists in the database, False otherwise
123
+ """
124
+ async with self.async_session_factory() as sess:
125
+ return await ais_table_available(session=sess, table_name=table_name)
126
+
127
+ async def _create_all_tables(self):
128
+ """Create all tables for the database."""
129
+ tables_to_create = [
130
+ (self.session_table_name, "sessions"),
131
+ (self.memory_table_name, "memories"),
132
+ (self.metrics_table_name, "metrics"),
133
+ (self.eval_table_name, "evals"),
134
+ (self.knowledge_table_name, "knowledge"),
135
+ ]
136
+
137
+ for table_name, table_type in tables_to_create:
138
+ await self._create_table(table_name=table_name, table_type=table_type)
115
139
 
116
140
  async def _create_table(self, table_name: str, table_type: str) -> Table:
117
141
  """
@@ -188,7 +212,7 @@ class AsyncSqliteDb(AsyncBaseDb):
188
212
  except Exception as e:
189
213
  log_warning(f"Error creating index {idx.name}: {e}")
190
214
 
191
- log_info(f"Successfully created table '{table_name}'")
215
+ log_debug(f"Successfully created table '{table_name}'")
192
216
  return table
193
217
 
194
218
  except Exception as e:
agno/db/sqlite/sqlite.py CHANGED
@@ -113,6 +113,30 @@ class SqliteDb(BaseDb):
113
113
  self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
114
114
 
115
115
  # -- DB methods --
116
+ def table_exists(self, table_name: str) -> bool:
117
+ """Check if a table with the given name exists in the SQLite database.
118
+
119
+ Args:
120
+ table_name: Name of the table to check
121
+
122
+ Returns:
123
+ bool: True if the table exists in the database, False otherwise
124
+ """
125
+ with self.Session() as sess:
126
+ return is_table_available(session=sess, table_name=table_name)
127
+
128
+ def _create_all_tables(self):
129
+ """Create all tables for the database."""
130
+ tables_to_create = [
131
+ (self.session_table_name, "sessions"),
132
+ (self.memory_table_name, "memories"),
133
+ (self.metrics_table_name, "metrics"),
134
+ (self.eval_table_name, "evals"),
135
+ (self.knowledge_table_name, "knowledge"),
136
+ ]
137
+
138
+ for table_name, table_type in tables_to_create:
139
+ self._create_table(table_name=table_name, table_type=table_type)
116
140
 
117
141
  def _create_table(self, table_name: str, table_type: str) -> Table:
118
142
  """
@@ -186,7 +210,7 @@ class SqliteDb(BaseDb):
186
210
  except Exception as e:
187
211
  log_warning(f"Error creating index {idx.name}: {e}")
188
212
 
189
- log_info(f"Successfully created table '{table_name}'")
213
+ log_debug(f"Successfully created table '{table_name}'")
190
214
  return table
191
215
 
192
216
  except Exception as e: