agno 1.8.1__py3-none-any.whl → 2.0.0rc1__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 +3181 -4169
  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 +1411 -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 +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 +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 +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 +131 -131
  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 +45 -150
  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 +489 -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 +255 -0
  185. agno/os/router.py +869 -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 +208 -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 +436 -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 +188 -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 +60 -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 +168 -0
  202. agno/os/schema.py +892 -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/{response.py → agent.py} +231 -74
  213. agno/run/base.py +44 -58
  214. agno/run/cancel.py +81 -0
  215. agno/run/team.py +133 -77
  216. agno/run/workflow.py +537 -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 +2960 -4252
  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 +42 -22
  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 +18 -13
  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 +18 -11
  245. agno/tools/daytona.py +13 -16
  246. agno/tools/decorator.py +6 -3
  247. agno/tools/desi_vocal.py +16 -7
  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 +61 -61
  253. agno/tools/eleven_labs.py +35 -28
  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 +29 -29
  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 +22 -10
  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 +31 -19
  277. agno/tools/mem0.py +18 -12
  278. agno/tools/memori.py +14 -10
  279. agno/tools/mlx_transcribe.py +3 -2
  280. agno/tools/models/azure_openai.py +32 -14
  281. agno/tools/models/gemini.py +58 -31
  282. agno/tools/models/groq.py +29 -20
  283. agno/tools/models/nebius.py +27 -11
  284. agno/tools/models_labs.py +39 -15
  285. agno/tools/moviepy_video.py +7 -6
  286. agno/tools/neo4j.py +10 -8
  287. agno/tools/newspaper.py +7 -2
  288. agno/tools/newspaper4k.py +8 -3
  289. agno/tools/openai.py +57 -26
  290. agno/tools/openbb.py +12 -11
  291. agno/tools/opencv.py +62 -46
  292. agno/tools/openweather.py +14 -12
  293. agno/tools/pandas.py +11 -3
  294. agno/tools/postgres.py +4 -12
  295. agno/tools/pubmed.py +4 -1
  296. agno/tools/python.py +9 -22
  297. agno/tools/reasoning.py +35 -27
  298. agno/tools/reddit.py +11 -26
  299. agno/tools/replicate.py +54 -41
  300. agno/tools/resend.py +4 -1
  301. agno/tools/scrapegraph.py +15 -14
  302. agno/tools/searxng.py +10 -23
  303. agno/tools/serpapi.py +6 -3
  304. agno/tools/serper.py +13 -4
  305. agno/tools/shell.py +9 -2
  306. agno/tools/slack.py +12 -11
  307. agno/tools/sleep.py +3 -2
  308. agno/tools/spider.py +24 -4
  309. agno/tools/sql.py +7 -6
  310. agno/tools/tavily.py +6 -4
  311. agno/tools/telegram.py +12 -4
  312. agno/tools/todoist.py +11 -31
  313. agno/tools/toolkit.py +1 -1
  314. agno/tools/trafilatura.py +22 -6
  315. agno/tools/trello.py +9 -22
  316. agno/tools/twilio.py +10 -3
  317. agno/tools/user_control_flow.py +6 -1
  318. agno/tools/valyu.py +34 -5
  319. agno/tools/visualization.py +19 -28
  320. agno/tools/webbrowser.py +4 -3
  321. agno/tools/webex.py +11 -7
  322. agno/tools/website.py +15 -46
  323. agno/tools/webtools.py +12 -4
  324. agno/tools/whatsapp.py +5 -9
  325. agno/tools/wikipedia.py +20 -13
  326. agno/tools/x.py +14 -13
  327. agno/tools/yfinance.py +13 -40
  328. agno/tools/youtube.py +26 -20
  329. agno/tools/zendesk.py +7 -2
  330. agno/tools/zep.py +10 -7
  331. agno/tools/zoom.py +10 -9
  332. agno/utils/common.py +1 -19
  333. agno/utils/events.py +95 -118
  334. agno/utils/gemini.py +31 -1
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/log.py +2 -2
  337. agno/utils/mcp.py +11 -5
  338. agno/utils/media.py +39 -0
  339. agno/utils/message.py +12 -1
  340. agno/utils/models/claude.py +55 -4
  341. agno/utils/models/mistral.py +8 -7
  342. agno/utils/models/schema_utils.py +3 -3
  343. agno/utils/pprint.py +33 -32
  344. agno/utils/print_response/agent.py +779 -0
  345. agno/utils/print_response/team.py +1565 -0
  346. agno/utils/print_response/workflow.py +1451 -0
  347. agno/utils/prompts.py +14 -14
  348. agno/utils/reasoning.py +87 -0
  349. agno/utils/response.py +42 -42
  350. agno/utils/streamlit.py +454 -0
  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 +334 -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 +2401 -696
  383. agno-2.0.0rc1.dist-info/METADATA +355 -0
  384. agno-2.0.0rc1.dist-info/RECORD +516 -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 -702
  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.1.dist-info/METADATA +0 -982
  568. agno-1.8.1.dist-info/RECORD +0 -566
  569. agno-1.8.1.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.1.dist-info → agno-2.0.0rc1.dist-info}/WHEEL +0 -0
  582. {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/licenses/LICENSE +0 -0
  583. {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  from hashlib import md5
2
3
  from typing import Any, Dict, List, Optional
3
4
 
@@ -10,8 +11,8 @@ try:
10
11
  except ImportError:
11
12
  raise ImportError("`clickhouse-connect` not installed. Use `pip install clickhouse-connect` to install it")
12
13
 
13
- from agno.document import Document
14
- from agno.embedder import Embedder
14
+ from agno.knowledge.document import Document
15
+ from agno.knowledge.embedder import Embedder
15
16
  from agno.utils.log import log_debug, log_info, logger
16
17
  from agno.vectordb.base import VectorDb
17
18
  from agno.vectordb.distance import Distance
@@ -62,7 +63,7 @@ class Clickhouse(VectorDb):
62
63
  # Embedder for embedding the document contents
63
64
  _embedder = embedder
64
65
  if _embedder is None:
65
- from agno.embedder.openai import OpenAIEmbedder
66
+ from agno.knowledge.embedder.openai import OpenAIEmbedder
66
67
 
67
68
  _embedder = OpenAIEmbedder()
68
69
  log_info("Embedder not provided, using OpenAIEmbedder as default.")
@@ -157,6 +158,7 @@ class Clickhouse(VectorDb):
157
158
  meta_data JSON DEFAULT '{{}}',
158
159
  filters JSON DEFAULT '{{}}',
159
160
  content String,
161
+ content_id String,
160
162
  embedding Array(Float32),
161
163
  usage JSON,
162
164
  created_at DateTime('UTC') DEFAULT now(),
@@ -201,6 +203,7 @@ class Clickhouse(VectorDb):
201
203
  meta_data JSON DEFAULT '{{}}',
202
204
  filters JSON DEFAULT '{{}}',
203
205
  content String,
206
+ content_id String,
204
207
  embedding Array(Float32),
205
208
  usage JSON,
206
209
  created_at DateTime('UTC') DEFAULT now(),
@@ -211,37 +214,6 @@ class Clickhouse(VectorDb):
211
214
  parameters=parameters,
212
215
  )
213
216
 
214
- def doc_exists(self, document: Document) -> bool:
215
- """
216
- Validating if the document exists or not
217
-
218
- Args:
219
- document (Document): Document to validate
220
- """
221
- cleaned_content = document.content.replace("\x00", "\ufffd")
222
- parameters = self._get_base_parameters()
223
- parameters["content_hash"] = md5(cleaned_content.encode()).hexdigest()
224
-
225
- result = self.client.query(
226
- "SELECT content_hash FROM {database_name:Identifier}.{table_name:Identifier} WHERE content_hash = {content_hash:String}",
227
- parameters=parameters,
228
- )
229
- return bool(result.result_rows)
230
-
231
- async def async_doc_exists(self, document: Document) -> bool:
232
- """Check if a document exists asynchronously."""
233
- cleaned_content = document.content.replace("\x00", "\ufffd")
234
- async_client = await self._ensure_async_client()
235
-
236
- parameters = self._get_base_parameters()
237
- parameters["content_hash"] = md5(cleaned_content.encode()).hexdigest()
238
-
239
- result = await async_client.query(
240
- "SELECT content_hash FROM {database_name:Identifier}.{table_name:Identifier} WHERE content_hash = {content_hash:String}",
241
- parameters=parameters,
242
- )
243
- return bool(result.result_rows)
244
-
245
217
  def name_exists(self, name: str) -> bool:
246
218
  """
247
219
  Validate if a row with this name exists or not
@@ -289,6 +261,7 @@ class Clickhouse(VectorDb):
289
261
 
290
262
  def insert(
291
263
  self,
264
+ content_hash: str,
292
265
  documents: List[Document],
293
266
  filters: Optional[Dict[str, Any]] = None,
294
267
  ) -> None:
@@ -296,8 +269,7 @@ class Clickhouse(VectorDb):
296
269
  for document in documents:
297
270
  document.embed(embedder=self.embedder)
298
271
  cleaned_content = document.content.replace("\x00", "\ufffd")
299
- content_hash = md5(cleaned_content.encode()).hexdigest()
300
- _id = document.id or content_hash
272
+ _id = md5(cleaned_content.encode()).hexdigest()
301
273
 
302
274
  row: List[Any] = [
303
275
  _id,
@@ -305,6 +277,7 @@ class Clickhouse(VectorDb):
305
277
  document.meta_data,
306
278
  filters,
307
279
  cleaned_content,
280
+ document.content_id,
308
281
  document.embedding,
309
282
  document.usage,
310
283
  content_hash,
@@ -320,6 +293,7 @@ class Clickhouse(VectorDb):
320
293
  "meta_data",
321
294
  "filters",
322
295
  "content",
296
+ "content_id",
323
297
  "embedding",
324
298
  "usage",
325
299
  "content_hash",
@@ -327,16 +301,19 @@ class Clickhouse(VectorDb):
327
301
  )
328
302
  log_debug(f"Inserted {len(documents)} documents")
329
303
 
330
- async def async_insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
304
+ async def async_insert(
305
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
306
+ ) -> None:
331
307
  """Insert documents asynchronously."""
332
308
  rows: List[List[Any]] = []
333
309
  async_client = await self._ensure_async_client()
334
310
 
311
+ embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
312
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
313
+
335
314
  for document in documents:
336
- document.embed(embedder=self.embedder)
337
315
  cleaned_content = document.content.replace("\x00", "\ufffd")
338
- content_hash = md5(cleaned_content.encode()).hexdigest()
339
- _id = document.id or content_hash
316
+ _id = md5(cleaned_content.encode()).hexdigest()
340
317
 
341
318
  row: List[Any] = [
342
319
  _id,
@@ -344,6 +321,7 @@ class Clickhouse(VectorDb):
344
321
  document.meta_data,
345
322
  filters,
346
323
  cleaned_content,
324
+ document.content_id,
347
325
  document.embedding,
348
326
  document.usage,
349
327
  content_hash,
@@ -359,6 +337,7 @@ class Clickhouse(VectorDb):
359
337
  "meta_data",
360
338
  "filters",
361
339
  "content",
340
+ "content_id",
362
341
  "embedding",
363
342
  "usage",
364
343
  "content_hash",
@@ -371,6 +350,20 @@ class Clickhouse(VectorDb):
371
350
 
372
351
  def upsert(
373
352
  self,
353
+ content_hash: str,
354
+ documents: List[Document],
355
+ filters: Optional[Dict[str, Any]] = None,
356
+ ) -> None:
357
+ """
358
+ Upsert documents into the database.
359
+ """
360
+ if self.content_hash_exists(content_hash):
361
+ self._delete_by_content_hash(content_hash)
362
+ self.insert(content_hash=content_hash, documents=documents, filters=filters)
363
+
364
+ def _upsert(
365
+ self,
366
+ content_hash: str,
374
367
  documents: List[Document],
375
368
  filters: Optional[Dict[str, Any]] = None,
376
369
  ) -> None:
@@ -384,7 +377,7 @@ class Clickhouse(VectorDb):
384
377
  """
385
378
  # We are using ReplacingMergeTree engine in our table, so we need to insert the documents,
386
379
  # then call SELECT with FINAL
387
- self.insert(documents=documents, filters=filters)
380
+ self.insert(content_hash=content_hash, documents=documents, filters=filters)
388
381
 
389
382
  parameters = self._get_base_parameters()
390
383
  self.client.query(
@@ -392,11 +385,21 @@ class Clickhouse(VectorDb):
392
385
  parameters=parameters,
393
386
  )
394
387
 
395
- async def async_upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
388
+ async def async_upsert(
389
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
390
+ ) -> None:
391
+ """Upsert documents asynchronously."""
392
+ if self.content_hash_exists(content_hash):
393
+ self._delete_by_content_hash(content_hash)
394
+ await self._async_upsert(content_hash=content_hash, documents=documents, filters=filters)
395
+
396
+ async def _async_upsert(
397
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
398
+ ) -> None:
396
399
  """Upsert documents asynchronously."""
397
400
  # We are using ReplacingMergeTree engine in our table, so we need to insert the documents,
398
401
  # then call SELECT with FINAL
399
- await self.async_insert(documents=documents, filters=filters)
402
+ await self.async_insert(content_hash=content_hash, documents=documents, filters=filters)
400
403
 
401
404
  parameters = self._get_base_parameters()
402
405
  await self.async_client.query( # type: ignore
@@ -412,13 +415,6 @@ class Clickhouse(VectorDb):
412
415
 
413
416
  parameters = self._get_base_parameters()
414
417
  where_query = ""
415
- # if filters:
416
- # query_filters: List[str] = []
417
- # for key, value in filters.values():
418
- # query_filters.append(f"{{{key}_key:String}} = {{{key}_value:String}}")
419
- # parameters[f"{key}_key"] = key
420
- # parameters[f"{key}_value"] = value
421
- # where_query = f"WHERE {' AND '.join(query_filters)}"
422
418
 
423
419
  order_by_query = ""
424
420
  if self.distance == Distance.l2 or self.distance == Distance.max_inner_product:
@@ -429,7 +425,7 @@ class Clickhouse(VectorDb):
429
425
  parameters["query_embedding"] = query_embedding
430
426
 
431
427
  clickhouse_query = (
432
- "SELECT name, meta_data, content, embedding, usage FROM "
428
+ "SELECT name, meta_data, content, content_id, embedding, usage FROM "
433
429
  "{database_name:Identifier}.{table_name:Identifier} "
434
430
  f"{where_query} {order_by_query} LIMIT {limit}"
435
431
  )
@@ -455,9 +451,10 @@ class Clickhouse(VectorDb):
455
451
  name=result[0],
456
452
  meta_data=result[1],
457
453
  content=result[2],
454
+ content_id=result[3],
458
455
  embedder=self.embedder,
459
- embedding=result[3],
460
- usage=result[4],
456
+ embedding=result[4],
457
+ usage=result[5],
461
458
  )
462
459
  )
