agno 1.8.1__py3-none-any.whl → 2.0.0__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 (590) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +3143 -4170
  4. agno/api/agent.py +11 -67
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +8 -19
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +11 -66
  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/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1743 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1432 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +882 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1045 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1416 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +297 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1710 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +280 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1367 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1712 -0
  67. agno/db/singlestore/utils.py +326 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1676 -0
  71. agno/db/sqlite/utils.py +268 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +154 -48
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +15 -11
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1551 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/{document → knowledge}/reader/json_reader.py +30 -9
  118. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  119. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  120. agno/knowledge/reader/reader_factory.py +268 -0
  121. agno/knowledge/reader/s3_reader.py +101 -0
  122. agno/{document → knowledge}/reader/text_reader.py +31 -10
  123. agno/knowledge/reader/url_reader.py +128 -0
  124. agno/knowledge/reader/web_search_reader.py +366 -0
  125. agno/{document → knowledge}/reader/website_reader.py +37 -10
  126. agno/knowledge/reader/wikipedia_reader.py +59 -0
  127. agno/knowledge/reader/youtube_reader.py +78 -0
  128. agno/knowledge/remote_content/remote_content.py +88 -0
  129. agno/{reranker → knowledge/reranker}/base.py +1 -1
  130. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  131. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  132. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  133. agno/knowledge/types.py +30 -0
  134. agno/knowledge/utils.py +169 -0
  135. agno/media.py +269 -268
  136. agno/memory/__init__.py +2 -10
  137. agno/memory/manager.py +1003 -148
  138. agno/models/aimlapi/__init__.py +2 -2
  139. agno/models/aimlapi/aimlapi.py +6 -6
  140. agno/models/anthropic/claude.py +131 -131
  141. agno/models/aws/bedrock.py +110 -182
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +346 -290
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +105 -46
  148. agno/models/groq/groq.py +97 -35
  149. agno/models/huggingface/huggingface.py +92 -27
  150. agno/models/ibm/watsonx.py +72 -13
  151. agno/models/litellm/chat.py +85 -13
  152. agno/models/message.py +46 -151
  153. agno/models/meta/llama.py +85 -49
  154. agno/models/metrics.py +120 -0
  155. agno/models/mistral/mistral.py +90 -21
  156. agno/models/ollama/__init__.py +0 -2
  157. agno/models/ollama/chat.py +85 -47
  158. agno/models/openai/chat.py +154 -37
  159. agno/models/openai/responses.py +178 -105
  160. agno/models/perplexity/perplexity.py +26 -2
  161. agno/models/portkey/portkey.py +0 -7
  162. agno/models/response.py +15 -9
  163. agno/models/utils.py +20 -0
  164. agno/models/vercel/__init__.py +2 -2
  165. agno/models/vercel/v0.py +1 -1
  166. agno/models/vllm/__init__.py +2 -2
  167. agno/models/vllm/vllm.py +3 -3
  168. agno/models/xai/xai.py +10 -10
  169. agno/os/__init__.py +3 -0
  170. agno/os/app.py +497 -0
  171. agno/os/auth.py +47 -0
  172. agno/os/config.py +103 -0
  173. agno/os/interfaces/agui/__init__.py +3 -0
  174. agno/os/interfaces/agui/agui.py +31 -0
  175. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  176. agno/{app → os/interfaces}/agui/utils.py +77 -33
  177. agno/os/interfaces/base.py +21 -0
  178. agno/os/interfaces/slack/__init__.py +3 -0
  179. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  180. agno/os/interfaces/slack/slack.py +32 -0
  181. agno/os/interfaces/whatsapp/__init__.py +3 -0
  182. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  183. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  184. agno/os/mcp.py +235 -0
  185. agno/os/router.py +1400 -0
  186. agno/os/routers/__init__.py +3 -0
  187. agno/os/routers/evals/__init__.py +3 -0
  188. agno/os/routers/evals/evals.py +393 -0
  189. agno/os/routers/evals/schemas.py +142 -0
  190. agno/os/routers/evals/utils.py +161 -0
  191. agno/os/routers/knowledge/__init__.py +3 -0
  192. agno/os/routers/knowledge/knowledge.py +850 -0
  193. agno/os/routers/knowledge/schemas.py +118 -0
  194. agno/os/routers/memory/__init__.py +3 -0
  195. agno/os/routers/memory/memory.py +410 -0
  196. agno/os/routers/memory/schemas.py +58 -0
  197. agno/os/routers/metrics/__init__.py +3 -0
  198. agno/os/routers/metrics/metrics.py +178 -0
  199. agno/os/routers/metrics/schemas.py +47 -0
  200. agno/os/routers/session/__init__.py +3 -0
  201. agno/os/routers/session/session.py +536 -0
  202. agno/os/schema.py +945 -0
  203. agno/{app/playground → os}/settings.py +7 -15
  204. agno/os/utils.py +270 -0
  205. agno/reasoning/azure_ai_foundry.py +4 -4
  206. agno/reasoning/deepseek.py +4 -4
  207. agno/reasoning/default.py +6 -11
  208. agno/reasoning/groq.py +4 -4
  209. agno/reasoning/helpers.py +4 -6
  210. agno/reasoning/ollama.py +4 -4
  211. agno/reasoning/openai.py +4 -4
  212. agno/run/agent.py +633 -0
  213. agno/run/base.py +53 -77
  214. agno/run/cancel.py +81 -0
  215. agno/run/team.py +243 -96
  216. agno/run/workflow.py +550 -12
  217. agno/session/__init__.py +10 -0
  218. agno/session/agent.py +244 -0
  219. agno/session/summary.py +225 -0
  220. agno/session/team.py +262 -0
  221. agno/{storage/session/v2 → session}/workflow.py +47 -24
  222. agno/team/__init__.py +15 -16
  223. agno/team/team.py +3260 -4824
  224. agno/tools/agentql.py +14 -5
  225. agno/tools/airflow.py +9 -4
  226. agno/tools/api.py +7 -3
  227. agno/tools/apify.py +2 -46
  228. agno/tools/arxiv.py +8 -3
  229. agno/tools/aws_lambda.py +7 -5
  230. agno/tools/aws_ses.py +7 -1
  231. agno/tools/baidusearch.py +4 -1
  232. agno/tools/bitbucket.py +4 -4
  233. agno/tools/brandfetch.py +14 -11
  234. agno/tools/bravesearch.py +4 -1
  235. agno/tools/brightdata.py +43 -23
  236. agno/tools/browserbase.py +13 -4
  237. agno/tools/calcom.py +12 -10
  238. agno/tools/calculator.py +10 -27
  239. agno/tools/cartesia.py +20 -17
  240. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  241. agno/tools/confluence.py +8 -8
  242. agno/tools/crawl4ai.py +7 -1
  243. agno/tools/csv_toolkit.py +9 -8
  244. agno/tools/dalle.py +22 -12
  245. agno/tools/daytona.py +13 -16
  246. agno/tools/decorator.py +6 -3
  247. agno/tools/desi_vocal.py +17 -8
  248. agno/tools/discord.py +11 -8
  249. agno/tools/docker.py +30 -42
  250. agno/tools/duckdb.py +34 -53
  251. agno/tools/duckduckgo.py +8 -7
  252. agno/tools/e2b.py +62 -62
  253. agno/tools/eleven_labs.py +36 -29
  254. agno/tools/email.py +4 -1
  255. agno/tools/evm.py +7 -1
  256. agno/tools/exa.py +19 -14
  257. agno/tools/fal.py +30 -30
  258. agno/tools/file.py +9 -8
  259. agno/tools/financial_datasets.py +25 -44
  260. agno/tools/firecrawl.py +22 -22
  261. agno/tools/function.py +127 -18
  262. agno/tools/giphy.py +23 -11
  263. agno/tools/github.py +48 -126
  264. agno/tools/gmail.py +45 -61
  265. agno/tools/google_bigquery.py +7 -6
  266. agno/tools/google_maps.py +11 -26
  267. agno/tools/googlesearch.py +7 -2
  268. agno/tools/googlesheets.py +21 -17
  269. agno/tools/hackernews.py +9 -5
  270. agno/tools/jina.py +5 -4
  271. agno/tools/jira.py +18 -9
  272. agno/tools/knowledge.py +31 -32
  273. agno/tools/linear.py +19 -34
  274. agno/tools/linkup.py +5 -1
  275. agno/tools/local_file_system.py +8 -5
  276. agno/tools/lumalab.py +32 -20
  277. agno/tools/mcp.py +1 -2
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +33 -15
  282. agno/tools/models/gemini.py +59 -32
  283. agno/tools/models/groq.py +30 -23
  284. agno/tools/models/nebius.py +28 -12
  285. agno/tools/models_labs.py +40 -16
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +10 -8
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +58 -32
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +63 -47
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +55 -42
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +100 -123
  335. agno/utils/gemini.py +32 -2
  336. agno/utils/knowledge.py +29 -0
  337. agno/utils/log.py +54 -4
  338. agno/utils/mcp.py +68 -10
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/aws_claude.py +1 -1
  342. agno/utils/models/claude.py +47 -4
  343. agno/utils/models/cohere.py +1 -1
  344. agno/utils/models/mistral.py +8 -7
  345. agno/utils/models/schema_utils.py +3 -3
  346. agno/utils/models/watsonx.py +1 -1
  347. agno/utils/openai.py +1 -1
  348. agno/utils/pprint.py +33 -32
  349. agno/utils/print_response/agent.py +779 -0
  350. agno/utils/print_response/team.py +1669 -0
  351. agno/utils/print_response/workflow.py +1451 -0
  352. agno/utils/prompts.py +14 -14
  353. agno/utils/reasoning.py +87 -0
  354. agno/utils/response.py +42 -42
  355. agno/utils/streamlit.py +481 -0
  356. agno/utils/string.py +8 -22
  357. agno/utils/team.py +50 -0
  358. agno/utils/timer.py +2 -2
  359. agno/vectordb/base.py +33 -21
  360. agno/vectordb/cassandra/cassandra.py +287 -23
  361. agno/vectordb/chroma/chromadb.py +482 -59
  362. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  363. agno/vectordb/couchbase/couchbase.py +309 -29
  364. agno/vectordb/lancedb/lance_db.py +360 -21
  365. agno/vectordb/langchaindb/__init__.py +5 -0
  366. agno/vectordb/langchaindb/langchaindb.py +145 -0
  367. agno/vectordb/lightrag/__init__.py +5 -0
  368. agno/vectordb/lightrag/lightrag.py +374 -0
  369. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  370. agno/vectordb/milvus/milvus.py +242 -32
  371. agno/vectordb/mongodb/mongodb.py +200 -24
  372. agno/vectordb/pgvector/pgvector.py +319 -37
  373. agno/vectordb/pineconedb/pineconedb.py +221 -27
  374. agno/vectordb/qdrant/qdrant.py +334 -14
  375. agno/vectordb/singlestore/singlestore.py +286 -29
  376. agno/vectordb/surrealdb/surrealdb.py +187 -7
  377. agno/vectordb/upstashdb/upstashdb.py +342 -26
  378. agno/vectordb/weaviate/weaviate.py +227 -165
  379. agno/workflow/__init__.py +17 -13
  380. agno/workflow/{v2/condition.py → condition.py} +135 -32
  381. agno/workflow/{v2/loop.py → loop.py} +115 -28
  382. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  383. agno/workflow/{v2/router.py → router.py} +133 -32
  384. agno/workflow/{v2/step.py → step.py} +207 -49
  385. agno/workflow/{v2/steps.py → steps.py} +147 -66
  386. agno/workflow/types.py +482 -0
  387. agno/workflow/workflow.py +2410 -696
  388. agno-2.0.0.dist-info/METADATA +494 -0
  389. agno-2.0.0.dist-info/RECORD +515 -0
  390. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  391. agno/agent/metrics.py +0 -107
  392. agno/api/app.py +0 -35
  393. agno/api/playground.py +0 -92
  394. agno/api/schemas/app.py +0 -12
  395. agno/api/schemas/playground.py +0 -22
  396. agno/api/schemas/user.py +0 -35
  397. agno/api/schemas/workspace.py +0 -46
  398. agno/api/user.py +0 -160
  399. agno/api/workflows.py +0 -33
  400. agno/api/workspace.py +0 -175
  401. agno/app/agui/__init__.py +0 -3
  402. agno/app/agui/app.py +0 -17
  403. agno/app/agui/sync_router.py +0 -120
  404. agno/app/base.py +0 -186
  405. agno/app/discord/__init__.py +0 -3
  406. agno/app/fastapi/__init__.py +0 -3
  407. agno/app/fastapi/app.py +0 -107
  408. agno/app/fastapi/async_router.py +0 -457
  409. agno/app/fastapi/sync_router.py +0 -448
  410. agno/app/playground/app.py +0 -228
  411. agno/app/playground/async_router.py +0 -1050
  412. agno/app/playground/deploy.py +0 -249
  413. agno/app/playground/operator.py +0 -183
  414. agno/app/playground/schemas.py +0 -220
  415. agno/app/playground/serve.py +0 -55
  416. agno/app/playground/sync_router.py +0 -1042
  417. agno/app/playground/utils.py +0 -46
  418. agno/app/settings.py +0 -15
  419. agno/app/slack/__init__.py +0 -3
  420. agno/app/slack/app.py +0 -19
  421. agno/app/slack/sync_router.py +0 -92
  422. agno/app/utils.py +0 -54
  423. agno/app/whatsapp/__init__.py +0 -3
  424. agno/app/whatsapp/app.py +0 -15
  425. agno/app/whatsapp/sync_router.py +0 -197
  426. agno/cli/auth_server.py +0 -249
  427. agno/cli/config.py +0 -274
  428. agno/cli/console.py +0 -88
  429. agno/cli/credentials.py +0 -23
  430. agno/cli/entrypoint.py +0 -571
  431. agno/cli/operator.py +0 -357
  432. agno/cli/settings.py +0 -96
  433. agno/cli/ws/ws_cli.py +0 -817
  434. agno/constants.py +0 -13
  435. agno/document/__init__.py +0 -5
  436. agno/document/chunking/semantic.py +0 -45
  437. agno/document/chunking/strategy.py +0 -31
  438. agno/document/reader/__init__.py +0 -5
  439. agno/document/reader/base.py +0 -47
  440. agno/document/reader/docx_reader.py +0 -60
  441. agno/document/reader/gcs/pdf_reader.py +0 -44
  442. agno/document/reader/s3/pdf_reader.py +0 -59
  443. agno/document/reader/s3/text_reader.py +0 -63
  444. agno/document/reader/url_reader.py +0 -59
  445. agno/document/reader/youtube_reader.py +0 -58
  446. agno/embedder/__init__.py +0 -5
  447. agno/embedder/langdb.py +0 -80
  448. agno/embedder/mistral.py +0 -82
  449. agno/embedder/openai.py +0 -78
  450. agno/file/__init__.py +0 -5
  451. agno/file/file.py +0 -16
  452. agno/file/local/csv.py +0 -32
  453. agno/file/local/txt.py +0 -19
  454. agno/infra/app.py +0 -240
  455. agno/infra/base.py +0 -144
  456. agno/infra/context.py +0 -20
  457. agno/infra/db_app.py +0 -52
  458. agno/infra/resource.py +0 -205
  459. agno/infra/resources.py +0 -55
  460. agno/knowledge/agent.py +0 -702
  461. agno/knowledge/arxiv.py +0 -33
  462. agno/knowledge/combined.py +0 -36
  463. agno/knowledge/csv.py +0 -144
  464. agno/knowledge/csv_url.py +0 -124
  465. agno/knowledge/document.py +0 -223
  466. agno/knowledge/docx.py +0 -137
  467. agno/knowledge/firecrawl.py +0 -34
  468. agno/knowledge/gcs/__init__.py +0 -0
  469. agno/knowledge/gcs/base.py +0 -39
  470. agno/knowledge/gcs/pdf.py +0 -125
  471. agno/knowledge/json.py +0 -137
  472. agno/knowledge/langchain.py +0 -71
  473. agno/knowledge/light_rag.py +0 -273
  474. agno/knowledge/llamaindex.py +0 -66
  475. agno/knowledge/markdown.py +0 -154
  476. agno/knowledge/pdf.py +0 -164
  477. agno/knowledge/pdf_bytes.py +0 -42
  478. agno/knowledge/pdf_url.py +0 -148
  479. agno/knowledge/s3/__init__.py +0 -0
  480. agno/knowledge/s3/base.py +0 -64
  481. agno/knowledge/s3/pdf.py +0 -33
  482. agno/knowledge/s3/text.py +0 -34
  483. agno/knowledge/text.py +0 -141
  484. agno/knowledge/url.py +0 -46
  485. agno/knowledge/website.py +0 -179
  486. agno/knowledge/wikipedia.py +0 -32
  487. agno/knowledge/youtube.py +0 -35
  488. agno/memory/agent.py +0 -423
  489. agno/memory/classifier.py +0 -104
  490. agno/memory/db/__init__.py +0 -5
  491. agno/memory/db/base.py +0 -42
  492. agno/memory/db/mongodb.py +0 -189
  493. agno/memory/db/postgres.py +0 -203
  494. agno/memory/db/sqlite.py +0 -193
  495. agno/memory/memory.py +0 -22
  496. agno/memory/row.py +0 -36
  497. agno/memory/summarizer.py +0 -201
  498. agno/memory/summary.py +0 -19
  499. agno/memory/team.py +0 -415
  500. agno/memory/v2/__init__.py +0 -2
  501. agno/memory/v2/db/__init__.py +0 -1
  502. agno/memory/v2/db/base.py +0 -42
  503. agno/memory/v2/db/firestore.py +0 -339
  504. agno/memory/v2/db/mongodb.py +0 -196
  505. agno/memory/v2/db/postgres.py +0 -214
  506. agno/memory/v2/db/redis.py +0 -187
  507. agno/memory/v2/db/schema.py +0 -54
  508. agno/memory/v2/db/sqlite.py +0 -209
  509. agno/memory/v2/manager.py +0 -437
  510. agno/memory/v2/memory.py +0 -1097
  511. agno/memory/v2/schema.py +0 -55
  512. agno/memory/v2/summarizer.py +0 -215
  513. agno/memory/workflow.py +0 -38
  514. agno/models/ollama/tools.py +0 -430
  515. agno/models/qwen/__init__.py +0 -5
  516. agno/playground/__init__.py +0 -10
  517. agno/playground/deploy.py +0 -3
  518. agno/playground/playground.py +0 -3
  519. agno/playground/serve.py +0 -3
  520. agno/playground/settings.py +0 -3
  521. agno/reranker/__init__.py +0 -0
  522. agno/run/response.py +0 -467
  523. agno/run/v2/__init__.py +0 -0
  524. agno/run/v2/workflow.py +0 -567
  525. agno/storage/__init__.py +0 -0
  526. agno/storage/agent/__init__.py +0 -0
  527. agno/storage/agent/dynamodb.py +0 -1
  528. agno/storage/agent/json.py +0 -1
  529. agno/storage/agent/mongodb.py +0 -1
  530. agno/storage/agent/postgres.py +0 -1
  531. agno/storage/agent/singlestore.py +0 -1
  532. agno/storage/agent/sqlite.py +0 -1
  533. agno/storage/agent/yaml.py +0 -1
  534. agno/storage/base.py +0 -60
  535. agno/storage/dynamodb.py +0 -673
  536. agno/storage/firestore.py +0 -297
  537. agno/storage/gcs_json.py +0 -261
  538. agno/storage/in_memory.py +0 -234
  539. agno/storage/json.py +0 -237
  540. agno/storage/mongodb.py +0 -328
  541. agno/storage/mysql.py +0 -685
  542. agno/storage/postgres.py +0 -682
  543. agno/storage/redis.py +0 -336
  544. agno/storage/session/__init__.py +0 -16
  545. agno/storage/session/agent.py +0 -64
  546. agno/storage/session/team.py +0 -63
  547. agno/storage/session/v2/__init__.py +0 -5
  548. agno/storage/session/workflow.py +0 -61
  549. agno/storage/singlestore.py +0 -606
  550. agno/storage/sqlite.py +0 -646
  551. agno/storage/workflow/__init__.py +0 -0
  552. agno/storage/workflow/mongodb.py +0 -1
  553. agno/storage/workflow/postgres.py +0 -1
  554. agno/storage/workflow/sqlite.py +0 -1
  555. agno/storage/yaml.py +0 -241
  556. agno/tools/thinking.py +0 -73
  557. agno/utils/defaults.py +0 -57
  558. agno/utils/filesystem.py +0 -39
  559. agno/utils/git.py +0 -52
  560. agno/utils/json_io.py +0 -30
  561. agno/utils/load_env.py +0 -19
  562. agno/utils/py_io.py +0 -19
  563. agno/utils/pyproject.py +0 -18
  564. agno/utils/resource_filter.py +0 -31
  565. agno/workflow/v2/__init__.py +0 -21
  566. agno/workflow/v2/types.py +0 -357
  567. agno/workflow/v2/workflow.py +0 -3312
  568. agno/workspace/__init__.py +0 -0
  569. agno/workspace/config.py +0 -325
  570. agno/workspace/enums.py +0 -6
  571. agno/workspace/helpers.py +0 -52
  572. agno/workspace/operator.py +0 -757
  573. agno/workspace/settings.py +0 -158
  574. agno-1.8.1.dist-info/METADATA +0 -982
  575. agno-1.8.1.dist-info/RECORD +0 -566
  576. agno-1.8.1.dist-info/entry_points.txt +0 -3
  577. agno-1.8.1.dist-info/licenses/LICENSE +0 -375
  578. /agno/{app → db/migrations}/__init__.py +0 -0
  579. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  580. /agno/{cli → integrations}/__init__.py +0 -0
  581. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  582. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  583. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  584. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  585. /agno/{app → os/interfaces}/slack/security.py +0 -0
  586. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  587. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  588. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  589. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  590. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
