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/redis.py CHANGED
@@ -1,8 +1,11 @@
1
1
  import time
2
2
  from datetime import date, datetime, timedelta, timezone
3
- from typing import Any, Dict, List, Optional, Tuple, Union
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
4
4
  from uuid import uuid4
5
5
 
6
+ if TYPE_CHECKING:
7
+ from agno.tracing.schemas import Span, Trace
8
+
6
9
  from agno.db.base import BaseDb, SessionType
7
10
  from agno.db.redis.utils import (
8
11
  apply_filters,
@@ -29,7 +32,7 @@ from agno.utils.log import log_debug, log_error, log_info
29
32
  from agno.utils.string import generate_id
30
33
 
31
34
  try:
32
- from redis import Redis
35
+ from redis import Redis, RedisCluster
33
36
  except ImportError:
34
37
  raise ImportError("`redis` not installed. Please install it using `pip install redis`")
35
38
 
@@ -38,7 +41,7 @@ class RedisDb(BaseDb):
38
41
  def __init__(
39
42
  self,
40
43
  id: Optional[str] = None,
41
- redis_client: Optional[Redis] = None,
44
+ redis_client: Optional[Union[Redis, RedisCluster]] = None,
42
45
  db_url: Optional[str] = None,
43
46
  db_prefix: str = "agno",
44
47
  expire: Optional[int] = None,
@@ -48,6 +51,8 @@ class RedisDb(BaseDb):
48
51
  eval_table: Optional[str] = None,
49
52
  knowledge_table: Optional[str] = None,
50
53
  culture_table: Optional[str] = None,
54
+ traces_table: Optional[str] = None,
55
+ spans_table: Optional[str] = None,
51
56
  ):
52
57
  """
53
58
  Interface for interacting with a Redis database.
@@ -57,6 +62,8 @@ class RedisDb(BaseDb):
57
62
  2. Use the db_url
58
63
  3. Raise an error if neither is provided
59
64
 
65
+ db_url only supports single-node Redis connections, if you need Redis Cluster support, provide a redis_client.
66
+
60
67
  Args:
61
68
  id (Optional[str]): The ID of the database.
62
69
  redis_client (Optional[Redis]): Redis client instance to use. If not provided a new client will be created.
@@ -69,6 +76,8 @@ class RedisDb(BaseDb):
69
76
  eval_table (Optional[str]): Name of the table to store evaluation runs
70
77
  knowledge_table (Optional[str]): Name of the table to store knowledge documents
71
78
  culture_table (Optional[str]): Name of the table to store cultural knowledge
79
+ traces_table (Optional[str]): Name of the table to store traces
80
+ spans_table (Optional[str]): Name of the table to store spans
72
81
 
73
82
  Raises:
74
83
  ValueError: If neither redis_client nor db_url is provided.
@@ -86,6 +95,8 @@ class RedisDb(BaseDb):
86
95
  eval_table=eval_table,
87
96
  knowledge_table=knowledge_table,
88
97
  culture_table=culture_table,
98
+ traces_table=traces_table,
99
+ spans_table=spans_table,
89
100
  )
90
101
 
91
102
  self.db_prefix = db_prefix
@@ -124,6 +135,12 @@ class RedisDb(BaseDb):
124
135
  elif table_type == "culture":
125
136
  return self.culture_table_name
126
137
 
138
+ elif table_type == "traces":
139
+ return self.trace_table_name
140
+
141
+ elif table_type == "spans":
142
+ return self.span_table_name
143
+
127
144
  else:
128
145
  raise ValueError(f"Unknown table type: {table_type}")
129
146
 
@@ -252,6 +269,14 @@ class RedisDb(BaseDb):
252
269
  log_error(f"Error getting all records for {table_type}: {e}")
253
270
  return []
254
271
 
272
+ def get_latest_schema_version(self):
273
+ """Get the latest version of the database schema."""
274
+ pass
275
+
276
+ def upsert_schema_version(self, version: str) -> None:
277
+ """Upsert the schema version into the database."""
278
+ pass
279
+
255
280
  # -- Session methods --
256
281
 
257
282
  def delete_session(self, session_id: str) -> bool:
@@ -831,12 +856,14 @@ class RedisDb(BaseDb):
831
856
  self,
832
857
  limit: Optional[int] = None,
833
858
  page: Optional[int] = None,
859
+ user_id: Optional[str] = None,
834
860
  ) -> Tuple[List[Dict[str, Any]], int]:
835
861
  """Get user memory stats from Redis.
836
862
 
837
863
  Args:
838
864
  limit (Optional[int]): The maximum number of stats to return.
839
865
  page (Optional[int]): The page number to return.
866
+ user_id (Optional[str]): User ID for filtering.
840
867
 
841
868
  Returns:
842
869
  Tuple[List[Dict[str, Any]], int]: A tuple containing the list of stats and the total number of stats.
@@ -851,6 +878,9 @@ class RedisDb(BaseDb):
851
878
  user_stats = {}
852
879
  for memory in all_memories:
853
880
  memory_user_id = memory.get("user_id")
881
+ # filter by user_id if provided
882
+ if user_id is not None and memory_user_id != user_id:
883
+ continue
854
884
  if memory_user_id is None:
855
885
  continue
856
886
 
@@ -903,6 +933,9 @@ class RedisDb(BaseDb):
903
933
  "memory_id": memory.memory_id,
904
934
  "memory": memory.memory,
905
935
  "topics": memory.topics,
936
+ "input": memory.input,
937
+ "feedback": memory.feedback,
938
+ "created_at": memory.created_at,
906
939
  "updated_at": int(time.time()),
907
940
  }
