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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (580) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2778 -4123
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +9 -64
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1749 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1438 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +888 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1051 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1417 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +142 -43
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +10 -10
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1515 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  136. agno/memory/__init__.py +2 -10
  137. agno/memory/manager.py +1003 -148
  138. agno/models/aimlapi/__init__.py +2 -2
  139. agno/models/aimlapi/aimlapi.py +6 -6
  140. agno/models/anthropic/claude.py +129 -82
  141. agno/models/aws/bedrock.py +107 -175
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +347 -287
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +100 -42
  148. agno/models/groq/groq.py +97 -35
  149. agno/models/huggingface/huggingface.py +92 -27
  150. agno/models/ibm/watsonx.py +72 -13
  151. agno/models/litellm/chat.py +85 -13
  152. agno/models/message.py +38 -144
  153. agno/models/meta/llama.py +85 -49
  154. agno/models/metrics.py +120 -0
  155. agno/models/mistral/mistral.py +90 -21
  156. agno/models/ollama/__init__.py +0 -2
  157. agno/models/ollama/chat.py +84 -46
  158. agno/models/openai/chat.py +121 -23
  159. agno/models/openai/responses.py +178 -105
  160. agno/models/perplexity/perplexity.py +26 -2
  161. agno/models/portkey/portkey.py +0 -7
  162. agno/models/response.py +14 -8
  163. agno/models/utils.py +20 -0
  164. agno/models/vercel/__init__.py +2 -2
  165. agno/models/vercel/v0.py +1 -1
  166. agno/models/vllm/__init__.py +2 -2
  167. agno/models/vllm/vllm.py +3 -3
  168. agno/models/xai/xai.py +10 -10
  169. agno/os/__init__.py +3 -0
  170. agno/os/app.py +393 -0
  171. agno/os/auth.py +47 -0
  172. agno/os/config.py +103 -0
  173. agno/os/interfaces/agui/__init__.py +3 -0
  174. agno/os/interfaces/agui/agui.py +31 -0
  175. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  176. agno/{app → os/interfaces}/agui/utils.py +65 -28
  177. agno/os/interfaces/base.py +21 -0
  178. agno/os/interfaces/slack/__init__.py +3 -0
  179. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  180. agno/os/interfaces/slack/slack.py +33 -0
  181. agno/os/interfaces/whatsapp/__init__.py +3 -0
  182. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  183. agno/os/interfaces/whatsapp/whatsapp.py +30 -0
  184. agno/os/router.py +843 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +204 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +413 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +179 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +58 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +163 -0
  201. agno/os/schema.py +892 -0
  202. agno/{app/playground → os}/settings.py +8 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/{response.py → agent.py} +144 -72
  212. agno/run/base.py +44 -58
  213. agno/run/cancel.py +83 -0
  214. agno/run/team.py +133 -77
  215. agno/run/workflow.py +537 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +2961 -4253
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +42 -22
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +18 -13
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +18 -11
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +16 -7
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +61 -61
  252. agno/tools/eleven_labs.py +35 -28
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +29 -29
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +22 -22
  260. agno/tools/function.py +68 -17
  261. agno/tools/giphy.py +22 -10
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +31 -19
  276. agno/tools/mem0.py +18 -12
  277. agno/tools/memori.py +14 -10
  278. agno/tools/mlx_transcribe.py +3 -2
  279. agno/tools/models/azure_openai.py +32 -14
  280. agno/tools/models/gemini.py +58 -31
  281. agno/tools/models/groq.py +29 -20
  282. agno/tools/models/nebius.py +27 -11
  283. agno/tools/models_labs.py +39 -15
  284. agno/tools/moviepy_video.py +7 -6
  285. agno/tools/neo4j.py +10 -8
  286. agno/tools/newspaper.py +7 -2
  287. agno/tools/newspaper4k.py +8 -3
  288. agno/tools/openai.py +57 -26
  289. agno/tools/openbb.py +12 -11
  290. agno/tools/opencv.py +62 -46
  291. agno/tools/openweather.py +14 -12
  292. agno/tools/pandas.py +11 -3
  293. agno/tools/postgres.py +4 -12
  294. agno/tools/pubmed.py +4 -1
  295. agno/tools/python.py +9 -22
  296. agno/tools/reasoning.py +35 -27
  297. agno/tools/reddit.py +11 -26
  298. agno/tools/replicate.py +54 -41
  299. agno/tools/resend.py +4 -1
  300. agno/tools/scrapegraph.py +15 -14
  301. agno/tools/searxng.py +10 -23
  302. agno/tools/serpapi.py +6 -3
  303. agno/tools/serper.py +13 -4
  304. agno/tools/shell.py +9 -2
  305. agno/tools/slack.py +12 -11
  306. agno/tools/sleep.py +3 -2
  307. agno/tools/spider.py +24 -4
  308. agno/tools/sql.py +7 -6
  309. agno/tools/tavily.py +6 -4
  310. agno/tools/telegram.py +12 -4
  311. agno/tools/todoist.py +11 -31
  312. agno/tools/toolkit.py +1 -1
  313. agno/tools/trafilatura.py +22 -6
  314. agno/tools/trello.py +9 -22
  315. agno/tools/twilio.py +10 -3
  316. agno/tools/user_control_flow.py +6 -1
  317. agno/tools/valyu.py +34 -5
  318. agno/tools/visualization.py +19 -28
  319. agno/tools/webbrowser.py +4 -3
  320. agno/tools/webex.py +11 -7
  321. agno/tools/website.py +15 -46
  322. agno/tools/webtools.py +12 -4
  323. agno/tools/whatsapp.py +5 -9
  324. agno/tools/wikipedia.py +20 -13
  325. agno/tools/x.py +14 -13
  326. agno/tools/yfinance.py +13 -40
  327. agno/tools/youtube.py +26 -20
  328. agno/tools/zendesk.py +7 -2
  329. agno/tools/zep.py +10 -7
  330. agno/tools/zoom.py +10 -9
  331. agno/utils/common.py +1 -19
  332. agno/utils/events.py +95 -118
  333. agno/utils/knowledge.py +29 -0
  334. agno/utils/log.py +2 -2
  335. agno/utils/mcp.py +11 -5
  336. agno/utils/media.py +39 -0
  337. agno/utils/message.py +12 -1
  338. agno/utils/models/claude.py +6 -4
  339. agno/utils/models/mistral.py +8 -7
  340. agno/utils/models/schema_utils.py +3 -3
  341. agno/utils/pprint.py +33 -32
  342. agno/utils/print_response/agent.py +779 -0
  343. agno/utils/print_response/team.py +1565 -0
  344. agno/utils/print_response/workflow.py +1451 -0
  345. agno/utils/prompts.py +14 -14
  346. agno/utils/reasoning.py +87 -0
  347. agno/utils/response.py +42 -42
  348. agno/utils/string.py +8 -22
  349. agno/utils/team.py +50 -0
  350. agno/utils/timer.py +2 -2
  351. agno/vectordb/base.py +33 -21
  352. agno/vectordb/cassandra/cassandra.py +287 -23
  353. agno/vectordb/chroma/chromadb.py +482 -59
  354. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  355. agno/vectordb/couchbase/couchbase.py +309 -29
  356. agno/vectordb/lancedb/lance_db.py +360 -21
  357. agno/vectordb/langchaindb/__init__.py +5 -0
  358. agno/vectordb/langchaindb/langchaindb.py +145 -0
  359. agno/vectordb/lightrag/__init__.py +5 -0
  360. agno/vectordb/lightrag/lightrag.py +374 -0
  361. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  362. agno/vectordb/milvus/milvus.py +242 -32
  363. agno/vectordb/mongodb/mongodb.py +200 -24
  364. agno/vectordb/pgvector/pgvector.py +319 -37
  365. agno/vectordb/pineconedb/pineconedb.py +221 -27
  366. agno/vectordb/qdrant/qdrant.py +334 -14
  367. agno/vectordb/singlestore/singlestore.py +286 -29
  368. agno/vectordb/surrealdb/surrealdb.py +187 -7
  369. agno/vectordb/upstashdb/upstashdb.py +342 -26
  370. agno/vectordb/weaviate/weaviate.py +227 -165
  371. agno/workflow/__init__.py +17 -13
  372. agno/workflow/{v2/condition.py → condition.py} +135 -32
  373. agno/workflow/{v2/loop.py → loop.py} +115 -28
  374. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  375. agno/workflow/{v2/router.py → router.py} +133 -32
  376. agno/workflow/{v2/step.py → step.py} +200 -42
  377. agno/workflow/{v2/steps.py → steps.py} +147 -66
  378. agno/workflow/types.py +482 -0
  379. agno/workflow/workflow.py +2394 -696
  380. agno-2.0.0a1.dist-info/METADATA +355 -0
  381. agno-2.0.0a1.dist-info/RECORD +514 -0
  382. agno/agent/metrics.py +0 -107
  383. agno/api/app.py +0 -35
  384. agno/api/playground.py +0 -92
  385. agno/api/schemas/app.py +0 -12
  386. agno/api/schemas/playground.py +0 -22
  387. agno/api/schemas/user.py +0 -35
  388. agno/api/schemas/workspace.py +0 -46
  389. agno/api/user.py +0 -160
  390. agno/api/workflows.py +0 -33
  391. agno/api/workspace.py +0 -175
  392. agno/app/agui/__init__.py +0 -3
  393. agno/app/agui/app.py +0 -17
  394. agno/app/agui/sync_router.py +0 -120
  395. agno/app/base.py +0 -186
  396. agno/app/discord/__init__.py +0 -3
  397. agno/app/fastapi/__init__.py +0 -3
  398. agno/app/fastapi/app.py +0 -107
  399. agno/app/fastapi/async_router.py +0 -457
  400. agno/app/fastapi/sync_router.py +0 -448
  401. agno/app/playground/app.py +0 -228
  402. agno/app/playground/async_router.py +0 -1050
  403. agno/app/playground/deploy.py +0 -249
  404. agno/app/playground/operator.py +0 -183
  405. agno/app/playground/schemas.py +0 -220
  406. agno/app/playground/serve.py +0 -55
  407. agno/app/playground/sync_router.py +0 -1042
  408. agno/app/playground/utils.py +0 -46
  409. agno/app/settings.py +0 -15
  410. agno/app/slack/__init__.py +0 -3
  411. agno/app/slack/app.py +0 -19
  412. agno/app/slack/sync_router.py +0 -92
  413. agno/app/utils.py +0 -54
  414. agno/app/whatsapp/__init__.py +0 -3
  415. agno/app/whatsapp/app.py +0 -15
  416. agno/app/whatsapp/sync_router.py +0 -197
  417. agno/cli/auth_server.py +0 -249
  418. agno/cli/config.py +0 -274
  419. agno/cli/console.py +0 -88
  420. agno/cli/credentials.py +0 -23
  421. agno/cli/entrypoint.py +0 -571
  422. agno/cli/operator.py +0 -357
  423. agno/cli/settings.py +0 -96
  424. agno/cli/ws/ws_cli.py +0 -817
  425. agno/constants.py +0 -13
  426. agno/document/__init__.py +0 -5
  427. agno/document/chunking/semantic.py +0 -45
  428. agno/document/chunking/strategy.py +0 -31
  429. agno/document/reader/__init__.py +0 -5
  430. agno/document/reader/base.py +0 -47
  431. agno/document/reader/docx_reader.py +0 -60
  432. agno/document/reader/gcs/pdf_reader.py +0 -44
  433. agno/document/reader/s3/pdf_reader.py +0 -59
  434. agno/document/reader/s3/text_reader.py +0 -63
  435. agno/document/reader/url_reader.py +0 -59
  436. agno/document/reader/youtube_reader.py +0 -58
  437. agno/embedder/__init__.py +0 -5
  438. agno/embedder/langdb.py +0 -80
  439. agno/embedder/mistral.py +0 -82
  440. agno/embedder/openai.py +0 -78
  441. agno/file/__init__.py +0 -5
  442. agno/file/file.py +0 -16
  443. agno/file/local/csv.py +0 -32
  444. agno/file/local/txt.py +0 -19
  445. agno/infra/app.py +0 -240
  446. agno/infra/base.py +0 -144
  447. agno/infra/context.py +0 -20
  448. agno/infra/db_app.py +0 -52
  449. agno/infra/resource.py +0 -205
  450. agno/infra/resources.py +0 -55
  451. agno/knowledge/agent.py +0 -702
  452. agno/knowledge/arxiv.py +0 -33
  453. agno/knowledge/combined.py +0 -36
  454. agno/knowledge/csv.py +0 -144
  455. agno/knowledge/csv_url.py +0 -124
  456. agno/knowledge/document.py +0 -223
  457. agno/knowledge/docx.py +0 -137
  458. agno/knowledge/firecrawl.py +0 -34
  459. agno/knowledge/gcs/__init__.py +0 -0
  460. agno/knowledge/gcs/base.py +0 -39
  461. agno/knowledge/gcs/pdf.py +0 -125
  462. agno/knowledge/json.py +0 -137
  463. agno/knowledge/langchain.py +0 -71
  464. agno/knowledge/light_rag.py +0 -273
  465. agno/knowledge/llamaindex.py +0 -66
  466. agno/knowledge/markdown.py +0 -154
  467. agno/knowledge/pdf.py +0 -164
  468. agno/knowledge/pdf_bytes.py +0 -42
  469. agno/knowledge/pdf_url.py +0 -148
  470. agno/knowledge/s3/__init__.py +0 -0
  471. agno/knowledge/s3/base.py +0 -64
  472. agno/knowledge/s3/pdf.py +0 -33
  473. agno/knowledge/s3/text.py +0 -34
  474. agno/knowledge/text.py +0 -141
  475. agno/knowledge/url.py +0 -46
  476. agno/knowledge/website.py +0 -179
  477. agno/knowledge/wikipedia.py +0 -32
  478. agno/knowledge/youtube.py +0 -35
  479. agno/memory/agent.py +0 -423
  480. agno/memory/classifier.py +0 -104
  481. agno/memory/db/__init__.py +0 -5
  482. agno/memory/db/base.py +0 -42
  483. agno/memory/db/mongodb.py +0 -189
  484. agno/memory/db/postgres.py +0 -203
  485. agno/memory/db/sqlite.py +0 -193
  486. agno/memory/memory.py +0 -22
  487. agno/memory/row.py +0 -36
  488. agno/memory/summarizer.py +0 -201
  489. agno/memory/summary.py +0 -19
  490. agno/memory/team.py +0 -415
  491. agno/memory/v2/__init__.py +0 -2
  492. agno/memory/v2/db/__init__.py +0 -1
  493. agno/memory/v2/db/base.py +0 -42
  494. agno/memory/v2/db/firestore.py +0 -339
  495. agno/memory/v2/db/mongodb.py +0 -196
  496. agno/memory/v2/db/postgres.py +0 -214
  497. agno/memory/v2/db/redis.py +0 -187
  498. agno/memory/v2/db/schema.py +0 -54
  499. agno/memory/v2/db/sqlite.py +0 -209
  500. agno/memory/v2/manager.py +0 -437
  501. agno/memory/v2/memory.py +0 -1097
  502. agno/memory/v2/schema.py +0 -55
  503. agno/memory/v2/summarizer.py +0 -215
  504. agno/memory/workflow.py +0 -38
  505. agno/models/ollama/tools.py +0 -430
  506. agno/models/qwen/__init__.py +0 -5
  507. agno/playground/__init__.py +0 -10
  508. agno/playground/deploy.py +0 -3
  509. agno/playground/playground.py +0 -3
  510. agno/playground/serve.py +0 -3
  511. agno/playground/settings.py +0 -3
  512. agno/reranker/__init__.py +0 -0
  513. agno/run/v2/__init__.py +0 -0
  514. agno/run/v2/workflow.py +0 -567
  515. agno/storage/__init__.py +0 -0
  516. agno/storage/agent/__init__.py +0 -0
  517. agno/storage/agent/dynamodb.py +0 -1
  518. agno/storage/agent/json.py +0 -1
  519. agno/storage/agent/mongodb.py +0 -1
  520. agno/storage/agent/postgres.py +0 -1
  521. agno/storage/agent/singlestore.py +0 -1
  522. agno/storage/agent/sqlite.py +0 -1
  523. agno/storage/agent/yaml.py +0 -1
  524. agno/storage/base.py +0 -60
  525. agno/storage/dynamodb.py +0 -673
  526. agno/storage/firestore.py +0 -297
  527. agno/storage/gcs_json.py +0 -261
  528. agno/storage/in_memory.py +0 -234
  529. agno/storage/json.py +0 -237
  530. agno/storage/mongodb.py +0 -328
  531. agno/storage/mysql.py +0 -685
  532. agno/storage/postgres.py +0 -682
  533. agno/storage/redis.py +0 -336
  534. agno/storage/session/__init__.py +0 -16
  535. agno/storage/session/agent.py +0 -64
  536. agno/storage/session/team.py +0 -63
  537. agno/storage/session/v2/__init__.py +0 -5
  538. agno/storage/session/workflow.py +0 -61
  539. agno/storage/singlestore.py +0 -606
  540. agno/storage/sqlite.py +0 -646
  541. agno/storage/workflow/__init__.py +0 -0
  542. agno/storage/workflow/mongodb.py +0 -1
  543. agno/storage/workflow/postgres.py +0 -1
  544. agno/storage/workflow/sqlite.py +0 -1
  545. agno/storage/yaml.py +0 -241
  546. agno/tools/thinking.py +0 -73
  547. agno/utils/defaults.py +0 -57
  548. agno/utils/filesystem.py +0 -39
  549. agno/utils/git.py +0 -52
  550. agno/utils/json_io.py +0 -30
  551. agno/utils/load_env.py +0 -19
  552. agno/utils/py_io.py +0 -19
  553. agno/utils/pyproject.py +0 -18
  554. agno/utils/resource_filter.py +0 -31
  555. agno/workflow/v2/__init__.py +0 -21
  556. agno/workflow/v2/types.py +0 -357
  557. agno/workflow/v2/workflow.py +0 -3312
  558. agno/workspace/__init__.py +0 -0
  559. agno/workspace/config.py +0 -325
  560. agno/workspace/enums.py +0 -6
  561. agno/workspace/helpers.py +0 -52
  562. agno/workspace/operator.py +0 -757
  563. agno/workspace/settings.py +0 -158
  564. agno-1.8.1.dist-info/METADATA +0 -982
  565. agno-1.8.1.dist-info/RECORD +0 -566
  566. agno-1.8.1.dist-info/entry_points.txt +0 -3
  567. /agno/{app → db/migrations}/__init__.py +0 -0
  568. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  569. /agno/{cli → integrations}/__init__.py +0 -0
  570. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  571. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  572. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  573. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  574. /agno/{app → os/interfaces}/slack/security.py +0 -0
  575. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  576. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  577. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  578. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  579. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  580. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,10 @@
