agno 1.8.1__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (590) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +3143 -4170
  4. agno/api/agent.py +11 -67
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +8 -19
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +11 -66
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1743 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1432 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +882 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1045 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1416 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +297 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1710 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +280 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1367 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1712 -0
  67. agno/db/singlestore/utils.py +326 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1676 -0
  71. agno/db/sqlite/utils.py +268 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +154 -48
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +15 -11
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1551 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/{document → knowledge}/reader/json_reader.py +30 -9
  118. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  119. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  120. agno/knowledge/reader/reader_factory.py +268 -0
  121. agno/knowledge/reader/s3_reader.py +101 -0
  122. agno/{document → knowledge}/reader/text_reader.py +31 -10
  123. agno/knowledge/reader/url_reader.py +128 -0
  124. agno/knowledge/reader/web_search_reader.py +366 -0
  125. agno/{document → knowledge}/reader/website_reader.py +37 -10
  126. agno/knowledge/reader/wikipedia_reader.py +59 -0
  127. agno/knowledge/reader/youtube_reader.py +78 -0
  128. agno/knowledge/remote_content/remote_content.py +88 -0
  129. agno/{reranker → knowledge/reranker}/base.py +1 -1
  130. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  131. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  132. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  133. agno/knowledge/types.py +30 -0
  134. agno/knowledge/utils.py +169 -0
  135. agno/media.py +269 -268
  136. agno/memory/__init__.py +2 -10
  137. agno/memory/manager.py +1003 -148
  138. agno/models/aimlapi/__init__.py +2 -2
  139. agno/models/aimlapi/aimlapi.py +6 -6
  140. agno/models/anthropic/claude.py +131 -131
  141. agno/models/aws/bedrock.py +110 -182
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +346 -290
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +105 -46
  148. agno/models/groq/groq.py +97 -35
  149. agno/models/huggingface/huggingface.py +92 -27
  150. agno/models/ibm/watsonx.py +72 -13
  151. agno/models/litellm/chat.py +85 -13
  152. agno/models/message.py +46 -151
  153. agno/models/meta/llama.py +85 -49
  154. agno/models/metrics.py +120 -0
  155. agno/models/mistral/mistral.py +90 -21
  156. agno/models/ollama/__init__.py +0 -2
  157. agno/models/ollama/chat.py +85 -47
  158. agno/models/openai/chat.py +154 -37
  159. agno/models/openai/responses.py +178 -105
  160. agno/models/perplexity/perplexity.py +26 -2
  161. agno/models/portkey/portkey.py +0 -7
  162. agno/models/response.py +15 -9
  163. agno/models/utils.py +20 -0
  164. agno/models/vercel/__init__.py +2 -2
  165. agno/models/vercel/v0.py +1 -1
  166. agno/models/vllm/__init__.py +2 -2
  167. agno/models/vllm/vllm.py +3 -3
  168. agno/models/xai/xai.py +10 -10
  169. agno/os/__init__.py +3 -0
  170. agno/os/app.py +497 -0
  171. agno/os/auth.py +47 -0
  172. agno/os/config.py +103 -0
  173. agno/os/interfaces/agui/__init__.py +3 -0
  174. agno/os/interfaces/agui/agui.py +31 -0
  175. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  176. agno/{app → os/interfaces}/agui/utils.py +77 -33
  177. agno/os/interfaces/base.py +21 -0
  178. agno/os/interfaces/slack/__init__.py +3 -0
  179. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  180. agno/os/interfaces/slack/slack.py +32 -0
  181. agno/os/interfaces/whatsapp/__init__.py +3 -0
  182. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  183. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  184. agno/os/mcp.py +235 -0
  185. agno/os/router.py +1400 -0
  186. agno/os/routers/__init__.py +3 -0
  187. agno/os/routers/evals/__init__.py +3 -0
  188. agno/os/routers/evals/evals.py +393 -0
  189. agno/os/routers/evals/schemas.py +142 -0
  190. agno/os/routers/evals/utils.py +161 -0
  191. agno/os/routers/knowledge/__init__.py +3 -0
  192. agno/os/routers/knowledge/knowledge.py +850 -0
  193. agno/os/routers/knowledge/schemas.py +118 -0
  194. agno/os/routers/memory/__init__.py +3 -0
  195. agno/os/routers/memory/memory.py +410 -0
  196. agno/os/routers/memory/schemas.py +58 -0
  197. agno/os/routers/metrics/__init__.py +3 -0
  198. agno/os/routers/metrics/metrics.py +178 -0
  199. agno/os/routers/metrics/schemas.py +47 -0
  200. agno/os/routers/session/__init__.py +3 -0
  201. agno/os/routers/session/session.py +536 -0
  202. agno/os/schema.py +945 -0
  203. agno/{app/playground → os}/settings.py +7 -15
  204. agno/os/utils.py +270 -0
  205. agno/reasoning/azure_ai_foundry.py +4 -4
  206. agno/reasoning/deepseek.py +4 -4
  207. agno/reasoning/default.py +6 -11
  208. agno/reasoning/groq.py +4 -4
  209. agno/reasoning/helpers.py +4 -6
  210. agno/reasoning/ollama.py +4 -4
  211. agno/reasoning/openai.py +4 -4
  212. agno/run/agent.py +633 -0
  213. agno/run/base.py +53 -77
  214. agno/run/cancel.py +81 -0
  215. agno/run/team.py +243 -96
  216. agno/run/workflow.py +550 -12
  217. agno/session/__init__.py +10 -0
  218. agno/session/agent.py +244 -0
  219. agno/session/summary.py +225 -0
  220. agno/session/team.py +262 -0
  221. agno/{storage/session/v2 → session}/workflow.py +47 -24
  222. agno/team/__init__.py +15 -16
  223. agno/team/team.py +3260 -4824
  224. agno/tools/agentql.py +14 -5
  225. agno/tools/airflow.py +9 -4
  226. agno/tools/api.py +7 -3
  227. agno/tools/apify.py +2 -46
  228. agno/tools/arxiv.py +8 -3
  229. agno/tools/aws_lambda.py +7 -5
  230. agno/tools/aws_ses.py +7 -1
  231. agno/tools/baidusearch.py +4 -1
  232. agno/tools/bitbucket.py +4 -4
  233. agno/tools/brandfetch.py +14 -11
  234. agno/tools/bravesearch.py +4 -1
  235. agno/tools/brightdata.py +43 -23
  236. agno/tools/browserbase.py +13 -4
  237. agno/tools/calcom.py +12 -10
  238. agno/tools/calculator.py +10 -27
  239. agno/tools/cartesia.py +20 -17
  240. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  241. agno/tools/confluence.py +8 -8
  242. agno/tools/crawl4ai.py +7 -1
  243. agno/tools/csv_toolkit.py +9 -8
  244. agno/tools/dalle.py +22 -12
  245. agno/tools/daytona.py +13 -16
  246. agno/tools/decorator.py +6 -3
  247. agno/tools/desi_vocal.py +17 -8
  248. agno/tools/discord.py +11 -8
  249. agno/tools/docker.py +30 -42
  250. agno/tools/duckdb.py +34 -53
  251. agno/tools/duckduckgo.py +8 -7
  252. agno/tools/e2b.py +62 -62
  253. agno/tools/eleven_labs.py +36 -29
  254. agno/tools/email.py +4 -1
  255. agno/tools/evm.py +7 -1
  256. agno/tools/exa.py +19 -14
  257. agno/tools/fal.py +30 -30
  258. agno/tools/file.py +9 -8
  259. agno/tools/financial_datasets.py +25 -44
  260. agno/tools/firecrawl.py +22 -22
  261. agno/tools/function.py +127 -18
  262. agno/tools/giphy.py +23 -11
  263. agno/tools/github.py +48 -126
  264. agno/tools/gmail.py +45 -61
  265. agno/tools/google_bigquery.py +7 -6
  266. agno/tools/google_maps.py +11 -26
  267. agno/tools/googlesearch.py +7 -2
  268. agno/tools/googlesheets.py +21 -17
  269. agno/tools/hackernews.py +9 -5
  270. agno/tools/jina.py +5 -4
  271. agno/tools/jira.py +18 -9
  272. agno/tools/knowledge.py +31 -32
  273. agno/tools/linear.py +19 -34
  274. agno/tools/linkup.py +5 -1
  275. agno/tools/local_file_system.py +8 -5
  276. agno/tools/lumalab.py +32 -20
  277. agno/tools/mcp.py +1 -2
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +33 -15
  282. agno/tools/models/gemini.py +59 -32
  283. agno/tools/models/groq.py +30 -23
  284. agno/tools/models/nebius.py +28 -12
  285. agno/tools/models_labs.py +40 -16
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +10 -8
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +58 -32
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +63 -47
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +55 -42
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +100 -123
  335. agno/utils/gemini.py +32 -2
  336. agno/utils/knowledge.py +29 -0
  337. agno/utils/log.py +54 -4
  338. agno/utils/mcp.py +68 -10
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/aws_claude.py +1 -1
  342. agno/utils/models/claude.py +47 -4
  343. agno/utils/models/cohere.py +1 -1
  344. agno/utils/models/mistral.py +8 -7
  345. agno/utils/models/schema_utils.py +3 -3
  346. agno/utils/models/watsonx.py +1 -1
  347. agno/utils/openai.py +1 -1
  348. agno/utils/pprint.py +33 -32
  349. agno/utils/print_response/agent.py +779 -0
  350. agno/utils/print_response/team.py +1669 -0
  351. agno/utils/print_response/workflow.py +1451 -0
  352. agno/utils/prompts.py +14 -14
  353. agno/utils/reasoning.py +87 -0
  354. agno/utils/response.py +42 -42
  355. agno/utils/streamlit.py +481 -0
  356. agno/utils/string.py +8 -22
  357. agno/utils/team.py +50 -0
  358. agno/utils/timer.py +2 -2
  359. agno/vectordb/base.py +33 -21
  360. agno/vectordb/cassandra/cassandra.py +287 -23
  361. agno/vectordb/chroma/chromadb.py +482 -59
  362. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  363. agno/vectordb/couchbase/couchbase.py +309 -29
  364. agno/vectordb/lancedb/lance_db.py +360 -21
  365. agno/vectordb/langchaindb/__init__.py +5 -0
  366. agno/vectordb/langchaindb/langchaindb.py +145 -0
  367. agno/vectordb/lightrag/__init__.py +5 -0
  368. agno/vectordb/lightrag/lightrag.py +374 -0
  369. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  370. agno/vectordb/milvus/milvus.py +242 -32
  371. agno/vectordb/mongodb/mongodb.py +200 -24
  372. agno/vectordb/pgvector/pgvector.py +319 -37
  373. agno/vectordb/pineconedb/pineconedb.py +221 -27
  374. agno/vectordb/qdrant/qdrant.py +334 -14
  375. agno/vectordb/singlestore/singlestore.py +286 -29
  376. agno/vectordb/surrealdb/surrealdb.py +187 -7
  377. agno/vectordb/upstashdb/upstashdb.py +342 -26
  378. agno/vectordb/weaviate/weaviate.py +227 -165
  379. agno/workflow/__init__.py +17 -13
  380. agno/workflow/{v2/condition.py → condition.py} +135 -32
  381. agno/workflow/{v2/loop.py → loop.py} +115 -28
  382. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  383. agno/workflow/{v2/router.py → router.py} +133 -32
  384. agno/workflow/{v2/step.py → step.py} +207 -49
  385. agno/workflow/{v2/steps.py → steps.py} +147 -66
  386. agno/workflow/types.py +482 -0
  387. agno/workflow/workflow.py +2410 -696
  388. agno-2.0.0.dist-info/METADATA +494 -0
  389. agno-2.0.0.dist-info/RECORD +515 -0
  390. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  391. agno/agent/metrics.py +0 -107
  392. agno/api/app.py +0 -35
  393. agno/api/playground.py +0 -92
  394. agno/api/schemas/app.py +0 -12
  395. agno/api/schemas/playground.py +0 -22
  396. agno/api/schemas/user.py +0 -35
  397. agno/api/schemas/workspace.py +0 -46
  398. agno/api/user.py +0 -160
  399. agno/api/workflows.py +0 -33
  400. agno/api/workspace.py +0 -175
  401. agno/app/agui/__init__.py +0 -3
  402. agno/app/agui/app.py +0 -17
  403. agno/app/agui/sync_router.py +0 -120
  404. agno/app/base.py +0 -186
  405. agno/app/discord/__init__.py +0 -3
  406. agno/app/fastapi/__init__.py +0 -3
  407. agno/app/fastapi/app.py +0 -107
  408. agno/app/fastapi/async_router.py +0 -457
  409. agno/app/fastapi/sync_router.py +0 -448
  410. agno/app/playground/app.py +0 -228
  411. agno/app/playground/async_router.py +0 -1050
  412. agno/app/playground/deploy.py +0 -249
  413. agno/app/playground/operator.py +0 -183
  414. agno/app/playground/schemas.py +0 -220
  415. agno/app/playground/serve.py +0 -55
  416. agno/app/playground/sync_router.py +0 -1042
  417. agno/app/playground/utils.py +0 -46
  418. agno/app/settings.py +0 -15
  419. agno/app/slack/__init__.py +0 -3
  420. agno/app/slack/app.py +0 -19
  421. agno/app/slack/sync_router.py +0 -92
  422. agno/app/utils.py +0 -54
  423. agno/app/whatsapp/__init__.py +0 -3
  424. agno/app/whatsapp/app.py +0 -15
  425. agno/app/whatsapp/sync_router.py +0 -197
  426. agno/cli/auth_server.py +0 -249
  427. agno/cli/config.py +0 -274
  428. agno/cli/console.py +0 -88
  429. agno/cli/credentials.py +0 -23
  430. agno/cli/entrypoint.py +0 -571
  431. agno/cli/operator.py +0 -357
  432. agno/cli/settings.py +0 -96
  433. agno/cli/ws/ws_cli.py +0 -817
  434. agno/constants.py +0 -13
  435. agno/document/__init__.py +0 -5
  436. agno/document/chunking/semantic.py +0 -45
  437. agno/document/chunking/strategy.py +0 -31
  438. agno/document/reader/__init__.py +0 -5
  439. agno/document/reader/base.py +0 -47
  440. agno/document/reader/docx_reader.py +0 -60
  441. agno/document/reader/gcs/pdf_reader.py +0 -44
  442. agno/document/reader/s3/pdf_reader.py +0 -59
  443. agno/document/reader/s3/text_reader.py +0 -63
  444. agno/document/reader/url_reader.py +0 -59
  445. agno/document/reader/youtube_reader.py +0 -58
  446. agno/embedder/__init__.py +0 -5
  447. agno/embedder/langdb.py +0 -80
  448. agno/embedder/mistral.py +0 -82
  449. agno/embedder/openai.py +0 -78
  450. agno/file/__init__.py +0 -5
  451. agno/file/file.py +0 -16
  452. agno/file/local/csv.py +0 -32
  453. agno/file/local/txt.py +0 -19
  454. agno/infra/app.py +0 -240
  455. agno/infra/base.py +0 -144
  456. agno/infra/context.py +0 -20
  457. agno/infra/db_app.py +0 -52
  458. agno/infra/resource.py +0 -205
  459. agno/infra/resources.py +0 -55
  460. agno/knowledge/agent.py +0 -702
  461. agno/knowledge/arxiv.py +0 -33
  462. agno/knowledge/combined.py +0 -36
  463. agno/knowledge/csv.py +0 -144
  464. agno/knowledge/csv_url.py +0 -124
  465. agno/knowledge/document.py +0 -223
  466. agno/knowledge/docx.py +0 -137
  467. agno/knowledge/firecrawl.py +0 -34
  468. agno/knowledge/gcs/__init__.py +0 -0
  469. agno/knowledge/gcs/base.py +0 -39
  470. agno/knowledge/gcs/pdf.py +0 -125
  471. agno/knowledge/json.py +0 -137
  472. agno/knowledge/langchain.py +0 -71
  473. agno/knowledge/light_rag.py +0 -273
  474. agno/knowledge/llamaindex.py +0 -66
  475. agno/knowledge/markdown.py +0 -154
  476. agno/knowledge/pdf.py +0 -164
  477. agno/knowledge/pdf_bytes.py +0 -42
  478. agno/knowledge/pdf_url.py +0 -148
  479. agno/knowledge/s3/__init__.py +0 -0
  480. agno/knowledge/s3/base.py +0 -64
  481. agno/knowledge/s3/pdf.py +0 -33
  482. agno/knowledge/s3/text.py +0 -34
  483. agno/knowledge/text.py +0 -141
  484. agno/knowledge/url.py +0 -46
  485. agno/knowledge/website.py +0 -179
  486. agno/knowledge/wikipedia.py +0 -32
  487. agno/knowledge/youtube.py +0 -35
  488. agno/memory/agent.py +0 -423
  489. agno/memory/classifier.py +0 -104
  490. agno/memory/db/__init__.py +0 -5
  491. agno/memory/db/base.py +0 -42
  492. agno/memory/db/mongodb.py +0 -189
  493. agno/memory/db/postgres.py +0 -203
  494. agno/memory/db/sqlite.py +0 -193
  495. agno/memory/memory.py +0 -22
  496. agno/memory/row.py +0 -36
  497. agno/memory/summarizer.py +0 -201
  498. agno/memory/summary.py +0 -19
  499. agno/memory/team.py +0 -415
  500. agno/memory/v2/__init__.py +0 -2
  501. agno/memory/v2/db/__init__.py +0 -1
  502. agno/memory/v2/db/base.py +0 -42
  503. agno/memory/v2/db/firestore.py +0 -339
  504. agno/memory/v2/db/mongodb.py +0 -196
  505. agno/memory/v2/db/postgres.py +0 -214
  506. agno/memory/v2/db/redis.py +0 -187
  507. agno/memory/v2/db/schema.py +0 -54
  508. agno/memory/v2/db/sqlite.py +0 -209
  509. agno/memory/v2/manager.py +0 -437
  510. agno/memory/v2/memory.py +0 -1097
  511. agno/memory/v2/schema.py +0 -55
  512. agno/memory/v2/summarizer.py +0 -215
  513. agno/memory/workflow.py +0 -38
  514. agno/models/ollama/tools.py +0 -430
  515. agno/models/qwen/__init__.py +0 -5
  516. agno/playground/__init__.py +0 -10
  517. agno/playground/deploy.py +0 -3
  518. agno/playground/playground.py +0 -3
  519. agno/playground/serve.py +0 -3
  520. agno/playground/settings.py +0 -3
  521. agno/reranker/__init__.py +0 -0
  522. agno/run/response.py +0 -467
  523. agno/run/v2/__init__.py +0 -0
  524. agno/run/v2/workflow.py +0 -567
  525. agno/storage/__init__.py +0 -0
  526. agno/storage/agent/__init__.py +0 -0
  527. agno/storage/agent/dynamodb.py +0 -1
  528. agno/storage/agent/json.py +0 -1
  529. agno/storage/agent/mongodb.py +0 -1
  530. agno/storage/agent/postgres.py +0 -1
  531. agno/storage/agent/singlestore.py +0 -1
  532. agno/storage/agent/sqlite.py +0 -1
  533. agno/storage/agent/yaml.py +0 -1
  534. agno/storage/base.py +0 -60
  535. agno/storage/dynamodb.py +0 -673
  536. agno/storage/firestore.py +0 -297
  537. agno/storage/gcs_json.py +0 -261
  538. agno/storage/in_memory.py +0 -234
  539. agno/storage/json.py +0 -237
  540. agno/storage/mongodb.py +0 -328
  541. agno/storage/mysql.py +0 -685
  542. agno/storage/postgres.py +0 -682
  543. agno/storage/redis.py +0 -336
  544. agno/storage/session/__init__.py +0 -16
  545. agno/storage/session/agent.py +0 -64
  546. agno/storage/session/team.py +0 -63
  547. agno/storage/session/v2/__init__.py +0 -5
  548. agno/storage/session/workflow.py +0 -61
  549. agno/storage/singlestore.py +0 -606
  550. agno/storage/sqlite.py +0 -646
  551. agno/storage/workflow/__init__.py +0 -0
  552. agno/storage/workflow/mongodb.py +0 -1
  553. agno/storage/workflow/postgres.py +0 -1
  554. agno/storage/workflow/sqlite.py +0 -1
  555. agno/storage/yaml.py +0 -241
  556. agno/tools/thinking.py +0 -73
  557. agno/utils/defaults.py +0 -57
  558. agno/utils/filesystem.py +0 -39
  559. agno/utils/git.py +0 -52
  560. agno/utils/json_io.py +0 -30
  561. agno/utils/load_env.py +0 -19
  562. agno/utils/py_io.py +0 -19
  563. agno/utils/pyproject.py +0 -18
  564. agno/utils/resource_filter.py +0 -31
  565. agno/workflow/v2/__init__.py +0 -21
  566. agno/workflow/v2/types.py +0 -357
  567. agno/workflow/v2/workflow.py +0 -3312
  568. agno/workspace/__init__.py +0 -0
  569. agno/workspace/config.py +0 -325
  570. agno/workspace/enums.py +0 -6
  571. agno/workspace/helpers.py +0 -52
  572. agno/workspace/operator.py +0 -757
  573. agno/workspace/settings.py +0 -158
  574. agno-1.8.1.dist-info/METADATA +0 -982
  575. agno-1.8.1.dist-info/RECORD +0 -566
  576. agno-1.8.1.dist-info/entry_points.txt +0 -3
  577. agno-1.8.1.dist-info/licenses/LICENSE +0 -375
  578. /agno/{app → db/migrations}/__init__.py +0 -0
  579. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  580. /agno/{cli → integrations}/__init__.py +0 -0
  581. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  582. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  583. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  584. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  585. /agno/{app → os/interfaces}/slack/security.py +0 -0
  586. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  587. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  588. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  589. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  590. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import json
