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
@@ -5,6 +5,7 @@ from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, cast
5
5
  from uuid import uuid4
6
6
 
7
7
  from agno.db.base import AsyncBaseDb, SessionType
8
+ from agno.db.migrations.manager import MigrationManager
8
9
  from agno.db.schemas.culture import CulturalKnowledge
9
10
  from agno.db.schemas.evals import EvalFilterType, EvalRunRecord, EvalType
10
11
  from agno.db.schemas.knowledge import KnowledgeRow
@@ -47,6 +48,7 @@ class AsyncSqliteDb(AsyncBaseDb):
47
48
  metrics_table: Optional[str] = None,
48
49
  eval_table: Optional[str] = None,
49
50
  knowledge_table: Optional[str] = None,
51
+ versions_table: Optional[str] = None,
50
52
  id: Optional[str] = None,
51
53
  ):
52
54
  """
@@ -68,6 +70,7 @@ class AsyncSqliteDb(AsyncBaseDb):
68
70
  metrics_table (Optional[str]): Name of the table to store metrics.
69
71
  eval_table (Optional[str]): Name of the table to store evaluation runs data.
70
72
  knowledge_table (Optional[str]): Name of the table to store knowledge documents data.
73
+ versions_table (Optional[str]): Name of the table to store schema versions.
71
74
  id (Optional[str]): ID of the database.
72
75
 
73
76
  Raises:
@@ -85,6 +88,7 @@ class AsyncSqliteDb(AsyncBaseDb):
85
88
  metrics_table=metrics_table,
86
89
  eval_table=eval_table,
87
90
  knowledge_table=knowledge_table,
91
+ versions_table=versions_table,
88
92
  )
89
93
 
90
94
  _engine: Optional[AsyncEngine] = db_engine
@@ -132,9 +136,15 @@ class AsyncSqliteDb(AsyncBaseDb):
132
136
  (self.metrics_table_name, "metrics"),
133
137
  (self.eval_table_name, "evals"),
134
138
  (self.knowledge_table_name, "knowledge"),
139
+ (self.versions_table_name, "versions"),
135
140
  ]
136
141
 
137
142
  for table_name, table_type in tables_to_create:
143
+ if table_name != self.versions_table_name:
144
+ # Also store the schema version for the created table
145
+ latest_schema_version = MigrationManager(self).latest_schema_version
146
+ await self.upsert_schema_version(table_name=table_name, version=latest_schema_version.public)
147
+
138
148
  await self._create_table(table_name=table_name, table_type=table_type)
139
149
 
140
150
  async def _create_table(self, table_name: str, table_type: str) -> Table:
@@ -268,6 +278,14 @@ class AsyncSqliteDb(AsyncBaseDb):
268
278
  )
269
279
  return self.culture_table
270
280
 
281
+ elif table_type == "versions":
282
+ if not hasattr(self, "versions_table"):
283
+ self.versions_table = await self._get_or_create_table(
284
+ table_name=self.versions_table_name,
285
+ table_type="versions",
286
+ )
287
+ return self.versions_table
288
+
271
289
  else:
272
290
  raise ValueError(f"Unknown table type: '{table_type}'")
273
291
 
@@ -290,6 +308,11 @@ class AsyncSqliteDb(AsyncBaseDb):
290
308
  table_is_available = await ais_table_available(session=sess, table_name=table_name)
291
309
 
292
310
  if not table_is_available:
311
+ if table_name != self.versions_table_name:
312
+ # Also store the schema version for the created table
313
+ latest_schema_version = MigrationManager(self).latest_schema_version
314
+ await self.upsert_schema_version(table_name=table_name, version=latest_schema_version.public)
315
+
293
316
  return await self._create_table(table_name=table_name, table_type=table_type)
294
317
 
295
318
  # SQLite version of table validation (no schema)
@@ -310,6 +333,43 @@ class AsyncSqliteDb(AsyncBaseDb):
310
333
  log_error(f"Error loading existing table {table_name}: {e}")
311
334
  raise e
312
335
 
336
+ async def get_latest_schema_version(self, table_name: str) -> str:
337
+ """Get the latest version of the database schema."""
338
+ table = await self._get_table(table_type="versions")
339
+ if table is None:
340
+ return "2.0.0"
341
+ async with self.async_session_factory() as sess:
342
+ stmt = select(table)
343
+ # Latest version for the given table
344
+ stmt = stmt.where(table.c.table_name == table_name)
345
+ stmt = stmt.order_by(table.c.version.desc()).limit(1)
346
+ result = await sess.execute(stmt)
347
+ row = result.fetchone()
348
+ if row is None:
349
+ return "2.0.0"
350
+ version_dict = dict(row._mapping)
351
+ return version_dict.get("version") or "2.0.0"
352
+
353
+ async def upsert_schema_version(self, table_name: str, version: str) -> None:
354
+ """Upsert the schema version into the database."""
355
+ table = await self._get_table(table_type="versions")
356
+ if table is None:
357
+ return
358
+ current_datetime = datetime.now().isoformat()
359
+ async with self.async_session_factory() as sess, sess.begin():
360
+ stmt = sqlite.insert(table).values(
361
+ table_name=table_name,
362
+ version=version,
363
+ created_at=current_datetime, # Store as ISO format string
364
+ updated_at=current_datetime,
365
+ )
366
+ # Update version if table_name already exists
367
+ stmt = stmt.on_conflict_do_update(
368
+ index_elements=["table_name"],
369
+ set_=dict(version=version, updated_at=current_datetime),
370
+ )
371
+ await sess.execute(stmt)
372
+
313
373
  # -- Session methods --
314
374
 
315
375
  async def delete_session(self, session_id: str) -> bool:
@@ -1248,29 +1308,39 @@ class AsyncSqliteDb(AsyncBaseDb):
1248
1308
  if memory.memory_id is None:
1249
1309
  memory.memory_id = str(uuid4())
1250
1310
 
1251
- async with self.async_session_factory() as sess, sess.begin():
1252
- stmt = sqlite.insert(table).values(
1253
- user_id=memory.user_id,
1254
- agent_id=memory.agent_id,
1255
- team_id=memory.team_id,
1256
- memory_id=memory.memory_id,
1257
- memory=memory.memory,
1258
- topics=memory.topics,
1259
- input=memory.input,
1260
- updated_at=int(time.time()),
1261
- )
1262
- stmt = stmt.on_conflict_do_update( # type: ignore
1263
- index_elements=["memory_id"],
1264
- set_=dict(
1311
+ current_time = int(time.time())
1312
+
1313
+ async with self.async_session_factory() as sess:
1314
+ async with sess.begin():
1315
+ stmt = sqlite.insert(table).values(
1316
+ user_id=memory.user_id,
1317
+ agent_id=memory.agent_id,
1318
+ team_id=memory.team_id,
1319
+ memory_id=memory.memory_id,
1265
1320
  memory=memory.memory,
1266
1321
  topics=memory.topics,
1267
1322
  input=memory.input,
1268
- updated_at=int(time.time()),
1269
- ),
1270
- ).returning(table)
1323
+ feedback=memory.feedback,
1324
+ created_at=memory.created_at,
1325
+ updated_at=memory.created_at,
1326
+ )
1327
+ stmt = stmt.on_conflict_do_update( # type: ignore
1328
+ index_elements=["memory_id"],
1329
+ set_=dict(
1330
+ memory=memory.memory,
1331
+ topics=memory.topics,
1332
+ input=memory.input,
1333
+ agent_id=memory.agent_id,
1334
+ team_id=memory.team_id,
1335
+ feedback=memory.feedback,
1336
+ updated_at=current_time,
1337
+ # Preserve created_at on update - don't overwrite existing value
1338
+ created_at=table.c.created_at,
1339
+ ),
1340
+ ).returning(table)
1271
1341
 
1272
- result = await sess.execute(stmt)
1273
- row = result.fetchone()
1342
+ result = await sess.execute(stmt)
1343
+ row = result.fetchone()
1274
1344
 
1275
1345
  if row is None:
1276
1346
  return None
@@ -1321,12 +1391,14 @@ class AsyncSqliteDb(AsyncBaseDb):
1321
1391
  # Prepare bulk data
1322
1392
  bulk_data = []
1323
1393
  current_time = int(time.time())
1394
+
1324
1395
  for memory in memories:
1325
1396
  if memory.memory_id is None:
1326
1397
  memory.memory_id = str(uuid4())
1327
1398
 
1328
1399
  # Use preserved updated_at if flag is set and value exists, otherwise use current time
1329
1400
  updated_at = memory.updated_at if preserve_updated_at else current_time
1401
+
1330
1402
  bulk_data.append(
1331
1403
  {
1332
1404
  "user_id": memory.user_id,
@@ -1335,6 +1407,9 @@ class AsyncSqliteDb(AsyncBaseDb):
1335
1407
  "memory_id": memory.memory_id,
1336
1408
  "memory": memory.memory,
1337
1409
  "topics": memory.topics,
1410
+ "input": memory.input,
1411
+ "feedback": memory.feedback,
1412
+ "created_at": memory.created_at,
1338
1413
  "updated_at": updated_at,
1339
1414
  }
1340
1415
  )
@@ -1352,7 +1427,10 @@ class AsyncSqliteDb(AsyncBaseDb):
1352
1427
  input=stmt.excluded.input,
1353
1428
  agent_id=stmt.excluded.agent_id,
1354
1429
  team_id=stmt.excluded.team_id,
1430
+ feedback=stmt.excluded.feedback,
1355
1431
  updated_at=stmt.excluded.updated_at,
1432
+ # Preserve created_at on update
1433
+ created_at=table.c.created_at,
1356
1434
  ),
1357
1435
  )
1358
1436
  await sess.execute(stmt, bulk_data)
agno/db/sqlite/schemas.py CHANGED
@@ -34,6 +34,8 @@ USER_MEMORY_TABLE_SCHEMA = {
34
34
  "team_id": {"type": String, "nullable": True},
35
35
  "user_id": {"type": String, "nullable": True, "index": True},
36
36
  "topics": {"type": JSON, "nullable": True},
37
+ "feedback": {"type": String, "nullable": True},
38
+ "created_at": {"type": BigInteger, "nullable": False, "index": True},
37
39
  "updated_at": {"type": BigInteger, "nullable": True, "index": True},
38
40
  }
39
41
 
@@ -106,6 +108,13 @@ CULTURAL_KNOWLEDGE_TABLE_SCHEMA = {
106
108
  "team_id": {"type": String, "nullable": True},
107
109
  }
108
110
 
111
+ VERSIONS_TABLE_SCHEMA = {
112
+ "table_name": {"type": String, "nullable": False, "primary_key": True},
113
+ "version": {"type": String, "nullable": False},
114
+ "created_at": {"type": String, "nullable": False, "index": True},
115
+ "updated_at": {"type": String, "nullable": True},
116
+ }
117
+
109
118
 
110
119
  def get_table_schema_definition(table_type: str) -> dict[str, Any]:
111
120
  """