1
1
  import asyncio
2
+ from hashlib import md5
2
3
  from math import sqrt
3
4
  from typing import Any, Dict, List, Optional, Union, cast
4
5
 
5
6
  try:
7
+ from sqlalchemy import update
6
8
  from sqlalchemy.dialects import postgresql
7
9
  from sqlalchemy.engine import Engine, create_engine
8
10
  from sqlalchemy.inspection import inspect
@@ -10,6 +12,7 @@ try:
10
12
  from sqlalchemy.schema import Column, Index, MetaData, Table
11
13
  from sqlalchemy.sql.expression import bindparam, desc, func, select, text
12
14
  from sqlalchemy.types import DateTime, String
15
+
13
16
  except ImportError:
14
17
  raise ImportError("`sqlalchemy` not installed. Please install using `pip install sqlalchemy psycopg`")
15
18
 
@@ -18,11 +21,10 @@ try:
18
21
  except ImportError:
19
22
  raise ImportError("`pgvector` not installed. Please install using `pip install pgvector`")
20
23
 
21
- from agno.document import Document
22
- from agno.embedder import Embedder
23
- from agno.reranker.base import Reranker
24
+ from agno.knowledge.document import Document
25
+ from agno.knowledge.embedder import Embedder
26
+ from agno.knowledge.reranker.base import Reranker
24
27
  from agno.utils.log import log_debug, log_info, logger