2
3
  import uuid
3
4
  from hashlib import md5
@@ -17,9 +18,9 @@ try:
17
18
  except ImportError:
18
19
  raise ImportError("Weaviate is not installed. Install using 'pip install weaviate-client'.")
19
20
 
20
- from agno.document import Document
21
- from agno.embedder import Embedder
22
- from agno.reranker.base import Reranker
21
+ from agno.knowledge.document import Document
22
+ from agno.knowledge.embedder import Embedder
23
+ from agno.knowledge.reranker.base import Reranker
23
24
  from agno.utils.log import log_debug, log_info, logger
24
25
  from agno.vectordb.base import VectorDb
25
26
  from agno.vectordb.search import SearchType
@@ -62,7 +63,7 @@ class Weaviate(VectorDb):
62
63
 
63
64
  # Embedder setup
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.")
@@ -139,6 +140,8 @@ class Weaviate(VectorDb):
139
140
  Property(name="name", data_type=DataType.TEXT),
140
141
  Property(name="content", data_type=DataType.TEXT, tokenization=Tokenization.LOWERCASE),
141
142
  Property(name="meta_data", data_type=DataType.TEXT),
143
+ Property(name="content_id", data_type=DataType.TEXT),
144
+ Property(name="content_hash", data_type=DataType.TEXT),
142
145
  ],
