agno 0.1.2__py3-none-any.whl → 2.3.13__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 (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -1,19 +1,23 @@
1
- from typing import Any, Dict, Iterable, List, Optional
1
+ import asyncio
2
+ from typing import Any, Dict, Iterable, List, Optional, Union
2
3
 
3
- from agno.document import Document
4
- from agno.embedder import Embedder
5
- from agno.utils.log import logger
4
+ from agno.filters import FilterExpr
5
+ from agno.knowledge.document import Document
6
+ from agno.knowledge.embedder import Embedder
7
+ from agno.utils.log import log_debug, log_error, log_info, log_warning
6
8
  from agno.vectordb.base import VectorDb
7
9
  from agno.vectordb.cassandra.index import AgnoMetadataVectorCassandraTable
8
10
 
9
11
 
10
- class CassandraDb(VectorDb):
12
+ class Cassandra(VectorDb):
11
13
  def __init__(
12
14
  self,
13
15
  table_name: str,
14
16
  keyspace: str,
15
17
  embedder: Optional[Embedder] = None,
16
18
  session=None,
19
+ name: Optional[str] = None,
20
+ description: Optional[str] = None,
17
21
  ) -> None:
18
22
  if not table_name:
19
23
  raise ValueError("Table name must be provided.")
@@ -25,9 +29,13 @@ class CassandraDb(VectorDb):
25
29
  raise ValueError("Keyspace must be provided")
26
30
 
27
31
  if embedder is None:
28
- from agno.embedder.openai import OpenAIEmbedder
32
+ from agno.knowledge.embedder.openai import OpenAIEmbedder
29
33
 
30
34
  embedder = OpenAIEmbedder()
35
+ log_info("Embedder not provided, using OpenAIEmbedder as default.")
36
+ # Initialize base class with name and description
37
+ super().__init__(name=name, description=description)
38
+
31
39
  self.table_name: str = table_name
32
40
  self.embedder: Embedder = embedder
33
41
  self.session = session
@@ -46,42 +54,130 @@ class CassandraDb(VectorDb):
46
54
  def create(self) -> None:
47
55
  """Create the table in Cassandra for storing vectors and metadata."""
48
56
  if not self.exists():
49
- logger.debug(f"Cassandra VectorDB : Creating table {self.table_name}")
57
+ log_debug(f"Cassandra VectorDB : Creating table {self.table_name}")
50
58
  self.initialize_table()
51
59
 
60
+ async def async_create(self) -> None:
61
+ """Create the table asynchronously by running in a thread."""
62
+ await asyncio.to_thread(self.create)
63
+
52
64
  def _row_to_document(self, row: Dict[str, Any]) -> Document:
65
+ metadata = row["metadata"]
53
66
  return Document(
54
67
  id=row["row_id"],
55
68
  content=row["body_blob"],
56
- meta_data=row["metadata"],
69
+ meta_data=metadata,
57
70
  embedding=row["vector"],
58
71
  name=row["document_name"],
72
+ content_id=metadata.get("content_id"),
59
73
  )
60
74
 
61
- def doc_exists(self, document: Document) -> bool:
62
- """Check if a document exists by ID."""
63
- query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
64
- result = self.session.execute(query, (document.id,))
65
- return result[0].count > 0
66
-
67
75
  def name_exists(self, name: str) -> bool:
68
76
  """Check if a document exists by name."""
69
- query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE document_name = %s"
77
+ query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE document_name = %s ALLOW FILTERING"
70
78
  result = self.session.execute(query, (name,))
71
- return result[0].count > 0
79
+ return result.one()[0] > 0
80
+
81
+ async def async_name_exists(self, name: str) -> bool:
82
+ """Check if a document with given name exists asynchronously."""
83
+ return await asyncio.to_thread(self.name_exists, name)
72
84
 
73
85
  def id_exists(self, id: str) -> bool:
74
86
  """Check if a document exists by ID."""
75
- query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
87
+ query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE row_id = %s ALLOW FILTERING"
76
88
  result = self.session.execute(query, (id,))
77
- return result[0].count > 0
89
+ return result.one()[0] > 0
90
+
91
+ def content_hash_exists(self, content_hash: str) -> bool:
92
+ """Check if a document exists by content hash."""
93
+ query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE metadata_s['content_hash'] = %s ALLOW FILTERING"
94
+ result = self.session.execute(query, (content_hash,))
95
+ return result.one()[0] > 0
78
96
 
79
- def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
80
- logger.debug(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
97
+ def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
98
+ log_info(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
81
99
  futures = []
82
100
  for doc in documents:
83
101
  doc.embed(embedder=self.embedder)
84
102
  metadata = {key: str(value) for key, value in doc.meta_data.items()}
103
+ metadata.update(filters or {})
104
+ metadata["content_id"] = doc.content_id or ""
105
+ metadata["content_hash"] = content_hash
106
+ futures.append(
107
+ self.table.put_async(
108
+ row_id=doc.id,
109
+ vector=doc.embedding,
110
+ metadata=metadata or {},
111
+ body_blob=doc.content,
112
+ document_name=doc.name,
113
+ )
114
+ )
115
+
116
+ for f in futures:
117
+ f.result()
118
+
119
+ async def async_insert(
120
+ self,
121
+ content_hash: str,
122
+ documents: List[Document],
123
+ filters: Optional[Dict[str, Any]] = None,
124
+ ) -> None:
125
+ """Insert documents asynchronously by running in a thread."""
126
+ log_info(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
127
+
128
+ if self.embedder.enable_batch and hasattr(self.embedder, "async_get_embeddings_batch_and_usage"):
129
+ # Use batch embedding when enabled and supported
130
+ try:
131
+ # Extract content from all documents
132
+ doc_contents = [doc.content for doc in documents]
133
+
134
+ # Get batch embeddings and usage
135
+ embeddings, usages = await self.embedder.async_get_embeddings_batch_and_usage(doc_contents)
136
+
137
+ # Process documents with pre-computed embeddings
138
+ for j, doc in enumerate(documents):
139
+ try:
140
+ if j < len(embeddings):
141
+ doc.embedding = embeddings[j]
142
+ doc.usage = usages[j] if j < len(usages) else None
143
+ except Exception as e:
144
+ log_error(f"Error assigning batch embedding to document '{doc.name}': {e}")
145
+
146
+ except Exception as e:
147
+ # Check if this is a rate limit error - don't fall back as it would make things worse
148
+ error_str = str(e).lower()
149
+ is_rate_limit = any(
150
+ phrase in error_str
151
+ for phrase in ["rate limit", "too many requests", "429", "trial key", "api calls / minute"]
152
+ )
153
+
154
+ if is_rate_limit:
155
+ log_error(f"Rate limit detected during batch embedding. {e}")
156
+ raise e
157
+ else:
158
+ log_error(f"Async batch embedding failed, falling back to individual embeddings: {e}")
159
+ # Fall back to individual embedding
160
+ for doc in documents:
161
+ try:
162
+ embed_tasks = [doc.async_embed(embedder=self.embedder)]
163
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
164
+ except Exception as e:
165
+ log_error(f"Error processing document '{doc.name}': {e}")
166
+ else:
167
+ # Use individual embedding (original behavior)
168
+ for doc in documents:
169
+ try:
170
+ embed_tasks = [doc.async_embed(embedder=self.embedder)]
171
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
172
+ except Exception as e:
173
+ log_error(f"Error processing document '{doc.name}': {e}")
174
+
175
+ futures = []
176
+ for doc in documents:
177
+ metadata = {key: str(value) for key, value in doc.meta_data.items()}
178
+ metadata.update(filters or {})
179
+ metadata["content_id"] = doc.content_id or ""
180
+ metadata["content_hash"] = content_hash
85
181
  futures.append(
86
182
  self.table.put_async(
87
183
  row_id=doc.id,
@@ -95,22 +191,44 @@ class CassandraDb(VectorDb):
95
191
  for f in futures:
96
192
  f.result()
97
193
 
98
- def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
194
+ def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
99
195
  """Insert or update documents based on primary key."""
100
- self.insert(documents, filters)
196
+ if self.content_hash_exists(content_hash):
197
+ self.delete_by_content_hash(content_hash)
198
+ self.insert(content_hash, documents, filters)
199
+
200
+ async def async_upsert(
201
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
202
+ ) -> None:
203
+ """Upsert documents asynchronously by running in a thread."""
204
+ if self.content_hash_exists(content_hash):
205
+ self.delete_by_content_hash(content_hash)
206
+ await self.async_insert(content_hash, documents, filters)
101
207
 
102
- def search(self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None) -> List[Document]:
208
+ def search(
209
+ self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
210
+ ) -> List[Document]:
103
211
  """Keyword-based search on document metadata."""
104
- logger.debug(f"Cassandra VectorDB : Performing Vector Search on {self.table_name} with query {query}")
212
+ log_debug(f"Cassandra VectorDB : Performing Vector Search on {self.table_name} with query {query}")
213
+ if filters is not None:
214
+ log_warning("Filters are not yet supported in Cassandra. No filters will be applied.")
105
215
  return self.vector_search(query=query, limit=limit)
106
216
 
217
+ async def async_search(
218
+ self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
219
+ ) -> List[Document]:
220
+ """Search asynchronously by running in a thread."""
221
+ return await asyncio.to_thread(self.search, query, limit, filters)
222
+
107
223
  def _search_to_documents(
108
224
  self,
109
225
  hits: Iterable[Dict[str, Any]],
110
226
  ) -> List[Document]:
111
227
  return [self._row_to_document(row=hit) for hit in hits]
112
228
 
113
- def vector_search(self, query: str, limit: int = 5) -> List[Document]:
229
+ def vector_search(
230
+ self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
231
+ ) -> List[Document]:
114
232
  """Vector similarity search implementation."""
115
233
  query_embedding = self.embedder.get_embedding(query)
116
234
  hits = list(
@@ -125,10 +243,14 @@ class CassandraDb(VectorDb):
125
243
 
126
244
  def drop(self) -> None:
127
245
  """Drop the vector table in Cassandra."""
128
- logger.debug(f"Cassandra VectorDB : Dropping Table {self.table_name}")
246
+ log_debug(f"Cassandra VectorDB : Dropping Table {self.table_name}")
129
247
  drop_table_query = f"DROP TABLE IF EXISTS {self.keyspace}.{self.table_name}"
130
248
  self.session.execute(drop_table_query)
131
249
 
250
+ async def async_drop(self) -> None:
251
+ """Drop the table asynchronously by running in a thread."""
252
+ await asyncio.to_thread(self.drop)
253
+
132
254
  def exists(self) -> bool:
133
255
  """Check if the table exists in Cassandra."""
134
256
  check_table_query = """
@@ -138,8 +260,242 @@ class CassandraDb(VectorDb):
138
260
  result = self.session.execute(check_table_query, (self.keyspace, self.table_name))
139
261
  return bool(result.one())
140
262
 
263
+ async def async_exists(self) -> bool:
264
+ """Check if table exists asynchronously by running in a thread."""
265
+ return await asyncio.to_thread(self.exists)
266
+
141
267
  def delete(self) -> bool:
142
268
  """Delete all documents in the table."""
143
- logger.debug(f"Cassandra VectorDB : Clearing the table {self.table_name}")
269
+ log_debug(f"Cassandra VectorDB : Clearing the table {self.table_name}")
144
270
  self.table.clear()
145
271
  return True
272
+
273
+ def delete_by_id(self, id: str) -> bool:
274
+ """
275
+ Delete a document by its ID.
276
+
277
+ Args:
278
+ id (str): The document ID to delete
279
+
280
+ Returns:
281
+ bool: True if document was deleted, False otherwise
282
+ """
283
+ try:
284
+ log_debug(f"Cassandra VectorDB : Deleting document with ID {id}")
285
+ # Check if document exists before deletion
286
+ if not self.id_exists(id):
287
+ return False
288
+
289
+ query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
290
+ self.session.execute(query, (id,))
291
+ return True
292
+ except Exception as e:
293
+ log_info(f"Error deleting document with ID {id}: {e}")
294
+ return False
295
+
296
+ def delete_by_name(self, name: str) -> bool:
297
+ """
298
+ Delete documents by name.
299
+
300
+ Args:
301
+ name (str): The document name to delete
302
+
303
+ Returns:
304
+ bool: True if documents were deleted, False otherwise
305
+ """
306
+ try:
307
+ log_debug(f"Cassandra VectorDB : Deleting documents with name {name}")
308
+ # Check if document exists before deletion
309
+ if not self.name_exists(name):
310
+ return False
311
+
312
+ # Query to find documents with matching name
313
+ query = f"SELECT row_id, document_name FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
314
+ result = self.session.execute(query)
315
+
316
+ deleted_count = 0
317
+ for row in result:
318
+ # Check if the row's document_name matches our criteria
319
+ # Use attribute access for Row objects
320
+ row_name = getattr(row, "document_name", None)
321
+ if row_name == name:
322
+ # Delete this specific document
323
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
324
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
325
+ deleted_count += 1
326
+
327
+ return deleted_count > 0
328
+ except Exception as e:
329
+ log_info(f"Error deleting documents with name {name}: {e}")
330
+ return False
331
+
332
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
333
+ """
334
+ Delete documents by metadata.
335
+
336
+ Args:
337
+ metadata (Dict[str, Any]): The metadata to match for deletion
338
+
339
+ Returns:
340
+ bool: True if documents were deleted, False otherwise
341
+ """
342
+ try:
343
+ log_debug(f"Cassandra VectorDB : Deleting documents with metadata {metadata}")
344
+ # For metadata deletion, we need to query first to find matching documents
345
+ # Then delete them by their IDs
346
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
347
+ result = self.session.execute(query)
348
+
349
+ deleted_count = 0
350
+ for row in result:
351
+ # Check if the row's metadata matches our criteria
352
+ # Use attribute access for Row objects
353
+ row_metadata = getattr(row, "metadata_s", {})
354
+ if self._metadata_matches(row_metadata, metadata):
355
+ # Delete this specific document
356
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
357
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
358
+ deleted_count += 1
359
+
360
+ return deleted_count > 0
361
+ except Exception as e:
362
+ log_debug(f"Error deleting documents with metadata {metadata}: {e}")
363
+ return False
364
+
365
+ def delete_by_content_id(self, content_id: str) -> bool:
366
+ """
367
+ Delete documents by content ID.
368
+
369
+ Args:
370
+ content_id (str): The content ID to delete
371
+
372
+ Returns:
373
+ bool: True if documents were deleted, False otherwise
374
+ """
375
+ try:
376
+ log_debug(f"Cassandra VectorDB : Deleting documents with content_id {content_id}")
377
+ # Query to find documents with matching content_id in metadata
378
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
379
+ result = self.session.execute(query)
380
+ deleted_count = 0
381
+ for row in result:
382
+ # Check if the row's metadata contains the content_id
383
+ # Use attribute access for Row objects
384
+ row_metadata = getattr(row, "metadata_s", {})
385
+ if row_metadata.get("content_id") == content_id:
386
+ # Delete this specific document
387
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
388
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
389
+ deleted_count += 1
390
+
391
+ return deleted_count > 0
392
+ except Exception as e:
393
+ log_info(f"Error deleting documents with content_id {content_id}: {e}")
394
+ return False
395
+
396
+ def delete_by_content_hash(self, content_hash: str) -> bool:
397
+ """
398
+ Delete documents by content hash.
399
+
400
+ Args:
401
+ content_hash (str): The content hash to delete
402
+
403
+ Returns:
404
+ bool: True if documents were deleted, False otherwise
405
+ """
406
+ try:
407
+ log_debug(f"Cassandra VectorDB : Deleting documents with content_hash {content_hash}")
408
+ # Query to find documents with matching content_hash in metadata
409
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
410
+ result = self.session.execute(query)
411
+ deleted_count = 0
412
+ for row in result:
413
+ # Check if the row's metadata contains the content_hash
414
+ # Use attribute access for Row objects
415
+ row_metadata = getattr(row, "metadata_s", {})
416
+ if row_metadata.get("content_hash") == content_hash:
417
+ # Delete this specific document
418
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
419
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
420
+ deleted_count += 1
421
+
422
+ return deleted_count > 0
423
+ except Exception as e:
424
+ log_info(f"Error deleting documents with content_hash {content_hash}: {e}")
425
+ return False
426
+
427
+ def _metadata_matches(self, row_metadata: Dict[str, Any], target_metadata: Dict[str, Any]) -> bool:
428
+ """
429
+ Check if row metadata matches target metadata criteria.
430
+
431
+ Args:
432
+ row_metadata (Dict[str, Any]): The metadata from the database row
433
+ target_metadata (Dict[str, Any]): The target metadata to match against
434
+
435
+ Returns:
436
+ bool: True if metadata matches, False otherwise
437
+ """
438
+ try:
439
+ for key, value in target_metadata.items():
440
+ if key not in row_metadata:
441
+ return False
442
+
443
+ # Handle boolean values specially
444
+ if isinstance(value, bool):
445
+ if row_metadata[key] != value:
446
+ return False
447
+ else:
448
+ # For non-boolean values, convert to string for comparison
449
+ if row_metadata[key] != str(value):
450
+ return False
451
+ return True
452
+ except Exception:
453
+ return False
454
+
455
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
456
+ """
457
+ Update the metadata for a document.
458
+
459
+ Args:
460
+ content_id (str): The content ID to update
461
+ metadata (Dict[str, Any]): The metadata to update
462
+ """
463
+ try:
464
+ log_debug(f"Cassandra VectorDB : Updating metadata for content_id {content_id}")
465
+
466
+ # First, find all documents with the given content_id
467
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
468
+ result = self.session.execute(query)
469
+
470
+ updated_count = 0
471
+ for row in result:
472
+ row_metadata = getattr(row, "metadata_s", {})
473
+ if row_metadata.get("content_id") == content_id:
474
+ # Merge existing metadata with new metadata
475
+ updated_metadata = row_metadata.copy()
476
+ # Convert new metadata values to strings (Cassandra requirement)
477
+ string_metadata = {key: str(value) for key, value in metadata.items()}
478
+ updated_metadata.update(string_metadata)
479
+
480
+ # Update the document with merged metadata
481
+ row_id = getattr(row, "row_id")
482
+ update_query = f"""
483
+ UPDATE {self.keyspace}.{self.table_name}
484
+ SET metadata_s = %s
485
+ WHERE row_id = %s
486
+ """
487
+ self.session.execute(update_query, (updated_metadata, row_id))
488
+ updated_count += 1
489
+
490
+ if updated_count == 0:
491
+ log_debug(f"No documents found with content_id {content_id}")
492
+ else:
493
+ log_debug(f"Updated metadata for {updated_count} documents with content_id {content_id}")
494
+
495
+ except Exception as e:
496
+ log_error(f"Error updating metadata for content_id {content_id}: {e}")
497
+ raise
498
+
499
+ def get_supported_search_types(self) -> List[str]:
500
+ """Get the supported search types for this vector database."""
501
+ return [] # Cassandra doesn't use SearchType enum
@@ -1 +1,5 @@
1
1
  from agno.vectordb.chroma.chromadb import ChromaDb
2
+
3
+ __all__ = [
4
+ "ChromaDb",
5
+ ]