25
- from agno.utils.string import safe_content_hash
26
28
  from agno.vectordb.base import VectorDb
27
29
  from agno.vectordb.distance import Distance
28
30
  from agno.vectordb.pgvector.index import HNSW, Ivfflat
@@ -53,6 +55,7 @@ class PgVector(VectorDb):
53
55
  schema_version: int = 1,
54
56
  auto_upgrade_schema: bool = False,
55
57
  reranker: Optional[Reranker] = None,
58
+ use_batch: bool = False,
56
59
  ):
57
60
  """
58
61
  Initialize the PgVector instance.
@@ -93,10 +96,11 @@ class PgVector(VectorDb):
93
96
  self.db_url: Optional[str] = db_url
94
97
  self.db_engine: Engine = db_engine
95
98
  self.metadata: MetaData = MetaData(schema=self.schema)
99
+ self.use_batch: bool = use_batch
96
100
 
97
101
  # Embedder for embedding the document contents
98
102
  if embedder is None:
99
- from agno.embedder.openai import OpenAIEmbedder
103
+ from agno.knowledge.embedder.openai import OpenAIEmbedder
100
104
 
101
105
  embedder = OpenAIEmbedder()
102
106
  log_info("Embedder not provided, using OpenAIEmbedder as default.")
@@ -155,6 +159,7 @@ class PgVector(VectorDb):
155
159
  Column("created_at", DateTime(timezone=True), server_default=func.now()),
156
160
  Column("updated_at", DateTime(timezone=True), onupdate=func.now()),
157
161
  Column("content_hash", String),
162
+ Column("content_id", String),
158
163
  extend_existing=True,
159
164
  )
160
165
 
@@ -162,7 +167,7 @@ class PgVector(VectorDb):
162
167
  Index(f"idx_{self.table_name}_id", table.c.id)
163
168
  Index(f"idx_{self.table_name}_name", table.c.name)
164
169
  Index(f"idx_{self.table_name}_content_hash", table.c.content_hash)
165
-
170
+ Index(f"idx_{self.table_name}_content_id", table.c.content_id)
166
171
  return table
167
172
 
168
173
  def get_table(self) -> Table:
@@ -229,23 +234,6 @@ class PgVector(VectorDb):
229
234
  logger.error(f"Error checking if record exists: {e}")
230
235
  return False
231
236
 
232
- def doc_exists(self, document: Document) -> bool:
233
- """
234
- Check if a document with the same content hash exists in the table.
235
-
236
- Args:
237
- document (Document): The document to check.
238
-
239
- Returns:
240
- bool: True if the document exists, False otherwise.
241
- """
242
- content_hash = safe_content_hash(document.content)
243
- return self._record_exists(self.table.c.content_hash, content_hash)
244
-
245
- async def async_doc_exists(self, document: Document) -> bool:
246
- """Check if document exists asynchronously by running in a thread."""
247
- return await asyncio.to_thread(self.doc_exists, document)
248
-
249
237
  def name_exists(self, name: str) -> bool:
250
238
  """