143
146
  vectorizer_config=Configure.Vectorizer.none(),
144
147
  vector_index_config=self.get_vector_index_config(self.vector_index, self.distance),
@@ -154,6 +157,8 @@ class Weaviate(VectorDb):
154
157
  Property(name="name", data_type=DataType.TEXT),
155
158
  Property(name="content", data_type=DataType.TEXT, tokenization=Tokenization.LOWERCASE),
156
159
  Property(name="meta_data", data_type=DataType.TEXT),
160
+ Property(name="content_id", data_type=DataType.TEXT),
161
+ Property(name="content_hash", data_type=DataType.TEXT),
157
162
  ],
158
163
  vectorizer_config=Configure.Vectorizer.none(),
159
164
  vector_index_config=self.get_vector_index_config(self.vector_index, self.distance),
@@ -162,95 +167,14 @@ class Weaviate(VectorDb):
162
167
  finally:
163
168
  await client.close()
164
169
 
165
- def doc_content_changed(self, document: Document, check_existing: Optional[bool] = True) -> Optional[bool]:
166
- """
167
- Check if the content of the document has changed by comparing its UUID.
168
-
169
- Args:
170
- document (Document): Document to check
171
-
172
- Returns:
173
- bool: True if the document content has changed, False otherwise. None on wrong input.
174
- check_existing (bool): If True, check if the document exists before checking if the content changed.
175
- """
176
- if not document or not document.content:
177
- logger.warning("Invalid document: Missing content.")
178
- return None
179
-
180
- if check_existing and document.name and not self.name_exists(document.name):
181
- logger.warning(f"A document by this name does not exist: {document.name}")
182
- return None
183
-
184
- doc_uuid, _ = self._get_doc_uuid(document)
185
-
186
- collection = self.get_client().collections.get(self.collection)
187
- existing_doc = collection.query.fetch_object_by_id(doc_uuid)
188
-
189
- if not existing_doc:
190
- return True
191
- else:
192
- return False
193
-
194
- def doc_delete(self, name: str) -> None:
195
- """
196
- Delete all documents from Weaviate with a specific 'name' property.
197
-
198
- Args:
199
- name (str): Document name to delete.
200
- """
201
- collection = self.get_client().collections.get(self.collection)
202
- filter_expr = Filter.by_property("name").equal(name)
203
-
204
- result = collection.data.delete_many(where=filter_expr)
205
-
206
- log_debug(f"Deleted document by name: '{name}' - {result.successful} documents deleted.")
207
- if result.failed > 0:
208
- logger.warning(
209
- f"Failed to delete (some chunks of) document with name: '{name}' - "
210
- f"Failed {result.failed} out of {result.matches} times. {result.successful} successful deletions."
211
- )
212
-
213
- def doc_exists(self, document: Document) -> bool:
214
- """
215
- Validate if the document exists using consistent UUID generation.
216
-
217
- Args:
218
- document (Document): Document to validate
219
-
220
- Returns:
221
- bool: True if the document exists, False otherwise
222
- """
223
- if not document or not document.content:
224
- logger.warning("Invalid document: Missing content.")
225
- return False # Early exit for invalid input
226
-
227
- doc_uuid, _ = self._get_doc_uuid(document)
228
-
170
+ def content_hash_exists(self, content_hash: str) -> bool:
171
+ """Check if a document with the given content hash exists in the collection."""
229
172
  collection = self.get_client().collections.get(self.collection)