@@ -124,6 +133,7 @@ def get_table_schema_definition(table_type: str) -> dict[str, Any]:
124
133
  "memories": USER_MEMORY_TABLE_SCHEMA,
125
134
  "knowledge": KNOWLEDGE_TABLE_SCHEMA,
126
135
  "culture": CULTURAL_KNOWLEDGE_TABLE_SCHEMA,
136
+ "versions": VERSIONS_TABLE_SCHEMA,
127
137
  }
128
138
  schema = schemas.get(table_type, {})
129
139
 
agno/db/sqlite/sqlite.py CHANGED
@@ -5,6 +5,7 @@ from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, cast
5
5
  from uuid import uuid4
6
6
 
7
7
  from agno.db.base import BaseDb, SessionType
8
+ from agno.db.migrations.manager import MigrationManager
8
9
  from agno.db.schemas.culture import CulturalKnowledge
9
10
  from agno.db.schemas.evals import EvalFilterType, EvalRunRecord, EvalType
10
11
  from agno.db.schemas.knowledge import KnowledgeRow
@@ -48,6 +49,7 @@ class SqliteDb(BaseDb):
48
49
  metrics_table: Optional[str] = None,
49
50
  eval_table: Optional[str] = None,
50
51
  knowledge_table: Optional[str] = None,