463
460
 
@@ -476,13 +473,6 @@ class Clickhouse(VectorDb):
476
473
 
477
474
  parameters = self._get_base_parameters()
478
475
  where_query = ""
479
- # if filters:
480
- # query_filters: List[str] = []
481
- # for key, value in filters.values():
482
- # query_filters.append(f"{{{key}_key:String}} = {{{key}_value:String}}")
483
- # parameters[f"{key}_key"] = key
484
- # parameters[f"{key}_value"] = value
485
- # where_query = f"WHERE {' AND '.join(query_filters)}"
486
476
 
487
477
  order_by_query = ""
488
478
  if self.distance == Distance.l2 or self.distance == Distance.max_inner_product:
@@ -493,7 +483,7 @@ class Clickhouse(VectorDb):
493
483
  parameters["query_embedding"] = query_embedding
494
484
 
495
485
  clickhouse_query = (
496
- "SELECT name, meta_data, content, embedding, usage FROM "
486
+ "SELECT name, meta_data, content, content_id, embedding, usage FROM "
497
487
  "{database_name:Identifier}.{table_name:Identifier} "
498
488
  f"{where_query} {order_by_query} LIMIT {limit}"
499
489
  )
@@ -519,9 +509,10 @@ class Clickhouse(VectorDb):
519
509
  name=result[0],