230
- return collection.data.exists(doc_uuid)
231
-
232
- async def async_doc_exists(self, document: Document) -> bool:
233
- """
234
- Validate if the document exists using consistent UUID generation asynchronously.
235
-
236
- Args:
237
- document (Document): Document to validate
238
-
239
- Returns:
240
- bool: True if the document exists, False otherwise
241
- """
242
- if not document or not document.content:
243
- logger.warning("Invalid document: Missing content.")
244
- return False # Early exit for invalid input
245
-
246
- doc_uuid, _ = self._get_doc_uuid(document)
247
-
248
- client = await self.get_async_client()
249
- try:
250
- collection = client.collections.get(self.collection)
251
- return await collection.data.exists(doc_uuid)
252
- finally:
253
- await client.close()
173
+ result = collection.query.fetch_objects(
174
+ limit=1,
175
+ filters=Filter.by_property("content_hash").equal(content_hash),
176
+ )
177
+ return len(result.objects) > 0
254
178
 
255
179
  def name_exists(self, name: str) -> bool:
256
180
  """
@@ -290,7 +214,7 @@ class Weaviate(VectorDb):
290
214
  finally:
291
215
  await client.close()
292
216
 
293
- def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
217
+ def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
294
218
  """
295
219
  Insert documents into Weaviate.