agno/vectordb/base.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from typing import Any, Dict, List, Optional
3
3
 
4
- from agno.document import Document
4
+ from agno.knowledge.document import Document
5
5
 
6
6
 
7
7
  class VectorDb(ABC):
@@ -16,41 +16,42 @@ class VectorDb(ABC):
16
16
  raise NotImplementedError
17
17
 
18
18
  @abstractmethod
19
- def doc_exists(self, document: Document) -> bool:
19
+ def name_exists(self, name: str) -> bool:
20
20
  raise NotImplementedError
21
21
 
22
22
  @abstractmethod
23
- async def async_doc_exists(self, document: Document) -> bool:
23
+ def async_name_exists(self, name: str) -> bool:
24
24
  raise NotImplementedError
25
25
 
26
26
  @abstractmethod
27
- def name_exists(self, name: str) -> bool:
27
+ def id_exists(self, id: str) -> bool:
28
28
  raise NotImplementedError
29
29
 
30
30
  @abstractmethod
31
- def async_name_exists(self, name: str) -> bool:
32
- raise NotImplementedError
33
-
34
- def id_exists(self, id: str) -> bool:
31
+ def content_hash_exists(self, content_hash: str) -> bool:
35
32
  raise NotImplementedError
36
33
 
37
34
  @abstractmethod
