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
@@ -67,6 +67,7 @@ USER_MEMORY_COLLECTION_SCHEMA = [
67
67
  {"key": "agent_id"},
68
68
  {"key": "team_id"},
69
69
  {"key": "topics"},
70
+ {"key": "created_at"},
70
71
  {"key": "updated_at"},
71
72
  # Composite indexes for memory queries
72
73
  {"key": [("user_id", "ASCENDING"), ("agent_id", "ASCENDING")], "collection_group": False},
@@ -121,6 +122,44 @@ CULTURAL_KNOWLEDGE_COLLECTION_SCHEMA = [
121
122
  {"key": "updated_at"},
122
123
  ]
123
124
 
125
+ TRACE_COLLECTION_SCHEMA = [
126
+ {"key": "trace_id", "unique": True},
127
+ {"key": "name"},
128
+ {"key": "status"},
129
+ {"key": "run_id"},
130
+ {"key": "session_id"},
131
+ {"key": "user_id"},
132
+ {"key": "agent_id"},
133
+ {"key": "team_id"},
134
+ {"key": "workflow_id"},
135
+ {"key": "start_time"},
136
+ {"key": "end_time"},
137
+ {"key": "created_at"},
138
+ # Composite indexes for common query patterns
139
+ {"key": [("session_id", "ASCENDING"), ("start_time", "DESCENDING")], "collection_group": False},
140
+ {"key": [("user_id", "ASCENDING"), ("start_time", "DESCENDING")], "collection_group": False},
141
+ {"key": [("agent_id", "ASCENDING"), ("start_time", "DESCENDING")], "collection_group": False},
142
+ {"key": [("team_id", "ASCENDING"), ("start_time", "DESCENDING")], "collection_group": False},
143
+ {"key": [("workflow_id", "ASCENDING"), ("start_time", "DESCENDING")], "collection_group": False},
144
+ {"key": [("run_id", "ASCENDING"), ("start_time", "DESCENDING")], "collection_group": False},
145
+ {"key": [("status", "ASCENDING"), ("start_time", "DESCENDING")], "collection_group": False},
146
+ ]
147
+
148
+ SPAN_COLLECTION_SCHEMA = [
149
+ {"key": "span_id", "unique": True},
150
+ {"key": "trace_id"},
151
+ {"key": "parent_span_id"},
152
+ {"key": "name"},
153
+ {"key": "span_kind"},
154
+ {"key": "status_code"},
155
+ {"key": "start_time"},
156
+ {"key": "end_time"},
157
+ {"key": "created_at"},
158
+ # Composite indexes for common query patterns
159
+ {"key": [("trace_id", "ASCENDING"), ("start_time", "ASCENDING")], "collection_group": False},
160
+ {"key": [("parent_span_id", "ASCENDING"), ("start_time", "ASCENDING")], "collection_group": False},
161
+ ]
162
+
124
163
 
125
164
  def get_collection_indexes(collection_type: str) -> List[Dict[str, Any]]:
126
165
  """Get the index definitions for a specific collection type."""
@@ -131,6 +170,8 @@ def get_collection_indexes(collection_type: str) -> List[Dict[str, Any]]:
131
170
  "evals": EVAL_COLLECTION_SCHEMA,
132
171
  "knowledge": KNOWLEDGE_COLLECTION_SCHEMA,
133
172
  "culture": CULTURAL_KNOWLEDGE_COLLECTION_SCHEMA,
173
+ "traces": TRACE_COLLECTION_SCHEMA,
174
+ "spans": SPAN_COLLECTION_SCHEMA,
134
175
  }
135
176
 
136
177
  indexes = index_definitions.get(collection_type)
@@ -8,6 +8,7 @@ from uuid import uuid4
8
8
 
9
9
  from agno.db.firestore.schemas import get_collection_indexes
10
10
  from agno.db.schemas.culture import CulturalKnowledge
11
+ from agno.db.utils import get_sort_value
11
12
  from agno.utils.log import log_debug, log_error, log_info, log_warning
12
13
 
13
14
  try:
