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.
- agno/agent/agent.py +197 -110
- agno/api/api.py +2 -0
- agno/db/base.py +26 -0
- agno/db/dynamo/dynamo.py +8 -0
- agno/db/dynamo/schemas.py +1 -0
- agno/db/firestore/firestore.py +8 -0
- agno/db/firestore/schemas.py +1 -0
- agno/db/gcs_json/gcs_json_db.py +8 -0
- agno/db/in_memory/in_memory_db.py +8 -1
- agno/db/json/json_db.py +8 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/async_mongo.py +16 -6
- agno/db/mongo/mongo.py +11 -0
- agno/db/mongo/schemas.py +3 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/mysql.py +76 -3
- agno/db/mysql/schemas.py +20 -10
- agno/db/postgres/async_postgres.py +99 -25
- agno/db/postgres/postgres.py +75 -6
- agno/db/postgres/schemas.py +30 -20
- agno/db/redis/redis.py +15 -2
- agno/db/redis/schemas.py +4 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +11 -0
- agno/db/singlestore/singlestore.py +79 -5
- agno/db/sqlite/async_sqlite.py +97 -19
- agno/db/sqlite/schemas.py +10 -0
- agno/db/sqlite/sqlite.py +79 -2
- agno/db/surrealdb/surrealdb.py +8 -0
- agno/knowledge/chunking/semantic.py +7 -2
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/knowledge.py +57 -86
- agno/knowledge/reader/csv_reader.py +7 -9
- agno/knowledge/reader/docx_reader.py +5 -5
- agno/knowledge/reader/field_labeled_csv_reader.py +16 -18
- agno/knowledge/reader/json_reader.py +5 -4
- agno/knowledge/reader/markdown_reader.py +8 -8
- agno/knowledge/reader/pdf_reader.py +11 -11
- agno/knowledge/reader/pptx_reader.py +5 -5
- agno/knowledge/reader/s3_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +8 -8
- agno/knowledge/reader/web_search_reader.py +1 -48
- agno/knowledge/reader/website_reader.py +10 -10
- agno/models/anthropic/claude.py +319 -28
- agno/models/aws/claude.py +32 -0
- agno/models/azure/openai_chat.py +19 -10
- agno/models/base.py +612 -545
- agno/models/cerebras/cerebras.py +8 -11
- agno/models/cohere/chat.py +27 -1
- agno/models/google/gemini.py +39 -7
- agno/models/groq/groq.py +25 -11
- agno/models/meta/llama.py +20 -9
- agno/models/meta/llama_openai.py +3 -19
- agno/models/nebius/nebius.py +4 -4
- agno/models/openai/chat.py +30 -14
- agno/models/openai/responses.py +10 -13
- agno/models/response.py +1 -0
- agno/models/vertexai/claude.py +26 -0
- agno/os/app.py +8 -19
- agno/os/router.py +54 -0
- agno/os/routers/knowledge/knowledge.py +2 -2
- agno/os/schema.py +2 -2
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -112
- agno/session/workflow.py +353 -57
- agno/team/team.py +227 -125
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/http.py +111 -0
- agno/utils/media.py +11 -0
- agno/utils/models/claude.py +8 -0
- agno/utils/print_response/agent.py +33 -12
- agno/utils/print_response/team.py +22 -12
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/workflow/condition.py +13 -0
- agno/workflow/loop.py +13 -0
- agno/workflow/parallel.py +13 -0
- agno/workflow/router.py +13 -0
- agno/workflow/step.py +120 -20
- agno/workflow/steps.py +13 -0
- agno/workflow/workflow.py +76 -63
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/METADATA +6 -2
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/RECORD +91 -88
- agno/tools/googlesearch.py +0 -98
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/WHEEL +0 -0
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.3.1.dist-info}/top_level.txt +0 -0
agno/db/sqlite/async_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 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
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
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
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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
|
-
|
|
1273
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
agno/db/surrealdb/surrealdb.py
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|