agno 1.8.1__py3-none-any.whl → 2.0.0a1__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 (580) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2778 -4123
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  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 +9 -64
  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 +1749 -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 +1438 -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 +888 -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 +1051 -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 +1417 -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 +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -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 +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +142 -43
  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 +10 -10
  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 +1515 -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 +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  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 +129 -82
  141. agno/models/aws/bedrock.py +107 -175
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +347 -287
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +100 -42
  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 +38 -144
  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 +84 -46
  158. agno/models/openai/chat.py +121 -23
  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 +14 -8
  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 +393 -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 +65 -28
  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 +33 -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 +30 -0
  184. agno/os/router.py +843 -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 +204 -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 +413 -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 +179 -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 +58 -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 +163 -0
  201. agno/os/schema.py +892 -0
  202. agno/{app/playground → os}/settings.py +8 -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/{response.py → agent.py} +144 -72
  212. agno/run/base.py +44 -58
  213. agno/run/cancel.py +83 -0
  214. agno/run/team.py +133 -77
  215. agno/run/workflow.py +537 -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 +2961 -4253
  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 +42 -22
  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 +18 -13
  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 +18 -11
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +16 -7
  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 +61 -61
  252. agno/tools/eleven_labs.py +35 -28
  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 +29 -29
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +22 -22
  260. agno/tools/function.py +68 -17
  261. agno/tools/giphy.py +22 -10
  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 +31 -19
  276. agno/tools/mem0.py +18 -12
  277. agno/tools/memori.py +14 -10
  278. agno/tools/mlx_transcribe.py +3 -2
  279. agno/tools/models/azure_openai.py +32 -14
  280. agno/tools/models/gemini.py +58 -31
  281. agno/tools/models/groq.py +29 -20
  282. agno/tools/models/nebius.py +27 -11
  283. agno/tools/models_labs.py +39 -15
  284. agno/tools/moviepy_video.py +7 -6
  285. agno/tools/neo4j.py +10 -8
  286. agno/tools/newspaper.py +7 -2
  287. agno/tools/newspaper4k.py +8 -3
  288. agno/tools/openai.py +57 -26
  289. agno/tools/openbb.py +12 -11
  290. agno/tools/opencv.py +62 -46
  291. agno/tools/openweather.py +14 -12
  292. agno/tools/pandas.py +11 -3
  293. agno/tools/postgres.py +4 -12
  294. agno/tools/pubmed.py +4 -1
  295. agno/tools/python.py +9 -22
  296. agno/tools/reasoning.py +35 -27
  297. agno/tools/reddit.py +11 -26
  298. agno/tools/replicate.py +54 -41
  299. agno/tools/resend.py +4 -1
  300. agno/tools/scrapegraph.py +15 -14
  301. agno/tools/searxng.py +10 -23
  302. agno/tools/serpapi.py +6 -3
  303. agno/tools/serper.py +13 -4
  304. agno/tools/shell.py +9 -2
  305. agno/tools/slack.py +12 -11
  306. agno/tools/sleep.py +3 -2
  307. agno/tools/spider.py +24 -4
  308. agno/tools/sql.py +7 -6
  309. agno/tools/tavily.py +6 -4
  310. agno/tools/telegram.py +12 -4
  311. agno/tools/todoist.py +11 -31
  312. agno/tools/toolkit.py +1 -1
  313. agno/tools/trafilatura.py +22 -6
  314. agno/tools/trello.py +9 -22
  315. agno/tools/twilio.py +10 -3
  316. agno/tools/user_control_flow.py +6 -1
  317. agno/tools/valyu.py +34 -5
  318. agno/tools/visualization.py +19 -28
  319. agno/tools/webbrowser.py +4 -3
  320. agno/tools/webex.py +11 -7
  321. agno/tools/website.py +15 -46
  322. agno/tools/webtools.py +12 -4
  323. agno/tools/whatsapp.py +5 -9
  324. agno/tools/wikipedia.py +20 -13
  325. agno/tools/x.py +14 -13
  326. agno/tools/yfinance.py +13 -40
  327. agno/tools/youtube.py +26 -20
  328. agno/tools/zendesk.py +7 -2
  329. agno/tools/zep.py +10 -7
  330. agno/tools/zoom.py +10 -9
  331. agno/utils/common.py +1 -19
  332. agno/utils/events.py +95 -118
  333. agno/utils/knowledge.py +29 -0
  334. agno/utils/log.py +2 -2
  335. agno/utils/mcp.py +11 -5
  336. agno/utils/media.py +39 -0
  337. agno/utils/message.py +12 -1
  338. agno/utils/models/claude.py +6 -4
  339. agno/utils/models/mistral.py +8 -7
  340. agno/utils/models/schema_utils.py +3 -3
  341. agno/utils/pprint.py +33 -32
  342. agno/utils/print_response/agent.py +779 -0
  343. agno/utils/print_response/team.py +1565 -0
  344. agno/utils/print_response/workflow.py +1451 -0
  345. agno/utils/prompts.py +14 -14
  346. agno/utils/reasoning.py +87 -0
  347. agno/utils/response.py +42 -42
  348. agno/utils/string.py +8 -22
  349. agno/utils/team.py +50 -0
  350. agno/utils/timer.py +2 -2
  351. agno/vectordb/base.py +33 -21
  352. agno/vectordb/cassandra/cassandra.py +287 -23
  353. agno/vectordb/chroma/chromadb.py +482 -59
  354. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  355. agno/vectordb/couchbase/couchbase.py +309 -29
  356. agno/vectordb/lancedb/lance_db.py +360 -21
  357. agno/vectordb/langchaindb/__init__.py +5 -0
  358. agno/vectordb/langchaindb/langchaindb.py +145 -0
  359. agno/vectordb/lightrag/__init__.py +5 -0
  360. agno/vectordb/lightrag/lightrag.py +374 -0
  361. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  362. agno/vectordb/milvus/milvus.py +242 -32
  363. agno/vectordb/mongodb/mongodb.py +200 -24
  364. agno/vectordb/pgvector/pgvector.py +319 -37
  365. agno/vectordb/pineconedb/pineconedb.py +221 -27
  366. agno/vectordb/qdrant/qdrant.py +334 -14
  367. agno/vectordb/singlestore/singlestore.py +286 -29
  368. agno/vectordb/surrealdb/surrealdb.py +187 -7
  369. agno/vectordb/upstashdb/upstashdb.py +342 -26
  370. agno/vectordb/weaviate/weaviate.py +227 -165
  371. agno/workflow/__init__.py +17 -13
  372. agno/workflow/{v2/condition.py → condition.py} +135 -32
  373. agno/workflow/{v2/loop.py → loop.py} +115 -28
  374. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  375. agno/workflow/{v2/router.py → router.py} +133 -32
  376. agno/workflow/{v2/step.py → step.py} +200 -42
  377. agno/workflow/{v2/steps.py → steps.py} +147 -66
  378. agno/workflow/types.py +482 -0
  379. agno/workflow/workflow.py +2394 -696
  380. agno-2.0.0a1.dist-info/METADATA +355 -0
  381. agno-2.0.0a1.dist-info/RECORD +514 -0
  382. agno/agent/metrics.py +0 -107
  383. agno/api/app.py +0 -35
  384. agno/api/playground.py +0 -92
  385. agno/api/schemas/app.py +0 -12
  386. agno/api/schemas/playground.py +0 -22
  387. agno/api/schemas/user.py +0 -35
  388. agno/api/schemas/workspace.py +0 -46
  389. agno/api/user.py +0 -160
  390. agno/api/workflows.py +0 -33
  391. agno/api/workspace.py +0 -175
  392. agno/app/agui/__init__.py +0 -3
  393. agno/app/agui/app.py +0 -17
  394. agno/app/agui/sync_router.py +0 -120
  395. agno/app/base.py +0 -186
  396. agno/app/discord/__init__.py +0 -3
  397. agno/app/fastapi/__init__.py +0 -3
  398. agno/app/fastapi/app.py +0 -107
  399. agno/app/fastapi/async_router.py +0 -457
  400. agno/app/fastapi/sync_router.py +0 -448
  401. agno/app/playground/app.py +0 -228
  402. agno/app/playground/async_router.py +0 -1050
  403. agno/app/playground/deploy.py +0 -249
  404. agno/app/playground/operator.py +0 -183
  405. agno/app/playground/schemas.py +0 -220
  406. agno/app/playground/serve.py +0 -55
  407. agno/app/playground/sync_router.py +0 -1042
  408. agno/app/playground/utils.py +0 -46
  409. agno/app/settings.py +0 -15
  410. agno/app/slack/__init__.py +0 -3
  411. agno/app/slack/app.py +0 -19
  412. agno/app/slack/sync_router.py +0 -92
  413. agno/app/utils.py +0 -54
  414. agno/app/whatsapp/__init__.py +0 -3
  415. agno/app/whatsapp/app.py +0 -15
  416. agno/app/whatsapp/sync_router.py +0 -197
  417. agno/cli/auth_server.py +0 -249
  418. agno/cli/config.py +0 -274
  419. agno/cli/console.py +0 -88
  420. agno/cli/credentials.py +0 -23
  421. agno/cli/entrypoint.py +0 -571
  422. agno/cli/operator.py +0 -357
  423. agno/cli/settings.py +0 -96
  424. agno/cli/ws/ws_cli.py +0 -817
  425. agno/constants.py +0 -13
  426. agno/document/__init__.py +0 -5
  427. agno/document/chunking/semantic.py +0 -45
  428. agno/document/chunking/strategy.py +0 -31
  429. agno/document/reader/__init__.py +0 -5
  430. agno/document/reader/base.py +0 -47
  431. agno/document/reader/docx_reader.py +0 -60
  432. agno/document/reader/gcs/pdf_reader.py +0 -44
  433. agno/document/reader/s3/pdf_reader.py +0 -59
  434. agno/document/reader/s3/text_reader.py +0 -63
  435. agno/document/reader/url_reader.py +0 -59
  436. agno/document/reader/youtube_reader.py +0 -58
  437. agno/embedder/__init__.py +0 -5
  438. agno/embedder/langdb.py +0 -80
  439. agno/embedder/mistral.py +0 -82
  440. agno/embedder/openai.py +0 -78
  441. agno/file/__init__.py +0 -5
  442. agno/file/file.py +0 -16
  443. agno/file/local/csv.py +0 -32
  444. agno/file/local/txt.py +0 -19
  445. agno/infra/app.py +0 -240
  446. agno/infra/base.py +0 -144
  447. agno/infra/context.py +0 -20
  448. agno/infra/db_app.py +0 -52
  449. agno/infra/resource.py +0 -205
  450. agno/infra/resources.py +0 -55
  451. agno/knowledge/agent.py +0 -702
  452. agno/knowledge/arxiv.py +0 -33
  453. agno/knowledge/combined.py +0 -36
  454. agno/knowledge/csv.py +0 -144
  455. agno/knowledge/csv_url.py +0 -124
  456. agno/knowledge/document.py +0 -223
  457. agno/knowledge/docx.py +0 -137
  458. agno/knowledge/firecrawl.py +0 -34
  459. agno/knowledge/gcs/__init__.py +0 -0
  460. agno/knowledge/gcs/base.py +0 -39
  461. agno/knowledge/gcs/pdf.py +0 -125
  462. agno/knowledge/json.py +0 -137
  463. agno/knowledge/langchain.py +0 -71
  464. agno/knowledge/light_rag.py +0 -273
  465. agno/knowledge/llamaindex.py +0 -66
  466. agno/knowledge/markdown.py +0 -154
  467. agno/knowledge/pdf.py +0 -164
  468. agno/knowledge/pdf_bytes.py +0 -42
  469. agno/knowledge/pdf_url.py +0 -148
  470. agno/knowledge/s3/__init__.py +0 -0
  471. agno/knowledge/s3/base.py +0 -64
  472. agno/knowledge/s3/pdf.py +0 -33
  473. agno/knowledge/s3/text.py +0 -34
  474. agno/knowledge/text.py +0 -141
  475. agno/knowledge/url.py +0 -46
  476. agno/knowledge/website.py +0 -179
  477. agno/knowledge/wikipedia.py +0 -32
  478. agno/knowledge/youtube.py +0 -35
  479. agno/memory/agent.py +0 -423
  480. agno/memory/classifier.py +0 -104
  481. agno/memory/db/__init__.py +0 -5
  482. agno/memory/db/base.py +0 -42
  483. agno/memory/db/mongodb.py +0 -189
  484. agno/memory/db/postgres.py +0 -203
  485. agno/memory/db/sqlite.py +0 -193
  486. agno/memory/memory.py +0 -22
  487. agno/memory/row.py +0 -36
  488. agno/memory/summarizer.py +0 -201
  489. agno/memory/summary.py +0 -19
  490. agno/memory/team.py +0 -415
  491. agno/memory/v2/__init__.py +0 -2
  492. agno/memory/v2/db/__init__.py +0 -1
  493. agno/memory/v2/db/base.py +0 -42
  494. agno/memory/v2/db/firestore.py +0 -339
  495. agno/memory/v2/db/mongodb.py +0 -196
  496. agno/memory/v2/db/postgres.py +0 -214
  497. agno/memory/v2/db/redis.py +0 -187
  498. agno/memory/v2/db/schema.py +0 -54
  499. agno/memory/v2/db/sqlite.py +0 -209
  500. agno/memory/v2/manager.py +0 -437
  501. agno/memory/v2/memory.py +0 -1097
  502. agno/memory/v2/schema.py +0 -55
  503. agno/memory/v2/summarizer.py +0 -215
  504. agno/memory/workflow.py +0 -38
  505. agno/models/ollama/tools.py +0 -430
  506. agno/models/qwen/__init__.py +0 -5
  507. agno/playground/__init__.py +0 -10
  508. agno/playground/deploy.py +0 -3
  509. agno/playground/playground.py +0 -3
  510. agno/playground/serve.py +0 -3
  511. agno/playground/settings.py +0 -3
  512. agno/reranker/__init__.py +0 -0
  513. agno/run/v2/__init__.py +0 -0
  514. agno/run/v2/workflow.py +0 -567
  515. agno/storage/__init__.py +0 -0
  516. agno/storage/agent/__init__.py +0 -0
  517. agno/storage/agent/dynamodb.py +0 -1
  518. agno/storage/agent/json.py +0 -1
  519. agno/storage/agent/mongodb.py +0 -1
  520. agno/storage/agent/postgres.py +0 -1
  521. agno/storage/agent/singlestore.py +0 -1
  522. agno/storage/agent/sqlite.py +0 -1
  523. agno/storage/agent/yaml.py +0 -1
  524. agno/storage/base.py +0 -60
  525. agno/storage/dynamodb.py +0 -673
  526. agno/storage/firestore.py +0 -297
  527. agno/storage/gcs_json.py +0 -261
  528. agno/storage/in_memory.py +0 -234
  529. agno/storage/json.py +0 -237
  530. agno/storage/mongodb.py +0 -328
  531. agno/storage/mysql.py +0 -685
  532. agno/storage/postgres.py +0 -682
  533. agno/storage/redis.py +0 -336
  534. agno/storage/session/__init__.py +0 -16
  535. agno/storage/session/agent.py +0 -64
  536. agno/storage/session/team.py +0 -63
  537. agno/storage/session/v2/__init__.py +0 -5
  538. agno/storage/session/workflow.py +0 -61
  539. agno/storage/singlestore.py +0 -606
  540. agno/storage/sqlite.py +0 -646
  541. agno/storage/workflow/__init__.py +0 -0
  542. agno/storage/workflow/mongodb.py +0 -1
  543. agno/storage/workflow/postgres.py +0 -1
  544. agno/storage/workflow/sqlite.py +0 -1
  545. agno/storage/yaml.py +0 -241
  546. agno/tools/thinking.py +0 -73
  547. agno/utils/defaults.py +0 -57
  548. agno/utils/filesystem.py +0 -39
  549. agno/utils/git.py +0 -52
  550. agno/utils/json_io.py +0 -30
  551. agno/utils/load_env.py +0 -19
  552. agno/utils/py_io.py +0 -19
  553. agno/utils/pyproject.py +0 -18
  554. agno/utils/resource_filter.py +0 -31
  555. agno/workflow/v2/__init__.py +0 -21
  556. agno/workflow/v2/types.py +0 -357
  557. agno/workflow/v2/workflow.py +0 -3312
  558. agno/workspace/__init__.py +0 -0
  559. agno/workspace/config.py +0 -325
  560. agno/workspace/enums.py +0 -6
  561. agno/workspace/helpers.py +0 -52
  562. agno/workspace/operator.py +0 -757
  563. agno/workspace/settings.py +0 -158
  564. agno-1.8.1.dist-info/METADATA +0 -982
  565. agno-1.8.1.dist-info/RECORD +0 -566
  566. agno-1.8.1.dist-info/entry_points.txt +0 -3
  567. /agno/{app → db/migrations}/__init__.py +0 -0
  568. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  569. /agno/{cli → integrations}/__init__.py +0 -0
  570. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  571. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  572. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  573. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  574. /agno/{app → os/interfaces}/slack/security.py +0 -0
  575. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  576. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  577. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  578. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  579. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  580. {agno-1.8.1.dist-info → agno-2.0.0a1.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