296
220
 
@@ -307,7 +231,9 @@ class Weaviate(VectorDb):
307
231
  logger.error(f"Document embedding is None: {document.name}")
308
232
  continue
309
233
 
310
- doc_uuid, cleaned_content = self._get_doc_uuid(document)
234
+ cleaned_content = document.content.replace("\x00", "\ufffd")
235
+ record_id = md5(cleaned_content.encode()).hexdigest()
236
+ doc_uuid = uuid.UUID(hex=record_id[:32])
311
237
 
312
238
  # Merge filters with metadata
313
239
  meta_data = document.meta_data or {}
@@ -322,13 +248,17 @@ class Weaviate(VectorDb):
322
248
  "name": document.name,
323
249
  "content": cleaned_content,
324
250
  "meta_data": meta_data_str,
251
+ "content_id": document.content_id,
252
+ "content_hash": content_hash,
325
253
  },
326
254
  vector=document.embedding,
327
255
  uuid=doc_uuid,
328
256
  )
329
257
  log_debug(f"Inserted document: {document.name} ({meta_data})")
330
258
 
331
- async def async_insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
259
+ async def async_insert(
260
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
261
+ ) -> None:
332
262
  """
333
263
  Insert documents into Weaviate asynchronously.
334
264
 
@@ -340,6 +270,10 @@ class Weaviate(VectorDb):
340
270
  if not documents:
341
271
  return
342
272
 
273
+ # Embed document
274
+ embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
275
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
276
+
343
277
  client = await self.get_async_client()
344
278
  try:
345
279
  collection = client.collections.get(self.collection)
@@ -347,14 +281,14 @@ class Weaviate(VectorDb):
347
281
  # Process documents first
348
282
  for document in documents:
349
283
  try:
350
- # Embed document
351
- document.embed(embedder=self.embedder)
352
284
  if document.embedding is None:
353
285
  logger.error(f"Document embedding is None: {document.name}")
354
286
  continue
355
287
 
356
288
  # Clean content and generate UUID
357
- doc_uuid, cleaned_content = self._get_doc_uuid(document)
289
+ cleaned_content = document.content.replace("\x00", "\ufffd")
290
+ record_id = md5(cleaned_content.encode()).hexdigest()
291
+ doc_uuid = uuid.UUID(hex=record_id[:32])
358
292
 
359
293
  # Serialize meta_data to JSON string
360
294
  meta_data_str = json.dumps(document.meta_data) if document.meta_data else None
@@ -364,6 +298,8 @@ class Weaviate(VectorDb):
364
298
  "name": document.name,
365
299
  "content": cleaned_content,
366
300
  "meta_data": meta_data_str,
301
+ "content_id": document.content_id,
302
+ "content_hash": content_hash,
367
303
  }
368
304
 
369
305
  # Use the API correctly - properties, vector and uuid are separate parameters
@@ -376,7 +312,7 @@ class Weaviate(VectorDb):
376
312
  finally:
377
313
  await client.close()
378
314
 
379
- def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
315
+ def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
380
316
  """
