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
@@ -3,10 +3,10 @@ import time
3
3
  from datetime import timedelta
4
4
  from typing import Any, Dict, List, Optional, Union
5
5
 
6
- from agno.document import Document
7
- from agno.embedder import Embedder
8
- from agno.embedder.openai import OpenAIEmbedder
9
- from agno.utils.log import log_debug, logger
6
+ from agno.knowledge.document import Document
7
+ from agno.knowledge.embedder import Embedder
8
+ from agno.knowledge.embedder.openai import OpenAIEmbedder
9
+ from agno.utils.log import log_debug, log_info, logger
10
10
  from agno.vectordb.base import VectorDb
11
11
 
12
12
  try:
@@ -287,12 +287,7 @@ class CouchbaseSearch(VectorDb):
287
287
  self._create_collection_and_scope()
288
288
  self._create_fts_index()
289
289
 
290
- def doc_exists(self, document: Document) -> bool:
291
- """Check if a document exists in the bucket based on its content."""
292
- doc_id = md5(document.content.encode("utf-8")).hexdigest()
293
- return self.id_exists(doc_id)
294
-
295
- def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
290
+ def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
296
291
  """
297
292
  Insert documents into the Couchbase bucket. Fails if any document already exists.
298
293
 
@@ -304,8 +299,13 @@ class CouchbaseSearch(VectorDb):
304
299
 
305
300
  docs_to_insert: Dict[str, Any] = {}
306
301
  for document in documents:
302
+ if document.embedding is None:
303
+ document.embed(embedder=self.embedder)
304
+
305
+ if document.embedding is None:
306
+ raise ValueError(f"Failed to generate embedding for document: {document.name}")
307
307
  try:
308
- doc_data = self.prepare_doc(document)
308
+ doc_data = self.prepare_doc(content_hash, document)
309
309
  if filters:
310
310
  doc_data["filters"] = filters
311
311
  # For insert_multi, the key of the dict is the document ID,
@@ -367,7 +367,19 @@ class CouchbaseSearch(VectorDb):
367
367
  if errors_occurred:
368
368
  logger.warning("Some errors occurred during the insert operation. Please check logs for details.")
369
369
 
370
- def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
370
+ def upsert_available(self) -> bool:
371
+ """Check if upsert is available in Couchbase."""
372
+ return True
373
+
374
+ def _upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
375
+ """
376
+ Update existing documents or insert new ones into the Couchbase bucket.
377
+ """
378
+ if self.content_hash_exists(content_hash):
379
+ self._delete_by_content_hash(content_hash)
380
+ self.insert(content_hash=content_hash, documents=documents, filters=filters)
381
+
382
+ def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
371
383
  """
372
384
  Update existing documents or insert new ones into the Couchbase bucket.
373
385
 
@@ -380,7 +392,13 @@ class CouchbaseSearch(VectorDb):
380
392
  docs_to_upsert: Dict[str, Any] = {}
381
393
  for document in documents:
382
394
  try:
383
- doc_data = self.prepare_doc(document)
395
+ if document.embedding is None:
396
+ document.embed(embedder=self.embedder)
397
+
398
+ if document.embedding is None:
399
+ raise ValueError(f"Failed to generate embedding for document: {document.name}")
400
+
401
+ doc_data = self.prepare_doc(content_hash, document)
384
402
  if filters:
385
403
  doc_data["filters"] = filters
386
404
  # For upsert_multi, the key of the dict is the document ID,
@@ -506,6 +524,7 @@ class CouchbaseSearch(VectorDb):
506
524
  content=value["content"],
507
525
  meta_data=value["meta_data"],
508
526
  embedding=value["embedding"],
527
+ content_id=value.get("content_id"),
509
528
  )
510
529
  )
511
530
 
@@ -543,7 +562,7 @@ class CouchbaseSearch(VectorDb):
543
562
  except Exception:
544
563
  return False
545
564
 