908
941
 
@@ -1658,3 +1691,498 @@ class RedisDb(BaseDb):
1658
1691
  except Exception as e:
1659
1692
  log_error(f"Error upserting cultural knowledge: {e}")
1660
1693
  raise e
1694
+
1695
+ # --- Traces ---
1696
+ def upsert_trace(self, trace: "Trace") -> None:
1697
+ """Create or update a single trace record in the database.
1698
+
1699
+ Args:
1700
+ trace: The Trace object to store (one per trace_id).
1701
+ """
1702
+ try:
1703
+ # Check if trace already exists
1704
+ existing = self._get_record("traces", trace.trace_id)
1705
+
1706
+ if existing:
1707
+ # workflow (level 3) > team (level 2) > agent (level 1) > child/unknown (level 0)
1708
+ def get_component_level(
1709
+ workflow_id: Optional[str], team_id: Optional[str], agent_id: Optional[str], name: str
1710
+ ) -> int:
1711
+ # Check if name indicates a root span
1712
+ is_root_name = ".run" in name or ".arun" in name
1713
+
1714
+ if not is_root_name:
1715
+ return 0 # Child span (not a root)
1716
+ elif workflow_id:
1717
+ return 3 # Workflow root
1718
+ elif team_id:
1719
+ return 2 # Team root
1720
+ elif agent_id:
1721
+ return 1 # Agent root
1722
+ else:
1723
+ return 0 # Unknown
1724
+
1725
+ existing_level = get_component_level(
1726
+ existing.get("workflow_id"),
1727
+ existing.get("team_id"),
1728
+ existing.get("agent_id"),
1729
+ existing.get("name", ""),
1730
+ )
1731
+ new_level = get_component_level(trace.workflow_id, trace.team_id, trace.agent_id, trace.name)
1732
+
1733
+ # Only update name if new trace is from a higher or equal level
1734
+ should_update_name = new_level > existing_level
1735
+
1736
+ # Parse existing start_time to calculate correct duration
1737
+ existing_start_time_str = existing.get("start_time")
1738
+ if isinstance(existing_start_time_str, str):
1739
+ existing_start_time = datetime.fromisoformat(existing_start_time_str.replace("Z", "+00:00"))
1740
+ else:
1741
+ existing_start_time = trace.start_time
1742
+
1743
+ recalculated_duration_ms = int((trace.end_time - existing_start_time).total_seconds() * 1000)
1744
+
1745
+ # Update existing record
1746
+ existing["end_time"] = trace.end_time.isoformat()
1747
+ existing["duration_ms"] = recalculated_duration_ms
1748
+ existing["status"] = trace.status
1749
+ if should_update_name:
1750
+ existing["name"] = trace.name
1751
+
1752
+ # Update context fields ONLY if new value is not None (preserve non-null values)
1753
+ if trace.run_id is not None:
1754
+ existing["run_id"] = trace.run_id
1755
+ if trace.session_id is not None:
1756
+ existing["session_id"] = trace.session_id
1757
+ if trace.user_id is not None:
1758
+ existing["user_id"] = trace.user_id
1759
+ if trace.agent_id is not None:
1760
+ existing["agent_id"] = trace.agent_id
1761
+ if trace.team_id is not None:
1762
+ existing["team_id"] = trace.team_id
1763
+ if trace.workflow_id is not None:
1764
+ existing["workflow_id"] = trace.workflow_id
1765
+
1766
+ log_debug(
1767
+ f" Updating trace with context: run_id={existing.get('run_id', 'unchanged')}, "
1768
+ f"session_id={existing.get('session_id', 'unchanged')}, "
1769
+ f"user_id={existing.get('user_id', 'unchanged')}, "
1770
+ f"agent_id={existing.get('agent_id', 'unchanged')}, "
1771
+ f"team_id={existing.get('team_id', 'unchanged')}, "
1772
+ )
1773
+
1774
+ self._store_record(
1775
+ "traces",
1776
+ trace.trace_id,
1777
+ existing,
1778
+ index_fields=["run_id", "session_id", "user_id", "agent_id", "team_id", "workflow_id", "status"],
1779
+ )
1780
+ else:
1781
+ trace_dict = trace.to_dict()
1782
+ trace_dict.pop("total_spans", None)
1783
+ trace_dict.pop("error_count", None)
1784
+ self._store_record(
1785
+ "traces",
1786
+ trace.trace_id,
1787
+ trace_dict,
1788
+ index_fields=["run_id", "session_id", "user_id", "agent_id", "team_id", "workflow_id", "status"],
1789
+ )
1790
+
1791
+ except Exception as e:
1792
+ log_error(f"Error creating trace: {e}")
1793
+ # Don't raise - tracing should not break the main application flow
1794
+
1795
+ def get_trace(
1796
+ self,
1797
+ trace_id: Optional[str] = None,
1798
+ run_id: Optional[str] = None,
1799
+ ):
1800
+ """Get a single trace by trace_id or other filters.
1801
+
1802
+ Args:
1803
+ trace_id: The unique trace identifier.
1804
+ run_id: Filter by run ID (returns first match).
1805
+
1806
+ Returns:
1807
+ Optional[Trace]: The trace if found, None otherwise.
1808
+
1809
+ Note:
1810
+ If multiple filters are provided, trace_id takes precedence.
1811
+ For other filters, the most recent trace is returned.
1812
+ """
1813
+ try:
1814
+ from agno.tracing.schemas import Trace as TraceSchema
1815
+
1816
+ if trace_id:
1817
+ result = self._get_record("traces", trace_id)
1818
+ if result:
1819
+ # Calculate total_spans and error_count
1820
+ all_spans = self._get_all_records("spans")
1821
+ trace_spans = [s for s in all_spans if s.get("trace_id") == trace_id]
1822
+ result["total_spans"] = len(trace_spans)
1823
+ result["error_count"] = len([s for s in trace_spans if s.get("status_code") == "ERROR"])
1824
+ return TraceSchema.from_dict(result)
1825
+ return None
1826
+
1827
+ elif run_id:
1828
+ all_traces = self._get_all_records("traces")
1829
+ matching = [t for t in all_traces if t.get("run_id") == run_id]
1830
+ if matching:
1831
+ # Sort by start_time descending and get most recent
1832
+ matching.sort(key=lambda x: x.get("start_time", ""), reverse=True)
1833
+ result = matching[0]
1834
+ # Calculate total_spans and error_count
1835
+ all_spans = self._get_all_records("spans")
1836
+ trace_spans = [s for s in all_spans if s.get("trace_id") == result.get("trace_id")]
1837
+ result["total_spans"] = len(trace_spans)
1838
+ result["error_count"] = len([s for s in trace_spans if s.get("status_code") == "ERROR"])
1839
+ return TraceSchema.from_dict(result)
1840
+ return None
1841
+
1842
+ else:
1843
+ log_debug("get_trace called without any filter parameters")
1844
+ return None
1845
+
1846
+ except Exception as e:
1847
+ log_error(f"Error getting trace: {e}")
1848
+ return None
1849
+
1850
+ def get_traces(
1851
+ self,
1852
+ run_id: Optional[str] = None,
1853
+ session_id: Optional[str] = None,
1854
+ user_id: Optional[str] = None,
1855
+ agent_id: Optional[str] = None,
1856
+ team_id: Optional[str] = None,
1857
+ workflow_id: Optional[str] = None,
1858
+ status: Optional[str] = None,
1859
+ start_time: Optional[datetime] = None,
1860
+ end_time: Optional[datetime] = None,
1861
+ limit: Optional[int] = 20,
1862
+ page: Optional[int] = 1,
1863
+ ) -> tuple[List, int]:
1864
+ """Get traces matching the provided filters.
1865
+
1866
+ Args:
1867
+ run_id: Filter by run ID.
1868
+ session_id: Filter by session ID.
1869
+ user_id: Filter by user ID.
1870
+ agent_id: Filter by agent ID.
1871
+ team_id: Filter by team ID.
1872
+ workflow_id: Filter by workflow ID.
1873
+ status: Filter by status (OK, ERROR, UNSET).
1874
+ start_time: Filter traces starting after this datetime.
1875
+ end_time: Filter traces ending before this datetime.
1876
+ limit: Maximum number of traces to return per page.
1877
+ page: Page number (1-indexed).
1878
+
1879
+ Returns:
1880
+ tuple[List[Trace], int]: Tuple of (list of matching traces, total count).
1881
+ """
1882
+ try:
1883
+ from agno.tracing.schemas import Trace as TraceSchema
1884
+
1885
+ log_debug(
1886
+ f"get_traces called with filters: run_id={run_id}, session_id={session_id}, "
1887
+ f"user_id={user_id}, agent_id={agent_id}, page={page}, limit={limit}"
1888
+ )
1889
+
1890
+ all_traces = self._get_all_records("traces")
1891
+ all_spans = self._get_all_records("spans")
1892
+
1893
+ # Apply filters
1894
+ filtered_traces = []
1895
+ for trace in all_traces:
1896
+ if run_id and trace.get("run_id") != run_id:
1897
+ continue
1898
+ if session_id and trace.get("session_id") != session_id:
1899
+ continue
1900
+ if user_id and trace.get("user_id") != user_id:
1901
+ continue
1902
+ if agent_id and trace.get("agent_id") != agent_id:
1903
+ continue
1904
+ if team_id and trace.get("team_id") != team_id:
1905
+ continue
1906
+ if workflow_id and trace.get("workflow_id") != workflow_id:
1907
+ continue
1908
+ if status and trace.get("status") != status:
1909
+ continue
1910
+ if start_time:
1911
+ trace_start = trace.get("start_time", "")
1912
+ if trace_start and trace_start < start_time.isoformat():
1913
+ continue
1914
+ if end_time:
1915
+ trace_end = trace.get("end_time", "")
1916
+ if trace_end and trace_end > end_time.isoformat():
1917
+ continue
1918
+
1919
+ filtered_traces.append(trace)
1920
+
1921
+ total_count = len(filtered_traces)
1922
+
1923
+ # Sort by start_time descending
1924
+ filtered_traces.sort(key=lambda x: x.get("start_time", ""), reverse=True)
1925
+
1926
+ # Apply pagination
1927
+ paginated_traces = apply_pagination(records=filtered_traces, limit=limit, page=page)
1928
+
1929
+ traces = []
1930
+ for row in paginated_traces:
1931
+ # Calculate total_spans and error_count
1932
+ trace_spans = [s for s in all_spans if s.get("trace_id") == row.get("trace_id")]
1933
+ row["total_spans"] = len(trace_spans)
1934
+ row["error_count"] = len([s for s in trace_spans if s.get("status_code") == "ERROR"])
1935
+ traces.append(TraceSchema.from_dict(row))
1936
+
1937
+ return traces, total_count
1938
+
1939
+ except Exception as e:
1940
+ log_error(f"Error getting traces: {e}")
1941
+ return [], 0
1942
+
1943
+ def get_trace_stats(
1944
+ self,
1945
+ user_id: Optional[str] = None,
1946
+ agent_id: Optional[str] = None,
1947
+ team_id: Optional[str] = None,
1948
+ workflow_id: Optional[str] = None,
1949
+ start_time: Optional[datetime] = None,
1950
+ end_time: Optional[datetime] = None,
1951
+ limit: Optional[int] = 20,
1952
+ page: Optional[int] = 1,
1953
+ ) -> tuple[List[Dict[str, Any]], int]:
1954
+ """Get trace statistics grouped by session.
1955
+
1956
+ Args:
1957
+ user_id: Filter by user ID.
1958
+ agent_id: Filter by agent ID.
1959
+ team_id: Filter by team ID.
1960
+ workflow_id: Filter by workflow ID.
1961
+ start_time: Filter sessions with traces created after this datetime.
1962
+ end_time: Filter sessions with traces created before this datetime.
1963
+ limit: Maximum number of sessions to return per page.
1964
+ page: Page number (1-indexed).
1965
+
1966
+ Returns:
1967
+ tuple[List[Dict], int]: Tuple of (list of session stats dicts, total count).
1968
+ Each dict contains: session_id, user_id, agent_id, team_id, total_traces,
1969
+ first_trace_at, last_trace_at.
1970
+ """
1971
+ try:
1972
+ log_debug(
1973
+ f"get_trace_stats called with filters: user_id={user_id}, agent_id={agent_id}, "
1974
+ f"workflow_id={workflow_id}, team_id={team_id}, "
1975
+ f"start_time={start_time}, end_time={end_time}, page={page}, limit={limit}"
1976
+ )
1977
+
1978
+ all_traces = self._get_all_records("traces")
1979
+
1980
+ # Filter traces and group by session_id
1981
+ session_stats: Dict[str, Dict[str, Any]] = {}
1982
+ for trace in all_traces:
1983
+ trace_session_id = trace.get("session_id")
1984
+ if not trace_session_id:
1985
+ continue
1986
+
1987
+ # Apply filters
1988
+ if user_id and trace.get("user_id") != user_id:
1989
+ continue
1990
+ if agent_id and trace.get("agent_id") != agent_id:
1991
+ continue
1992
+ if team_id and trace.get("team_id") != team_id:
1993
+ continue
1994
+ if workflow_id and trace.get("workflow_id") != workflow_id:
1995
+ continue
1996
+
1997
+ created_at = trace.get("created_at", "")
1998
+ if start_time and created_at < start_time.isoformat():
1999
+ continue
2000
+ if end_time and created_at > end_time.isoformat():
2001
+ continue
2002
+
2003
+ if trace_session_id not in session_stats:
2004
+ session_stats[trace_session_id] = {
2005
+ "session_id": trace_session_id,
2006
+ "user_id": trace.get("user_id"),
2007
+ "agent_id": trace.get("agent_id"),
2008
+ "team_id": trace.get("team_id"),
2009
+ "workflow_id": trace.get("workflow_id"),
2010
+ "total_traces": 0,
2011
+ "first_trace_at": created_at,
2012
+ "last_trace_at": created_at,
2013
+ }
2014
+
2015
+ session_stats[trace_session_id]["total_traces"] += 1
2016
+ if created_at < session_stats[trace_session_id]["first_trace_at"]:
2017
+ session_stats[trace_session_id]["first_trace_at"] = created_at
2018
+ if created_at > session_stats[trace_session_id]["last_trace_at"]:
2019
+ session_stats[trace_session_id]["last_trace_at"] = created_at
2020
+
2021
+ # Convert to list and sort by last_trace_at descending
2022
+ stats_list = list(session_stats.values())
2023
+ stats_list.sort(key=lambda x: x.get("last_trace_at", ""), reverse=True)
2024
+
2025
+ total_count = len(stats_list)
2026
+
2027
+ # Apply pagination
2028
+ paginated_stats = apply_pagination(records=stats_list, limit=limit, page=page)
2029
+
2030
+ # Convert ISO strings to datetime objects
2031
+ for stat in paginated_stats:
2032
+ first_trace_at_str = stat["first_trace_at"]
2033
+ last_trace_at_str = stat["last_trace_at"]
2034
+ stat["first_trace_at"] = datetime.fromisoformat(first_trace_at_str.replace("Z", "+00:00"))
2035
+ stat["last_trace_at"] = datetime.fromisoformat(last_trace_at_str.replace("Z", "+00:00"))
2036
+
2037
+ return paginated_stats, total_count
2038
+
2039
+ except Exception as e:
2040
+ log_error(f"Error getting trace stats: {e}")
2041
+ return [], 0
2042
+
2043
+ # --- Spans ---
2044
+ def create_span(self, span: "Span") -> None:
2045
+ """Create a single span in the database.
2046
+
2047
+ Args:
2048
+ span: The Span object to store.
2049
+ """
2050
+ try:
2051
+ self._store_record(
2052
+ "spans",
2053
+ span.span_id,
2054
+ span.to_dict(),
2055
+ index_fields=["trace_id", "parent_span_id"],
2056
+ )
2057
+
2058
+ except Exception as e:
2059
+ log_error(f"Error creating span: {e}")
2060
+
2061
+ def create_spans(self, spans: List) -> None:
2062
+ """Create multiple spans in the database as a batch.
2063
+
2064
+ Args:
2065
+ spans: List of Span objects to store.
2066
+ """
2067
+ if not spans:
2068
+ return
2069
+
2070
+ try:
2071
+ for span in spans:
2072
+ self._store_record(
2073
+ "spans",
2074
+ span.span_id,
2075
+ span.to_dict(),
2076
+ index_fields=["trace_id", "parent_span_id"],
2077
+ )
2078
+
2079
+ except Exception as e:
2080
+ log_error(f"Error creating spans batch: {e}")
2081
+
2082
+ def get_span(self, span_id: str):
2083
+ """Get a single span by its span_id.
2084
+
2085
+ Args:
2086
+ span_id: The unique span identifier.
2087
+
2088
+ Returns:
2089
+ Optional[Span]: The span if found, None otherwise.
2090
+ """
2091
+ try:
2092
+ from agno.tracing.schemas import Span as SpanSchema
2093
+
2094
+ result = self._get_record("spans", span_id)
2095
+ if result:
2096
+ return SpanSchema.from_dict(result)
2097
+ return None
2098
+
2099
+ except Exception as e:
2100
+ log_error(f"Error getting span: {e}")
2101
+ return None
2102
+
2103
+ def get_spans(
2104
+ self,
2105
+ trace_id: Optional[str] = None,
2106
+ parent_span_id: Optional[str] = None,
2107
+ limit: Optional[int] = 1000,
2108
+ ) -> List:
2109
+ """Get spans matching the provided filters.
2110
+
2111
+ Args:
2112
+ trace_id: Filter by trace ID.
2113
+ parent_span_id: Filter by parent span ID.
2114
+ limit: Maximum number of spans to return.
2115
+
2116
+ Returns:
2117
+ List[Span]: List of matching spans.
2118
+ """
2119
+ try:
2120
+ from agno.tracing.schemas import Span as SpanSchema
2121
+
2122
+ all_spans = self._get_all_records("spans")
2123
+
2124
+ # Apply filters
2125
+ filtered_spans = []
2126
+ for span in all_spans:
2127
+ if trace_id and span.get("trace_id") != trace_id:
2128
+ continue
2129
+ if parent_span_id and span.get("parent_span_id") != parent_span_id:
2130
+ continue
2131
+ filtered_spans.append(span)
2132
+
2133
+ # Apply limit
2134
+ if limit:
2135
+ filtered_spans = filtered_spans[:limit]
2136
+
2137
+ return [SpanSchema.from_dict(s) for s in filtered_spans]
2138
+
2139
+ except Exception as e:
2140
+ log_error(f"Error getting spans: {e}")
2141
+ return []
2142
+
2143
+ # -- Learning methods (stubs) --
2144
+ def get_learning(
2145
+ self,
2146
+ learning_type: str,
2147
+ user_id: Optional[str] = None,
2148
+ agent_id: Optional[str] = None,
2149
+ team_id: Optional[str] = None,
2150
+ session_id: Optional[str] = None,
2151
+ namespace: Optional[str] = None,
2152
+ entity_id: Optional[str] = None,
2153
+ entity_type: Optional[str] = None,
2154
+ ) -> Optional[Dict[str, Any]]:
2155
+ raise NotImplementedError("Learning methods not yet implemented for RedisDb")
2156
+
2157
+ def upsert_learning(
2158
+ self,
2159
+ id: str,
2160
+ learning_type: str,
2161
+ content: Dict[str, Any],
2162
+ user_id: Optional[str] = None,
2163
+ agent_id: Optional[str] = None,
2164
+ team_id: Optional[str] = None,
2165
+ session_id: Optional[str] = None,
2166
+ namespace: Optional[str] = None,
2167
+ entity_id: Optional[str] = None,
2168
+ entity_type: Optional[str] = None,
2169
+ metadata: Optional[Dict[str, Any]] = None,
2170
+ ) -> None:
2171
+ raise NotImplementedError("Learning methods not yet implemented for RedisDb")
2172
+
2173
+ def delete_learning(self, id: str) -> bool:
2174
+ raise NotImplementedError("Learning methods not yet implemented for RedisDb")
2175
+
2176
+ def get_learnings(
2177
+ self,
2178
+ learning_type: Optional[str] = None,
2179
+ user_id: Optional[str] = None,
2180
+ agent_id: Optional[str] = None,
2181
+ team_id: Optional[str] = None,
2182
+ session_id: Optional[str] = None,
2183
+ namespace: Optional[str] = None,
2184
+ entity_id: Optional[str] = None,
2185
+ entity_type: Optional[str] = None,
2186
+ limit: Optional[int] = None,
2187
+ ) -> List[Dict[str, Any]]:
2188
+ raise NotImplementedError("Learning methods not yet implemented for RedisDb")
agno/db/redis/schemas.py CHANGED
@@ -27,6 +27,9 @@ USER_MEMORY_SCHEMA = {
27
27
  "team_id": {"type": "string"},
28
28
  "user_id": {"type": "string"},
29
29
  "topics": {"type": "json"},
30
+ "input": {"type": "string"},
31
+ "feedback": {"type": "string"},
32
+ "created_at": {"type": "integer"},
30
33
  "updated_at": {"type": "integer"},
31
34
  }
