agno 2.2.13__py3-none-any.whl → 2.4.3__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 (383) hide show
  1. agno/agent/__init__.py +6 -0
  2. agno/agent/agent.py +5252 -3145
  3. agno/agent/remote.py +525 -0
  4. agno/api/api.py +2 -0
  5. agno/client/__init__.py +3 -0
  6. agno/client/a2a/__init__.py +10 -0
  7. agno/client/a2a/client.py +554 -0
  8. agno/client/a2a/schemas.py +112 -0
  9. agno/client/a2a/utils.py +369 -0
  10. agno/client/os.py +2669 -0
  11. agno/compression/__init__.py +3 -0
  12. agno/compression/manager.py +247 -0
  13. agno/culture/manager.py +2 -2
  14. agno/db/base.py +927 -6
  15. agno/db/dynamo/dynamo.py +788 -2
  16. agno/db/dynamo/schemas.py +128 -0
  17. agno/db/dynamo/utils.py +26 -3
  18. agno/db/firestore/firestore.py +674 -50
  19. agno/db/firestore/schemas.py +41 -0
  20. agno/db/firestore/utils.py +25 -10
  21. agno/db/gcs_json/gcs_json_db.py +506 -3
  22. agno/db/gcs_json/utils.py +14 -2
  23. agno/db/in_memory/in_memory_db.py +203 -4
  24. agno/db/in_memory/utils.py +14 -2
  25. agno/db/json/json_db.py +498 -2
  26. agno/db/json/utils.py +14 -2
  27. agno/db/migrations/manager.py +199 -0
  28. agno/db/migrations/utils.py +19 -0
  29. agno/db/migrations/v1_to_v2.py +54 -16
  30. agno/db/migrations/versions/__init__.py +0 -0
  31. agno/db/migrations/versions/v2_3_0.py +977 -0
  32. agno/db/mongo/async_mongo.py +1013 -39
  33. agno/db/mongo/mongo.py +684 -4
  34. agno/db/mongo/schemas.py +48 -0
  35. agno/db/mongo/utils.py +17 -0
  36. agno/db/mysql/__init__.py +2 -1
  37. agno/db/mysql/async_mysql.py +2958 -0
  38. agno/db/mysql/mysql.py +722 -53
  39. agno/db/mysql/schemas.py +77 -11
  40. agno/db/mysql/utils.py +151 -8
  41. agno/db/postgres/async_postgres.py +1254 -137
  42. agno/db/postgres/postgres.py +2316 -93
  43. agno/db/postgres/schemas.py +153 -21
  44. agno/db/postgres/utils.py +22 -7
  45. agno/db/redis/redis.py +531 -3
  46. agno/db/redis/schemas.py +36 -0
  47. agno/db/redis/utils.py +31 -15
  48. agno/db/schemas/evals.py +1 -0
  49. agno/db/schemas/memory.py +20 -9
  50. agno/db/singlestore/schemas.py +70 -1
  51. agno/db/singlestore/singlestore.py +737 -74
  52. agno/db/singlestore/utils.py +13 -3
  53. agno/db/sqlite/async_sqlite.py +1069 -89
  54. agno/db/sqlite/schemas.py +133 -1
  55. agno/db/sqlite/sqlite.py +2203 -165
  56. agno/db/sqlite/utils.py +21 -11
  57. agno/db/surrealdb/models.py +25 -0
  58. agno/db/surrealdb/surrealdb.py +603 -1
  59. agno/db/utils.py +60 -0
  60. agno/eval/__init__.py +26 -3
  61. agno/eval/accuracy.py +25 -12
  62. agno/eval/agent_as_judge.py +871 -0
  63. agno/eval/base.py +29 -0
  64. agno/eval/performance.py +10 -4
  65. agno/eval/reliability.py +22 -13
  66. agno/eval/utils.py +2 -1
  67. agno/exceptions.py +42 -0
  68. agno/hooks/__init__.py +3 -0
  69. agno/hooks/decorator.py +164 -0
  70. agno/integrations/discord/client.py +13 -2
  71. agno/knowledge/__init__.py +4 -0
  72. agno/knowledge/chunking/code.py +90 -0
  73. agno/knowledge/chunking/document.py +65 -4
  74. agno/knowledge/chunking/fixed.py +4 -1
  75. agno/knowledge/chunking/markdown.py +102 -11
  76. agno/knowledge/chunking/recursive.py +2 -2
  77. agno/knowledge/chunking/semantic.py +130 -48
  78. agno/knowledge/chunking/strategy.py +18 -0
  79. agno/knowledge/embedder/azure_openai.py +0 -1
  80. agno/knowledge/embedder/google.py +1 -1
  81. agno/knowledge/embedder/mistral.py +1 -1
  82. agno/knowledge/embedder/nebius.py +1 -1
  83. agno/knowledge/embedder/openai.py +16 -12
  84. agno/knowledge/filesystem.py +412 -0
  85. agno/knowledge/knowledge.py +4261 -1199
  86. agno/knowledge/protocol.py +134 -0
  87. agno/knowledge/reader/arxiv_reader.py +3 -2
  88. agno/knowledge/reader/base.py +9 -7
  89. agno/knowledge/reader/csv_reader.py +91 -42
  90. agno/knowledge/reader/docx_reader.py +9 -10
  91. agno/knowledge/reader/excel_reader.py +225 -0
  92. agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
  93. agno/knowledge/reader/firecrawl_reader.py +3 -2
  94. agno/knowledge/reader/json_reader.py +16 -22
  95. agno/knowledge/reader/markdown_reader.py +15 -14
  96. agno/knowledge/reader/pdf_reader.py +33 -28
  97. agno/knowledge/reader/pptx_reader.py +9 -10
  98. agno/knowledge/reader/reader_factory.py +135 -1
  99. agno/knowledge/reader/s3_reader.py +8 -16
  100. agno/knowledge/reader/tavily_reader.py +3 -3
  101. agno/knowledge/reader/text_reader.py +15 -14
  102. agno/knowledge/reader/utils/__init__.py +17 -0
  103. agno/knowledge/reader/utils/spreadsheet.py +114 -0
  104. agno/knowledge/reader/web_search_reader.py +8 -65
  105. agno/knowledge/reader/website_reader.py +16 -13
  106. agno/knowledge/reader/wikipedia_reader.py +36 -3
  107. agno/knowledge/reader/youtube_reader.py +3 -2
  108. agno/knowledge/remote_content/__init__.py +33 -0
  109. agno/knowledge/remote_content/config.py +266 -0
  110. agno/knowledge/remote_content/remote_content.py +105 -17
  111. agno/knowledge/utils.py +76 -22
  112. agno/learn/__init__.py +71 -0
  113. agno/learn/config.py +463 -0
  114. agno/learn/curate.py +185 -0
  115. agno/learn/machine.py +725 -0
  116. agno/learn/schemas.py +1114 -0
  117. agno/learn/stores/__init__.py +38 -0
  118. agno/learn/stores/decision_log.py +1156 -0
  119. agno/learn/stores/entity_memory.py +3275 -0
  120. agno/learn/stores/learned_knowledge.py +1583 -0
  121. agno/learn/stores/protocol.py +117 -0
  122. agno/learn/stores/session_context.py +1217 -0
  123. agno/learn/stores/user_memory.py +1495 -0
  124. agno/learn/stores/user_profile.py +1220 -0
  125. agno/learn/utils.py +209 -0
  126. agno/media.py +22 -6
  127. agno/memory/__init__.py +14 -1
  128. agno/memory/manager.py +223 -8
  129. agno/memory/strategies/__init__.py +15 -0
  130. agno/memory/strategies/base.py +66 -0
  131. agno/memory/strategies/summarize.py +196 -0
  132. agno/memory/strategies/types.py +37 -0
  133. agno/models/aimlapi/aimlapi.py +17 -0
  134. agno/models/anthropic/claude.py +434 -59
  135. agno/models/aws/bedrock.py +121 -20
  136. agno/models/aws/claude.py +131 -274
  137. agno/models/azure/ai_foundry.py +10 -6
  138. agno/models/azure/openai_chat.py +33 -10
  139. agno/models/base.py +1162 -561
  140. agno/models/cerebras/cerebras.py +120 -24
  141. agno/models/cerebras/cerebras_openai.py +21 -2
  142. agno/models/cohere/chat.py +65 -6
  143. agno/models/cometapi/cometapi.py +18 -1
  144. agno/models/dashscope/dashscope.py +2 -3
  145. agno/models/deepinfra/deepinfra.py +18 -1
  146. agno/models/deepseek/deepseek.py +69 -3
  147. agno/models/fireworks/fireworks.py +18 -1
  148. agno/models/google/gemini.py +959 -89
  149. agno/models/google/utils.py +22 -0
  150. agno/models/groq/groq.py +48 -18
  151. agno/models/huggingface/huggingface.py +17 -6
  152. agno/models/ibm/watsonx.py +16 -6
  153. agno/models/internlm/internlm.py +18 -1
  154. agno/models/langdb/langdb.py +13 -1
  155. agno/models/litellm/chat.py +88 -9
  156. agno/models/litellm/litellm_openai.py +18 -1
  157. agno/models/message.py +24 -5
  158. agno/models/meta/llama.py +40 -13
  159. agno/models/meta/llama_openai.py +22 -21
  160. agno/models/metrics.py +12 -0
  161. agno/models/mistral/mistral.py +8 -4
  162. agno/models/n1n/__init__.py +3 -0
  163. agno/models/n1n/n1n.py +57 -0
  164. agno/models/nebius/nebius.py +6 -7
  165. agno/models/nvidia/nvidia.py +20 -3
  166. agno/models/ollama/__init__.py +2 -0
  167. agno/models/ollama/chat.py +17 -6
  168. agno/models/ollama/responses.py +100 -0
  169. agno/models/openai/__init__.py +2 -0
  170. agno/models/openai/chat.py +117 -26
  171. agno/models/openai/open_responses.py +46 -0
  172. agno/models/openai/responses.py +110 -32
  173. agno/models/openrouter/__init__.py +2 -0
  174. agno/models/openrouter/openrouter.py +67 -2
  175. agno/models/openrouter/responses.py +146 -0
  176. agno/models/perplexity/perplexity.py +19 -1
  177. agno/models/portkey/portkey.py +7 -6
  178. agno/models/requesty/requesty.py +19 -2
  179. agno/models/response.py +20 -2
  180. agno/models/sambanova/sambanova.py +20 -3
  181. agno/models/siliconflow/siliconflow.py +19 -2
  182. agno/models/together/together.py +20 -3
  183. agno/models/vercel/v0.py +20 -3
  184. agno/models/vertexai/claude.py +124 -4
  185. agno/models/vllm/vllm.py +19 -14
  186. agno/models/xai/xai.py +19 -2
  187. agno/os/app.py +467 -137
  188. agno/os/auth.py +253 -5
  189. agno/os/config.py +22 -0
  190. agno/os/interfaces/a2a/a2a.py +7 -6
  191. agno/os/interfaces/a2a/router.py +635 -26
  192. agno/os/interfaces/a2a/utils.py +32 -33
  193. agno/os/interfaces/agui/agui.py +5 -3
  194. agno/os/interfaces/agui/router.py +26 -16
  195. agno/os/interfaces/agui/utils.py +97 -57
  196. agno/os/interfaces/base.py +7 -7
  197. agno/os/interfaces/slack/router.py +16 -7
  198. agno/os/interfaces/slack/slack.py +7 -7
  199. agno/os/interfaces/whatsapp/router.py +35 -7
  200. agno/os/interfaces/whatsapp/security.py +3 -1
  201. agno/os/interfaces/whatsapp/whatsapp.py +11 -8
  202. agno/os/managers.py +326 -0
  203. agno/os/mcp.py +652 -79
  204. agno/os/middleware/__init__.py +4 -0
  205. agno/os/middleware/jwt.py +718 -115
  206. agno/os/middleware/trailing_slash.py +27 -0
  207. agno/os/router.py +105 -1558
  208. agno/os/routers/agents/__init__.py +3 -0
  209. agno/os/routers/agents/router.py +655 -0
  210. agno/os/routers/agents/schema.py +288 -0
  211. agno/os/routers/components/__init__.py +3 -0
  212. agno/os/routers/components/components.py +475 -0
  213. agno/os/routers/database.py +155 -0
  214. agno/os/routers/evals/evals.py +111 -18
  215. agno/os/routers/evals/schemas.py +38 -5
  216. agno/os/routers/evals/utils.py +80 -11
  217. agno/os/routers/health.py +3 -3
  218. agno/os/routers/knowledge/knowledge.py +284 -35
  219. agno/os/routers/knowledge/schemas.py +14 -2
  220. agno/os/routers/memory/memory.py +274 -11
  221. agno/os/routers/memory/schemas.py +44 -3
  222. agno/os/routers/metrics/metrics.py +30 -15
  223. agno/os/routers/metrics/schemas.py +10 -6
  224. agno/os/routers/registry/__init__.py +3 -0
  225. agno/os/routers/registry/registry.py +337 -0
  226. agno/os/routers/session/session.py +143 -14
  227. agno/os/routers/teams/__init__.py +3 -0
  228. agno/os/routers/teams/router.py +550 -0
  229. agno/os/routers/teams/schema.py +280 -0
  230. agno/os/routers/traces/__init__.py +3 -0
  231. agno/os/routers/traces/schemas.py +414 -0
  232. agno/os/routers/traces/traces.py +549 -0
  233. agno/os/routers/workflows/__init__.py +3 -0
  234. agno/os/routers/workflows/router.py +757 -0
  235. agno/os/routers/workflows/schema.py +139 -0
  236. agno/os/schema.py +157 -584
  237. agno/os/scopes.py +469 -0
  238. agno/os/settings.py +3 -0
  239. agno/os/utils.py +574 -185
  240. agno/reasoning/anthropic.py +85 -1
  241. agno/reasoning/azure_ai_foundry.py +93 -1
  242. agno/reasoning/deepseek.py +102 -2
  243. agno/reasoning/default.py +6 -7
  244. agno/reasoning/gemini.py +87 -3
  245. agno/reasoning/groq.py +109 -2
  246. agno/reasoning/helpers.py +6 -7
  247. agno/reasoning/manager.py +1238 -0
  248. agno/reasoning/ollama.py +93 -1
  249. agno/reasoning/openai.py +115 -1
  250. agno/reasoning/vertexai.py +85 -1
  251. agno/registry/__init__.py +3 -0
  252. agno/registry/registry.py +68 -0
  253. agno/remote/__init__.py +3 -0
  254. agno/remote/base.py +581 -0
  255. agno/run/__init__.py +2 -4
  256. agno/run/agent.py +134 -19
  257. agno/run/base.py +49 -1
  258. agno/run/cancel.py +65 -52
  259. agno/run/cancellation_management/__init__.py +9 -0
  260. agno/run/cancellation_management/base.py +78 -0
  261. agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
  262. agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
  263. agno/run/requirement.py +181 -0
  264. agno/run/team.py +111 -19
  265. agno/run/workflow.py +2 -1
  266. agno/session/agent.py +57 -92
  267. agno/session/summary.py +1 -1
  268. agno/session/team.py +62 -115
  269. agno/session/workflow.py +353 -57
  270. agno/skills/__init__.py +17 -0
  271. agno/skills/agent_skills.py +377 -0
  272. agno/skills/errors.py +32 -0
  273. agno/skills/loaders/__init__.py +4 -0
  274. agno/skills/loaders/base.py +27 -0
  275. agno/skills/loaders/local.py +216 -0
  276. agno/skills/skill.py +65 -0
  277. agno/skills/utils.py +107 -0
  278. agno/skills/validator.py +277 -0
  279. agno/table.py +10 -0
  280. agno/team/__init__.py +5 -1
  281. agno/team/remote.py +447 -0
  282. agno/team/team.py +3769 -2202
  283. agno/tools/brandfetch.py +27 -18
  284. agno/tools/browserbase.py +225 -16
  285. agno/tools/crawl4ai.py +3 -0
  286. agno/tools/duckduckgo.py +25 -71
  287. agno/tools/exa.py +0 -21
  288. agno/tools/file.py +14 -13
  289. agno/tools/file_generation.py +12 -6
  290. agno/tools/firecrawl.py +15 -7
  291. agno/tools/function.py +94 -113
  292. agno/tools/google_bigquery.py +11 -2
  293. agno/tools/google_drive.py +4 -3
  294. agno/tools/knowledge.py +9 -4
  295. agno/tools/mcp/mcp.py +301 -18
  296. agno/tools/mcp/multi_mcp.py +269 -14
  297. agno/tools/mem0.py +11 -10
  298. agno/tools/memory.py +47 -46
  299. agno/tools/mlx_transcribe.py +10 -7
  300. agno/tools/models/nebius.py +5 -5
  301. agno/tools/models_labs.py +20 -10
  302. agno/tools/nano_banana.py +151 -0
  303. agno/tools/parallel.py +0 -7
  304. agno/tools/postgres.py +76 -36
  305. agno/tools/python.py +14 -6
  306. agno/tools/reasoning.py +30 -23
  307. agno/tools/redshift.py +406 -0
  308. agno/tools/shopify.py +1519 -0
  309. agno/tools/spotify.py +919 -0
  310. agno/tools/tavily.py +4 -1
  311. agno/tools/toolkit.py +253 -18
  312. agno/tools/websearch.py +93 -0
  313. agno/tools/website.py +1 -1
  314. agno/tools/wikipedia.py +1 -1
  315. agno/tools/workflow.py +56 -48
  316. agno/tools/yfinance.py +12 -11
  317. agno/tracing/__init__.py +12 -0
  318. agno/tracing/exporter.py +161 -0
  319. agno/tracing/schemas.py +276 -0
  320. agno/tracing/setup.py +112 -0
  321. agno/utils/agent.py +251 -10
  322. agno/utils/cryptography.py +22 -0
  323. agno/utils/dttm.py +33 -0
  324. agno/utils/events.py +264 -7
  325. agno/utils/hooks.py +111 -3
  326. agno/utils/http.py +161 -2
  327. agno/utils/mcp.py +49 -8
  328. agno/utils/media.py +22 -1
  329. agno/utils/models/ai_foundry.py +9 -2
  330. agno/utils/models/claude.py +20 -5
  331. agno/utils/models/cohere.py +9 -2
  332. agno/utils/models/llama.py +9 -2
  333. agno/utils/models/mistral.py +4 -2
  334. agno/utils/os.py +0 -0
  335. agno/utils/print_response/agent.py +99 -16
  336. agno/utils/print_response/team.py +223 -24
  337. agno/utils/print_response/workflow.py +0 -2
  338. agno/utils/prompts.py +8 -6
  339. agno/utils/remote.py +23 -0
  340. agno/utils/response.py +1 -13
  341. agno/utils/string.py +91 -2
  342. agno/utils/team.py +62 -12
  343. agno/utils/tokens.py +657 -0
  344. agno/vectordb/base.py +15 -2
  345. agno/vectordb/cassandra/cassandra.py +1 -1
  346. agno/vectordb/chroma/__init__.py +2 -1
  347. agno/vectordb/chroma/chromadb.py +468 -23
  348. agno/vectordb/clickhouse/clickhousedb.py +1 -1
  349. agno/vectordb/couchbase/couchbase.py +6 -2
  350. agno/vectordb/lancedb/lance_db.py +7 -38
  351. agno/vectordb/lightrag/lightrag.py +7 -6
  352. agno/vectordb/milvus/milvus.py +118 -84
  353. agno/vectordb/mongodb/__init__.py +2 -1
  354. agno/vectordb/mongodb/mongodb.py +14 -31
  355. agno/vectordb/pgvector/pgvector.py +120 -66
  356. agno/vectordb/pineconedb/pineconedb.py +2 -19
  357. agno/vectordb/qdrant/__init__.py +2 -1
  358. agno/vectordb/qdrant/qdrant.py +33 -56
  359. agno/vectordb/redis/__init__.py +2 -1
  360. agno/vectordb/redis/redisdb.py +19 -31
  361. agno/vectordb/singlestore/singlestore.py +17 -9
  362. agno/vectordb/surrealdb/surrealdb.py +2 -38
  363. agno/vectordb/weaviate/__init__.py +2 -1
  364. agno/vectordb/weaviate/weaviate.py +7 -3
  365. agno/workflow/__init__.py +5 -1
  366. agno/workflow/agent.py +2 -2
  367. agno/workflow/condition.py +12 -10
  368. agno/workflow/loop.py +28 -9
  369. agno/workflow/parallel.py +21 -13
  370. agno/workflow/remote.py +362 -0
  371. agno/workflow/router.py +12 -9
  372. agno/workflow/step.py +261 -36
  373. agno/workflow/steps.py +12 -8
  374. agno/workflow/types.py +40 -77
  375. agno/workflow/workflow.py +939 -213
  376. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
  377. agno-2.4.3.dist-info/RECORD +677 -0
  378. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
  379. agno/tools/googlesearch.py +0 -98
  380. agno/tools/memori.py +0 -339
  381. agno-2.2.13.dist-info/RECORD +0 -575
  382. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
  383. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/db/redis/utils.py CHANGED