381
317
  Upsert documents into Weaviate.
382
318
 
@@ -385,30 +321,13 @@ class Weaviate(VectorDb):
385
321
  filters (Optional[Dict[str, Any]]): Filters to apply while upserting
386
322
  """
387
323
  log_debug(f"Upserting {len(documents)} documents into Weaviate.")
324
+ if self.content_hash_exists(content_hash):
325
+ self._delete_by_content_hash(content_hash)
326
+ self.insert(content_hash=content_hash, documents=documents, filters=filters)
388
327
 
389
- _docs_to_insert = []
390
- for document in documents:
391
- assert document.name is not None, "Document name must be set for upsert operation."
392
-
393
- if self.name_exists(document.name):
394
- if self.doc_content_changed(document, check_existing=False):
395
- log_debug(
396
- f"Document already exists, but content changed. Document will be deleted and added again: {document.name}"
397
- )
398
-
399
- is_first_or_only_chunk = ("chunk" in document.meta_data and document.meta_data["chunk"] == 1) or (
400
- "chunk" not in document.meta_data
401
- )
402
- if is_first_or_only_chunk:
403
- self.doc_delete(document.name)
404
- _docs_to_insert.append(document)
405
- else:
406
- log_debug(f"Document skipped, content is unchanged: {document.name}")
407
- else:
408
- _docs_to_insert.append(document)
409
- self.insert(_docs_to_insert)
410
-
411
- async def async_upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
328
+ async def async_upsert(
329
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
330
+ ) -> None:
412
331
  """
413
332
  Upsert documents into Weaviate asynchronously.
414
333
  When documents with the same ID already exist, they will be replaced.
@@ -418,37 +337,10 @@ class Weaviate(VectorDb):
418
337
  documents (List[Document]): List of documents to upsert
419
338
  filters (Optional[Dict[str, Any]]): Filters to apply while upserting
420
339
  """
421
- if not documents:
422
- return
423
-
424
- log_debug(f"Upserting {len(documents)} documents into Weaviate asynchronously.")
425
-
426
- client = await self.get_async_client()
427
- try:
428
- collection = client.collections.get(self.collection)
429
-
430
- for document in documents:
431
- document.embed(embedder=self.embedder)
432
- if document.embedding is None:
433
- logger.error(f"Document embedding is None: {document.name}")
434
- continue
435
-
436
- doc_uuid, cleaned_content = self._get_doc_uuid(document)
437
-
438
- # Serialize meta_data to JSON string
439
- meta_data_str = json.dumps(document.meta_data) if document.meta_data else None
440
-
441
- properties = {
442
- "name": document.name,
443
- "content": cleaned_content,
444
- "meta_data": meta_data_str,
445
- }
446
-
447
- await collection.data.replace(uuid=doc_uuid, properties=properties, vector=document.embedding)
448
-
449
- log_debug(f"Upserted document asynchronously: {document.name}")
450
- finally:
451
- await client.close()
340
+ if self.content_hash_exists(content_hash):
341
+ self._delete_by_content_hash(content_hash)
342
+ await self.async_insert(content_hash=content_hash, documents=documents, filters=filters)
343
+ return
452
344
 
453
345
  def search(self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None) -> List[Document]:
454
346
  """
@@ -509,7 +401,7 @@ class Weaviate(VectorDb):
509
401
  response = collection.query.near_vector(
510
402
  near_vector=query_embedding,
511
403
  limit=limit,
512
- return_properties=["name", "content", "meta_data"],
404
+ return_properties=["name", "content", "meta_data", "content_id"],
513
405
  include_vector=True,
514
406
  filters=filter_expr,
515
407
  )
@@ -557,7 +449,7 @@ class Weaviate(VectorDb):
557
449
  response = await collection.query.near_vector(
558
450
  near_vector=query_embedding,
559
451
  limit=limit,
560
- return_properties=["name", "content", "meta_data"],
452
+ return_properties=["name", "content", "meta_data", "content_id"],
561
453
  include_vector=True,
562
454
  filters=filter_expr,
563
455
  )