546
- def prepare_doc(self, document: Document) -> Dict[str, Any]:
565
+ def prepare_doc(self, content_hash: str, document: Document) -> Dict[str, Any]:
547
566
  """
548
567
  Prepare a document for insertion into Couchbase.
549
568
 
@@ -561,13 +580,6 @@ class CouchbaseSearch(VectorDb):
561
580
 
562
581
  logger.debug(f"Preparing document: {document.name}")
563
582
 
564
- # Generate embedding if needed
565
- if document.embedding is None:
566
- document.embed(embedder=self.embedder)
567
-
568
- if document.embedding is None:
569
- raise ValueError(f"Failed to generate embedding for document: {document.name}")
570
-
571
583
  # Clean content and generate ID
572
584
  cleaned_content = document.content.replace("\x00", "\ufffd")
573
585
  doc_id = md5(cleaned_content.encode("utf-8")).hexdigest()
@@ -578,6 +590,8 @@ class CouchbaseSearch(VectorDb):
578
590
  "content": cleaned_content,
579
591
  "meta_data": document.meta_data, # Ensure meta_data is never None
580
592
  "embedding": document.embedding,
593
+ "content_id": document.content_id,
594
+ "content_hash": content_hash,
581
595
  }
582
596
 
583
597
  def get_count(self) -> int:
@@ -617,6 +631,24 @@ class CouchbaseSearch(VectorDb):
617
631
  logger.error(f"Error checking document existence: {e}")
618
632
  return False
619
633
 
634
+ def content_hash_exists(self, content_hash: str) -> bool:
635
+ """Check if a document exists in the bucket based on its content hash."""
636
+ try:
637
+ # Use N1QL query to check if document with given content_hash exists
638
+ query = f"SELECT content_hash FROM {self.bucket_name}.{self.scope_name}.{self.collection_name} WHERE content_hash = $content_hash LIMIT 1"
639
+ result = self.scope.query(
640
+ query,
641
+ QueryOptions(
642
+ named_parameters={"content_hash": content_hash}, scan_consistency=QueryScanConsistency.REQUEST_PLUS
643
+ ),
644
+ )
645
+ for row in result.rows():
646
+ return True
647
+ return False
648
+ except Exception as e:
649
+ logger.error(f"Error checking document content_hash existence: {e}")
650
+ return False
651
+
620
652
  # === ASYNC SUPPORT USING acouchbase ===
621
653
 
622
654
  async def _create_async_cluster_instance(self) -> AsyncCluster:
@@ -806,10 +838,6 @@ class CouchbaseSearch(VectorDb):
806
838
  raise TimeoutError("Timeout waiting for FTS index to become ready")
807
839
  await asyncio.sleep(1)
808
840
 
809
- async def async_doc_exists(self, document: Document) -> bool:
810
- doc_id = md5(document.content.encode("utf-8")).hexdigest()
811
- return await self.async_id_exists(doc_id)
812
-
813
841
  async def async_id_exists(self, id: str) -> bool:
814
842
  try:
815
843
  async_collection_instance = await self.get_async_collection()
@@ -835,16 +863,21 @@ class CouchbaseSearch(VectorDb):
835
863
  logger.error(f"[async] Error checking document name existence: {e}")
836
864
  return False
837
865
 
838
- async def async_insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
866
+ async def async_insert(
867
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
868
+ ) -> None:
839
869
  logger.info(f"[async] Inserting {len(documents)} documents")
840
870
 
841
871
  async_collection_instance = await self.get_async_collection()
842
872
  all_docs_to_insert: Dict[str, Any] = {}
843
873
 
874
+ embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
875
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
876
+
844
877
  for document in documents:
845
878
  try:
846
879
  # User edit: self.prepare_doc is no longer awaited with to_thread
847
- doc_data = self.prepare_doc(document)
880
+ doc_data = self.prepare_doc(content_hash, document)
848
881
  if filters:
849
882
  doc_data["filters"] = filters
850
883
  doc_id = doc_data.pop("_id") # Remove _id as it's used as key
@@ -888,16 +921,29 @@ class CouchbaseSearch(VectorDb):
888
921
  logger.info(f"[async] Finished processing {processed_doc_count} documents.")
889
922
  logger.info(f"[async] Total successfully inserted: {total_inserted_count}, Total failed: {total_failed_count}.")
890
923
 
891
- async def async_upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
924
+ async def async_upsert(
925
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
926
+ ) -> None:
927
+ """Upsert documents asynchronously."""
928
+ if self.content_hash_exists(content_hash):
929
+ self._delete_by_content_hash(content_hash)
930
+ await self._async_upsert(content_hash=content_hash, documents=documents, filters=filters)
931
+
932
+ async def _async_upsert(
933
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
934
+ ) -> None:
892
935
  logger.info(f"[async] Upserting {len(documents)} documents")
893
936
 
894
937
  async_collection_instance = await self.get_async_collection()
895
938
  all_docs_to_upsert: Dict[str, Any] = {}
896
939
 
940
+ embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
941
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
942
+
897
943
  for document in documents:
898
944
  try:
899
945
  # Consistent with async_insert, prepare_doc is not awaited with to_thread based on prior user edits
900
- doc_data = self.prepare_doc(document)
946
+ doc_data = self.prepare_doc(content_hash, document)
901
947
  if filters:
902
948
  doc_data["filters"] = filters
903
949
  doc_id = doc_data.pop("_id") # _id is used as key for upsert
@@ -1069,3 +1115,237 @@ class CouchbaseSearch(VectorDb):
1069
1115
  continue
1070
1116
 
1071
1117
  return documents
1118
+
1119
+ def delete_by_id(self, id: str) -> bool:
1120
+ """
1121
+ Delete a document by its ID.
1122
+
1123
+ Args:
1124
+ id (str): The document ID to delete
1125
+
1126
+ Returns:
1127
+ bool: True if document was deleted, False otherwise
1128
+ """
1129
+ try:
1130
+ log_debug(f"Couchbase VectorDB : Deleting document with ID {id}")
1131
+ if not self.id_exists(id):
1132
+ return False
1133
+
1134
+ # Delete by ID using Couchbase collection.delete()
1135
+ self.collection.remove(id)
1136
+ log_info(f"Successfully deleted document with ID {id}")
1137
+ return True
1138
+ except Exception as e:
1139
+ log_info(f"Error deleting document with ID {id}: {e}")
1140
+ return False
1141
+
1142
+ def delete_by_name(self, name: str) -> bool:
1143
+ """
1144
+ Delete documents by name.
1145
+
1146
+ Args:
1147
+ name (str): The document name to delete
1148
+
1149
+ Returns:
1150
+ bool: True if documents were deleted, False otherwise
1151
+ """
1152
+ try:
1153
+ log_debug(f"Couchbase VectorDB : Deleting documents with name {name}")
1154
+
1155
+ query = f"SELECT META().id as doc_id, * FROM {self.bucket_name}.{self.scope_name}.{self.collection_name} WHERE name = $name"
1156
+ result = self.scope.query(
1157
+ query, QueryOptions(named_parameters={"name": name}, scan_consistency=QueryScanConsistency.REQUEST_PLUS)
1158
+ )
1159
+ rows = list(result.rows()) # Collect once
1160
+
1161
+ for row in rows:
1162
+ self.collection.remove(row.get("doc_id"))
1163
+ log_info(f"Deleted {len(rows)} documents with name {name}")
1164
+ return True
1165
+
1166
+ except Exception as e:
1167
+ log_info(f"Error deleting documents with name {name}: {e}")
1168
+ return False
1169
+
1170
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
1171
+ """
1172
+ Delete documents by metadata.
1173
+
1174
+ Args:
1175
+ metadata (Dict[str, Any]): The metadata to match for deletion
1176
+
1177
+ Returns:
1178
+ bool: True if documents were deleted, False otherwise
1179
+ """
1180
+ try:
1181
+ log_debug(f"Couchbase VectorDB : Deleting documents with metadata {metadata}")
1182
+
1183
+ if not metadata:
1184
+ log_info("No metadata provided for deletion")
1185
+ return False
1186
+
1187
+ # Build WHERE clause for metadata matching
1188
+ where_conditions = []
1189
+ named_parameters: Dict[str, Any] = {}
1190
+
1191
+ for key, value in metadata.items():
1192
+ if isinstance(value, (list, tuple)):
1193
+ # For array values, use ARRAY_CONTAINS
1194
+ where_conditions.append(
1195
+ f"(ARRAY_CONTAINS(filters.{key}, $value_{key}) OR ARRAY_CONTAINS(recipes.filters.{key}, $value_{key}))"
1196
+ )
1197
+ named_parameters[f"value_{key}"] = value
1198
+ elif isinstance(value, str):
1199
+ where_conditions.append(f"(filters.{key} = $value_{key} OR recipes.filters.{key} = $value_{key})")
1200
+ named_parameters[f"value_{key}"] = value
1201
+ elif isinstance(value, bool):
1202
+ where_conditions.append(f"(filters.{key} = $value_{key} OR recipes.filters.{key} = $value_{key})")
1203
+ named_parameters[f"value_{key}"] = value
1204
+ elif isinstance(value, (int, float)):
1205
+ where_conditions.append(f"(filters.{key} = $value_{key} OR recipes.filters.{key} = $value_{key})")
1206
+ named_parameters[f"value_{key}"] = value
1207
+ elif value is None:
1208
+ where_conditions.append(f"(filters.{key} IS NULL OR recipes.filters.{key} IS NULL)")
1209
+ else:
1210
+ # For other types, convert to string
1211
+ where_conditions.append(f"(filters.{key} = $value_{key} OR recipes.filters.{key} = $value_{key})")
1212
+ named_parameters[f"value_{key}"] = str(value)
1213
+
1214
+ if not where_conditions:
1215
+ log_info("No valid metadata conditions for deletion")
1216
+ return False
1217
+
1218
+ where_clause = " AND ".join(where_conditions)
1219
+ query = f"SELECT META().id as doc_id, * FROM {self.bucket_name}.{self.scope_name}.{self.collection_name} WHERE {where_clause}"
1220
+
1221
+ result = self.scope.query(
1222
+ query,
1223
+ QueryOptions(named_parameters=named_parameters, scan_consistency=QueryScanConsistency.REQUEST_PLUS),
1224
+ )
1225
+ rows = list(result.rows()) # Collect once
1226
+
1227
+ for row in rows:
1228
+ print(row)
1229
+ self.collection.remove(row.get("doc_id"))
1230
+ log_info(f"Deleted {len(rows)} documents with metadata {metadata}")
1231
+ return True
1232
+
1233
+ except Exception as e:
1234
+ log_info(f"Error deleting documents with metadata {metadata}: {e}")
1235
+ return False
1236
+
1237
+ def delete_by_content_id(self, content_id: str) -> bool:
1238
+ """
1239
+ Delete documents by content ID.
1240
+
1241
+ Args:
1242
+ content_id (str): The content ID to delete
1243
+
1244
+ Returns:
1245
+ bool: True if documents were deleted, False otherwise
1246
+ """
1247
+ try:
1248
+ log_debug(f"Couchbase VectorDB : Deleting documents with content_id {content_id}")
1249
+
1250
+ query = f"SELECT META().id as doc_id, * FROM {self.bucket_name}.{self.scope_name}.{self.collection_name} WHERE content_id = $content_id OR recipes.content_id = $content_id"
1251
+ result = self.scope.query(
1252
+ query,
1253
+ QueryOptions(
1254
+ named_parameters={"content_id": content_id}, scan_consistency=QueryScanConsistency.REQUEST_PLUS
1255
+ ),
1256
+ )
1257
+ rows = list(result.rows()) # Collect once
1258
+
1259
+ for row in rows:
1260
+ self.collection.remove(row.get("doc_id"))
1261
+ log_info(f"Deleted {len(rows)} documents with content_id {content_id}")
1262
+ return True
1263
+
1264
+ except Exception as e:
1265
+ log_info(f"Error deleting documents with content_id {content_id}: {e}")
1266
+ return False
1267
+
1268
+ def _delete_by_content_hash(self, content_hash: str) -> bool:
1269
+ """
1270
+ Delete documents by content hash.
1271
+
1272
+ Args:
1273
+ content_hash (str): The content hash to delete
1274
+
1275
+ Returns:
1276
+ bool: True if documents were deleted, False otherwise
1277
+ """
1278
+ try:
1279
+ log_debug(f"Couchbase VectorDB : Deleting documents with content_hash {content_hash}")
1280
+
1281
+ query = f"SELECT META().id as doc_id, * FROM {self.bucket_name}.{self.scope_name}.{self.collection_name} WHERE content_hash = $content_hash"
1282
+ result = self.scope.query(
1283
+ query,
1284
+ QueryOptions(
1285
+ named_parameters={"content_hash": content_hash}, scan_consistency=QueryScanConsistency.REQUEST_PLUS
1286
+ ),
1287
+ )
1288
+ rows = list(result.rows()) # Collect once
1289
+
1290
+ for row in rows:
1291
+ self.collection.remove(row.get("doc_id"))
1292
+ log_info(f"Deleted {len(rows)} documents with content_hash {content_hash}")
1293
+ return True
1294
+
1295
+ except Exception as e:
1296
+ log_info(f"Error deleting documents with content_hash {content_hash}: {e}")
1297
+ return False
1298
+
1299
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
1300
+ """
1301
+ Update the metadata for documents with the given content_id.
1302
+
1303
+ Args:
1304
+ content_id (str): The content ID to update
1305
+ metadata (Dict[str, Any]): The metadata to update
1306
+ """
1307
+ try:
1308
+ # Query for documents with the given content_id
1309
+ query = f"SELECT META().id as doc_id, meta_data, filters FROM `{self.bucket_name}` WHERE content_id = $content_id"
1310
+ result = self.cluster.query(query, content_id=content_id)
1311
+
1312
+ updated_count = 0
1313
+ for row in result:
1314
+ doc_id = row.get("doc_id")
1315
+ current_metadata = row.get("meta_data", {})
1316
+ current_filters = row.get("filters", {})
1317
+
1318
+ # Merge existing metadata with new metadata
1319
+ if isinstance(current_metadata, dict):
1320
+ updated_metadata = current_metadata.copy()
1321
+ updated_metadata.update(metadata)
1322
+ else:
1323
+ updated_metadata = metadata
1324
+
1325
+ # Merge existing filters with new metadata
1326
+ if isinstance(current_filters, dict):
1327
+ updated_filters = current_filters.copy()
1328
+ updated_filters.update(metadata)
1329
+ else:
1330
+ updated_filters = metadata
1331
+
1332
+ # Update the document
1333
+ try:
1334
+ doc = self.collection.get(doc_id)
1335
+ doc_content = doc.content_as[dict]
1336
+ doc_content["meta_data"] = updated_metadata
1337
+ doc_content["filters"] = updated_filters
1338
+
1339
+ self.collection.upsert(doc_id, doc_content)
1340
+ updated_count += 1
1341
+ except Exception as doc_error:
1342
+ logger.warning(f"Failed to update document {doc_id}: {doc_error}")
1343
+
1344
+ if updated_count == 0:
1345
+ logger.debug(f"No documents found with content_id: {content_id}")
1346
+ else:
1347
+ logger.debug(f"Updated metadata for {updated_count} documents with content_id: {content_id}")
1348
+
1349
+ except Exception as e:
1350
+ logger.error(f"Error updating metadata for content_id '{content_id}': {e}")
1351
+ raise