520
510
  meta_data=result[1],
521
511
  content=result[2],
512
+ content_id=result[3],
522
513
  embedder=self.embedder,
523
- embedding=result[3],
524
- usage=result[4],
514
+ embedding=result[4],
515
+ usage=result[5],
525
516
  )
526
517
  )
527
518
 
@@ -573,3 +564,219 @@ class Clickhouse(VectorDb):
573
564
  parameters=parameters,
574
565
  )
575
566
  return True
567
+
568
+ def delete_by_id(self, id: str) -> bool:
569
+ """
570
+
571
+ Delete a document by its ID.
572
+
573
+ Args:
574
+ id (str): The document ID to delete
575
+
576
+ Returns:
577
+ bool: True if document was deleted, False otherwise
578
+ """
579
+ try:
580
+ log_debug(f"ClickHouse VectorDB : Deleting document with ID {id}")
581
+ if not self.id_exists(id):
582
+ return False
583
+
584
+ parameters = self._get_base_parameters()
585
+ parameters["id"] = id
586
+
587
+ self.client.command(
588
+ "DELETE FROM {database_name:Identifier}.{table_name:Identifier} WHERE id = {id:String}",
589
+ parameters=parameters,
590
+ )
591
+ return True
592
+ except Exception as e:
593
+ log_info(f"Error deleting document with ID {id}: {e}")
594
+ return False
595
+
596
+ def delete_by_name(self, name: str) -> bool:
597
+ """
598
+ Delete documents by name.
599
+
600
+ Args:
601
+ name (str): The document name to delete
602
+
603
+ Returns:
604
+ bool: True if documents were deleted, False otherwise
605
+ """
606
+ try:
607
+ log_debug(f"ClickHouse VectorDB : Deleting documents with name {name}")
608
+ if not self.name_exists(name):
609
+ return False
610
+
611
+ parameters = self._get_base_parameters()
612
+ parameters["name"] = name
613
+
614
+ self.client.command(
615
+ "DELETE FROM {database_name:Identifier}.{table_name:Identifier} WHERE name = {name:String}",
616
+ parameters=parameters,
617
+ )
618
+ return True
619
+ except Exception as e:
620
+ log_info(f"Error deleting documents with name {name}: {e}")
621
+ return False
622
+
623
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
624
+ """
625
+ Delete documents by metadata.
626
+
627
+ Args:
628
+ metadata (Dict[str, Any]): The metadata to match for deletion
629
+
630
+ Returns:
631
+ bool: True if documents were deleted, False otherwise
632
+ """
633
+ try:
634
+ log_debug(f"ClickHouse VectorDB : Deleting documents with metadata {metadata}")
635
+ parameters = self._get_base_parameters()
636
+
637
+ # Build WHERE clause for metadata matching using proper ClickHouse JSON syntax
638
+ where_conditions = []
639
+ for key, value in metadata.items():
640
+ if isinstance(value, bool):
641
+ where_conditions.append(f"JSONExtractBool(toString(filters), '{key}') = {str(value).lower()}")
642
+ elif isinstance(value, (int, float)):
643
+ where_conditions.append(f"JSONExtractFloat(toString(filters), '{key}') = {value}")
644
+ else:
645
+ where_conditions.append(f"JSONExtractString(toString(filters), '{key}') = '{value}'")
646
+
647
+ if not where_conditions:
648
+ return False
649
+
650
+ where_clause = " AND ".join(where_conditions)
651
+
652
+ self.client.command(
653
+ f"DELETE FROM {{database_name:Identifier}}.{{table_name:Identifier}} WHERE {where_clause}",
654
+ parameters=parameters,
655
+ )
656
+ return True
657
+ except Exception as e:
658
+ log_info(f"Error deleting documents with metadata {metadata}: {e}")
659
+ return False
660
+
661
+ def delete_by_content_id(self, content_id: str) -> bool:
662
+ """
663
+ Delete documents by content ID.
664
+
665
+ Args:
666
+ content_id (str): The content ID to delete
667
+
668
+ Returns:
669
+ bool: True if documents were deleted, False otherwise
670
+ """
671
+ try:
672
+ log_debug(f"ClickHouse VectorDB : Deleting documents with content_id {content_id}")
673
+ parameters = self._get_base_parameters()
674
+ parameters["content_id"] = content_id
675
+
676
+ self.client.command(
677
+ "DELETE FROM {database_name:Identifier}.{table_name:Identifier} WHERE content_id = {content_id:String}",
678
+ parameters=parameters,
679
+ )
680
+ return True
681
+ except Exception as e:
682
+ log_info(f"Error deleting documents with content_id {content_id}: {e}")
683
+ return False
684
+
685
+ def content_hash_exists(self, content_hash: str) -> bool:
686
+ """
687
+ Validate if a row with this content_hash exists or not
688
+
689
+ Args:
690
+ content_hash (str): Content hash to check
691
+ """
692
+ parameters = self._get_base_parameters()
693
+ parameters["content_hash"] = content_hash
694
+
695
+ result = self.client.query(
696
+ "SELECT content_hash FROM {database_name:Identifier}.{table_name:Identifier} WHERE content_hash = {content_hash:String}",
697
+ parameters=parameters,
698
+ )
699
+ return bool(result)
700
+
701
+ def _delete_by_content_hash(self, content_hash: str) -> bool:
702
+ """
703
+ Delete documents by content hash.
704
+ """
705
+ try:
706
+ parameters = self._get_base_parameters()
707
+ parameters["content_hash"] = content_hash
708
+
709
+ self.client.command(
710
+ "DELETE FROM {database_name:Identifier}.{table_name:Identifier} WHERE content_hash = {content_hash:String}",
711
+ parameters=parameters,
712
+ )
713
+ return True
714
+ except Exception:
715
+ return False
716
+
717
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
718
+ """
719
+ Update the metadata for documents with the given content_id.
720
+
721
+ Args:
722
+ content_id (str): The content ID to update
723
+ metadata (Dict[str, Any]): The metadata to update
724
+ """
725
+ import json
726
+
727
+ try:
728
+ parameters = self._get_base_parameters()
729
+ parameters["content_id"] = content_id
730
+
731
+ # First, get existing documents with their current metadata and filters
732
+ result = self.client.query(
733
+ "SELECT id, meta_data, filters FROM {database_name:Identifier}.{table_name:Identifier} WHERE content_id = {content_id:String}",
734
+ parameters=parameters,
735
+ )
736
+
737
+ if not result.result_rows:
738
+ logger.debug(f"No documents found with content_id: {content_id}")
739
+ return
740
+
741
+ # Update each document
742
+ updated_count = 0
743
+ for row in result.result_rows:
744
+ doc_id, current_meta_json, current_filters_json = row
745
+
746
+ # Parse existing metadata
747
+ try:
748
+ current_metadata = json.loads(current_meta_json) if current_meta_json else {}
749
+ except (json.JSONDecodeError, TypeError):
750
+ current_metadata = {}
751
+
752
+ # Parse existing filters
753
+ try:
754
+ current_filters = json.loads(current_filters_json) if current_filters_json else {}
755
+ except (json.JSONDecodeError, TypeError):
756
+ current_filters = {}
757
+
758
+ # Merge existing metadata with new metadata
759
+ updated_metadata = current_metadata.copy()
760
+ updated_metadata.update(metadata)
761
+
762
+ # Merge existing filters with new metadata
763
+ updated_filters = current_filters.copy()
764
+ updated_filters.update(metadata)
765
+
766
+ # Update the document
767
+ update_params = parameters.copy()
768
+ update_params["doc_id"] = doc_id
769
+ update_params["metadata_json"] = json.dumps(updated_metadata)
770
+ update_params["filters_json"] = json.dumps(updated_filters)
771
+
772
+ self.client.command(
773
+ "ALTER TABLE {database_name:Identifier}.{table_name:Identifier} UPDATE meta_data = {metadata_json:String}, filters = {filters_json:String} WHERE id = {doc_id:String}",
774
+ parameters=update_params,
775
+ )
776
+ updated_count += 1
777
+
778
+ logger.debug(f"Updated metadata for {updated_count} documents with content_id: {content_id}")
779
+
780
+ except Exception as e:
781
+ logger.error(f"Error updating metadata for content_id '{content_id}': {e}")
782
+ raise