@@ -126,19 +127,33 @@ def apply_pagination(query, limit: Optional[int] = None, page: Optional[int] = N
126
127
  def apply_sorting_to_records(
127
128
  records: List[Dict[str, Any]], sort_by: Optional[str] = None, sort_order: Optional[str] = None
128
129
  ) -> List[Dict[str, Any]]:
129
- """Apply sorting to in-memory records (for cases where Firestore query sorting isn't possible)."""
130
- if sort_by is None:
131
- return records
130
+ """Apply sorting to in-memory records (for cases where Firestore query sorting isn't possible).
131
+
132
+ Args:
133
+ records: The list of dictionaries to sort
134
+ sort_by: The field to sort by
135
+ sort_order: The sort order ('asc' or 'desc')
132
136
 
133
- def get_sort_key(record):
134
- value = record.get(sort_by, 0)
135
- if value is None:
136
- return 0 if records and isinstance(records[0].get(sort_by, 0), (int, float)) else ""
137
- return value
137
+ Returns:
138
+ The sorted list
139
+
140
+ Note:
141
+ If sorting by "updated_at", will fallback to "created_at" in case of None.
142
+ """
143
+ if sort_by is None or not records:
144
+ return records
138
145
 
139
146
  try:
140
- is_reverse = sort_order == "desc"
141
- return sorted(records, key=get_sort_key, reverse=is_reverse)
147
+ is_descending = sort_order == "desc"
148
+
149
+ # Sort using the helper function that handles updated_at -> created_at fallback
150
+ sorted_records = sorted(
151
+ records,
152
+ key=lambda x: (get_sort_value(x, sort_by) is None, get_sort_value(x, sort_by)),
153
+ reverse=is_descending,
154
+ )
155
+
156
+ return sorted_records
142
157
  except Exception as e:
143
158
  log_warning(f"Error sorting Firestore records: {e}")
144
159
  return records
@@ -1,9 +1,12 @@
1
1
  import json
2
2
  import time
3
3
  from datetime import date, datetime, timedelta, timezone
4
- from typing import Any, Dict, List, Optional, Tuple, Union
4
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
5
5
  from uuid import uuid4
6
6
 
7
+ if TYPE_CHECKING:
8
+ from agno.tracing.schemas import Span, Trace
9
+
7
10
  from agno.db.base import BaseDb, SessionType
8
11
  from agno.db.gcs_json.utils import (
9
12
  apply_sorting,
@@ -38,6 +41,8 @@ class GcsJsonDb(BaseDb):
38
41
  eval_table: Optional[str] = None,
39
42
  knowledge_table: Optional[str] = None,
40
43
  culture_table: Optional[str] = None,
44
+ traces_table: Optional[str] = None,
45
+ spans_table: Optional[str] = None,
41
46
  project: Optional[str] = None,
42
47
  credentials: Optional[Any] = None,
43
48
  id: Optional[str] = None,
@@ -54,6 +59,8 @@ class GcsJsonDb(BaseDb):
54
59
  eval_table (Optional[str]): Name of the JSON file to store evaluation runs.
55
60
  knowledge_table (Optional[str]): Name of the JSON file to store knowledge content.
56
61
  culture_table (Optional[str]): Name of the JSON file to store cultural knowledge.
62
+ traces_table (Optional[str]): Name of the JSON file to store traces.
63
+ spans_table (Optional[str]): Name of the JSON file to store spans.
57
64
  project (Optional[str]): GCP project ID. If None, uses default project.
58
65
  location (Optional[str]): GCS bucket location. If None, uses default location.
59
66
  credentials (Optional[Any]): GCP credentials. If None, uses default credentials.
@@ -72,6 +79,8 @@ class GcsJsonDb(BaseDb):
72
79
  eval_table=eval_table,
73
80
  knowledge_table=knowledge_table,
74
81
  culture_table=culture_table,
82
+ traces_table=traces_table,
83
+ spans_table=spans_table,
75
84
  )
76
85
 
77
86
  self.bucket_name = bucket_name
@@ -142,6 +151,14 @@ class GcsJsonDb(BaseDb):
142
151
  log_error(f"Error writing to the {blob_name} JSON file in GCS: {e}")
143
152
  return
144
153
 
154
+ def get_latest_schema_version(self):
155
+ """Get the latest version of the database schema."""
156
+ pass
157
+
158
+ def upsert_schema_version(self, version: str) -> None:
159
+ """Upsert the schema version into the database."""
160
+ pass
161
+
145
162
  # -- Session methods --
146
163
 
147
164
  def delete_session(self, session_id: str) -> bool:
@@ -627,13 +644,14 @@ class GcsJsonDb(BaseDb):
627
644
  raise e
628
645
 
629
646
  def get_user_memory_stats(
630
- self, limit: Optional[int] = None, page: Optional[int] = None
647
+ self, limit: Optional[int] = None, page: Optional[int] = None, user_id: Optional[str] = None
631
648
  ) -> Tuple[List[Dict[str, Any]], int]:
632
649
  """Get user memory statistics.
633
650
 
634
651
  Args:
635
652
  limit (Optional[int]): Maximum number of results to return.
636
653
  page (Optional[int]): Page number for pagination.
654
+ user_id (Optional[str]): User ID for filtering.
637
655
 
638
656
  Returns:
639
657
  Tuple[List[Dict[str, Any]], int]: List of user memory statistics and total count.
@@ -644,7 +662,9 @@ class GcsJsonDb(BaseDb):
644
662
 
645
663
  for memory in memories:
646
664
  memory_user_id = memory.get("user_id")
647
-
665
+ # filter by user_id if provided
666
+ if user_id is not None and memory_user_id != user_id:
667
+ continue
648
668
  if memory_user_id:
649
669
  if memory_user_id not in user_stats:
650
670
  user_stats[memory_user_id] = {
@@ -1333,3 +1353,486 @@ class GcsJsonDb(BaseDb):
1333
1353
  except Exception as e:
1334
1354
  log_warning(f"Error upserting cultural knowledge: {e}")
1335
1355
  raise e
1356
+
1357
+ # --- Traces ---
1358
+ def upsert_trace(self, trace: "Trace") -> None:
1359
+ """Create or update a single trace record in the database.
1360
+
1361
+ Args:
1362
+ trace: The Trace object to store (one per trace_id).
1363
+ """
1364
+ try:
1365
+ traces = self._read_json_file(self.trace_table_name, create_table_if_not_found=True)
1366
+
1367
+ # Check if trace exists
1368
+ existing_idx = None
1369
+ for i, existing in enumerate(traces):
1370
+ if existing.get("trace_id") == trace.trace_id:
1371
+ existing_idx = i
1372
+ break
1373
+
1374
+ if existing_idx is not None:
1375
+ existing = traces[existing_idx]
1376
+
1377
+ # workflow (level 3) > team (level 2) > agent (level 1) > child/unknown (level 0)
1378
+ def get_component_level(workflow_id: Any, team_id: Any, agent_id: Any, name: str) -> int:
1379
+ is_root_name = ".run" in name or ".arun" in name
1380
+ if not is_root_name:
1381
+ return 0
1382
+ elif workflow_id:
1383
+ return 3
1384
+ elif team_id:
1385
+ return 2
1386
+ elif agent_id:
1387
+ return 1
1388
+ else:
1389
+ return 0
1390
+
1391
+ existing_level = get_component_level(
1392
+ existing.get("workflow_id"),
1393
+ existing.get("team_id"),
1394
+ existing.get("agent_id"),
1395
+ existing.get("name", ""),
1396
+ )
1397
+ new_level = get_component_level(trace.workflow_id, trace.team_id, trace.agent_id, trace.name)
1398
+ should_update_name = new_level > existing_level
1399
+
1400
+ # Parse existing start_time to calculate correct duration
1401
+ existing_start_time_str = existing.get("start_time")
1402
+ if isinstance(existing_start_time_str, str):
1403
+ existing_start_time = datetime.fromisoformat(existing_start_time_str.replace("Z", "+00:00"))
1404
+ else:
1405
+ existing_start_time = trace.start_time
1406
+
1407
+ recalculated_duration_ms = int((trace.end_time - existing_start_time).total_seconds() * 1000)
1408
+
1409
+ # Update existing trace
1410
+ existing["end_time"] = trace.end_time.isoformat()
1411
+ existing["duration_ms"] = recalculated_duration_ms
1412
+ existing["status"] = trace.status
1413
+ if should_update_name:
1414
+ existing["name"] = trace.name
1415
+
1416
+ # Update context fields only if new value is not None
1417
+ if trace.run_id is not None:
1418
+ existing["run_id"] = trace.run_id
1419
+ if trace.session_id is not None:
1420
+ existing["session_id"] = trace.session_id
1421
+ if trace.user_id is not None:
1422
+ existing["user_id"] = trace.user_id
1423
+ if trace.agent_id is not None:
1424
+ existing["agent_id"] = trace.agent_id
1425
+ if trace.team_id is not None:
1426
+ existing["team_id"] = trace.team_id
1427
+ if trace.workflow_id is not None:
1428
+ existing["workflow_id"] = trace.workflow_id
1429
+
1430
+ traces[existing_idx] = existing
1431
+ else:
1432
+ # Add new trace
1433
+ trace_dict = trace.to_dict()
1434
+ trace_dict.pop("total_spans", None)
1435
+ trace_dict.pop("error_count", None)
1436
+ traces.append(trace_dict)
1437
+
1438
+ self._write_json_file(self.trace_table_name, traces)
1439
+
1440
+ except Exception as e:
1441
+ log_error(f"Error creating trace: {e}")
1442
+
1443
+ def get_trace(
1444
+ self,
1445
+ trace_id: Optional[str] = None,
1446
+ run_id: Optional[str] = None,
1447
+ ):
1448
+ """Get a single trace by trace_id or other filters.
1449
+
1450
+ Args:
1451
+ trace_id: The unique trace identifier.
1452
+ run_id: Filter by run ID (returns first match).
1453
+
1454
+ Returns:
1455
+ Optional[Trace]: The trace if found, None otherwise.
1456
+
1457
+ Note:
1458
+ If multiple filters are provided, trace_id takes precedence.
1459
+ For other filters, the most recent trace is returned.
1460
+ """
1461
+ try:
1462
+ from agno.tracing.schemas import Trace
1463
+
1464
+ traces = self._read_json_file(self.trace_table_name, create_table_if_not_found=False)
1465
+ if not traces:
1466
+ return None
1467
+
1468
+ # Get spans for calculating total_spans and error_count
1469
+ spans = self._read_json_file(self.span_table_name, create_table_if_not_found=False)
1470
+
1471
+ # Filter traces
1472
+ filtered = []
1473
+ for t in traces:
1474
+ if trace_id and t.get("trace_id") == trace_id:
1475
+ filtered.append(t)
1476
+ break
1477
+ elif run_id and t.get("run_id") == run_id:
1478
+ filtered.append(t)
1479
+
1480
+ if not filtered:
1481
+ return None
1482
+
1483
+ # Sort by start_time desc and get first
1484
+ filtered.sort(key=lambda x: x.get("start_time", ""), reverse=True)
1485
+ trace_data = filtered[0]
1486
+
1487
+ # Calculate total_spans and error_count
1488
+ trace_spans = [s for s in spans if s.get("trace_id") == trace_data.get("trace_id")]
1489
+ trace_data["total_spans"] = len(trace_spans)
1490
+ trace_data["error_count"] = sum(1 for s in trace_spans if s.get("status_code") == "ERROR")
1491
+
1492
+ return Trace.from_dict(trace_data)
1493
+
1494
+ except Exception as e:
1495
+ log_error(f"Error getting trace: {e}")
1496
+ return None
1497
+
1498
+ def get_traces(
1499
+ self,
1500
+ run_id: Optional[str] = None,
1501
+ session_id: Optional[str] = None,
1502
+ user_id: Optional[str] = None,
1503
+ agent_id: Optional[str] = None,
1504
+ team_id: Optional[str] = None,
1505
+ workflow_id: Optional[str] = None,
1506
+ status: Optional[str] = None,
1507
+ start_time: Optional[datetime] = None,
1508
+ end_time: Optional[datetime] = None,
1509
+ limit: Optional[int] = 20,
1510
+ page: Optional[int] = 1,
1511
+ ) -> tuple[List, int]:
1512
+ """Get traces matching the provided filters with pagination.
1513
+
1514
+ Args:
1515
+ run_id: Filter by run ID.
1516
+ session_id: Filter by session ID.
1517
+ user_id: Filter by user ID.
1518
+ agent_id: Filter by agent ID.
1519
+ team_id: Filter by team ID.
1520
+ workflow_id: Filter by workflow ID.
1521
+ status: Filter by status (OK, ERROR, UNSET).
1522
+ start_time: Filter traces starting after this datetime.
1523
+ end_time: Filter traces ending before this datetime.
1524
+ limit: Maximum number of traces to return per page.
1525
+ page: Page number (1-indexed).
1526
+
1527
+ Returns:
1528
+ tuple[List[Trace], int]: Tuple of (list of matching traces, total count).
1529
+ """
1530
+ try:
1531
+ from agno.tracing.schemas import Trace
1532
+
1533
+ traces = self._read_json_file(self.trace_table_name, create_table_if_not_found=False)
1534
+ if not traces:
1535
+ return [], 0
1536
+
1537
+ # Get spans for calculating total_spans and error_count
1538
+ spans = self._read_json_file(self.span_table_name, create_table_if_not_found=False)
1539
+
1540
+ # Apply filters
1541
+ filtered = []
1542
+ for t in traces:
1543
+ if run_id and t.get("run_id") != run_id:
1544
+ continue
1545
+ if session_id and t.get("session_id") != session_id:
1546
+ continue
1547
+ if user_id and t.get("user_id") != user_id:
1548
+ continue
1549
+ if agent_id and t.get("agent_id") != agent_id:
1550
+ continue
1551
+ if team_id and t.get("team_id") != team_id:
1552
+ continue
1553
+ if workflow_id and t.get("workflow_id") != workflow_id:
1554
+ continue
1555
+ if status and t.get("status") != status:
1556
+ continue
1557
+ if start_time:
1558
+ trace_start = t.get("start_time", "")
1559
+ if trace_start < start_time.isoformat():
1560
+ continue
1561
+ if end_time:
1562
+ trace_end = t.get("end_time", "")
1563
+ if trace_end > end_time.isoformat():
1564
+ continue
1565
+ filtered.append(t)
1566
+
1567
+ total_count = len(filtered)
1568
+
1569
+ # Sort by start_time desc
1570
+ filtered.sort(key=lambda x: x.get("start_time", ""), reverse=True)
1571
+
1572
+ # Apply pagination
1573
+ if limit and page:
1574
+ start_idx = (page - 1) * limit
1575
+ filtered = filtered[start_idx : start_idx + limit]
1576
+
1577
+ # Add total_spans and error_count to each trace
1578
+ result_traces = []
1579
+ for t in filtered:
1580
+ trace_spans = [s for s in spans if s.get("trace_id") == t.get("trace_id")]
1581
+ t["total_spans"] = len(trace_spans)
1582
+ t["error_count"] = sum(1 for s in trace_spans if s.get("status_code") == "ERROR")
1583
+ result_traces.append(Trace.from_dict(t))
1584
+
1585
+ return result_traces, total_count
1586
+
1587
+ except Exception as e:
1588
+ log_error(f"Error getting traces: {e}")
1589
+ return [], 0
1590
+
1591
+ def get_trace_stats(
1592
+ self,
1593
+ user_id: Optional[str] = None,
1594
+ agent_id: Optional[str] = None,
1595
+ team_id: Optional[str] = None,
1596
+ workflow_id: Optional[str] = None,
1597
+ start_time: Optional[datetime] = None,
1598
+ end_time: Optional[datetime] = None,
1599
+ limit: Optional[int] = 20,
1600
+ page: Optional[int] = 1,
1601
+ ) -> tuple[List[Dict[str, Any]], int]:
1602
+ """Get trace statistics grouped by session.
1603
+
1604
+ Args:
1605
+ user_id: Filter by user ID.
1606
+ agent_id: Filter by agent ID.
1607
+ team_id: Filter by team ID.
1608
+ workflow_id: Filter by workflow ID.
1609
+ start_time: Filter sessions with traces created after this datetime.
1610
+ end_time: Filter sessions with traces created before this datetime.
1611
+ limit: Maximum number of sessions to return per page.
1612
+ page: Page number (1-indexed).
1613
+
1614
+ Returns:
1615
+ tuple[List[Dict], int]: Tuple of (list of session stats dicts, total count).
1616
+ Each dict contains: session_id, user_id, agent_id, team_id, workflow_id, total_traces,
1617
+ first_trace_at, last_trace_at.
1618
+ """
1619
+ try:
1620
+ traces = self._read_json_file(self.trace_table_name, create_table_if_not_found=False)
1621
+ if not traces:
1622
+ return [], 0
1623
+
1624
+ # Group by session_id
1625
+ session_stats: Dict[str, Dict[str, Any]] = {}
1626
+
1627
+ for t in traces:
1628
+ trace_session_id = t.get("session_id")
1629
+ if not trace_session_id:
1630
+ continue
1631
+
1632
+ # Apply filters
1633
+ if user_id and t.get("user_id") != user_id:
1634
+ continue
1635
+ if agent_id and t.get("agent_id") != agent_id:
1636
+ continue
1637
+ if team_id and t.get("team_id") != team_id:
1638
+ continue
1639
+ if workflow_id and t.get("workflow_id") != workflow_id:
1640
+ continue
1641
+
1642
+ created_at = t.get("created_at", "")
1643
+ if start_time and created_at < start_time.isoformat():
1644
+ continue
1645
+ if end_time and created_at > end_time.isoformat():
1646
+ continue
1647
+
1648
+ if trace_session_id not in session_stats:
1649
+ session_stats[trace_session_id] = {
1650
+ "session_id": trace_session_id,
1651
+ "user_id": t.get("user_id"),
1652
+ "agent_id": t.get("agent_id"),
1653
+ "team_id": t.get("team_id"),
1654
+ "workflow_id": t.get("workflow_id"),
1655
+ "total_traces": 0,
1656
+ "first_trace_at": created_at,
1657
+ "last_trace_at": created_at,
1658
+ }
1659
+
1660
+ session_stats[trace_session_id]["total_traces"] += 1
1661
+ if created_at and session_stats[trace_session_id]["first_trace_at"]:
1662
+ if created_at < session_stats[trace_session_id]["first_trace_at"]:
1663
+ session_stats[trace_session_id]["first_trace_at"] = created_at
1664
+ if created_at and session_stats[trace_session_id]["last_trace_at"]:
1665
+ if created_at > session_stats[trace_session_id]["last_trace_at"]:
1666
+ session_stats[trace_session_id]["last_trace_at"] = created_at
1667
+
1668
+ stats_list = list(session_stats.values())
1669
+ total_count = len(stats_list)
1670
+
1671
+ # Sort by last_trace_at desc
1672
+ stats_list.sort(key=lambda x: x.get("last_trace_at", ""), reverse=True)
1673
+
1674
+ # Apply pagination
1675
+ if limit and page:
1676
+ start_idx = (page - 1) * limit
1677
+ stats_list = stats_list[start_idx : start_idx + limit]
1678
+
1679
+ # Convert ISO strings to datetime objects
1680
+ for stat in stats_list:
1681
+ first_at = stat.get("first_trace_at", "")
1682
+ last_at = stat.get("last_trace_at", "")
1683
+ if first_at:
1684
+ stat["first_trace_at"] = datetime.fromisoformat(first_at.replace("Z", "+00:00"))
1685
+ if last_at:
1686
+ stat["last_trace_at"] = datetime.fromisoformat(last_at.replace("Z", "+00:00"))
1687
+
1688
+ return stats_list, total_count
1689
+
1690
+ except Exception as e:
1691
+ log_error(f"Error getting trace stats: {e}")
1692
+ return [], 0
1693
+
1694
+ # --- Spans ---
1695
+ def create_span(self, span: "Span") -> None:
1696
+ """Create a single span in the database.
1697
+
1698
+ Args:
1699
+ span: The Span object to store.
1700
+ """
1701
+ try:
1702
+ spans = self._read_json_file(self.span_table_name, create_table_if_not_found=True)
1703
+ spans.append(span.to_dict())
1704
+ self._write_json_file(self.span_table_name, spans)
1705
+
1706
+ except Exception as e:
1707
+ log_error(f"Error creating span: {e}")
1708
+
1709
+ def create_spans(self, spans: List) -> None:
1710
+ """Create multiple spans in the database as a batch.
1711
+
1712
+ Args:
1713
+ spans: List of Span objects to store.
1714
+ """
1715
+ if not spans:
1716
+ return
1717
+
1718
+ try:
1719
+ existing_spans = self._read_json_file(self.span_table_name, create_table_if_not_found=True)
1720
+ for span in spans:
1721
+ existing_spans.append(span.to_dict())
1722
+ self._write_json_file(self.span_table_name, existing_spans)
1723
+
1724
+ except Exception as e:
1725
+ log_error(f"Error creating spans batch: {e}")
1726
+
1727
+ def get_span(self, span_id: str):
1728
+ """Get a single span by its span_id.
1729
+
1730
+ Args:
1731
+ span_id: The unique span identifier.
1732
+
1733
+ Returns:
1734
+ Optional[Span]: The span if found, None otherwise.
1735
+ """
1736
+ try:
1737
+ from agno.tracing.schemas import Span
1738
+
1739
+ spans = self._read_json_file(self.span_table_name, create_table_if_not_found=False)
1740
+
1741
+ for s in spans:
1742
+ if s.get("span_id") == span_id:
1743
+ return Span.from_dict(s)
1744
+
1745
+ return None
1746
+
1747
+ except Exception as e:
1748
+ log_error(f"Error getting span: {e}")
1749
+ return None
1750
+
1751
+ def get_spans(
1752
+ self,
1753
+ trace_id: Optional[str] = None,
1754
+ parent_span_id: Optional[str] = None,
1755
+ limit: Optional[int] = 1000,
1756
+ ) -> List:
1757
+ """Get spans matching the provided filters.
1758
+
1759
+ Args:
1760
+ trace_id: Filter by trace ID.
1761
+ parent_span_id: Filter by parent span ID.
1762
+ limit: Maximum number of spans to return.
1763
+
1764
+ Returns:
1765
+ List[Span]: List of matching spans.
1766
+ """
1767
+ try:
1768
+ from agno.tracing.schemas import Span
1769
+
1770
+ spans = self._read_json_file(self.span_table_name, create_table_if_not_found=False)
1771
+ if not spans:
1772
+ return []
1773
+
1774
+ # Apply filters
1775
+ filtered = []
1776
+ for s in spans:
1777
+ if trace_id and s.get("trace_id") != trace_id:
1778
+ continue
1779
+ if parent_span_id and s.get("parent_span_id") != parent_span_id:
1780
+ continue
1781
+ filtered.append(s)
1782
+
1783
+ # Apply limit
1784
+ if limit:
1785
+ filtered = filtered[:limit]
1786
+
1787
+ return [Span.from_dict(s) for s in filtered]
1788
+
1789
+ except Exception as e:
1790
+ log_error(f"Error getting spans: {e}")
1791
+ return []
1792
+
1793
+ # -- Learning methods (stubs) --
1794
+ def get_learning(
1795
+ self,
1796
+ learning_type: str,
1797
+ user_id: Optional[str] = None,
1798
+ agent_id: Optional[str] = None,
1799
+ team_id: Optional[str] = None,
1800
+ session_id: Optional[str] = None,
1801
+ namespace: Optional[str] = None,
1802
+ entity_id: Optional[str] = None,
1803
+ entity_type: Optional[str] = None,
1804
+ ) -> Optional[Dict[str, Any]]:
1805
+ raise NotImplementedError("Learning methods not yet implemented for GcsJsonDb")
1806
+
1807
+ def upsert_learning(
1808
+ self,
1809
+ id: str,
1810
+ learning_type: str,
1811
+ content: Dict[str, Any],
1812
+ user_id: Optional[str] = None,
1813
+ agent_id: Optional[str] = None,
1814
+ team_id: Optional[str] = None,
1815
+ session_id: Optional[str] = None,
1816
+ namespace: Optional[str] = None,
1817
+ entity_id: Optional[str] = None,
1818
+ entity_type: Optional[str] = None,
1819
+ metadata: Optional[Dict[str, Any]] = None,
1820
+ ) -> None:
1821
+ raise NotImplementedError("Learning methods not yet implemented for GcsJsonDb")
1822
+
1823
+ def delete_learning(self, id: str) -> bool:
1824
+ raise NotImplementedError("Learning methods not yet implemented for GcsJsonDb")
1825
+
1826
+ def get_learnings(
1827
+ self,
1828
+ learning_type: Optional[str] = None,
1829
+ user_id: Optional[str] = None,
1830
+ agent_id: Optional[str] = None,
1831
+ team_id: Optional[str] = None,
1832
+ session_id: Optional[str] = None,
1833
+ namespace: Optional[str] = None,
1834
+ entity_id: Optional[str] = None,
1835
+ entity_type: Optional[str] = None,
1836
+ limit: Optional[int] = None,
1837
+ ) -> List[Dict[str, Any]]:
1838
+ raise NotImplementedError("Learning methods not yet implemented for GcsJsonDb")