38
- def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
35
+ def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
39
36
  raise NotImplementedError
40
37
 
41
38
  @abstractmethod
42
- async def async_insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
39
+ async def async_insert(
40
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
41
+ ) -> None:
43
42
  raise NotImplementedError
44
43
 
45
44
  def upsert_available(self) -> bool:
46
45
  return False
47
46
 
48
47
  @abstractmethod
49
- def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
48
+ def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
50
49
  raise NotImplementedError
51
50
 
52
51
  @abstractmethod
53
- async def async_upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
52
+ async def async_upsert(
53
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
54
+ ) -> None:
54
55
  raise NotImplementedError
55
56
 
56
57
  @abstractmethod
@@ -63,15 +64,6 @@ class VectorDb(ABC):
63
64
  ) -> List[Document]:
64
65
  raise NotImplementedError
65
66
 
66
- def vector_search(self, query: str, limit: int = 5) -> List[Document]:
67
- raise NotImplementedError
68
-
69
- def keyword_search(self, query: str, limit: int = 5) -> List[Document]:
70
- raise NotImplementedError
71
-
72
- def hybrid_search(self, query: str, limit: int = 5) -> List[Document]:
73
- raise NotImplementedError
74
-
75
67
  @abstractmethod
76
68
  def drop(self) -> None:
77
69
  raise NotImplementedError
@@ -94,3 +86,23 @@ class VectorDb(ABC):
94
86
  @abstractmethod
95
87
  def delete(self) -> bool:
96
88
  raise NotImplementedError
89
+
90
+ @abstractmethod
91
+ def delete_by_id(self, id: str) -> bool:
92
+ raise NotImplementedError
93
+
94
+ @abstractmethod
95
+ def delete_by_name(self, name: str) -> bool:
96
+ raise NotImplementedError
97
+
98
+ @abstractmethod
99
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
100
+ raise NotImplementedError
101
+
102
+ @abstractmethod
103
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
104
+ raise NotImplementedError
105
+
106
+ @abstractmethod
107
+ def delete_by_content_id(self, content_id: str) -> bool:
108
+ raise NotImplementedError
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
2
  from typing import Any, Dict, Iterable, List, Optional
3
3
 
4
- from agno.document import Document
5
- from agno.embedder import Embedder
6
- from agno.utils.log import log_debug, log_info
4
+ from agno.knowledge.document import Document
5
+ from agno.knowledge.embedder import Embedder
6
+ from agno.utils.log import log_debug, log_error, log_info
7
7
  from agno.vectordb.base import VectorDb
8
8
  from agno.vectordb.cassandra.index import AgnoMetadataVectorCassandraTable