@@ -585,7 +477,7 @@ class Weaviate(VectorDb):
585
477
  query=query,
586
478
  query_properties=["content"],
587
479
  limit=limit,
588
- return_properties=["name", "content", "meta_data"],
480
+ return_properties=["name", "content", "meta_data", "content_id"],
589
481
  include_vector=True,
590
482
  filters=filter_expr,
591
483
  )
@@ -629,7 +521,7 @@ class Weaviate(VectorDb):
629
521
  query=query,
630
522
  query_properties=["content"],
631
523
  limit=limit,
632
- return_properties=["name", "content", "meta_data"],
524
+ return_properties=["name", "content", "meta_data", "content_id"],
633
525
  include_vector=True,
634
526
  filters=filter_expr,
635
527
  )
@@ -662,7 +554,7 @@ class Weaviate(VectorDb):
662
554
  query=query,
663
555
  vector=query_embedding,
664
556
  limit=limit,
665
- return_properties=["name", "content", "meta_data"],
557
+ return_properties=["name", "content", "meta_data", "content_id"],
666
558
  include_vector=True,
667
559
  query_properties=["content"],
668
560
  alpha=self.hybrid_search_alpha,
@@ -713,7 +605,7 @@ class Weaviate(VectorDb):
713
605
  query=query,
714
606
  vector=query_embedding,
715
607
  limit=limit,
716
- return_properties=["name", "content", "meta_data"],
608
+ return_properties=["name", "content", "meta_data", "content_id"],
717
609
  include_vector=True,
718
610
  query_properties=["content"],
719
611
  alpha=self.hybrid_search_alpha,
@@ -771,6 +663,86 @@ class Weaviate(VectorDb):
771
663
  self.drop()
772
664
  return True
773
665
 
666
+ def delete_by_id(self, id: str) -> bool:
667
+ """Delete document by ID."""
668
+ try:
669
+ try:
670
+ doc_uuid = uuid.UUID(hex=id[:32]) if len(id) == 32 else uuid.UUID(id)
671
+ except ValueError:
672
+ log_info(f"Invalid UUID format for ID '{id}' - treating as non-existent")
673
+ return True
674
+
675
+ collection = self.get_client().collections.get(self.collection)
676
+
677
+ if not collection.data.exists(doc_uuid):
678
+ log_info(f"Document with ID {id} does not exist")
679
+ return True
680
+
681
+ collection.data.delete_by_id(doc_uuid)
682
+ log_info(f"Deleted document with ID '{id}' from collection '{self.collection}'.")
683
+ return True
684
+ except Exception as e:
685
+ logger.error(f"Error deleting document by ID '{id}': {e}")
686
+ return False
687
+
688
+ def delete_by_name(self, name: str) -> bool:
689
+ """Delete content by name using direct filter deletion."""
690
+ try:
691
+ collection = self.get_client().collections.get(self.collection)
692
+
693
+ collection.data.delete_many(where=Filter.by_property("name").equal(name))
694
+
695
+ log_info(f"Deleted documents with name '{name}' from collection '{self.collection}'.")
696
+ return True
697
+
698
+ except Exception as e:
699
+ logger.error(f"Error deleting documents by name '{name}': {e}")
700
+ return False
701
+
702
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
703
+ """Delete content by metadata using direct filter deletion."""
704
+ try:
705
+ collection = self.get_client().collections.get(self.collection)
706
+
707
+ # Build filter for metadata search
708
+ filter_expr = self._build_filter_expression(metadata)
709
+ if filter_expr is None:
710
+ log_info(f"No valid filter could be built for metadata: {metadata}")
711
+ return False
712
+
713
+ collection.data.delete_many(where=filter_expr)
714
+
715
+ log_info(f"Deleted documents with metadata '{metadata}' from collection '{self.collection}'.")
716
+ return True
717
+
718
+ except Exception as e:
719
+ logger.error(f"Error deleting documents by metadata '{metadata}': {e}")
720
+ return False
721
+
722
+ def delete_by_content_id(self, content_id: str) -> bool:
723
+ """Delete content by content ID using direct filter deletion."""
724
+ try:
725
+ collection = self.get_client().collections.get(self.collection)
726
+
727
+ collection.data.delete_many(where=Filter.by_property("content_id").equal(content_id))
728
+
729
+ log_info(f"Deleted documents with content_id '{content_id}' from collection '{self.collection}'.")
730
+ return True
731
+
732
+ except Exception as e:
733
+ logger.error(f"Error deleting documents by content_id '{content_id}': {e}")
734
+ return False
735
+
736
+ def delete_by_content_hash(self, content_hash: str) -> bool:
737
+ """Delete content by content hash using direct filter deletion."""
738
+ try:
739
+ collection = self.get_client().collections.get(self.collection)
740
+ collection.data.delete_many(where=Filter.by_property("content_hash").equal(content_hash))
741
+ return True
742
+ except Exception as e:
743
+ logger.error(f"Error deleting documents by content_hash '{content_hash}': {e}")
744
+ return False
745
+
774
746
  def get_vector_index_config(self, index_type: VectorIndex, distance_metric: Distance):
