agno 1.8.0__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 (583) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2781 -4126
  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/media.py +2 -2
  137. agno/memory/__init__.py +2 -10
  138. agno/memory/manager.py +1003 -148
  139. agno/models/aimlapi/__init__.py +2 -2
  140. agno/models/aimlapi/aimlapi.py +6 -6
  141. agno/models/anthropic/claude.py +129 -82
  142. agno/models/aws/bedrock.py +107 -175
  143. agno/models/aws/claude.py +64 -18
  144. agno/models/azure/ai_foundry.py +73 -23
  145. agno/models/base.py +347 -287
  146. agno/models/cerebras/cerebras.py +84 -27
  147. agno/models/cohere/chat.py +106 -98
  148. agno/models/dashscope/dashscope.py +14 -5
  149. agno/models/google/gemini.py +123 -53
  150. agno/models/groq/groq.py +97 -35
  151. agno/models/huggingface/huggingface.py +92 -27
  152. agno/models/ibm/watsonx.py +72 -13
  153. agno/models/litellm/chat.py +85 -13
  154. agno/models/message.py +38 -144
  155. agno/models/meta/llama.py +85 -49
  156. agno/models/metrics.py +120 -0
  157. agno/models/mistral/mistral.py +90 -21
  158. agno/models/ollama/__init__.py +0 -2
  159. agno/models/ollama/chat.py +84 -46
  160. agno/models/openai/chat.py +135 -27
  161. agno/models/openai/responses.py +233 -115
  162. agno/models/perplexity/perplexity.py +26 -2
  163. agno/models/portkey/portkey.py +0 -7
  164. agno/models/response.py +14 -8
  165. agno/models/utils.py +20 -0
  166. agno/models/vercel/__init__.py +2 -2
  167. agno/models/vercel/v0.py +1 -1
  168. agno/models/vllm/__init__.py +2 -2
  169. agno/models/vllm/vllm.py +3 -3
  170. agno/models/xai/xai.py +10 -10
  171. agno/os/__init__.py +3 -0
  172. agno/os/app.py +393 -0
  173. agno/os/auth.py +47 -0
  174. agno/os/config.py +103 -0
  175. agno/os/interfaces/agui/__init__.py +3 -0
  176. agno/os/interfaces/agui/agui.py +31 -0
  177. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  178. agno/{app → os/interfaces}/agui/utils.py +65 -28
  179. agno/os/interfaces/base.py +21 -0
  180. agno/os/interfaces/slack/__init__.py +3 -0
  181. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  182. agno/os/interfaces/slack/slack.py +33 -0
  183. agno/os/interfaces/whatsapp/__init__.py +3 -0
  184. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  185. agno/os/interfaces/whatsapp/whatsapp.py +30 -0
  186. agno/os/router.py +843 -0
  187. agno/os/routers/__init__.py +3 -0
  188. agno/os/routers/evals/__init__.py +3 -0
  189. agno/os/routers/evals/evals.py +204 -0
  190. agno/os/routers/evals/schemas.py +142 -0
  191. agno/os/routers/evals/utils.py +161 -0
  192. agno/os/routers/knowledge/__init__.py +3 -0
  193. agno/os/routers/knowledge/knowledge.py +413 -0
  194. agno/os/routers/knowledge/schemas.py +118 -0
  195. agno/os/routers/memory/__init__.py +3 -0
  196. agno/os/routers/memory/memory.py +179 -0
  197. agno/os/routers/memory/schemas.py +58 -0
  198. agno/os/routers/metrics/__init__.py +3 -0
  199. agno/os/routers/metrics/metrics.py +58 -0
  200. agno/os/routers/metrics/schemas.py +47 -0
  201. agno/os/routers/session/__init__.py +3 -0
  202. agno/os/routers/session/session.py +163 -0
  203. agno/os/schema.py +892 -0
  204. agno/{app/playground → os}/settings.py +8 -15
  205. agno/os/utils.py +270 -0
  206. agno/reasoning/azure_ai_foundry.py +4 -4
  207. agno/reasoning/deepseek.py +4 -4
  208. agno/reasoning/default.py +6 -11
  209. agno/reasoning/groq.py +4 -4
  210. agno/reasoning/helpers.py +4 -6
  211. agno/reasoning/ollama.py +4 -4
  212. agno/reasoning/openai.py +4 -4
  213. agno/run/{response.py → agent.py} +144 -72
  214. agno/run/base.py +44 -58
  215. agno/run/cancel.py +83 -0
  216. agno/run/team.py +133 -77
  217. agno/run/workflow.py +537 -12
  218. agno/session/__init__.py +10 -0
  219. agno/session/agent.py +244 -0
  220. agno/session/summary.py +225 -0
  221. agno/session/team.py +262 -0
  222. agno/{storage/session/v2 → session}/workflow.py +47 -24
  223. agno/team/__init__.py +15 -16
  224. agno/team/team.py +2967 -4243
  225. agno/tools/agentql.py +14 -5
  226. agno/tools/airflow.py +9 -4
  227. agno/tools/api.py +7 -3
  228. agno/tools/apify.py +2 -46
  229. agno/tools/arxiv.py +8 -3
  230. agno/tools/aws_lambda.py +7 -5
  231. agno/tools/aws_ses.py +7 -1
  232. agno/tools/baidusearch.py +4 -1
  233. agno/tools/bitbucket.py +4 -4
  234. agno/tools/brandfetch.py +14 -11
  235. agno/tools/bravesearch.py +4 -1
  236. agno/tools/brightdata.py +42 -22
  237. agno/tools/browserbase.py +13 -4
  238. agno/tools/calcom.py +12 -10
  239. agno/tools/calculator.py +10 -27
  240. agno/tools/cartesia.py +18 -13
  241. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  242. agno/tools/confluence.py +71 -18
  243. agno/tools/crawl4ai.py +7 -1
  244. agno/tools/csv_toolkit.py +9 -8
  245. agno/tools/dalle.py +18 -11
  246. agno/tools/daytona.py +13 -16
  247. agno/tools/decorator.py +6 -3
  248. agno/tools/desi_vocal.py +16 -7
  249. agno/tools/discord.py +11 -8
  250. agno/tools/docker.py +30 -42
  251. agno/tools/duckdb.py +34 -53
  252. agno/tools/duckduckgo.py +8 -7
  253. agno/tools/e2b.py +62 -62
  254. agno/tools/eleven_labs.py +35 -28
  255. agno/tools/email.py +4 -1
  256. agno/tools/evm.py +7 -1
  257. agno/tools/exa.py +19 -14
  258. agno/tools/fal.py +29 -29
  259. agno/tools/file.py +9 -8
  260. agno/tools/financial_datasets.py +25 -44
  261. agno/tools/firecrawl.py +22 -22
  262. agno/tools/function.py +68 -17
  263. agno/tools/giphy.py +22 -10
  264. agno/tools/github.py +48 -126
  265. agno/tools/gmail.py +46 -62
  266. agno/tools/google_bigquery.py +7 -6
  267. agno/tools/google_maps.py +11 -26
  268. agno/tools/googlesearch.py +7 -2
  269. agno/tools/googlesheets.py +21 -17
  270. agno/tools/hackernews.py +9 -5
  271. agno/tools/jina.py +5 -4
  272. agno/tools/jira.py +18 -9
  273. agno/tools/knowledge.py +31 -32
  274. agno/tools/linear.py +18 -33
  275. agno/tools/linkup.py +5 -1
  276. agno/tools/local_file_system.py +8 -5
  277. agno/tools/lumalab.py +31 -19
  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 +32 -14
  282. agno/tools/models/gemini.py +58 -31
  283. agno/tools/models/groq.py +29 -20
  284. agno/tools/models/nebius.py +27 -11
  285. agno/tools/models_labs.py +39 -15
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +134 -0
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +57 -26
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +62 -46
  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 +54 -41
  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 +95 -118
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/location.py +2 -2
  337. agno/utils/log.py +2 -2
  338. agno/utils/mcp.py +11 -5
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/claude.py +6 -4
  342. agno/utils/models/mistral.py +8 -7
  343. agno/utils/models/schema_utils.py +3 -3
  344. agno/utils/pprint.py +33 -32
  345. agno/utils/print_response/agent.py +779 -0
  346. agno/utils/print_response/team.py +1565 -0
  347. agno/utils/print_response/workflow.py +1451 -0
  348. agno/utils/prompts.py +14 -14
  349. agno/utils/reasoning.py +87 -0
  350. agno/utils/response.py +42 -42
  351. agno/utils/string.py +8 -22
  352. agno/utils/team.py +50 -0
  353. agno/utils/timer.py +2 -2
  354. agno/vectordb/base.py +33 -21
  355. agno/vectordb/cassandra/cassandra.py +287 -23
  356. agno/vectordb/chroma/chromadb.py +482 -59
  357. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  358. agno/vectordb/couchbase/couchbase.py +309 -29
  359. agno/vectordb/lancedb/lance_db.py +360 -21
  360. agno/vectordb/langchaindb/__init__.py +5 -0
  361. agno/vectordb/langchaindb/langchaindb.py +145 -0
  362. agno/vectordb/lightrag/__init__.py +5 -0
  363. agno/vectordb/lightrag/lightrag.py +374 -0
  364. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  365. agno/vectordb/milvus/milvus.py +242 -32
  366. agno/vectordb/mongodb/mongodb.py +200 -24
  367. agno/vectordb/pgvector/pgvector.py +319 -37
  368. agno/vectordb/pineconedb/pineconedb.py +221 -27
  369. agno/vectordb/qdrant/qdrant.py +356 -14
  370. agno/vectordb/singlestore/singlestore.py +286 -29
  371. agno/vectordb/surrealdb/surrealdb.py +187 -7
  372. agno/vectordb/upstashdb/upstashdb.py +342 -26
  373. agno/vectordb/weaviate/weaviate.py +227 -165
  374. agno/workflow/__init__.py +17 -13
  375. agno/workflow/{v2/condition.py → condition.py} +135 -32
  376. agno/workflow/{v2/loop.py → loop.py} +115 -28
  377. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  378. agno/workflow/{v2/router.py → router.py} +133 -32
  379. agno/workflow/{v2/step.py → step.py} +200 -42
  380. agno/workflow/{v2/steps.py → steps.py} +147 -66
  381. agno/workflow/types.py +482 -0
  382. agno/workflow/workflow.py +2394 -696
  383. agno-2.0.0a1.dist-info/METADATA +355 -0
  384. agno-2.0.0a1.dist-info/RECORD +514 -0
  385. agno/agent/metrics.py +0 -107
  386. agno/api/app.py +0 -35
  387. agno/api/playground.py +0 -92
  388. agno/api/schemas/app.py +0 -12
  389. agno/api/schemas/playground.py +0 -22
  390. agno/api/schemas/user.py +0 -35
  391. agno/api/schemas/workspace.py +0 -46
  392. agno/api/user.py +0 -160
  393. agno/api/workflows.py +0 -33
  394. agno/api/workspace.py +0 -175
  395. agno/app/agui/__init__.py +0 -3
  396. agno/app/agui/app.py +0 -17
  397. agno/app/agui/sync_router.py +0 -120
  398. agno/app/base.py +0 -186
  399. agno/app/discord/__init__.py +0 -3
  400. agno/app/fastapi/__init__.py +0 -3
  401. agno/app/fastapi/app.py +0 -107
  402. agno/app/fastapi/async_router.py +0 -457
  403. agno/app/fastapi/sync_router.py +0 -448
  404. agno/app/playground/app.py +0 -228
  405. agno/app/playground/async_router.py +0 -1050
  406. agno/app/playground/deploy.py +0 -249
  407. agno/app/playground/operator.py +0 -183
  408. agno/app/playground/schemas.py +0 -220
  409. agno/app/playground/serve.py +0 -55
  410. agno/app/playground/sync_router.py +0 -1042
  411. agno/app/playground/utils.py +0 -46
  412. agno/app/settings.py +0 -15
  413. agno/app/slack/__init__.py +0 -3
  414. agno/app/slack/app.py +0 -19
  415. agno/app/slack/sync_router.py +0 -92
  416. agno/app/utils.py +0 -54
  417. agno/app/whatsapp/__init__.py +0 -3
  418. agno/app/whatsapp/app.py +0 -15
  419. agno/app/whatsapp/sync_router.py +0 -197
  420. agno/cli/auth_server.py +0 -249
  421. agno/cli/config.py +0 -274
  422. agno/cli/console.py +0 -88
  423. agno/cli/credentials.py +0 -23
  424. agno/cli/entrypoint.py +0 -571
  425. agno/cli/operator.py +0 -357
  426. agno/cli/settings.py +0 -96
  427. agno/cli/ws/ws_cli.py +0 -817
  428. agno/constants.py +0 -13
  429. agno/document/__init__.py +0 -5
  430. agno/document/chunking/semantic.py +0 -45
  431. agno/document/chunking/strategy.py +0 -31
  432. agno/document/reader/__init__.py +0 -5
  433. agno/document/reader/base.py +0 -47
  434. agno/document/reader/docx_reader.py +0 -60
  435. agno/document/reader/gcs/pdf_reader.py +0 -44
  436. agno/document/reader/s3/pdf_reader.py +0 -59
  437. agno/document/reader/s3/text_reader.py +0 -63
  438. agno/document/reader/url_reader.py +0 -59
  439. agno/document/reader/youtube_reader.py +0 -58
  440. agno/embedder/__init__.py +0 -5
  441. agno/embedder/langdb.py +0 -80
  442. agno/embedder/mistral.py +0 -82
  443. agno/embedder/openai.py +0 -78
  444. agno/file/__init__.py +0 -5
  445. agno/file/file.py +0 -16
  446. agno/file/local/csv.py +0 -32
  447. agno/file/local/txt.py +0 -19
  448. agno/infra/app.py +0 -240
  449. agno/infra/base.py +0 -144
  450. agno/infra/context.py +0 -20
  451. agno/infra/db_app.py +0 -52
  452. agno/infra/resource.py +0 -205
  453. agno/infra/resources.py +0 -55
  454. agno/knowledge/agent.py +0 -698
  455. agno/knowledge/arxiv.py +0 -33
  456. agno/knowledge/combined.py +0 -36
  457. agno/knowledge/csv.py +0 -144
  458. agno/knowledge/csv_url.py +0 -124
  459. agno/knowledge/document.py +0 -223
  460. agno/knowledge/docx.py +0 -137
  461. agno/knowledge/firecrawl.py +0 -34
  462. agno/knowledge/gcs/__init__.py +0 -0
  463. agno/knowledge/gcs/base.py +0 -39
  464. agno/knowledge/gcs/pdf.py +0 -125
  465. agno/knowledge/json.py +0 -137
  466. agno/knowledge/langchain.py +0 -71
  467. agno/knowledge/light_rag.py +0 -273
  468. agno/knowledge/llamaindex.py +0 -66
  469. agno/knowledge/markdown.py +0 -154
  470. agno/knowledge/pdf.py +0 -164
  471. agno/knowledge/pdf_bytes.py +0 -42
  472. agno/knowledge/pdf_url.py +0 -148
  473. agno/knowledge/s3/__init__.py +0 -0
  474. agno/knowledge/s3/base.py +0 -64
  475. agno/knowledge/s3/pdf.py +0 -33
  476. agno/knowledge/s3/text.py +0 -34
  477. agno/knowledge/text.py +0 -141
  478. agno/knowledge/url.py +0 -46
  479. agno/knowledge/website.py +0 -179
  480. agno/knowledge/wikipedia.py +0 -32
  481. agno/knowledge/youtube.py +0 -35
  482. agno/memory/agent.py +0 -423
  483. agno/memory/classifier.py +0 -104
  484. agno/memory/db/__init__.py +0 -5
  485. agno/memory/db/base.py +0 -42
  486. agno/memory/db/mongodb.py +0 -189
  487. agno/memory/db/postgres.py +0 -203
  488. agno/memory/db/sqlite.py +0 -193
  489. agno/memory/memory.py +0 -22
  490. agno/memory/row.py +0 -36
  491. agno/memory/summarizer.py +0 -201
  492. agno/memory/summary.py +0 -19
  493. agno/memory/team.py +0 -415
  494. agno/memory/v2/__init__.py +0 -2
  495. agno/memory/v2/db/__init__.py +0 -1
  496. agno/memory/v2/db/base.py +0 -42
  497. agno/memory/v2/db/firestore.py +0 -339
  498. agno/memory/v2/db/mongodb.py +0 -196
  499. agno/memory/v2/db/postgres.py +0 -214
  500. agno/memory/v2/db/redis.py +0 -187
  501. agno/memory/v2/db/schema.py +0 -54
  502. agno/memory/v2/db/sqlite.py +0 -209
  503. agno/memory/v2/manager.py +0 -437
  504. agno/memory/v2/memory.py +0 -1097
  505. agno/memory/v2/schema.py +0 -55
  506. agno/memory/v2/summarizer.py +0 -215
  507. agno/memory/workflow.py +0 -38
  508. agno/models/ollama/tools.py +0 -430
  509. agno/models/qwen/__init__.py +0 -5
  510. agno/playground/__init__.py +0 -10
  511. agno/playground/deploy.py +0 -3
  512. agno/playground/playground.py +0 -3
  513. agno/playground/serve.py +0 -3
  514. agno/playground/settings.py +0 -3
  515. agno/reranker/__init__.py +0 -0
  516. agno/run/v2/__init__.py +0 -0
  517. agno/run/v2/workflow.py +0 -567
  518. agno/storage/__init__.py +0 -0
  519. agno/storage/agent/__init__.py +0 -0
  520. agno/storage/agent/dynamodb.py +0 -1
  521. agno/storage/agent/json.py +0 -1
  522. agno/storage/agent/mongodb.py +0 -1
  523. agno/storage/agent/postgres.py +0 -1
  524. agno/storage/agent/singlestore.py +0 -1
  525. agno/storage/agent/sqlite.py +0 -1
  526. agno/storage/agent/yaml.py +0 -1
  527. agno/storage/base.py +0 -60
  528. agno/storage/dynamodb.py +0 -673
  529. agno/storage/firestore.py +0 -297
  530. agno/storage/gcs_json.py +0 -261
  531. agno/storage/in_memory.py +0 -234
  532. agno/storage/json.py +0 -237
  533. agno/storage/mongodb.py +0 -328
  534. agno/storage/mysql.py +0 -685
  535. agno/storage/postgres.py +0 -682
  536. agno/storage/redis.py +0 -336
  537. agno/storage/session/__init__.py +0 -16
  538. agno/storage/session/agent.py +0 -64
  539. agno/storage/session/team.py +0 -63
  540. agno/storage/session/v2/__init__.py +0 -5
  541. agno/storage/session/workflow.py +0 -61
  542. agno/storage/singlestore.py +0 -606
  543. agno/storage/sqlite.py +0 -646
  544. agno/storage/workflow/__init__.py +0 -0
  545. agno/storage/workflow/mongodb.py +0 -1
  546. agno/storage/workflow/postgres.py +0 -1
  547. agno/storage/workflow/sqlite.py +0 -1
  548. agno/storage/yaml.py +0 -241
  549. agno/tools/thinking.py +0 -73
  550. agno/utils/defaults.py +0 -57
  551. agno/utils/filesystem.py +0 -39
  552. agno/utils/git.py +0 -52
  553. agno/utils/json_io.py +0 -30
  554. agno/utils/load_env.py +0 -19
  555. agno/utils/py_io.py +0 -19
  556. agno/utils/pyproject.py +0 -18
  557. agno/utils/resource_filter.py +0 -31
  558. agno/workflow/v2/__init__.py +0 -21
  559. agno/workflow/v2/types.py +0 -357
  560. agno/workflow/v2/workflow.py +0 -3312
  561. agno/workspace/__init__.py +0 -0
  562. agno/workspace/config.py +0 -325
  563. agno/workspace/enums.py +0 -6
  564. agno/workspace/helpers.py +0 -52
  565. agno/workspace/operator.py +0 -757
  566. agno/workspace/settings.py +0 -158
  567. agno-1.8.0.dist-info/METADATA +0 -979
  568. agno-1.8.0.dist-info/RECORD +0 -565
  569. agno-1.8.0.dist-info/entry_points.txt +0 -3
  570. /agno/{app → db/migrations}/__init__.py +0 -0
  571. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  572. /agno/{cli → integrations}/__init__.py +0 -0
  573. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  574. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  575. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  576. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  577. /agno/{app → os/interfaces}/slack/security.py +0 -0
  578. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  579. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  580. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  581. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  582. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  583. {agno-1.8.0.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