32
35
 
@@ -94,6 +97,36 @@ CULTURAL_KNOWLEDGE_SCHEMA = {
94
97
  "team_id": {"type": "string"},
95
98
  }
96
99
 
100
+ TRACE_SCHEMA = {
101
+ "trace_id": {"type": "string", "primary_key": True},
102
+ "name": {"type": "string"},
103
+ "status": {"type": "string"},
104
+ "duration_ms": {"type": "integer"},
105
+ "run_id": {"type": "string"},
106
+ "session_id": {"type": "string"},
107
+ "user_id": {"type": "string"},
108
+ "agent_id": {"type": "string"},
109
+ "team_id": {"type": "string"},
110
+ "workflow_id": {"type": "string"},
111
+ "start_time": {"type": "string"},
112
+ "end_time": {"type": "string"},
113
+ "created_at": {"type": "string"},
114
+ }
115
+
116
+ SPAN_SCHEMA = {
117
+ "span_id": {"type": "string", "primary_key": True},
118
+ "trace_id": {"type": "string"},
119
+ "parent_span_id": {"type": "string"},
120
+ "name": {"type": "string"},
121
+ "span_kind": {"type": "string"},
122
+ "status_code": {"type": "string"},
123
+ "status_message": {"type": "string"},
124
+ "start_time": {"type": "string"},
125
+ "end_time": {"type": "string"},
126
+ "attributes": {"type": "json"},
127
+ "created_at": {"type": "string"},
128
+ }
129
+
97
130
 
98
131
  def get_table_schema_definition(table_type: str) -> dict[str, Any]:
99
132
  """
@@ -114,6 +147,9 @@ def get_table_schema_definition(table_type: str) -> dict[str, Any]:
114
147
  "metrics": METRICS_SCHEMA,
115
148
  "evals": EVAL_SCHEMA,
116
149
  "knowledge": KNOWLEDGE_SCHEMA,
150
+ "culture": CULTURAL_KNOWLEDGE_SCHEMA,
151
+ "traces": TRACE_SCHEMA,
152
+ "spans": SPAN_SCHEMA,
117
153
  }
118
154
 
119
155
  schema = schemas.get(table_type, {})