9
9
 
@@ -26,7 +26,7 @@ class Cassandra(VectorDb):
26
26
  raise ValueError("Keyspace must be provided")
27
27
 
28
28
  if embedder is None:
29
- from agno.embedder.openai import OpenAIEmbedder
29
+ from agno.knowledge.embedder.openai import OpenAIEmbedder
30
30
 
31
31
  embedder = OpenAIEmbedder()
32
32
  log_info("Embedder not provided, using OpenAIEmbedder as default.")
@@ -56,24 +56,16 @@ class Cassandra(VectorDb):
56
56
  await asyncio.to_thread(self.create)
57
57
 
58
58
  def _row_to_document(self, row: Dict[str, Any]) -> Document:
59
+ metadata = row["metadata"]
59
60
  return Document(
60
61
  id=row["row_id"],
61
62
  content=row["body_blob"],
62
- meta_data=row["metadata"],
63
+ meta_data=metadata,
63
64
  embedding=row["vector"],
64
65
  name=row["document_name"],
66
+ content_id=metadata.get("content_id"),
65
67
  )
66
68
 
67
- def doc_exists(self, document: Document) -> bool:
68
- """Check if a document exists by ID."""
69
- query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
70
- result = self.session.execute(query, (document.id,))
71
- return result.one()[0] > 0
72
-
73
- async def async_doc_exists(self, document: Document) -> bool:
74
- """Check if a document exists asynchronously."""
75
- return await asyncio.to_thread(self.doc_exists, document)
76
-
77
69
  def name_exists(self, name: str) -> bool:
78
70
  """Check if a document exists by name."""
79
71
  query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE document_name = %s ALLOW FILTERING"
@@ -90,12 +82,21 @@ class Cassandra(VectorDb):
90
82
  result = self.session.execute(query, (id,))
91
83
  return result.one()[0] > 0
92
84
 
93
- def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
94
- log_debug(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
85
+ def content_hash_exists(self, content_hash: str) -> bool:
86
+ """Check if a document exists by content hash."""
87
+ query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE metadata_s['content_hash'] = %s ALLOW FILTERING"
88
+ result = self.session.execute(query, (content_hash,))
89
+ return result.one()[0] > 0
90
+
91
+ def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
92
+ log_info(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
95
93
  futures = []
96
94
  for doc in documents:
97
95
  doc.embed(embedder=self.embedder)
98
96
  metadata = {key: str(value) for key, value in doc.meta_data.items()}
97
+ metadata.update(filters or {})
98
+ metadata["content_id"] = doc.content_id or ""
99
+ metadata["content_hash"] = content_hash
99
100
  futures.append(
100
101
  self.table.put_async(
101
102
  row_id=doc.id,
@@ -109,17 +110,54 @@ class Cassandra(VectorDb):
109
110
  for f in futures:
110
111
  f.result()
111
112
 
112
- async def async_insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
113
+ async def async_insert(
114
+ self,
115
+ content_hash: str,
116
+ documents: List[Document],
117
+ filters: Optional[Dict[str, Any]] = None,
118
+ ) -> None:
113
119
  """Insert documents asynchronously by running in a thread."""
114
- await asyncio.to_thread(self.insert, documents, filters)
120
+ log_info(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
121
+
122
+ for doc in documents:
123
+ try:
124
+ embed_tasks = [doc.async_embed(embedder=self.embedder)]
125
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
126
+ except Exception as e:
127
+ log_error(f"Error processing document '{doc.name}': {e}")
128
+
129
+ futures = []
130
+ for doc in documents:
131
+ metadata = {key: str(value) for key, value in doc.meta_data.items()}
132
+ metadata.update(filters or {})
133
+ metadata["content_id"] = doc.content_id or ""
134
+ metadata["content_hash"] = content_hash
135
+ futures.append(
136
+ self.table.put_async(
137
+ row_id=doc.id,
138
+ vector=doc.embedding,
139
+ metadata=metadata or {},
140
+ body_blob=doc.content,
141
+ document_name=doc.name,
142
+ )
143
+ )
144
+
145
+ for f in futures:
146
+ f.result()
115
147
 
116
- def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
148
+ def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
117
149
  """Insert or update documents based on primary key."""
118
- self.insert(documents, filters)
150
+ if self.content_hash_exists(content_hash):
151
+ self.delete_by_content_hash(content_hash)
152
+ self.insert(content_hash, documents, filters)
119
153
 
120
- async def async_upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
154
+ async def async_upsert(
155
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
156
+ ) -> None:
121
157
  """Upsert documents asynchronously by running in a thread."""
122
- await asyncio.to_thread(self.upsert, documents, filters)
158
+ if self.content_hash_exists(content_hash):
159
+ self.delete_by_content_hash(content_hash)
160
+ await self.async_insert(content_hash, documents, filters)
123
161
 
124
162
  def search(self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None) -> List[Document]:
125
163
  """Keyword-based search on document metadata."""
@@ -179,3 +217,229 @@ class Cassandra(VectorDb):
179
217
  log_debug(f"Cassandra VectorDB : Clearing the table {self.table_name}")
180
218
  self.table.clear()
181
219
  return True
220
+
221
+ def delete_by_id(self, id: str) -> bool:
222
+ """
223
+ Delete a document by its ID.
224
+
225
+ Args:
226
+ id (str): The document ID to delete
227
+
228
+ Returns:
229
+ bool: True if document was deleted, False otherwise
230
+ """
231
+ try:
232
+ log_debug(f"Cassandra VectorDB : Deleting document with ID {id}")
233
+ # Check if document exists before deletion
234
+ if not self.id_exists(id):
235
+ return False
236
+
237
+ query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
238
+ self.session.execute(query, (id,))
239
+ return True
240
+ except Exception as e:
241
+ log_info(f"Error deleting document with ID {id}: {e}")
242
+ return False
243
+
244
+ def delete_by_name(self, name: str) -> bool:
245
+ """
246
+ Delete documents by name.
247
+
248
+ Args:
249
+ name (str): The document name to delete
250
+
251
+ Returns:
252
+ bool: True if documents were deleted, False otherwise
253
+ """
254
+ try:
255
+ log_debug(f"Cassandra VectorDB : Deleting documents with name {name}")
256
+ # Check if document exists before deletion
257
+ if not self.name_exists(name):
258
+ return False
259
+
260
+ # Query to find documents with matching name
261
+ query = f"SELECT row_id, document_name FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
262
+ result = self.session.execute(query)
263
+
264
+ deleted_count = 0
265
+ for row in result:
266
+ # Check if the row's document_name matches our criteria
267
+ # Use attribute access for Row objects
268
+ row_name = getattr(row, "document_name", None)
269
+ if row_name == name:
270
+ # Delete this specific document
271
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
272
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
273
+ deleted_count += 1
274
+
275
+ return deleted_count > 0
276
+ except Exception as e:
277
+ log_info(f"Error deleting documents with name {name}: {e}")
278
+ return False
279
+
280
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
281
+ """
282
+ Delete documents by metadata.
283
+
284
+ Args:
285
+ metadata (Dict[str, Any]): The metadata to match for deletion
286
+
287
+ Returns:
288
+ bool: True if documents were deleted, False otherwise
289
+ """
290
+ try:
291
+ log_debug(f"Cassandra VectorDB : Deleting documents with metadata {metadata}")
292
+ # For metadata deletion, we need to query first to find matching documents
293
+ # Then delete them by their IDs
294
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
295
+ result = self.session.execute(query)
296
+
297
+ deleted_count = 0
298
+ for row in result:
299
+ # Check if the row's metadata matches our criteria
300
+ # Use attribute access for Row objects
301
+ row_metadata = getattr(row, "metadata_s", {})
302
+ if self._metadata_matches(row_metadata, metadata):
303
+ # Delete this specific document
304
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
305
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
306
+ deleted_count += 1
307
+
308
+ return deleted_count > 0
309
+ except Exception as e:
310
+ log_debug(f"Error deleting documents with metadata {metadata}: {e}")
311
+ return False
312
+
313
+ def delete_by_content_id(self, content_id: str) -> bool:
314
+ """
315
+ Delete documents by content ID.
316
+
317
+ Args:
318
+ content_id (str): The content ID to delete
319
+
320
+ Returns:
321
+ bool: True if documents were deleted, False otherwise
322
+ """
323
+ try:
324
+ log_debug(f"Cassandra VectorDB : Deleting documents with content_id {content_id}")
325
+ # Query to find documents with matching content_id in metadata
326
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
327
+ result = self.session.execute(query)
328
+ deleted_count = 0
329
+ for row in result:
330
+ # Check if the row's metadata contains the content_id
331
+ # Use attribute access for Row objects
332
+ row_metadata = getattr(row, "metadata_s", {})
333
+ if row_metadata.get("content_id") == content_id:
334
+ # Delete this specific document
335
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
336
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
337
+ deleted_count += 1
338
+
339
+ return deleted_count > 0
340
+ except Exception as e:
341
+ log_info(f"Error deleting documents with content_id {content_id}: {e}")
342
+ return False
343
+
344
+ def delete_by_content_hash(self, content_hash: str) -> bool:
345
+ """
346
+ Delete documents by content hash.
347
+
348
+ Args:
349
+ content_hash (str): The content hash to delete
350
+
351
+ Returns:
352
+ bool: True if documents were deleted, False otherwise
353
+ """
354
+ try:
355
+ log_debug(f"Cassandra VectorDB : Deleting documents with content_hash {content_hash}")
356
+ # Query to find documents with matching content_hash in metadata
357
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
358
+ result = self.session.execute(query)
359
+ deleted_count = 0
360
+ for row in result:
361
+ # Check if the row's metadata contains the content_hash
362
+ # Use attribute access for Row objects
363
+ row_metadata = getattr(row, "metadata_s", {})
364
+ if row_metadata.get("content_hash") == content_hash:
365
+ # Delete this specific document
366
+ delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
367
+ self.session.execute(delete_query, (getattr(row, "row_id"),))
368
+ deleted_count += 1
369
+
370
+ return deleted_count > 0
371
+ except Exception as e:
372
+ log_info(f"Error deleting documents with content_hash {content_hash}: {e}")
373
+ return False
374
+
375
+ def _metadata_matches(self, row_metadata: Dict[str, Any], target_metadata: Dict[str, Any]) -> bool:
376
+ """
377
+ Check if row metadata matches target metadata criteria.
378
+
379
+ Args:
380
+ row_metadata (Dict[str, Any]): The metadata from the database row
381
+ target_metadata (Dict[str, Any]): The target metadata to match against
382
+
383
+ Returns:
384
+ bool: True if metadata matches, False otherwise
385
+ """
386
+ try:
387
+ for key, value in target_metadata.items():
388
+ if key not in row_metadata:
389
+ return False
390
+
391
+ # Handle boolean values specially
392
+ if isinstance(value, bool):
393
+ if row_metadata[key] != value:
394
+ return False
395
+ else:
396
+ # For non-boolean values, convert to string for comparison
397
+ if row_metadata[key] != str(value):
398
+ return False
399
+ return True
400
+ except Exception:
401
+ return False
402
+
403
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
404
+ """
405
+ Update the metadata for a document.
406
+
407
+ Args:
408
+ content_id (str): The content ID to update
409
+ metadata (Dict[str, Any]): The metadata to update
410
+ """
411
+ try:
412
+ log_debug(f"Cassandra VectorDB : Updating metadata for content_id {content_id}")
413
+
414
+ # First, find all documents with the given content_id
415
+ query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
416
+ result = self.session.execute(query)
417
+
418
+ updated_count = 0
419
+ for row in result:
420
+ row_metadata = getattr(row, "metadata_s", {})
421
+ if row_metadata.get("content_id") == content_id:
422
+ # Merge existing metadata with new metadata
423
+ updated_metadata = row_metadata.copy()
424
+ # Convert new metadata values to strings (Cassandra requirement)
425
+ string_metadata = {key: str(value) for key, value in metadata.items()}
426
+ updated_metadata.update(string_metadata)
427
+
428
+ # Update the document with merged metadata
429
+ row_id = getattr(row, "row_id")
430
+ update_query = f"""
431
+ UPDATE {self.keyspace}.{self.table_name}
432
+ SET metadata_s = %s
433
+ WHERE row_id = %s
434
+ """
435
+ self.session.execute(update_query, (updated_metadata, row_id))
436
+ updated_count += 1
437
+
438
+ if updated_count == 0:
439
+ log_debug(f"No documents found with content_id {content_id}")
440
+ else:
441
+ log_debug(f"Updated metadata for {updated_count} documents with content_id {content_id}")
442
+
443
+ except Exception as e:
444
+ log_error(f"Error updating metadata for content_id {content_id}: {e}")
445
+ raise