agno 1.8.2__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 (589) hide show
  1. agno/agent/__init__.py +19 -27
  2. agno/agent/agent.py +3143 -4170
  3. agno/api/agent.py +11 -67
  4. agno/api/api.py +5 -46
  5. agno/api/evals.py +8 -19
  6. agno/api/os.py +17 -0
  7. agno/api/routes.py +6 -41
  8. agno/api/schemas/__init__.py +9 -0
  9. agno/api/schemas/agent.py +5 -21
  10. agno/api/schemas/evals.py +7 -16
  11. agno/api/schemas/os.py +14 -0
  12. agno/api/schemas/team.py +5 -21
  13. agno/api/schemas/utils.py +21 -0
  14. agno/api/schemas/workflows.py +11 -7
  15. agno/api/settings.py +53 -0
  16. agno/api/team.py +11 -66
  17. agno/api/workflow.py +28 -0
  18. agno/cloud/aws/base.py +214 -0
  19. agno/cloud/aws/s3/__init__.py +2 -0
  20. agno/cloud/aws/s3/api_client.py +43 -0
  21. agno/cloud/aws/s3/bucket.py +195 -0
  22. agno/cloud/aws/s3/object.py +57 -0
  23. agno/db/__init__.py +24 -0
  24. agno/db/base.py +245 -0
  25. agno/db/dynamo/__init__.py +3 -0
  26. agno/db/dynamo/dynamo.py +1743 -0
  27. agno/db/dynamo/schemas.py +278 -0
  28. agno/db/dynamo/utils.py +684 -0
  29. agno/db/firestore/__init__.py +3 -0
  30. agno/db/firestore/firestore.py +1432 -0
  31. agno/db/firestore/schemas.py +130 -0
  32. agno/db/firestore/utils.py +278 -0
  33. agno/db/gcs_json/__init__.py +3 -0
  34. agno/db/gcs_json/gcs_json_db.py +1001 -0
  35. agno/db/gcs_json/utils.py +194 -0
  36. agno/db/in_memory/__init__.py +3 -0
  37. agno/db/in_memory/in_memory_db.py +882 -0
  38. agno/db/in_memory/utils.py +172 -0
  39. agno/db/json/__init__.py +3 -0
  40. agno/db/json/json_db.py +1045 -0
  41. agno/db/json/utils.py +196 -0
  42. agno/db/migrations/v1_to_v2.py +162 -0
  43. agno/db/mongo/__init__.py +3 -0
  44. agno/db/mongo/mongo.py +1416 -0
  45. agno/db/mongo/schemas.py +77 -0
  46. agno/db/mongo/utils.py +204 -0
  47. agno/db/mysql/__init__.py +3 -0
  48. agno/db/mysql/mysql.py +1719 -0
  49. agno/db/mysql/schemas.py +124 -0
  50. agno/db/mysql/utils.py +297 -0
  51. agno/db/postgres/__init__.py +3 -0
  52. agno/db/postgres/postgres.py +1710 -0
  53. agno/db/postgres/schemas.py +124 -0
  54. agno/db/postgres/utils.py +280 -0
  55. agno/db/redis/__init__.py +3 -0
  56. agno/db/redis/redis.py +1367 -0
  57. agno/db/redis/schemas.py +109 -0
  58. agno/db/redis/utils.py +288 -0
  59. agno/db/schemas/__init__.py +3 -0
  60. agno/db/schemas/evals.py +33 -0
  61. agno/db/schemas/knowledge.py +40 -0
  62. agno/db/schemas/memory.py +46 -0
  63. agno/db/singlestore/__init__.py +3 -0
  64. agno/db/singlestore/schemas.py +116 -0
  65. agno/db/singlestore/singlestore.py +1712 -0
  66. agno/db/singlestore/utils.py +326 -0
  67. agno/db/sqlite/__init__.py +3 -0
  68. agno/db/sqlite/schemas.py +119 -0
  69. agno/db/sqlite/sqlite.py +1676 -0
  70. agno/db/sqlite/utils.py +268 -0
  71. agno/db/utils.py +88 -0
  72. agno/eval/__init__.py +14 -0
  73. agno/eval/accuracy.py +154 -48
  74. agno/eval/performance.py +88 -23
  75. agno/eval/reliability.py +73 -20
  76. agno/eval/utils.py +23 -13
  77. agno/integrations/discord/__init__.py +3 -0
  78. agno/{app → integrations}/discord/client.py +10 -10
  79. agno/knowledge/__init__.py +2 -2
  80. agno/{document → knowledge}/chunking/agentic.py +2 -2
  81. agno/{document → knowledge}/chunking/document.py +2 -2
  82. agno/{document → knowledge}/chunking/fixed.py +3 -3
  83. agno/{document → knowledge}/chunking/markdown.py +2 -2
  84. agno/{document → knowledge}/chunking/recursive.py +2 -2
  85. agno/{document → knowledge}/chunking/row.py +2 -2
  86. agno/knowledge/chunking/semantic.py +59 -0
  87. agno/knowledge/chunking/strategy.py +121 -0
  88. agno/knowledge/content.py +74 -0
  89. agno/knowledge/document/__init__.py +5 -0
  90. agno/{document → knowledge/document}/base.py +12 -2
  91. agno/knowledge/embedder/__init__.py +5 -0
  92. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  93. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  94. agno/{embedder → knowledge/embedder}/base.py +6 -0
  95. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  96. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  97. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  98. agno/{embedder → knowledge/embedder}/google.py +74 -1
  99. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  100. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  101. agno/knowledge/embedder/langdb.py +22 -0
  102. agno/knowledge/embedder/mistral.py +139 -0
  103. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  104. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  105. agno/knowledge/embedder/openai.py +223 -0
  106. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  107. agno/{embedder → knowledge/embedder}/together.py +1 -1
  108. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  109. agno/knowledge/knowledge.py +1551 -0
  110. agno/knowledge/reader/__init__.py +7 -0
  111. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  112. agno/knowledge/reader/base.py +88 -0
  113. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  114. agno/knowledge/reader/docx_reader.py +83 -0
  115. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  116. agno/{document → knowledge}/reader/json_reader.py +30 -9
  117. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  118. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  119. agno/knowledge/reader/reader_factory.py +268 -0
  120. agno/knowledge/reader/s3_reader.py +101 -0
  121. agno/{document → knowledge}/reader/text_reader.py +31 -10
  122. agno/knowledge/reader/url_reader.py +128 -0
  123. agno/knowledge/reader/web_search_reader.py +366 -0
  124. agno/{document → knowledge}/reader/website_reader.py +37 -10
  125. agno/knowledge/reader/wikipedia_reader.py +59 -0
  126. agno/knowledge/reader/youtube_reader.py +78 -0
  127. agno/knowledge/remote_content/remote_content.py +88 -0
  128. agno/{reranker → knowledge/reranker}/base.py +1 -1
  129. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  130. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  131. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  132. agno/knowledge/types.py +30 -0
  133. agno/knowledge/utils.py +169 -0
  134. agno/media.py +269 -268
  135. agno/memory/__init__.py +2 -10
  136. agno/memory/manager.py +1003 -148
  137. agno/models/aimlapi/__init__.py +2 -2
  138. agno/models/aimlapi/aimlapi.py +6 -6
  139. agno/models/anthropic/claude.py +128 -72
  140. agno/models/aws/bedrock.py +107 -175
  141. agno/models/aws/claude.py +64 -18
  142. agno/models/azure/ai_foundry.py +73 -23
  143. agno/models/base.py +346 -290
  144. agno/models/cerebras/cerebras.py +84 -27
  145. agno/models/cohere/chat.py +106 -98
  146. agno/models/google/gemini.py +105 -46
  147. agno/models/groq/groq.py +97 -35
  148. agno/models/huggingface/huggingface.py +92 -27
  149. agno/models/ibm/watsonx.py +72 -13
  150. agno/models/litellm/chat.py +85 -13
  151. agno/models/message.py +46 -151
  152. agno/models/meta/llama.py +85 -49
  153. agno/models/metrics.py +120 -0
  154. agno/models/mistral/mistral.py +90 -21
  155. agno/models/ollama/__init__.py +0 -2
  156. agno/models/ollama/chat.py +85 -47
  157. agno/models/openai/chat.py +154 -37
  158. agno/models/openai/responses.py +178 -105
  159. agno/models/perplexity/perplexity.py +26 -2
  160. agno/models/portkey/portkey.py +0 -7
  161. agno/models/response.py +15 -9
  162. agno/models/utils.py +20 -0
  163. agno/models/vercel/__init__.py +2 -2
  164. agno/models/vercel/v0.py +1 -1
  165. agno/models/vllm/__init__.py +2 -2
  166. agno/models/vllm/vllm.py +3 -3
  167. agno/models/xai/xai.py +10 -10
  168. agno/os/__init__.py +3 -0
  169. agno/os/app.py +497 -0
  170. agno/os/auth.py +47 -0
  171. agno/os/config.py +103 -0
  172. agno/os/interfaces/agui/__init__.py +3 -0
  173. agno/os/interfaces/agui/agui.py +31 -0
  174. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  175. agno/{app → os/interfaces}/agui/utils.py +65 -28
  176. agno/os/interfaces/base.py +21 -0
  177. agno/os/interfaces/slack/__init__.py +3 -0
  178. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  179. agno/os/interfaces/slack/slack.py +32 -0
  180. agno/os/interfaces/whatsapp/__init__.py +3 -0
  181. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  182. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  183. agno/os/mcp.py +235 -0
  184. agno/os/router.py +1400 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +393 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +850 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +410 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +178 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +536 -0
  201. agno/os/schema.py +945 -0
  202. agno/{app/playground → os}/settings.py +7 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/agent.py +633 -0
  212. agno/run/base.py +53 -77
  213. agno/run/cancel.py +81 -0
  214. agno/run/team.py +243 -96
  215. agno/run/workflow.py +550 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +3260 -4824
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +43 -23
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +20 -17
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +22 -12
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +17 -8
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +62 -62
  252. agno/tools/eleven_labs.py +36 -29
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +30 -30
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +17 -18
  260. agno/tools/function.py +127 -18
  261. agno/tools/giphy.py +23 -11
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +32 -20
  276. agno/tools/mcp.py +1 -2
  277. agno/tools/mem0.py +18 -12
  278. agno/tools/memori.py +14 -10
  279. agno/tools/mlx_transcribe.py +3 -2
  280. agno/tools/models/azure_openai.py +33 -15
  281. agno/tools/models/gemini.py +59 -32
  282. agno/tools/models/groq.py +30 -23
  283. agno/tools/models/nebius.py +28 -12
  284. agno/tools/models_labs.py +40 -16
  285. agno/tools/moviepy_video.py +7 -6
  286. agno/tools/neo4j.py +10 -8
  287. agno/tools/newspaper.py +7 -2
  288. agno/tools/newspaper4k.py +8 -3
  289. agno/tools/openai.py +58 -32
  290. agno/tools/openbb.py +12 -11
  291. agno/tools/opencv.py +63 -47
  292. agno/tools/openweather.py +14 -12
  293. agno/tools/pandas.py +11 -3
  294. agno/tools/postgres.py +4 -12
  295. agno/tools/pubmed.py +4 -1
  296. agno/tools/python.py +9 -22
  297. agno/tools/reasoning.py +35 -27
  298. agno/tools/reddit.py +11 -26
  299. agno/tools/replicate.py +55 -42
  300. agno/tools/resend.py +4 -1
  301. agno/tools/scrapegraph.py +15 -14
  302. agno/tools/searxng.py +10 -23
  303. agno/tools/serpapi.py +6 -3
  304. agno/tools/serper.py +13 -4
  305. agno/tools/shell.py +9 -2
  306. agno/tools/slack.py +12 -11
  307. agno/tools/sleep.py +3 -2
  308. agno/tools/spider.py +24 -4
  309. agno/tools/sql.py +7 -6
  310. agno/tools/tavily.py +6 -4
  311. agno/tools/telegram.py +12 -4
  312. agno/tools/todoist.py +11 -31
  313. agno/tools/toolkit.py +1 -1
  314. agno/tools/trafilatura.py +22 -6
  315. agno/tools/trello.py +9 -22
  316. agno/tools/twilio.py +10 -3
  317. agno/tools/user_control_flow.py +6 -1
  318. agno/tools/valyu.py +34 -5
  319. agno/tools/visualization.py +19 -28
  320. agno/tools/webbrowser.py +4 -3
  321. agno/tools/webex.py +11 -7
  322. agno/tools/website.py +15 -46
  323. agno/tools/webtools.py +12 -4
  324. agno/tools/whatsapp.py +5 -9
  325. agno/tools/wikipedia.py +20 -13
  326. agno/tools/x.py +14 -13
  327. agno/tools/yfinance.py +13 -40
  328. agno/tools/youtube.py +26 -20
  329. agno/tools/zendesk.py +7 -2
  330. agno/tools/zep.py +10 -7
  331. agno/tools/zoom.py +10 -9
  332. agno/utils/common.py +1 -19
  333. agno/utils/events.py +100 -123
  334. agno/utils/gemini.py +1 -1
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/log.py +54 -4
  337. agno/utils/mcp.py +68 -10
  338. agno/utils/media.py +39 -0
  339. agno/utils/message.py +12 -1
  340. agno/utils/models/aws_claude.py +1 -1
  341. agno/utils/models/claude.py +6 -12
  342. agno/utils/models/cohere.py +1 -1
  343. agno/utils/models/mistral.py +8 -7
  344. agno/utils/models/schema_utils.py +3 -3
  345. agno/utils/models/watsonx.py +1 -1
  346. agno/utils/openai.py +1 -1
  347. agno/utils/pprint.py +33 -32
  348. agno/utils/print_response/agent.py +779 -0
  349. agno/utils/print_response/team.py +1669 -0
  350. agno/utils/print_response/workflow.py +1451 -0
  351. agno/utils/prompts.py +14 -14
  352. agno/utils/reasoning.py +87 -0
  353. agno/utils/response.py +42 -42
  354. agno/utils/streamlit.py +481 -0
  355. agno/utils/string.py +8 -22
  356. agno/utils/team.py +50 -0
  357. agno/utils/timer.py +2 -2
  358. agno/vectordb/base.py +33 -21
  359. agno/vectordb/cassandra/cassandra.py +287 -23
  360. agno/vectordb/chroma/chromadb.py +482 -59
  361. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  362. agno/vectordb/couchbase/couchbase.py +309 -29
  363. agno/vectordb/lancedb/lance_db.py +360 -21
  364. agno/vectordb/langchaindb/__init__.py +5 -0
  365. agno/vectordb/langchaindb/langchaindb.py +145 -0
  366. agno/vectordb/lightrag/__init__.py +5 -0
  367. agno/vectordb/lightrag/lightrag.py +374 -0
  368. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  369. agno/vectordb/milvus/milvus.py +242 -32
  370. agno/vectordb/mongodb/mongodb.py +200 -24
  371. agno/vectordb/pgvector/pgvector.py +319 -37
  372. agno/vectordb/pineconedb/pineconedb.py +221 -27
  373. agno/vectordb/qdrant/qdrant.py +334 -14
  374. agno/vectordb/singlestore/singlestore.py +286 -29
  375. agno/vectordb/surrealdb/surrealdb.py +187 -7
  376. agno/vectordb/upstashdb/upstashdb.py +342 -26
  377. agno/vectordb/weaviate/weaviate.py +227 -165
  378. agno/workflow/__init__.py +17 -13
  379. agno/workflow/{v2/condition.py → condition.py} +135 -32
  380. agno/workflow/{v2/loop.py → loop.py} +115 -28
  381. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  382. agno/workflow/{v2/router.py → router.py} +133 -32
  383. agno/workflow/{v2/step.py → step.py} +207 -49
  384. agno/workflow/{v2/steps.py → steps.py} +147 -66
  385. agno/workflow/types.py +482 -0
  386. agno/workflow/workflow.py +2410 -696
  387. agno-2.0.0.dist-info/METADATA +494 -0
  388. agno-2.0.0.dist-info/RECORD +515 -0
  389. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  390. agno/agent/metrics.py +0 -110
  391. agno/api/app.py +0 -35
  392. agno/api/playground.py +0 -92
  393. agno/api/schemas/app.py +0 -12
  394. agno/api/schemas/playground.py +0 -22
  395. agno/api/schemas/user.py +0 -35
  396. agno/api/schemas/workspace.py +0 -46
  397. agno/api/user.py +0 -160
  398. agno/api/workflows.py +0 -33
  399. agno/api/workspace.py +0 -175
  400. agno/app/agui/__init__.py +0 -3
  401. agno/app/agui/app.py +0 -17
  402. agno/app/agui/sync_router.py +0 -120
  403. agno/app/base.py +0 -186
  404. agno/app/discord/__init__.py +0 -3
  405. agno/app/fastapi/__init__.py +0 -3
  406. agno/app/fastapi/app.py +0 -107
  407. agno/app/fastapi/async_router.py +0 -457
  408. agno/app/fastapi/sync_router.py +0 -448
  409. agno/app/playground/app.py +0 -228
  410. agno/app/playground/async_router.py +0 -1053
  411. agno/app/playground/deploy.py +0 -249
  412. agno/app/playground/operator.py +0 -183
  413. agno/app/playground/schemas.py +0 -223
  414. agno/app/playground/serve.py +0 -55
  415. agno/app/playground/sync_router.py +0 -1045
  416. agno/app/playground/utils.py +0 -46
  417. agno/app/settings.py +0 -15
  418. agno/app/slack/__init__.py +0 -3
  419. agno/app/slack/app.py +0 -19
  420. agno/app/slack/sync_router.py +0 -92
  421. agno/app/utils.py +0 -54
  422. agno/app/whatsapp/__init__.py +0 -3
  423. agno/app/whatsapp/app.py +0 -15
  424. agno/app/whatsapp/sync_router.py +0 -197
  425. agno/cli/auth_server.py +0 -249
  426. agno/cli/config.py +0 -274
  427. agno/cli/console.py +0 -88
  428. agno/cli/credentials.py +0 -23
  429. agno/cli/entrypoint.py +0 -571
  430. agno/cli/operator.py +0 -357
  431. agno/cli/settings.py +0 -96
  432. agno/cli/ws/ws_cli.py +0 -817
  433. agno/constants.py +0 -13
  434. agno/document/__init__.py +0 -5
  435. agno/document/chunking/semantic.py +0 -45
  436. agno/document/chunking/strategy.py +0 -31
  437. agno/document/reader/__init__.py +0 -5
  438. agno/document/reader/base.py +0 -47
  439. agno/document/reader/docx_reader.py +0 -60
  440. agno/document/reader/gcs/pdf_reader.py +0 -44
  441. agno/document/reader/s3/pdf_reader.py +0 -59
  442. agno/document/reader/s3/text_reader.py +0 -63
  443. agno/document/reader/url_reader.py +0 -59
  444. agno/document/reader/youtube_reader.py +0 -58
  445. agno/embedder/__init__.py +0 -5
  446. agno/embedder/langdb.py +0 -80
  447. agno/embedder/mistral.py +0 -82
  448. agno/embedder/openai.py +0 -78
  449. agno/file/__init__.py +0 -5
  450. agno/file/file.py +0 -16
  451. agno/file/local/csv.py +0 -32
  452. agno/file/local/txt.py +0 -19
  453. agno/infra/app.py +0 -240
  454. agno/infra/base.py +0 -144
  455. agno/infra/context.py +0 -20
  456. agno/infra/db_app.py +0 -52
  457. agno/infra/resource.py +0 -205
  458. agno/infra/resources.py +0 -55
  459. agno/knowledge/agent.py +0 -702
  460. agno/knowledge/arxiv.py +0 -33
  461. agno/knowledge/combined.py +0 -36
  462. agno/knowledge/csv.py +0 -144
  463. agno/knowledge/csv_url.py +0 -124
  464. agno/knowledge/document.py +0 -223
  465. agno/knowledge/docx.py +0 -137
  466. agno/knowledge/firecrawl.py +0 -34
  467. agno/knowledge/gcs/__init__.py +0 -0
  468. agno/knowledge/gcs/base.py +0 -39
  469. agno/knowledge/gcs/pdf.py +0 -125
  470. agno/knowledge/json.py +0 -137
  471. agno/knowledge/langchain.py +0 -71
  472. agno/knowledge/light_rag.py +0 -273
  473. agno/knowledge/llamaindex.py +0 -66
  474. agno/knowledge/markdown.py +0 -154
  475. agno/knowledge/pdf.py +0 -164
  476. agno/knowledge/pdf_bytes.py +0 -42
  477. agno/knowledge/pdf_url.py +0 -148
  478. agno/knowledge/s3/__init__.py +0 -0
  479. agno/knowledge/s3/base.py +0 -64
  480. agno/knowledge/s3/pdf.py +0 -33
  481. agno/knowledge/s3/text.py +0 -34
  482. agno/knowledge/text.py +0 -141
  483. agno/knowledge/url.py +0 -46
  484. agno/knowledge/website.py +0 -179
  485. agno/knowledge/wikipedia.py +0 -32
  486. agno/knowledge/youtube.py +0 -35
  487. agno/memory/agent.py +0 -423
  488. agno/memory/classifier.py +0 -104
  489. agno/memory/db/__init__.py +0 -5
  490. agno/memory/db/base.py +0 -42
  491. agno/memory/db/mongodb.py +0 -189
  492. agno/memory/db/postgres.py +0 -203
  493. agno/memory/db/sqlite.py +0 -193
  494. agno/memory/memory.py +0 -22
  495. agno/memory/row.py +0 -36
  496. agno/memory/summarizer.py +0 -201
  497. agno/memory/summary.py +0 -19
  498. agno/memory/team.py +0 -415
  499. agno/memory/v2/__init__.py +0 -2
  500. agno/memory/v2/db/__init__.py +0 -1
  501. agno/memory/v2/db/base.py +0 -42
  502. agno/memory/v2/db/firestore.py +0 -339
  503. agno/memory/v2/db/mongodb.py +0 -196
  504. agno/memory/v2/db/postgres.py +0 -214
  505. agno/memory/v2/db/redis.py +0 -187
  506. agno/memory/v2/db/schema.py +0 -54
  507. agno/memory/v2/db/sqlite.py +0 -209
  508. agno/memory/v2/manager.py +0 -437
  509. agno/memory/v2/memory.py +0 -1097
  510. agno/memory/v2/schema.py +0 -55
  511. agno/memory/v2/summarizer.py +0 -215
  512. agno/memory/workflow.py +0 -38
  513. agno/models/ollama/tools.py +0 -430
  514. agno/models/qwen/__init__.py +0 -5
  515. agno/playground/__init__.py +0 -10
  516. agno/playground/deploy.py +0 -3
  517. agno/playground/playground.py +0 -3
  518. agno/playground/serve.py +0 -3
  519. agno/playground/settings.py +0 -3
  520. agno/reranker/__init__.py +0 -0
  521. agno/run/response.py +0 -467
  522. agno/run/v2/__init__.py +0 -0
  523. agno/run/v2/workflow.py +0 -567
  524. agno/storage/__init__.py +0 -0
  525. agno/storage/agent/__init__.py +0 -0
  526. agno/storage/agent/dynamodb.py +0 -1
  527. agno/storage/agent/json.py +0 -1
  528. agno/storage/agent/mongodb.py +0 -1
  529. agno/storage/agent/postgres.py +0 -1
  530. agno/storage/agent/singlestore.py +0 -1
  531. agno/storage/agent/sqlite.py +0 -1
  532. agno/storage/agent/yaml.py +0 -1
  533. agno/storage/base.py +0 -60
  534. agno/storage/dynamodb.py +0 -673
  535. agno/storage/firestore.py +0 -297
  536. agno/storage/gcs_json.py +0 -261
  537. agno/storage/in_memory.py +0 -234
  538. agno/storage/json.py +0 -237
  539. agno/storage/mongodb.py +0 -328
  540. agno/storage/mysql.py +0 -685
  541. agno/storage/postgres.py +0 -682
  542. agno/storage/redis.py +0 -336
  543. agno/storage/session/__init__.py +0 -16
  544. agno/storage/session/agent.py +0 -64
  545. agno/storage/session/team.py +0 -63
  546. agno/storage/session/v2/__init__.py +0 -5
  547. agno/storage/session/workflow.py +0 -61
  548. agno/storage/singlestore.py +0 -606
  549. agno/storage/sqlite.py +0 -646
  550. agno/storage/workflow/__init__.py +0 -0
  551. agno/storage/workflow/mongodb.py +0 -1
  552. agno/storage/workflow/postgres.py +0 -1
  553. agno/storage/workflow/sqlite.py +0 -1
  554. agno/storage/yaml.py +0 -241
  555. agno/tools/thinking.py +0 -73
  556. agno/utils/defaults.py +0 -57
  557. agno/utils/filesystem.py +0 -39
  558. agno/utils/git.py +0 -52
  559. agno/utils/json_io.py +0 -30
  560. agno/utils/load_env.py +0 -19
  561. agno/utils/py_io.py +0 -19
  562. agno/utils/pyproject.py +0 -18
  563. agno/utils/resource_filter.py +0 -31
  564. agno/workflow/v2/__init__.py +0 -21
  565. agno/workflow/v2/types.py +0 -357
  566. agno/workflow/v2/workflow.py +0 -3313
  567. agno/workspace/__init__.py +0 -0
  568. agno/workspace/config.py +0 -325
  569. agno/workspace/enums.py +0 -6
  570. agno/workspace/helpers.py +0 -52
  571. agno/workspace/operator.py +0 -757
  572. agno/workspace/settings.py +0 -158
  573. agno-1.8.2.dist-info/METADATA +0 -982
  574. agno-1.8.2.dist-info/RECORD +0 -566
  575. agno-1.8.2.dist-info/entry_points.txt +0 -3
  576. agno-1.8.2.dist-info/licenses/LICENSE +0 -375
  577. /agno/{app → db/migrations}/__init__.py +0 -0
  578. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  579. /agno/{cli → integrations}/__init__.py +0 -0
  580. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  581. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  582. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  583. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  584. /agno/{app → os/interfaces}/slack/security.py +0 -0
  585. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  586. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  587. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  588. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  589. {agno-1.8.2.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