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
@@ -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