775
747
  """
776
748
  Returns the appropriate vector index configuration with the specified distance metric.
@@ -807,17 +779,17 @@ class Weaviate(VectorDb):
807
779
  search_results: List[Document] = []
808
780
  for obj in response.objects:
809
781
  properties = obj.properties
810
- meta_data = json.loads(properties["meta_data"]) if properties.get("meta_data") else None
782
+ meta_data = json.loads(properties["meta_data"]) if properties.get("meta_data") else {}
811
783
  embedding = obj.vector["default"] if isinstance(obj.vector, dict) else obj.vector
812
784
 
813
785
  search_results.append(
814
786
  Document(
815
- name=properties["name"],
816
- meta_data=meta_data if meta_data else {},
817
- content=properties["content"],
787
+ name=properties.get("name"),
788
+ meta_data=meta_data,
789
+ content=properties.get("content", ""),
818
790
  embedder=self.embedder,
819
791
  embedding=embedding,
820
- usage=None,
792
+ content_id=properties.get("content_id"),
821
793
  )
822
794
  )
823
795
 
@@ -827,7 +799,7 @@ class Weaviate(VectorDb):
827
799
  """Indicate that upsert functionality is available."""
828
800
  return True
829
801
 
830
- def _build_filter_expression(self, filters: Optional[Dict[str, Any]]) -> Optional[Filter]:
802
+ def _build_filter_expression(self, filters: Optional[Dict[str, Any]]):
831
803
  """
832
804
  Build a filter expression for Weaviate queries.
833
805
 
@@ -870,3 +842,93 @@ class Weaviate(VectorDb):
870
842
  return None
871
843
 
872
844
  return None
845
+
846
+ def id_exists(self, id: str) -> bool:
847
+ """Check if a document with the given ID exists in the collection.
848
+
849
+ Args:
850
+ id (str): The document ID to check.
851
+
852
+ Returns:
853
+ bool: True if the document exists, False otherwise.
854
+ """
855
+ try:
856
+ doc_uuid = uuid.UUID(hex=id[:32]) if len(id) == 32 else uuid.UUID(id)
857
+ collection = self.get_client().collections.get(self.collection)
858
+ return collection.data.exists(doc_uuid)
859
+ except ValueError:
860
+ log_info(f"Invalid UUID format for ID '{id}' - treating as non-existent")
861
+ return False
862
+ except Exception as e:
863
+ logger.error(f"Error checking if ID '{id}' exists: {e}")
864
+ return False
865
+
866
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
867
+ """
868
+ Update the metadata for documents with the given content_id.
869
+
870
+ Args:
871
+ content_id (str): The content ID to update
872
+ metadata (Dict[str, Any]): The metadata to update
873
+ """
874
+ try:
875
+ weaviate_client = self.get_client()
876
+ collection = weaviate_client.collections.get(self.collection)
877
+
878
+ # Query for objects with the given content_id
879
+ query_result = collection.query.fetch_objects( # type: ignore
880
+ where=Filter.by_property("content_id").equal(content_id),
881
+ limit=1000, # Get all matching objects
882
+ )
883
+
884
+ if not query_result.objects:
885
+ logger.debug(f"No documents found with content_id: {content_id}")
886
+ return
887
+
888
+ # Update each matching object
889
+ updated_count = 0
890
+ for obj in query_result.objects:
891
+ # Get current properties
892
+ current_properties = obj.properties or {}
893
+
894
+ # Merge existing metadata with new metadata
895
+ updated_properties = current_properties.copy()
896
+
897
+ # Handle nested metadata updates
898
+ if "meta_data" in updated_properties and isinstance(updated_properties["meta_data"], dict):
899
+ updated_properties["meta_data"].update(metadata)
900
+ else:
901
+ # If no existing meta_data or it's not a dict, set it directly
902
+ updated_properties["meta_data"] = metadata
903
+
904
+ if "filters" in updated_properties and isinstance(updated_properties["filters"], dict):
905
+ updated_properties["filters"].update(metadata)
906
+ else:
907
+ updated_properties["filters"] = metadata
908
+
909
+ # Update the object
910
+ collection.data.update(uuid=obj.uuid, properties=updated_properties)
911
+ updated_count += 1
912
+
913
+ logger.debug(f"Updated metadata for {updated_count} documents with content_id: {content_id}")
914
+
915
+ except Exception as e:
916
+ logger.error(f"Error updating metadata for content_id '{content_id}': {e}")
917
+ raise
918
+
919
+ def _delete_by_content_hash(self, content_hash: str) -> bool:
920
+ """Delete documents by content hash using direct filter deletion."""
921
+ try:
922
+ collection = self.get_client().collections.get(self.collection)
923
+
924
+ # Build filter for content_hash search
925
+ filter_expr = Filter.by_property("content_hash").equal(content_hash)
926
+
927
+ collection.data.delete_many(where=filter_expr)
928
+
929
+ log_info(f"Deleted documents with content_hash '{content_hash}' from collection '{self.collection}'.")
930
+ return True
931
+
932
+ except Exception as e:
933
+ logger.error(f"Error deleting documents by content_hash '{content_hash}': {e}")
934
+ return False
agno/workflow/__init__.py CHANGED
@@ -1,17 +1,21 @@
1
- from agno.run.workflow import (
2
- RunEvent,
3
- WorkflowCompletedEvent,
4
- WorkflowRunResponseEvent,
5
- WorkflowRunResponseStartedEvent,
6
- )
7
- from agno.workflow.workflow import RunResponse, Workflow, WorkflowSession
1
+ from agno.workflow.condition import Condition
2
+ from agno.workflow.loop import Loop
3
+ from agno.workflow.parallel import Parallel
4
+ from agno.workflow.router import Router
5
+ from agno.workflow.step import Step
6
+ from agno.workflow.steps import Steps
7
+ from agno.workflow.types import StepInput, StepOutput, WorkflowExecutionInput
8
+ from agno.workflow.workflow import Workflow
8
9
 
9
10
  __all__ = [
10
- "RunEvent",
11
- "RunResponse",
12
11
  "Workflow",
13
- "WorkflowSession",
14
- "WorkflowRunResponseEvent",
15
- "WorkflowRunResponseStartedEvent",
16
- "WorkflowCompletedEvent",
12
+ "Steps",
13
+ "Step",
14
+ "Loop",
15
+ "Parallel",
16
+ "Condition",
17
+ "Router",
18
+ "WorkflowExecutionInput",
19
+ "StepInput",
20
+ "StepOutput",
17
21
  ]