@@ -3,14 +3,15 @@
3
3
  import json
4
4
  import time
5
5
  from datetime import date, datetime, timedelta, timezone
6
- from typing import Any, Dict, List, Optional
6
+ from typing import Any, Dict, List, Optional, Union
7
7
  from uuid import UUID
8
8
 
9
9
  from agno.db.schemas.culture import CulturalKnowledge
10
+ from agno.db.utils import get_sort_value
10
11
  from agno.utils.log import log_warning
11
12
 
12
13
  try:
13
- from redis import Redis
14
+ from redis import Redis, RedisCluster
14
15
  except ImportError:
15
16
  raise ImportError("`redis` not installed. Please install it using `pip install redis`")
16
17
 
@@ -51,7 +52,7 @@ def generate_index_key(prefix: str, table_type: str, index_field: str, index_val
51
52
  return f"{prefix}:{table_type}:index:{index_field}:{index_value}"
52
53
 
53
54
 
54
- def get_all_keys_for_table(redis_client: Redis, prefix: str, table_type: str) -> List[str]:
55
+ def get_all_keys_for_table(redis_client: Union[Redis, RedisCluster], prefix: str, table_type: str) -> List[str]:
55
56
  """Get all relevant keys for the given table type.
56
57
 
57
58
  Args:
@@ -80,21 +81,36 @@ def get_all_keys_for_table(redis_client: Redis, prefix: str, table_type: str) ->
80
81
  def apply_sorting(
81
82
  records: List[Dict[str, Any]], sort_by: Optional[str] = None, sort_order: Optional[str] = None
82
83
  ) -> List[Dict[str, Any]]:
83
- if sort_by is None:
84
- return records
84
+ """Apply sorting to the given records list.
85
+
86
+ Args:
87
+ records: The list of dictionaries to sort
88
+ sort_by: The field to sort by
89
+ sort_order: The sort order ('asc' or 'desc')
90
+
91
+ Returns:
92
+ The sorted list
85
93
 
86
- def get_sort_key(record):
87
- value = record.get(sort_by, 0)
88
- if value is None:
89
- return 0 if isinstance(records[0].get(sort_by, 0), (int, float)) else ""
90
- return value
94
+ Note:
95
+ If sorting by "updated_at", will fallback to "created_at" in case of None.
96
+ """
97
+ if sort_by is None or not records:
98
+ return records
91
99
 
92
100
  try:
93
- is_reverse = sort_order == "desc"
94
- return sorted(records, key=get_sort_key, reverse=is_reverse)
101
+ is_descending = sort_order == "desc"
102
+
103
+ # Sort using the helper function that handles updated_at -> created_at fallback
104
+ sorted_records = sorted(
105
+ records,
106
+ key=lambda x: (get_sort_value(x, sort_by) is None, get_sort_value(x, sort_by)),
107
+ reverse=is_descending,
108
+ )
109
+
110
+ return sorted_records
95
111
 
96
112
  except Exception as e:
97
- log_warning(f"Error sorting Redisrecords: {e}")
113
+ log_warning(f"Error sorting Redis records: {e}")
98
114
  return records
99
115
 
100
116
 
@@ -130,7 +146,7 @@ def apply_filters(records: List[Dict[str, Any]], conditions: Dict[str, Any]) ->
130
146
 
131
147
 
132
148
  def create_index_entries(
133
- redis_client: Redis,
149
+ redis_client: Union[Redis, RedisCluster],
134
150
  prefix: str,
135
151
  table_type: str,
136
152
  record_id: str,
@@ -144,7 +160,7 @@ def create_index_entries(
144
160
 
145
161
 
146
162
  def remove_index_entries(
147
- redis_client: Redis,
163
+ redis_client: Union[Redis, RedisCluster],
148
164
  prefix: str,
149
165
  table_type: str,
150
166
  record_id: str,
agno/db/schemas/evals.py CHANGED
@@ -6,6 +6,7 @@ from pydantic import BaseModel
6
6
 
7
7
  class EvalType(str, Enum):
8
8
  ACCURACY = "accuracy"
9
+ AGENT_AS_JUDGE = "agent_as_judge"
9
10
  PERFORMANCE = "performance"
10
11
  RELIABILITY = "reliability"
11
12
 
agno/db/schemas/memory.py CHANGED
@@ -1,7 +1,9 @@
1
1
  from dataclasses import dataclass
2
- from datetime import datetime, timezone
2
+ from datetime import datetime
3
3
  from typing import Any, Dict, List, Optional
4
4
 
5
+ from agno.utils.dttm import now_epoch_s, to_epoch_s
6
+
5
7
 
6
8
  @dataclass
7
9
  class UserMemory:
@@ -12,18 +14,28 @@ class UserMemory:
12
14
  topics: Optional[List[str]] = None
13
15
  user_id: Optional[str] = None
14
16
  input: Optional[str] = None
15
- updated_at: Optional[datetime] = None
17
+ created_at: Optional[int] = None
18
+ updated_at: Optional[int] = None
16
19
  feedback: Optional[str] = None
17
20
 
18
21
  agent_id: Optional[str] = None
19
22
  team_id: Optional[str] = None
20
23
 
24
+ def __post_init__(self) -> None:
25
+ """Automatically set/normalize created_at and updated_at."""
26
+ self.created_at = now_epoch_s() if self.created_at is None else to_epoch_s(self.created_at)
27
+ if self.updated_at is not None:
28
+ self.updated_at = to_epoch_s(self.updated_at)
29
+
21
30
  def to_dict(self) -> Dict[str, Any]:
31
+ created_at = datetime.fromtimestamp(self.created_at).isoformat() if self.created_at is not None else None
32
+ updated_at = datetime.fromtimestamp(self.updated_at).isoformat() if self.updated_at is not None else created_at
22
33
  _dict = {
23
34
  "memory_id": self.memory_id,
24
35
  "memory": self.memory,
25
36
  "topics": self.topics,
26
- "updated_at": self.updated_at.isoformat() if self.updated_at else None,
37
+ "created_at": created_at,
38
+ "updated_at": updated_at,
27
39
  "input": self.input,
28
40
  "user_id": self.user_id,
29
41
  "agent_id": self.agent_id,
@@ -36,11 +48,10 @@ class UserMemory:
36
48
  def from_dict(cls, data: Dict[str, Any]) -> "UserMemory":
37
49
  data = dict(data)
38
50
 
39
- # Convert updated_at to datetime
40
- if updated_at := data.get("updated_at"):
41
- if isinstance(updated_at, (int, float)):
42
- data["updated_at"] = datetime.fromtimestamp(updated_at, tz=timezone.utc)
43
- else:
44
- data["updated_at"] = datetime.fromisoformat(updated_at)
51
+ # Preserve 0 and None explicitly; only process if key exists
52
+ if "created_at" in data and data["created_at"] is not None:
53
+ data["created_at"] = to_epoch_s(data["created_at"])
54
+ if "updated_at" in data and data["updated_at"] is not None:
55
+ data["updated_at"] = to_epoch_s(data["updated_at"])
45
56
 
46
57
  return cls(**data)
@@ -39,6 +39,8 @@ USER_MEMORY_TABLE_SCHEMA = {
39
39
  "team_id": {"type": lambda: String(128), "nullable": True},
40
40
  "user_id": {"type": lambda: String(128), "nullable": True, "index": True},
41
41
  "topics": {"type": JSON, "nullable": True},
42
+ "feedback": {"type": Text, "nullable": True},
43
+ "created_at": {"type": BigInteger, "nullable": False, "index": True},
42
44
  "updated_at": {"type": BigInteger, "nullable": True, "index": True},
43
45
  }
44
46
 
@@ -106,14 +108,79 @@ CULTURAL_KNOWLEDGE_TABLE_SCHEMA = {
106
108
  }
107
109
 
108
110
 
109
- def get_table_schema_definition(table_type: str) -> dict[str, Any]:
111
+ VERSIONS_TABLE_SCHEMA = {
112
+ "table_name": {"type": lambda: String(128), "nullable": False, "primary_key": True},
113
+ "version": {"type": lambda: String(10), "nullable": False},
114
+ "created_at": {"type": lambda: String(128), "nullable": False, "index": True},
115
+ "updated_at": {"type": lambda: String(128), "nullable": True},
116
+ }
117
+
118
+ TRACE_TABLE_SCHEMA = {
119
+ "trace_id": {"type": lambda: String(128), "primary_key": True, "nullable": False},
120
+ "name": {"type": lambda: String(512), "nullable": False},
121
+ "status": {"type": lambda: String(20), "nullable": False, "index": True},
122
+ "start_time": {"type": lambda: String(64), "nullable": False, "index": True}, # ISO 8601 datetime string
123
+ "end_time": {"type": lambda: String(64), "nullable": False}, # ISO 8601 datetime string
124
+ "duration_ms": {"type": BigInteger, "nullable": False},
125
+ "run_id": {"type": lambda: String(128), "nullable": True, "index": True},
126
+ "session_id": {"type": lambda: String(128), "nullable": True, "index": True},
127
+ "user_id": {"type": lambda: String(128), "nullable": True, "index": True},
128
+ "agent_id": {"type": lambda: String(128), "nullable": True, "index": True},
129
+ "team_id": {"type": lambda: String(128), "nullable": True, "index": True},
130
+ "workflow_id": {"type": lambda: String(128), "nullable": True, "index": True},
131
+ "created_at": {"type": lambda: String(64), "nullable": False, "index": True}, # ISO 8601 datetime string
132
+ }
133
+
134
+
135
+ def _get_span_table_schema(traces_table_name: str = "agno_traces", db_schema: str = "agno") -> dict[str, Any]:
136
+ """Get the span table schema with the correct foreign key reference.
137
+
138
+ Args:
139
+ traces_table_name: The name of the traces table to reference in the foreign key.
140
+ db_schema: The database schema name.
141
+
142
+ Returns:
143
+ The span table schema dictionary.
144
+ """
145
+ return {
146
+ "span_id": {"type": lambda: String(128), "primary_key": True, "nullable": False},
147
+ "trace_id": {
148
+ "type": lambda: String(128),
149
+ "nullable": False,
150
+ "index": True,
151
+ "foreign_key": f"{db_schema}.{traces_table_name}.trace_id",
152
+ },
153
+ "parent_span_id": {"type": lambda: String(128), "nullable": True, "index": True},
154
+ "name": {"type": lambda: String(512), "nullable": False},
155
+ "span_kind": {"type": lambda: String(50), "nullable": False},
156
+ "status_code": {"type": lambda: String(20), "nullable": False},
157
+ "status_message": {"type": Text, "nullable": True},
158
+ "start_time": {"type": lambda: String(64), "nullable": False, "index": True}, # ISO 8601 datetime string
159
+ "end_time": {"type": lambda: String(64), "nullable": False}, # ISO 8601 datetime string
160
+ "duration_ms": {"type": BigInteger, "nullable": False},
161
+ "attributes": {"type": JSON, "nullable": True},
162
+ "created_at": {"type": lambda: String(64), "nullable": False, "index": True}, # ISO 8601 datetime string
163
+ }
164
+
165
+
166
+ def get_table_schema_definition(
167
+ table_type: str, traces_table_name: str = "agno_traces", db_schema: str = "agno"
168
+ ) -> dict[str, Any]:
110
169
  """
111
170
  Get the expected schema definition for the given table.
171
+
112
172
  Args:
113
173
  table_type (str): The type of table to get the schema for.
174
+ traces_table_name (str): The name of the traces table (used for spans foreign key).
175
+ db_schema (str): The database schema name (used for spans foreign key).
176
+
114
177
  Returns:
115
178
  Dict[str, Any]: Dictionary containing column definitions for the table
116
179
  """
180
+ # Handle spans table specially to resolve the foreign key reference
181
+ if table_type == "spans":
182
+ return _get_span_table_schema(traces_table_name, db_schema)
183
+
117
184
  schemas = {
118
185
  "sessions": SESSION_TABLE_SCHEMA,
119
186
  "evals": EVAL_TABLE_SCHEMA,
@@ -121,6 +188,8 @@ def get_table_schema_definition(table_type: str) -> dict[str, Any]:
121
188
  "memories": USER_MEMORY_TABLE_SCHEMA,
122
189
  "knowledge": KNOWLEDGE_TABLE_SCHEMA,
123
190
  "culture": CULTURAL_KNOWLEDGE_TABLE_SCHEMA,
191
+ "versions": VERSIONS_TABLE_SCHEMA,
192
+ "traces": TRACE_TABLE_SCHEMA,
124
193
  }
125
194
  schema = schemas.get(table_type, {})
126
195