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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (583) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2781 -4126
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +9 -64
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1749 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1438 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +888 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1051 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1417 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +142 -43
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +10 -10
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1515 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  136. agno/media.py +2 -2
  137. agno/memory/__init__.py +2 -10
  138. agno/memory/manager.py +1003 -148
  139. agno/models/aimlapi/__init__.py +2 -2
  140. agno/models/aimlapi/aimlapi.py +6 -6
  141. agno/models/anthropic/claude.py +129 -82
  142. agno/models/aws/bedrock.py +107 -175
  143. agno/models/aws/claude.py +64 -18
  144. agno/models/azure/ai_foundry.py +73 -23
  145. agno/models/base.py +347 -287
  146. agno/models/cerebras/cerebras.py +84 -27
  147. agno/models/cohere/chat.py +106 -98
  148. agno/models/dashscope/dashscope.py +14 -5
  149. agno/models/google/gemini.py +123 -53
  150. agno/models/groq/groq.py +97 -35
  151. agno/models/huggingface/huggingface.py +92 -27
  152. agno/models/ibm/watsonx.py +72 -13
  153. agno/models/litellm/chat.py +85 -13
  154. agno/models/message.py +38 -144
  155. agno/models/meta/llama.py +85 -49
  156. agno/models/metrics.py +120 -0
  157. agno/models/mistral/mistral.py +90 -21
  158. agno/models/ollama/__init__.py +0 -2
  159. agno/models/ollama/chat.py +84 -46
  160. agno/models/openai/chat.py +135 -27
  161. agno/models/openai/responses.py +233 -115
  162. agno/models/perplexity/perplexity.py +26 -2
  163. agno/models/portkey/portkey.py +0 -7
  164. agno/models/response.py +14 -8
  165. agno/models/utils.py +20 -0
  166. agno/models/vercel/__init__.py +2 -2
  167. agno/models/vercel/v0.py +1 -1
  168. agno/models/vllm/__init__.py +2 -2
  169. agno/models/vllm/vllm.py +3 -3
  170. agno/models/xai/xai.py +10 -10
  171. agno/os/__init__.py +3 -0
  172. agno/os/app.py +393 -0
  173. agno/os/auth.py +47 -0
  174. agno/os/config.py +103 -0
  175. agno/os/interfaces/agui/__init__.py +3 -0
  176. agno/os/interfaces/agui/agui.py +31 -0
  177. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  178. agno/{app → os/interfaces}/agui/utils.py +65 -28
  179. agno/os/interfaces/base.py +21 -0
  180. agno/os/interfaces/slack/__init__.py +3 -0
  181. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  182. agno/os/interfaces/slack/slack.py +33 -0
  183. agno/os/interfaces/whatsapp/__init__.py +3 -0
  184. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  185. agno/os/interfaces/whatsapp/whatsapp.py +30 -0
  186. agno/os/router.py +843 -0
  187. agno/os/routers/__init__.py +3 -0
  188. agno/os/routers/evals/__init__.py +3 -0
  189. agno/os/routers/evals/evals.py +204 -0
  190. agno/os/routers/evals/schemas.py +142 -0
  191. agno/os/routers/evals/utils.py +161 -0
  192. agno/os/routers/knowledge/__init__.py +3 -0
  193. agno/os/routers/knowledge/knowledge.py +413 -0
  194. agno/os/routers/knowledge/schemas.py +118 -0
  195. agno/os/routers/memory/__init__.py +3 -0
  196. agno/os/routers/memory/memory.py +179 -0
  197. agno/os/routers/memory/schemas.py +58 -0
  198. agno/os/routers/metrics/__init__.py +3 -0
  199. agno/os/routers/metrics/metrics.py +58 -0
  200. agno/os/routers/metrics/schemas.py +47 -0
  201. agno/os/routers/session/__init__.py +3 -0
  202. agno/os/routers/session/session.py +163 -0
  203. agno/os/schema.py +892 -0
  204. agno/{app/playground → os}/settings.py +8 -15
  205. agno/os/utils.py +270 -0
  206. agno/reasoning/azure_ai_foundry.py +4 -4
  207. agno/reasoning/deepseek.py +4 -4
  208. agno/reasoning/default.py +6 -11
  209. agno/reasoning/groq.py +4 -4
  210. agno/reasoning/helpers.py +4 -6
  211. agno/reasoning/ollama.py +4 -4
  212. agno/reasoning/openai.py +4 -4
  213. agno/run/{response.py → agent.py} +144 -72
  214. agno/run/base.py +44 -58
  215. agno/run/cancel.py +83 -0
  216. agno/run/team.py +133 -77
  217. agno/run/workflow.py +537 -12
  218. agno/session/__init__.py +10 -0
  219. agno/session/agent.py +244 -0
  220. agno/session/summary.py +225 -0
  221. agno/session/team.py +262 -0
  222. agno/{storage/session/v2 → session}/workflow.py +47 -24
  223. agno/team/__init__.py +15 -16
  224. agno/team/team.py +2967 -4243
  225. agno/tools/agentql.py +14 -5
  226. agno/tools/airflow.py +9 -4
  227. agno/tools/api.py +7 -3
  228. agno/tools/apify.py +2 -46
  229. agno/tools/arxiv.py +8 -3
  230. agno/tools/aws_lambda.py +7 -5
  231. agno/tools/aws_ses.py +7 -1
  232. agno/tools/baidusearch.py +4 -1
  233. agno/tools/bitbucket.py +4 -4
  234. agno/tools/brandfetch.py +14 -11
  235. agno/tools/bravesearch.py +4 -1
  236. agno/tools/brightdata.py +42 -22
  237. agno/tools/browserbase.py +13 -4
  238. agno/tools/calcom.py +12 -10
  239. agno/tools/calculator.py +10 -27
  240. agno/tools/cartesia.py +18 -13
  241. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  242. agno/tools/confluence.py +71 -18
  243. agno/tools/crawl4ai.py +7 -1
  244. agno/tools/csv_toolkit.py +9 -8
  245. agno/tools/dalle.py +18 -11
  246. agno/tools/daytona.py +13 -16
  247. agno/tools/decorator.py +6 -3
  248. agno/tools/desi_vocal.py +16 -7
  249. agno/tools/discord.py +11 -8
  250. agno/tools/docker.py +30 -42
  251. agno/tools/duckdb.py +34 -53
  252. agno/tools/duckduckgo.py +8 -7
  253. agno/tools/e2b.py +62 -62
  254. agno/tools/eleven_labs.py +35 -28
  255. agno/tools/email.py +4 -1
  256. agno/tools/evm.py +7 -1
  257. agno/tools/exa.py +19 -14
  258. agno/tools/fal.py +29 -29
  259. agno/tools/file.py +9 -8
  260. agno/tools/financial_datasets.py +25 -44
  261. agno/tools/firecrawl.py +22 -22
  262. agno/tools/function.py +68 -17
  263. agno/tools/giphy.py +22 -10
  264. agno/tools/github.py +48 -126
  265. agno/tools/gmail.py +46 -62
  266. agno/tools/google_bigquery.py +7 -6
  267. agno/tools/google_maps.py +11 -26
  268. agno/tools/googlesearch.py +7 -2
  269. agno/tools/googlesheets.py +21 -17
  270. agno/tools/hackernews.py +9 -5
  271. agno/tools/jina.py +5 -4
  272. agno/tools/jira.py +18 -9
  273. agno/tools/knowledge.py +31 -32
  274. agno/tools/linear.py +18 -33
  275. agno/tools/linkup.py +5 -1
  276. agno/tools/local_file_system.py +8 -5
  277. agno/tools/lumalab.py +31 -19
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +32 -14
  282. agno/tools/models/gemini.py +58 -31
  283. agno/tools/models/groq.py +29 -20
  284. agno/tools/models/nebius.py +27 -11
  285. agno/tools/models_labs.py +39 -15
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +134 -0
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +57 -26
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +62 -46
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +54 -41
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +95 -118
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/location.py +2 -2
  337. agno/utils/log.py +2 -2
  338. agno/utils/mcp.py +11 -5
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/claude.py +6 -4
  342. agno/utils/models/mistral.py +8 -7
  343. agno/utils/models/schema_utils.py +3 -3
  344. agno/utils/pprint.py +33 -32
  345. agno/utils/print_response/agent.py +779 -0
  346. agno/utils/print_response/team.py +1565 -0
  347. agno/utils/print_response/workflow.py +1451 -0
  348. agno/utils/prompts.py +14 -14
  349. agno/utils/reasoning.py +87 -0
  350. agno/utils/response.py +42 -42
  351. agno/utils/string.py +8 -22
  352. agno/utils/team.py +50 -0
  353. agno/utils/timer.py +2 -2
  354. agno/vectordb/base.py +33 -21
  355. agno/vectordb/cassandra/cassandra.py +287 -23
  356. agno/vectordb/chroma/chromadb.py +482 -59
  357. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  358. agno/vectordb/couchbase/couchbase.py +309 -29
  359. agno/vectordb/lancedb/lance_db.py +360 -21
  360. agno/vectordb/langchaindb/__init__.py +5 -0
  361. agno/vectordb/langchaindb/langchaindb.py +145 -0
  362. agno/vectordb/lightrag/__init__.py +5 -0
  363. agno/vectordb/lightrag/lightrag.py +374 -0
  364. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  365. agno/vectordb/milvus/milvus.py +242 -32
  366. agno/vectordb/mongodb/mongodb.py +200 -24
  367. agno/vectordb/pgvector/pgvector.py +319 -37
  368. agno/vectordb/pineconedb/pineconedb.py +221 -27
  369. agno/vectordb/qdrant/qdrant.py +356 -14
  370. agno/vectordb/singlestore/singlestore.py +286 -29
  371. agno/vectordb/surrealdb/surrealdb.py +187 -7
  372. agno/vectordb/upstashdb/upstashdb.py +342 -26
  373. agno/vectordb/weaviate/weaviate.py +227 -165
  374. agno/workflow/__init__.py +17 -13
  375. agno/workflow/{v2/condition.py → condition.py} +135 -32
  376. agno/workflow/{v2/loop.py → loop.py} +115 -28
  377. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  378. agno/workflow/{v2/router.py → router.py} +133 -32
  379. agno/workflow/{v2/step.py → step.py} +200 -42
  380. agno/workflow/{v2/steps.py → steps.py} +147 -66
  381. agno/workflow/types.py +482 -0
  382. agno/workflow/workflow.py +2394 -696
  383. agno-2.0.0a1.dist-info/METADATA +355 -0
  384. agno-2.0.0a1.dist-info/RECORD +514 -0
  385. agno/agent/metrics.py +0 -107
  386. agno/api/app.py +0 -35
  387. agno/api/playground.py +0 -92
  388. agno/api/schemas/app.py +0 -12
  389. agno/api/schemas/playground.py +0 -22
  390. agno/api/schemas/user.py +0 -35
  391. agno/api/schemas/workspace.py +0 -46
  392. agno/api/user.py +0 -160
  393. agno/api/workflows.py +0 -33
  394. agno/api/workspace.py +0 -175
  395. agno/app/agui/__init__.py +0 -3
  396. agno/app/agui/app.py +0 -17
  397. agno/app/agui/sync_router.py +0 -120
  398. agno/app/base.py +0 -186
  399. agno/app/discord/__init__.py +0 -3
  400. agno/app/fastapi/__init__.py +0 -3
  401. agno/app/fastapi/app.py +0 -107
  402. agno/app/fastapi/async_router.py +0 -457
  403. agno/app/fastapi/sync_router.py +0 -448
  404. agno/app/playground/app.py +0 -228
  405. agno/app/playground/async_router.py +0 -1050
  406. agno/app/playground/deploy.py +0 -249
  407. agno/app/playground/operator.py +0 -183
  408. agno/app/playground/schemas.py +0 -220
  409. agno/app/playground/serve.py +0 -55
  410. agno/app/playground/sync_router.py +0 -1042
  411. agno/app/playground/utils.py +0 -46
  412. agno/app/settings.py +0 -15
  413. agno/app/slack/__init__.py +0 -3
  414. agno/app/slack/app.py +0 -19
  415. agno/app/slack/sync_router.py +0 -92
  416. agno/app/utils.py +0 -54
  417. agno/app/whatsapp/__init__.py +0 -3
  418. agno/app/whatsapp/app.py +0 -15
  419. agno/app/whatsapp/sync_router.py +0 -197
  420. agno/cli/auth_server.py +0 -249
  421. agno/cli/config.py +0 -274
  422. agno/cli/console.py +0 -88
  423. agno/cli/credentials.py +0 -23
  424. agno/cli/entrypoint.py +0 -571
  425. agno/cli/operator.py +0 -357
  426. agno/cli/settings.py +0 -96
  427. agno/cli/ws/ws_cli.py +0 -817
  428. agno/constants.py +0 -13
  429. agno/document/__init__.py +0 -5
  430. agno/document/chunking/semantic.py +0 -45
  431. agno/document/chunking/strategy.py +0 -31
  432. agno/document/reader/__init__.py +0 -5
  433. agno/document/reader/base.py +0 -47
  434. agno/document/reader/docx_reader.py +0 -60
  435. agno/document/reader/gcs/pdf_reader.py +0 -44
  436. agno/document/reader/s3/pdf_reader.py +0 -59
  437. agno/document/reader/s3/text_reader.py +0 -63
  438. agno/document/reader/url_reader.py +0 -59
  439. agno/document/reader/youtube_reader.py +0 -58
  440. agno/embedder/__init__.py +0 -5
  441. agno/embedder/langdb.py +0 -80
  442. agno/embedder/mistral.py +0 -82
  443. agno/embedder/openai.py +0 -78
  444. agno/file/__init__.py +0 -5
  445. agno/file/file.py +0 -16
  446. agno/file/local/csv.py +0 -32
  447. agno/file/local/txt.py +0 -19
  448. agno/infra/app.py +0 -240
  449. agno/infra/base.py +0 -144
  450. agno/infra/context.py +0 -20
  451. agno/infra/db_app.py +0 -52
  452. agno/infra/resource.py +0 -205
  453. agno/infra/resources.py +0 -55
  454. agno/knowledge/agent.py +0 -698
  455. agno/knowledge/arxiv.py +0 -33
  456. agno/knowledge/combined.py +0 -36
  457. agno/knowledge/csv.py +0 -144
  458. agno/knowledge/csv_url.py +0 -124
  459. agno/knowledge/document.py +0 -223
  460. agno/knowledge/docx.py +0 -137
  461. agno/knowledge/firecrawl.py +0 -34
  462. agno/knowledge/gcs/__init__.py +0 -0
  463. agno/knowledge/gcs/base.py +0 -39
  464. agno/knowledge/gcs/pdf.py +0 -125
  465. agno/knowledge/json.py +0 -137
  466. agno/knowledge/langchain.py +0 -71
  467. agno/knowledge/light_rag.py +0 -273
  468. agno/knowledge/llamaindex.py +0 -66
  469. agno/knowledge/markdown.py +0 -154
  470. agno/knowledge/pdf.py +0 -164
  471. agno/knowledge/pdf_bytes.py +0 -42
  472. agno/knowledge/pdf_url.py +0 -148
  473. agno/knowledge/s3/__init__.py +0 -0
  474. agno/knowledge/s3/base.py +0 -64
  475. agno/knowledge/s3/pdf.py +0 -33
  476. agno/knowledge/s3/text.py +0 -34
  477. agno/knowledge/text.py +0 -141
  478. agno/knowledge/url.py +0 -46
  479. agno/knowledge/website.py +0 -179
  480. agno/knowledge/wikipedia.py +0 -32
  481. agno/knowledge/youtube.py +0 -35
  482. agno/memory/agent.py +0 -423
  483. agno/memory/classifier.py +0 -104
  484. agno/memory/db/__init__.py +0 -5
  485. agno/memory/db/base.py +0 -42
  486. agno/memory/db/mongodb.py +0 -189
  487. agno/memory/db/postgres.py +0 -203
  488. agno/memory/db/sqlite.py +0 -193
  489. agno/memory/memory.py +0 -22
  490. agno/memory/row.py +0 -36
  491. agno/memory/summarizer.py +0 -201
  492. agno/memory/summary.py +0 -19
  493. agno/memory/team.py +0 -415
  494. agno/memory/v2/__init__.py +0 -2
  495. agno/memory/v2/db/__init__.py +0 -1
  496. agno/memory/v2/db/base.py +0 -42
  497. agno/memory/v2/db/firestore.py +0 -339
  498. agno/memory/v2/db/mongodb.py +0 -196
  499. agno/memory/v2/db/postgres.py +0 -214
  500. agno/memory/v2/db/redis.py +0 -187
  501. agno/memory/v2/db/schema.py +0 -54
  502. agno/memory/v2/db/sqlite.py +0 -209
  503. agno/memory/v2/manager.py +0 -437
  504. agno/memory/v2/memory.py +0 -1097
  505. agno/memory/v2/schema.py +0 -55
  506. agno/memory/v2/summarizer.py +0 -215
  507. agno/memory/workflow.py +0 -38
  508. agno/models/ollama/tools.py +0 -430
  509. agno/models/qwen/__init__.py +0 -5
  510. agno/playground/__init__.py +0 -10
  511. agno/playground/deploy.py +0 -3
  512. agno/playground/playground.py +0 -3
  513. agno/playground/serve.py +0 -3
  514. agno/playground/settings.py +0 -3
  515. agno/reranker/__init__.py +0 -0
  516. agno/run/v2/__init__.py +0 -0
  517. agno/run/v2/workflow.py +0 -567
  518. agno/storage/__init__.py +0 -0
  519. agno/storage/agent/__init__.py +0 -0
  520. agno/storage/agent/dynamodb.py +0 -1
  521. agno/storage/agent/json.py +0 -1
  522. agno/storage/agent/mongodb.py +0 -1
  523. agno/storage/agent/postgres.py +0 -1
  524. agno/storage/agent/singlestore.py +0 -1
  525. agno/storage/agent/sqlite.py +0 -1
  526. agno/storage/agent/yaml.py +0 -1
  527. agno/storage/base.py +0 -60
  528. agno/storage/dynamodb.py +0 -673
  529. agno/storage/firestore.py +0 -297
  530. agno/storage/gcs_json.py +0 -261
  531. agno/storage/in_memory.py +0 -234
  532. agno/storage/json.py +0 -237
  533. agno/storage/mongodb.py +0 -328
  534. agno/storage/mysql.py +0 -685
  535. agno/storage/postgres.py +0 -682
  536. agno/storage/redis.py +0 -336
  537. agno/storage/session/__init__.py +0 -16
  538. agno/storage/session/agent.py +0 -64
  539. agno/storage/session/team.py +0 -63
  540. agno/storage/session/v2/__init__.py +0 -5
  541. agno/storage/session/workflow.py +0 -61
  542. agno/storage/singlestore.py +0 -606
  543. agno/storage/sqlite.py +0 -646
  544. agno/storage/workflow/__init__.py +0 -0
  545. agno/storage/workflow/mongodb.py +0 -1
  546. agno/storage/workflow/postgres.py +0 -1
  547. agno/storage/workflow/sqlite.py +0 -1
  548. agno/storage/yaml.py +0 -241
  549. agno/tools/thinking.py +0 -73
  550. agno/utils/defaults.py +0 -57
  551. agno/utils/filesystem.py +0 -39
  552. agno/utils/git.py +0 -52
  553. agno/utils/json_io.py +0 -30
  554. agno/utils/load_env.py +0 -19
  555. agno/utils/py_io.py +0 -19
  556. agno/utils/pyproject.py +0 -18
  557. agno/utils/resource_filter.py +0 -31
  558. agno/workflow/v2/__init__.py +0 -21
  559. agno/workflow/v2/types.py +0 -357
  560. agno/workflow/v2/workflow.py +0 -3312
  561. agno/workspace/__init__.py +0 -0
  562. agno/workspace/config.py +0 -325
  563. agno/workspace/enums.py +0 -6
  564. agno/workspace/helpers.py +0 -52
  565. agno/workspace/operator.py +0 -757
  566. agno/workspace/settings.py +0 -158
  567. agno-1.8.0.dist-info/METADATA +0 -979
  568. agno-1.8.0.dist-info/RECORD +0 -565
  569. agno-1.8.0.dist-info/entry_points.txt +0 -3
  570. /agno/{app → db/migrations}/__init__.py +0 -0
  571. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  572. /agno/{cli → integrations}/__init__.py +0 -0
  573. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  574. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  575. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  576. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  577. /agno/{app → os/interfaces}/slack/security.py +0 -0
  578. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  579. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  580. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  581. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  582. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  583. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
@@ -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.