251
239
  Check if a document with the given name exists in the table.
@@ -274,6 +262,12 @@ class PgVector(VectorDb):
274
262
  """
275
263
  return self._record_exists(self.table.c.id, id)
276
264
 
265
+ def content_hash_exists(self, content_hash: str) -> bool:
266
+ """
267
+ Check if a document with the given content hash exists in the table.
268
+ """
269
+ return self._record_exists(self.table.c.content_hash, content_hash)
270
+
277
271
  def _clean_content(self, content: str) -> str:
278
272
  """
279
273
  Clean the content by replacing null characters.
@@ -288,6 +282,7 @@ class PgVector(VectorDb):
288
282
 
289
283
  def insert(
290
284
  self,
285
+ content_hash: str,
291
286
  documents: List[Document],
292
287
  filters: Optional[Dict[str, Any]] = None,
293
288
  batch_size: int = 100,
@@ -296,6 +291,7 @@ class PgVector(VectorDb):
296
291
  Insert documents into the database.
297
292
 
298
293
  Args:
294
+ content_hash (str): The content hash to insert.
299
295
  documents (List[Document]): List of documents to insert.
300
296
  filters (Optional[Dict[str, Any]]): Filters to apply to the documents.
301
297
  batch_size (int): Number of documents to insert in each batch.
@@ -310,7 +306,7 @@ class PgVector(VectorDb):
310
306
  batch_records = []
311
307
  for doc in batch_docs:
312
308
  try:
313
- batch_records.append(self._get_document_record(doc, filters))
309
+ batch_records.append(self._get_document_record(doc, filters, content_hash))
314
310
  except Exception as e:
315
311
  logger.error(f"Error processing document '{doc.name}': {e}")
316
312
 
@@ -327,9 +323,62 @@ class PgVector(VectorDb):
327
323
  logger.error(f"Error inserting documents: {e}")
328
324
  raise
329
325
 
330
- async def async_insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
331
- """Insert documents asynchronously by running in a thread."""
332
- await asyncio.to_thread(self.insert, documents, filters)
326
+ async def async_insert(
327
+ self,
328
+ content_hash: str,
329
+ documents: List[Document],
330
+ filters: Optional[Dict[str, Any]] = None,
331
+ batch_size: int = 100,
332
+ ) -> None:
333
+ """Insert documents asynchronously with parallel embedding."""
334
+ try:
335
+ with self.Session() as sess:
336
+ for i in range(0, len(documents), batch_size):
337
+ batch_docs = documents[i : i + batch_size]
338
+ log_debug(f"Processing batch starting at index {i}, size: {len(batch_docs)}")
339
+ try:
340
+ embed_tasks = [doc.async_embed(embedder=self.embedder) for doc in batch_docs]
341
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
342
+
343
+ # Prepare documents for insertion
344
+ batch_records = []
345
+ for doc in batch_docs:
346
+ try:
347
+ cleaned_content = self._clean_content(doc.content)
348
+ record_id = doc.id or content_hash
349
+
350
+ meta_data = doc.meta_data or {}
351
+ if filters:
352
+ meta_data.update(filters)
353
+
354
+ record = {
355
+ "id": record_id,
356
+ "name": doc.name,
357
+ "meta_data": doc.meta_data,
358
+ "filters": filters,
359
+ "content": cleaned_content,
360
+ "embedding": doc.embedding,
361
+ "usage": doc.usage,
362
+ "content_hash": content_hash,
363
+ "content_id": doc.content_id,
364
+ }
365
+ batch_records.append(record)
366
+ except Exception as e:
367
+ logger.error(f"Error processing document '{doc.name}': {e}")
368
+
369
+ # Insert the batch of records
370
+ if batch_records:
371
+ insert_stmt = postgresql.insert(self.table)
372
+ sess.execute(insert_stmt, batch_records)
373
+ sess.commit() # Commit batch independently
374
+ log_info(f"Inserted batch of {len(batch_records)} documents.")
375
+ except Exception as e:
376
+ logger.error(f"Error with batch starting at index {i}: {e}")
377
+ sess.rollback() # Rollback the current batch if there's an error
378
+ raise
379
+ except Exception as e:
380
+ logger.error(f"Error inserting documents: {e}")
381
+ raise
333
382
 
334
383
  def upsert_available(self) -> bool:
335
384
  """
@@ -342,6 +391,27 @@ class PgVector(VectorDb):
342
391
 
343
392
  def upsert(
344
393
  self,
394
+ content_hash: str,
395
+ documents: List[Document],
396
+ filters: Optional[Dict[str, Any]] = None,
397
+ batch_size: int = 100,
398
+ ) -> None:
399
+ """
400
+ Upsert documents by content hash.
401
+ First delete all documents with the same content hash.
402
+ Then upsert the new documents.
403
+ """
404
+ try:
405
+ if self.content_hash_exists(content_hash):
406
+ self._delete_by_content_hash(content_hash)
407
+ self._upsert(content_hash, documents, filters, batch_size)
408
+ except Exception as e:
409
+ logger.error(f"Error upserting documents by content hash: {e}")
410
+ raise
411
+
412
+ def _upsert(
413
+ self,
414
+ content_hash: str,
345
415
  documents: List[Document],
346
416
  filters: Optional[Dict[str, Any]] = None,
347
417
  batch_size: int = 100,
@@ -358,16 +428,22 @@ class PgVector(VectorDb):
358
428
  with self.Session() as sess:
359
429
  for i in range(0, len(documents), batch_size):
360
430
  batch_docs = documents[i : i + batch_size]
361
- log_debug(f"Processing batch starting at index {i}, size: {len(batch_docs)}")
431
+ log_info(f"Processing batch starting at index {i}, size: {len(batch_docs)}")
362
432
  try:
363
433
  # Prepare documents for upserting
364
- batch_records = []
434
+ batch_records_dict: Dict[str, Dict[str, Any]] = {} # Use dict to deduplicate by ID
365
435
  for doc in batch_docs:
366
436
  try:
367
- batch_records.append(self._get_document_record(doc, filters))
437
+ batch_records_dict[doc.id] = self._get_document_record(doc, filters, content_hash) # type: ignore
368
438
  except Exception as e:
369
439
  logger.error(f"Error processing document '{doc.name}': {e}")
370
440
 
441
+ # Convert dict to list for upsert
442
+ batch_records = list(batch_records_dict.values())
443
+ if not batch_records:
444
+ log_info("No valid records to upsert in this batch.")
445
+ continue
446
+
371
447
  # Upsert the batch of records
372
448
  insert_stmt = postgresql.insert(self.table).values(batch_records)
373
449
  upsert_stmt = insert_stmt.on_conflict_do_update(
@@ -380,6 +456,7 @@ class PgVector(VectorDb):
380
456
  "embedding": insert_stmt.excluded.embedding,
381
457
  "usage": insert_stmt.excluded.usage,
382
458
  "content_hash": insert_stmt.excluded.content_hash,
459
+ "content_id": insert_stmt.excluded.content_id,
383
460
  },
384
461
  )
385
462
  sess.execute(upsert_stmt)
@@ -393,30 +470,155 @@ class PgVector(VectorDb):
393
470
  logger.error(f"Error upserting documents: {e}")
394
471
  raise
395
472
 
396
- def _get_document_record(self, doc: Document, filters: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
473
+ def _get_document_record(
474
+ self, doc: Document, filters: Optional[Dict[str, Any]] = None, content_hash: str = ""
475
+ ) -> Dict[str, Any]:
397
476
  doc.embed(embedder=self.embedder)
398
477
  cleaned_content = self._clean_content(doc.content)
399
- content_hash = safe_content_hash(doc.content)
400
- _id = doc.id or content_hash
478
+ record_id = doc.id or content_hash
401
479
 
402
480
  meta_data = doc.meta_data or {}
403
481
  if filters:
404
482
  meta_data.update(filters)
405
483
 
406
484
  return {
407
- "id": _id,
485
+ "id": record_id,
408
486
  "name": doc.name,
409
- "meta_data": meta_data,
487
+ "meta_data": doc.meta_data,
410
488
  "filters": filters,
411
489
  "content": cleaned_content,
412
490
  "embedding": doc.embedding,
413
491
  "usage": doc.usage,
414
492
  "content_hash": content_hash,
493
+ "content_id": doc.content_id,
415
494
  }
416
495
 
417
- async def async_upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
496
+ async def async_upsert(
497
+ self,
498
+ content_hash: str,
499
+ documents: List[Document],
500
+ filters: Optional[Dict[str, Any]] = None,
501
+ batch_size: int = 100,
502
+ ) -> None:
418
503
  """Upsert documents asynchronously by running in a thread."""
419
- await asyncio.to_thread(self.upsert, documents, filters)
504
+ try:
505
+ if self.content_hash_exists(content_hash):
506
+ self._delete_by_content_hash(content_hash)
507
+ await self._async_upsert(content_hash, documents, filters, batch_size)
508
+ except Exception as e:
509
+ logger.error(f"Error upserting documents by content hash: {e}")
510
+ raise
511
+
512
+ async def _async_upsert(
513
+ self,
514
+ content_hash: str,
515
+ documents: List[Document],
516
+ filters: Optional[Dict[str, Any]] = None,
517
+ batch_size: int = 100,
518
+ ) -> None:
519
+ """
520
+ Upsert (insert or update) documents in the database.
521
+
522
+ Args:
523
+ documents (List[Document]): List of documents to upsert.
524
+ filters (Optional[Dict[str, Any]]): Filters to apply to the documents.
525
+ batch_size (int): Number of documents to upsert in each batch.
526
+ """
527
+ try:
528
+ with self.Session() as sess:
529
+ for i in range(0, len(documents), batch_size):
530
+ batch_docs = documents[i : i + batch_size]
531
+ log_info(f"Processing batch starting at index {i}, size: {len(batch_docs)}")
532
+ try:
533
+ embed_tasks = [doc.async_embed(embedder=self.embedder) for doc in batch_docs]
534
+ await asyncio.gather(*embed_tasks, return_exceptions=True)
535
+
536
+ # Prepare documents for upserting
537
+ batch_records_dict = {} # Use dict to deduplicate by ID
538
+ for doc in batch_docs:
539
+ try:
540
+ cleaned_content = self._clean_content(doc.content)
541
+ record_id = md5(cleaned_content.encode()).hexdigest()
542
+
543
+ meta_data = doc.meta_data or {}
544
+ if filters:
545
+ meta_data.update(filters)
546
+
547
+ record = {
548
+ "id": record_id, # use record_id as a reproducible id to avoid duplicates while upsert
549
+ "name": doc.name,
550
+ "meta_data": doc.meta_data,
551
+ "filters": filters,
552
+ "content": cleaned_content,
553
+ "embedding": doc.embedding,
554
+ "usage": doc.usage,
555
+ "content_hash": content_hash,
556
+ "content_id": doc.content_id,
557
+ }
558
+ batch_records_dict[record_id] = record # This deduplicates by ID
559
+ except Exception as e:
560
+ logger.error(f"Error processing document '{doc.name}': {e}")
561
+
562
+ # Convert dict to list for upsert
563
+ batch_records = list(batch_records_dict.values())
564
+ if not batch_records:
565
+ log_info("No valid records to upsert in this batch.")
566
+ continue
567
+
568
+ # Upsert the batch of records
569
+ insert_stmt = postgresql.insert(self.table).values(batch_records)
570
+ upsert_stmt = insert_stmt.on_conflict_do_update(
571
+ index_elements=["id"],
572
+ set_={
573
+ "name": insert_stmt.excluded.name,
574
+ "meta_data": insert_stmt.excluded.meta_data,
575
+ "filters": insert_stmt.excluded.filters,
576
+ "content": insert_stmt.excluded.content,
577
+ "embedding": insert_stmt.excluded.embedding,
578
+ "usage": insert_stmt.excluded.usage,
579
+ "content_hash": insert_stmt.excluded.content_hash,
580
+ "content_id": insert_stmt.excluded.content_id,
581
+ },
582
+ )
583
+ sess.execute(upsert_stmt)
584
+ sess.commit() # Commit batch independently
585
+ log_info(f"Upserted batch of {len(batch_records)} documents.")
586
+ except Exception as e:
587
+ logger.error(f"Error with batch starting at index {i}: {e}")
588
+ sess.rollback() # Rollback the current batch if there's an error
589
+ raise
590
+ except Exception as e:
591
+ logger.error(f"Error upserting documents: {e}")
592
+ raise
593
+
594
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
595
+ """
596
+ Update the metadata for a document.
597
+
598
+ Args:
599
+ id (str): The ID of the document.
600
+ metadata (Dict[str, Any]): The metadata to update.
601
+ """
602
+ try:
603
+ with self.Session() as sess:
604
+ # Merge JSONB instead of overwriting: coalesce(existing, '{}') || :new
605
+ stmt = (
606
+ update(self.table)
607
+ .where(self.table.c.content_id == content_id)
608
+ .values(
609
+ meta_data=func.coalesce(self.table.c.meta_data, text("'{}'::jsonb")).op("||")(
610
+ bindparam("md", metadata, type_=postgresql.JSONB)
611
+ ),
612
+ filters=func.coalesce(self.table.c.filters, text("'{}'::jsonb")).op("||")(
613
+ bindparam("ft", metadata, type_=postgresql.JSONB)
614
+ ),
615
+ )
616
+ )
617
+ sess.execute(stmt)
618
+ sess.commit()
619
+ except Exception as e:
620
+ logger.error(f"Error updating metadata for document {content_id}: {e}")
621
+ raise
420
622
 
421
623
  def search(self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None) -> List[Document]:
422
624
  """
@@ -1025,6 +1227,86 @@ class PgVector(VectorDb):
1025
1227
  sess.rollback()
1026
1228
  return False
1027
1229
 
1230
+ def delete_by_id(self, id: str) -> bool:
1231
+ """
1232
+ Delete content by ID.
1233
+ """
1234
+ try:
1235
+ with self.Session() as sess, sess.begin():
1236
+ stmt = self.table.delete().where(self.table.c.id == id)
1237
+ sess.execute(stmt)
1238
+ sess.commit()
1239
+ log_info(f"Deleted records with id '{id}' from table '{self.table.fullname}'.")
1240
+ return True
1241
+ except Exception as e:
1242
+ logger.error(f"Error deleting rows from table '{self.table.fullname}': {e}")
1243
+ sess.rollback()
1244
+ return False
1245
+
1246
+ def delete_by_name(self, name: str) -> bool:
1247
+ """
1248
+ Delete content by name.
1249
+ """
1250
+ try:
1251
+ with self.Session() as sess, sess.begin():
1252
+ stmt = self.table.delete().where(self.table.c.name == name)
1253
+ sess.execute(stmt)
1254
+ sess.commit()
1255
+ log_info(f"Deleted records with name '{name}' from table '{self.table.fullname}'.")
1256
+ return True
1257
+ except Exception as e:
1258
+ logger.error(f"Error deleting rows from table '{self.table.fullname}': {e}")
1259
+ sess.rollback()
1260
+ return False
1261
+
1262
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
1263
+ """
1264
+ Delete content by metadata.
1265
+ """
1266
+ try:
1267
+ with self.Session() as sess, sess.begin():
1268
+ stmt = self.table.delete().where(self.table.c.meta_data.contains(metadata))
1269
+ sess.execute(stmt)
1270
+ sess.commit()
1271
+ log_info(f"Deleted records with metadata '{metadata}' from table '{self.table.fullname}'.")
1272
+ return True
1273
+ except Exception as e:
1274
+ logger.error(f"Error deleting rows from table '{self.table.fullname}': {e}")
1275
+ sess.rollback()
1276
+ return False
1277
+
1278
+ def delete_by_content_id(self, content_id: str) -> bool:
1279
+ """
1280
+ Delete content by content ID.
1281
+ """
1282
+ try:
1283
+ with self.Session() as sess, sess.begin():
1284
+ stmt = self.table.delete().where(self.table.c.content_id == content_id)
1285
+ sess.execute(stmt)
1286
+ sess.commit()
1287
+ log_info(f"Deleted records with content ID '{content_id}' from table '{self.table.fullname}'.")
1288
+ return True
1289
+ except Exception as e:
1290
+ logger.error(f"Error deleting rows from table '{self.table.fullname}': {e}")
1291
+ sess.rollback()
1292
+ return False
1293
+
1294
+ def _delete_by_content_hash(self, content_hash: str) -> bool:
1295
+ """
1296
+ Delete content by content hash.
1297
+ """
1298
+ try:
1299
+ with self.Session() as sess, sess.begin():
1300
+ stmt = self.table.delete().where(self.table.c.content_hash == content_hash)
1301
+ sess.execute(stmt)
1302
+ sess.commit()
1303
+ log_info(f"Deleted records with content hash '{content_hash}' from table '{self.table.fullname}'.")
1304
+ return True
1305
+ except Exception as e:
1306
+ logger.error(f"Error deleting rows from table '{self.table.fullname}': {e}")
1307
+ sess.rollback()
1308
+ return False
1309
+
1028
1310
  def __deepcopy__(self, memo):
1029
1311
  """
1030
1312
  Create a deep copy of the PgVector instance, handling unpickleable attributes.