52
+ versions_table: Optional[str] = None,
51
53
  id: Optional[str] = None,
52
54
  ):
53
55
  """
@@ -69,6 +71,7 @@ class SqliteDb(BaseDb):
69
71
  metrics_table (Optional[str]): Name of the table to store metrics.
70
72
  eval_table (Optional[str]): Name of the table to store evaluation runs data.
71
73
  knowledge_table (Optional[str]): Name of the table to store knowledge documents data.
74
+ versions_table (Optional[str]): Name of the table to store schema versions.
72
75
  id (Optional[str]): ID of the database.
73
76
 
74
77
  Raises:
@@ -86,6 +89,7 @@ class SqliteDb(BaseDb):
86
89
  metrics_table=metrics_table,
87
90
  eval_table=eval_table,
88
91
  knowledge_table=knowledge_table,
92
+ versions_table=versions_table,
89
93
  )
90
94
 
91
95
  _engine: Optional[Engine] = db_engine
@@ -133,9 +137,15 @@ class SqliteDb(BaseDb):
133
137
  (self.metrics_table_name, "metrics"),
134
138
  (self.eval_table_name, "evals"),
135
139
  (self.knowledge_table_name, "knowledge"),
140
+ (self.versions_table_name, "versions"),
136
141
  ]
137
142
 
138
143
  for table_name, table_type in tables_to_create:
144
+ if table_name != self.versions_table_name:
145
+ # Also store the schema version for the created table
146
+ latest_schema_version = MigrationManager(self).latest_schema_version
147
+ self.upsert_schema_version(table_name=table_name, version=latest_schema_version.public)
148
+
139
149
  self._create_table(table_name=table_name, table_type=table_type)
140
150
 
141
151
  def _create_table(self, table_name: str, table_type: str) -> Table:
@@ -267,6 +277,14 @@ class SqliteDb(BaseDb):
267
277
  )
268
278
  return self.culture_table
269
279
 
280
+ elif table_type == "versions":
281
+ self.versions_table = self._get_or_create_table(
282
+ table_name=self.versions_table_name,
283
+ table_type="versions",
284
+ create_table_if_not_found=create_table_if_not_found,
285
+ )
286
+ return self.versions_table
287
+
270
288
  else:
271
289
  raise ValueError(f"Unknown table type: '{table_type}'")
272
290
 
@@ -292,6 +310,12 @@ class SqliteDb(BaseDb):
292
310
  if not table_is_available:
293
311
  if not create_table_if_not_found:
294
312
  return None
313
+
314
+ if table_name != self.versions_table_name:
315
+ # Also store the schema version for the created table
316
+ latest_schema_version = MigrationManager(self).latest_schema_version
317
+ self.upsert_schema_version(table_name=table_name, version=latest_schema_version.public)
318
+
295
319
  return self._create_table(table_name=table_name, table_type=table_type)
296
320
 
297
321
  # SQLite version of table validation (no schema)
@@ -307,6 +331,42 @@ class SqliteDb(BaseDb):
307
331
  log_error(f"Error loading existing table {table_name}: {e}")
308
332
  raise e
309
333
 
334
+ def get_latest_schema_version(self, table_name: str):
335
+ """Get the latest version of the database schema."""
336
+ table = self._get_table(table_type="versions", create_table_if_not_found=True)
337
+ if table is None:
338
+ return "2.0.0"
339
+ with self.Session() as sess:
340
+ stmt = select(table)
341
+ # Latest version for the given table
342
+ stmt = stmt.where(table.c.table_name == table_name)
343
+ stmt = stmt.order_by(table.c.version.desc()).limit(1)
344
+ result = sess.execute(stmt).fetchone()
345
+ if result is None:
346
+ return "2.0.0"
347
+ version_dict = dict(result._mapping)
348
+ return version_dict.get("version") or "2.0.0"
349
+
350
+ def upsert_schema_version(self, table_name: str, version: str) -> None:
351
+ """Upsert the schema version into the database."""
352
+ table = self._get_table(table_type="versions", create_table_if_not_found=True)
353
+ if table is None:
354
+ return
355
+ current_datetime = datetime.now().isoformat()
356
+ with self.Session() as sess, sess.begin():
357
+ stmt = sqlite.insert(table).values(
358
+ table_name=table_name,
359
+ version=version,
360
+ created_at=current_datetime, # Store as ISO format string
361
+ updated_at=current_datetime,
362
+ )
363
+ # Update version if table_name already exists
364
+ stmt = stmt.on_conflict_do_update(
365
+ index_elements=["table_name"],
366
+ set_=dict(version=version, updated_at=current_datetime),
367
+ )
368
+ sess.execute(stmt)
369
+
310
370
  # -- Session methods --
311
371
 
312
372
  def delete_session(self, session_id: str) -> bool:
@@ -1242,6 +1302,8 @@ class SqliteDb(BaseDb):
1242
1302
  if memory.memory_id is None:
1243
1303
  memory.memory_id = str(uuid4())
1244
1304
 
1305
+ current_time = int(time.time())
1306
+
1245
1307
  with self.Session() as sess, sess.begin():
1246
1308
  stmt = sqlite.insert(table).values(
1247
1309
  user_id=memory.user_id,
@@ -1251,7 +1313,9 @@ class SqliteDb(BaseDb):
1251
1313
  memory=memory.memory,
1252
1314
  topics=memory.topics,
1253
1315
  input=memory.input,
1254
- updated_at=int(time.time()),
1316
+ feedback=memory.feedback,
1317
+ created_at=memory.created_at,
1318
+ updated_at=memory.created_at,
1255
1319
  )
1256
1320
  stmt = stmt.on_conflict_do_update( # type: ignore
1257
1321
  index_elements=["memory_id"],
@@ -1259,7 +1323,12 @@ class SqliteDb(BaseDb):
1259
1323
  memory=memory.memory,
1260
1324
  topics=memory.topics,
1261
1325
  input=memory.input,
1262
- updated_at=int(time.time()),
1326
+ agent_id=memory.agent_id,
1327
+ team_id=memory.team_id,
1328
+ feedback=memory.feedback,
1329
+ updated_at=current_time,
1330
+ # Preserve created_at on update - don't overwrite existing value
1331
+ created_at=table.c.created_at,
1263
1332
  ),
1264
1333
  ).returning(table)
1265
1334
 
@@ -1315,12 +1384,14 @@ class SqliteDb(BaseDb):
1315
1384
  # Prepare bulk data
1316
1385
  bulk_data = []
1317
1386
  current_time = int(time.time())
1387
+
1318
1388
  for memory in memories:
1319
1389
  if memory.memory_id is None:
1320
1390
  memory.memory_id = str(uuid4())
1321
1391
 
1322
1392
  # Use preserved updated_at if flag is set and value exists, otherwise use current time
1323
1393
  updated_at = memory.updated_at if preserve_updated_at else current_time
1394
+
1324
1395
  bulk_data.append(
1325
1396
  {
1326
1397
  "user_id": memory.user_id,
@@ -1329,6 +1400,9 @@ class SqliteDb(BaseDb):
1329
1400
  "memory_id": memory.memory_id,
1330
1401
  "memory": memory.memory,
1331
1402
  "topics": memory.topics,
1403
+ "input": memory.input,
1404
+ "feedback": memory.feedback,
1405
+ "created_at": memory.created_at,
1332
1406
  "updated_at": updated_at,
1333
1407
  }
1334
1408
  )
@@ -1346,7 +1420,10 @@ class SqliteDb(BaseDb):
1346
1420
  input=stmt.excluded.input,
1347
1421
  agent_id=stmt.excluded.agent_id,
1348
1422
  team_id=stmt.excluded.team_id,
1423
+ feedback=stmt.excluded.feedback,
1349
1424
  updated_at=stmt.excluded.updated_at,
1425
+ # Preserve created_at on update
1426
+ created_at=table.c.created_at,
1350
1427
  ),
1351
1428
  )
1352
1429
  sess.execute(stmt, bulk_data)
@@ -167,6 +167,14 @@ class SurrealDb(BaseDb):
167
167
 
168
168
  return table_name
169
169
 
170
+ def get_latest_schema_version(self):
171
+ """Get the latest version of the database schema."""
172
+ pass
173
+
174
+ def upsert_schema_version(self, version: str) -> None:
175
+ """Upsert the schema version into the database."""
176
+ pass
177
+
170
178
  def _query(
171
179
  self,
172
180
  query: str,
@@ -4,14 +4,19 @@ from typing import Any, Dict, List, Optional
4
4
  from agno.knowledge.chunking.strategy import ChunkingStrategy
5
5
  from agno.knowledge.document.base import Document
6
6
  from agno.knowledge.embedder.base import Embedder
7
- from agno.knowledge.embedder.openai import OpenAIEmbedder
7
+ from agno.utils.log import log_info
8
8
 
9
9
 
10
10
  class SemanticChunking(ChunkingStrategy):
11
11
  """Chunking strategy that splits text into semantic chunks using chonkie"""
12
12
 
13
13
  def __init__(self, embedder: Optional[Embedder] = None, chunk_size: int = 5000, similarity_threshold: float = 0.5):
14
- self.embedder = embedder or OpenAIEmbedder(id="text-embedding-3-small") # type: ignore
14
+ if embedder is None:
15
+ from agno.knowledge.embedder.openai import OpenAIEmbedder
16
+
17
+ embedder = OpenAIEmbedder() # type: ignore
18
+ log_info("Embedder not provided, using OpenAIEmbedder as default.")
19
+ self.embedder = embedder
15
20
  self.chunk_size = chunk_size
16
21
  self.similarity_threshold = similarity_threshold
17
22
  self.chunker = None # Will be initialized lazily when needed
@@ -10,4 +10,4 @@ class NebiusEmbedder(OpenAIEmbedder):
10
10
  id: str = "BAAI/bge-en-icl"
11
11
  dimensions: int = 1024
12
12
  api_key: Optional[str] = getenv("NEBIUS_API_KEY")
13
- base_url: str = "https://api.studio.nebius.com/v1/"
13
+ base_url: str = "https://api.tokenfactory.nebius.com/v1/"