agno 0.1.2__py3-none-any.whl → 2.3.13__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 (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  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/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,3 @@
1
+ from agno.vectordb.surrealdb.surrealdb import SurrealDb
2
+
3
+ __all__ = ["SurrealDb"]
@@ -0,0 +1,663 @@
1
+ from typing import Any, Dict, Final, List, Optional, Union
2
+
3
+ try:
4
+ from surrealdb import (
5
+ AsyncHttpSurrealConnection,
6
+ AsyncWsSurrealConnection,
7
+ BlockingHttpSurrealConnection,
8
+ BlockingWsSurrealConnection,
9
+ )
10
+ except ImportError as e:
11
+ msg = "The `surrealdb` package is not installed. Please install it via `pip install surrealdb`."
12
+ raise ImportError(msg) from e
13
+
14
+ from agno.filters import FilterExpr
15
+ from agno.knowledge.document import Document
16
+ from agno.knowledge.embedder import Embedder
17
+ from agno.utils.log import log_debug, log_error, log_info, log_warning
18
+ from agno.vectordb.base import VectorDb
19
+ from agno.vectordb.distance import Distance
20
+
21
+
22
+ class SurrealDb(VectorDb):
23
+ """SurrealDB Vector Database implementation supporting both sync and async operations."""
24
+
25
+ # SQL Query Constants
26
+ CREATE_TABLE_QUERY: Final[str] = """
27
+ DEFINE TABLE IF NOT EXISTS {collection} SCHEMAFUL;
28
+ DEFINE FIELD IF NOT EXISTS content ON {collection} TYPE string;
29
+ DEFINE FIELD IF NOT EXISTS embedding ON {collection} TYPE array<float>;
30
+ DEFINE FIELD IF NOT EXISTS meta_data ON {collection} FLEXIBLE TYPE object;
31
+ DEFINE INDEX IF NOT EXISTS vector_idx ON {collection} FIELDS embedding HNSW DIMENSION {dimensions} DIST {distance};
32
+ """
33
+
34
+ NAME_EXISTS_QUERY: Final[str] = """
35
+ SELECT * FROM {collection}
36
+ WHERE meta_data.name = $name
37
+ LIMIT 1
38
+ """
39
+
40
+ ID_EXISTS_QUERY: Final[str] = """
41
+ SELECT * FROM {collection}
42
+ WHERE id = $id
43
+ LIMIT 1
44
+ """
45
+
46
+ CONTENT_HASH_EXISTS_QUERY: Final[str] = """
47
+ SELECT * FROM {collection}
48
+ WHERE meta_data.content_hash = $content_hash
49
+ LIMIT 1
50
+ """
51
+
52
+ DELETE_BY_ID_QUERY: Final[str] = """
53
+ DELETE FROM {collection}
54
+ WHERE id = $id
55
+ """
56
+
57
+ DELETE_BY_NAME_QUERY: Final[str] = """
58
+ DELETE FROM {collection}
59
+ WHERE meta_data.name = $name
60
+ """
61
+
62
+ DELETE_BY_METADATA_QUERY: Final[str] = """
63
+ DELETE FROM {collection}
64
+ WHERE {conditions}
65
+ """
66
+
67
+ DELETE_BY_CONTENT_ID_QUERY: Final[str] = """
68
+ DELETE FROM {collection}
69
+ WHERE content_id = $content_id
70
+ """
71
+
72
+ UPSERT_QUERY: Final[str] = """
73
+ UPSERT {thing}
74
+ SET content = $content,
75
+ embedding = $embedding,
76
+ meta_data = $meta_data
77
+ """
78
+
79
+ SEARCH_QUERY: Final[str] = """
80
+ SELECT
81
+ content,
82
+ meta_data,
83
+ vector::distance::knn() as distance
84
+ FROM {collection}
85
+ WHERE embedding <|{limit}, {search_ef}|> $query_embedding
86
+ {filter_condition}
87
+ ORDER BY distance ASC
88
+ LIMIT {limit};
89
+ """
90
+
91
+ INFO_DB_QUERY: Final[str] = "INFO FOR DB;"
92
+ DROP_TABLE_QUERY: Final[str] = "REMOVE TABLE {collection}"
93
+ DELETE_ALL_QUERY: Final[str] = "DELETE {collection}"
94
+
95
+ def __init__(
96
+ self,
97
+ client: Optional[Union[BlockingWsSurrealConnection, BlockingHttpSurrealConnection]] = None,
98
+ async_client: Optional[Union[AsyncWsSurrealConnection, AsyncHttpSurrealConnection]] = None,
99
+ collection: str = "documents",
100
+ distance: Distance = Distance.cosine,
101
+ efc: int = 150,
102
+ m: int = 12,
103
+ search_ef: int = 40,
104
+ embedder: Optional[Embedder] = None,
105
+ name: Optional[str] = None,
106
+ description: Optional[str] = None,
107
+ id: Optional[str] = None,
108
+ ):
109
+ """Initialize SurrealDB connection.
110
+
111
+ Args:
112
+ client: A blocking connection, either HTTP or WS
113
+ async_client: An async connection, either HTTP or WS (default: None)
114
+ collection: Collection name to store documents (default: documents)
115
+ distance: Distance metric to use (default: cosine)
116
+ efc: HNSW construction time/accuracy trade-off (default: 150)
117
+ m: HNSW max number of connections per element (default: 12)
118
+ search_ef: HNSW search time/accuracy trade-off (default: 40)
119
+ embedder: Embedder instance for creating embeddings (default: OpenAIEmbedder)
120
+
121
+ """
122
+ # Dynamic ID generation based on unique identifiers
123
+ if id is None:
124
+ from agno.utils.string import generate_id
125
+
126
+ client_info = str(client) if client else str(async_client) if async_client else "default"
127
+ seed = f"{client_info}#{collection}"
128
+ id = generate_id(seed)
129
+
130
+ # Initialize base class with name, description, and generated ID
131
+ super().__init__(id=id, name=name, description=description)
132
+
133
+ # Embedder for embedding the document contents
134
+ if embedder is None:
135
+ from agno.knowledge.embedder.openai import OpenAIEmbedder
136
+
137
+ embedder = OpenAIEmbedder()
138
+ log_info("Embedder not provided, using OpenAIEmbedder as default.")
139
+ self.embedder: Embedder = embedder
140
+ self.dimensions = self.embedder.dimensions
141
+ self.collection = collection
142
+ # Convert Distance enum to SurrealDB distance type
143
+ self.distance = {Distance.cosine: "COSINE", Distance.l2: "EUCLIDEAN", Distance.max_inner_product: "DOT"}[
144
+ distance
145
+ ]
146
+
147
+ self._client: Optional[Union[BlockingHttpSurrealConnection, BlockingWsSurrealConnection]] = client
148
+ self._async_client: Optional[Union[AsyncWsSurrealConnection, AsyncHttpSurrealConnection]] = async_client
149
+
150
+ if self._client is None and self._async_client is None:
151
+ msg = "Client and async client are not provided. Please provide one of them."
152
+ raise RuntimeError(msg)
153
+
154
+ # HNSW index parameters
155
+ self.efc = efc
156
+ self.m = m
157
+ self.search_ef = search_ef
158
+
159
+ @property
160
+ def async_client(self) -> Union[AsyncWsSurrealConnection, AsyncHttpSurrealConnection]:
161
+ """Check if the async client is initialized.
162
+
163
+ Raises:
164
+ RuntimeError: If the async client is not initialized.
165
+
166
+ Returns:
167
+ The async client.
168
+
169
+ """
170
+ if self._async_client is None:
171
+ msg = "Async client is not initialized"
172
+ raise RuntimeError(msg)
173
+ return self._async_client
174
+
175
+ @property
176
+ def client(self) -> Union[BlockingHttpSurrealConnection, BlockingWsSurrealConnection]:
177
+ """Check if the client is initialized.
178
+
179
+ Returns:
180
+ The client.
181
+
182
+ """
183
+ if self._client is None:
184
+ msg = "Client is not initialized"
185
+ raise RuntimeError(msg)
186
+ return self._client
187
+
188
+ @staticmethod
189
+ def _build_filter_condition(filters: Optional[Dict[str, Any]] = None) -> str:
190
+ """Build filter condition for queries.
191
+
192
+ Args:
193
+ filters: A dictionary of filters to apply to the query.
194
+
195
+ Returns:
196
+ A string representing the filter condition.
197
+
198
+ """
199
+ if not filters:
200
+ return ""
201
+ conditions = [f"meta_data.{key} = ${key}" for key in filters]
202
+ return "AND " + " AND ".join(conditions)
203
+
204
+ # Synchronous methods
205
+ def create(self) -> None:
206
+ """Create the vector collection and index."""
207
+ if not self.exists():
208
+ log_debug(f"Creating collection: {self.collection}")
209
+ query = self.CREATE_TABLE_QUERY.format(
210
+ collection=self.collection,
211
+ distance=self.distance,
212
+ dimensions=self.dimensions,
213
+ efc=self.efc,
214
+ m=self.m,
215
+ )
216
+ self.client.query(query)
217
+
218
+ def name_exists(self, name: str) -> bool:
219
+ """Check if a document exists by its name.
220
+
221
+ Args:
222
+ name: The name of the document to check.
223
+
224
+ Returns:
225
+ True if the document exists, False otherwise.
226
+
227
+ """
228
+ log_debug(f"Checking if document exists: {name}")
229
+ result = self.client.query(self.NAME_EXISTS_QUERY.format(collection=self.collection), {"name": name})
230
+ return bool(self._extract_result(result))
231
+
232
+ def id_exists(self, id: str) -> bool:
233
+ """Check if a document exists by its ID.
234
+
235
+ Args:
236
+ id: The ID of the document to check.
237
+
238
+ Returns:
239
+ True if the document exists, False otherwise.
240
+
241
+ """
242
+ log_debug(f"Checking if document exists by ID: {id}")
243
+ result = self.client.query(self.ID_EXISTS_QUERY.format(collection=self.collection), {"id": id})
244
+ return bool(self._extract_result(result))
245
+
246
+ def content_hash_exists(self, content_hash: str) -> bool:
247
+ """Check if a document exists by its content hash.
248
+
249
+ Args:
250
+ content_hash: The content hash of the document to check.
251
+
252
+ Returns:
253
+ True if the document exists, False otherwise.
254
+
255
+ """
256
+ log_debug(f"Checking if document exists by content hash: {content_hash}")
257
+ result = self.client.query(
258
+ self.CONTENT_HASH_EXISTS_QUERY.format(collection=self.collection), {"content_hash": content_hash}
259
+ )
260
+ return bool(self._extract_result(result))
261
+
262
+ def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
263
+ """Insert documents into the vector store.
264
+
265
+ Args:
266
+ content_hash: The content hash for the documents.
267
+ documents: A list of documents to insert.
268
+ filters: A dictionary of filters to apply to the query.
269
+
270
+ """
271
+ for doc in documents:
272
+ doc.embed(embedder=self.embedder)
273
+ meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
274
+ meta_data["content_hash"] = content_hash
275
+ data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
276
+ if filters:
277
+ data["meta_data"].update(filters)
278
+ self.client.create(self.collection, data)
279
+
280
+ def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
281
+ """Upsert documents into the vector store.
282
+
283
+ Args:
284
+ content_hash: The content hash for the documents.
285
+ documents: A list of documents to upsert.
286
+ filters: A dictionary of filters to apply to the query.
287
+
288
+ """
289
+ for doc in documents:
290
+ doc.embed(embedder=self.embedder)
291
+ meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
292
+ meta_data["content_hash"] = content_hash
293
+ data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
294
+ if filters:
295
+ data["meta_data"].update(filters)
296
+ thing = f"{self.collection}:{doc.id}" if doc.id else self.collection
297
+ self.client.query(self.UPSERT_QUERY.format(thing=thing), data)
298
+
299
+ def search(
300
+ self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
301
+ ) -> List[Document]:
302
+ """Search for similar documents.
303
+
304
+ Args:
305
+ query: The query to search for.
306
+ limit: The maximum number of documents to return.
307
+ filters: A dictionary of filters to apply to the query.
308
+
309
+ Returns:
310
+ A list of documents that are similar to the query.
311
+
312
+ """
313
+ if isinstance(filters, List):
314
+ log_warning("Filters Expressions are not supported in SurrealDB. No filters will be applied.")
315
+ filters = None
316
+ query_embedding = self.embedder.get_embedding(query)
317
+ if query_embedding is None:
318
+ log_error(f"Error getting embedding for Query: {query}")
319
+ return []
320
+
321
+ filter_condition = self._build_filter_condition(filters)
322
+ log_debug(f"Filter condition: {filter_condition}")
323
+ search_query = self.SEARCH_QUERY.format(
324
+ collection=self.collection,
325
+ limit=limit,
326
+ search_ef=self.search_ef,
327
+ filter_condition=filter_condition,
328
+ distance=self.distance,
329
+ )
330
+ log_debug(f"Search query: {search_query}")
331
+ response = self.client.query(
332
+ search_query,
333
+ {"query_embedding": query_embedding, **filters} if filters else {"query_embedding": query_embedding},
334
+ )
335
+ log_debug(f"Search response: {response}")
336
+
337
+ documents = []
338
+ for item in response:
339
+ if isinstance(item, dict):
340
+ doc = Document(
341
+ content=item.get("content", ""),
342
+ embedding=item.get("embedding", []),
343
+ meta_data=item.get("meta_data", {}),
344
+ embedder=self.embedder,
345
+ )
346
+ documents.append(doc)
347
+ log_debug(f"Found {len(documents)} documents")
348
+ return documents
349
+
350
+ def drop(self) -> None:
351
+ """Drop the vector collection."""
352
+ log_debug(f"Dropping collection: {self.collection}")
353
+ self.client.query(self.DROP_TABLE_QUERY.format(collection=self.collection))
354
+
355
+ def exists(self) -> bool:
356
+ """Check if the vector collection exists.
357
+
358
+ Returns:
359
+ True if the collection exists, False otherwise.
360
+
361
+ """
362
+ log_debug(f"Checking if collection exists: {self.collection}")
363
+ response = self.client.query(self.INFO_DB_QUERY)
364
+ result = self._extract_result(response)
365
+ if isinstance(result, dict) and "tables" in result:
366
+ return self.collection in result["tables"]
367
+ return False
368
+
369
+ def delete(self) -> bool:
370
+ """Delete all documents from the vector store.
371
+
372
+ Returns:
373
+ True if the collection was deleted, False otherwise.
374
+
375
+ """
376
+ self.client.query(self.DELETE_ALL_QUERY.format(collection=self.collection))
377
+ return True
378
+
379
+ def delete_by_id(self, id: str) -> bool:
380
+ """Delete a document by its ID.
381
+
382
+ Args:
383
+ id: The ID of the document to delete.
384
+
385
+ Returns:
386
+ True if the document was deleted, False otherwise.
387
+
388
+ """
389
+ log_debug(f"Deleting document by ID: {id}")
390
+ result = self.client.query(self.DELETE_BY_ID_QUERY.format(collection=self.collection), {"id": id})
391
+ return bool(result)
392
+
393
+ def delete_by_name(self, name: str) -> bool:
394
+ """Delete documents by their name.
395
+
396
+ Args:
397
+ name: The name of the documents to delete.
398
+
399
+ Returns:
400
+ True if documents were deleted, False otherwise.
401
+
402
+ """
403
+ log_debug(f"Deleting documents by name: {name}")
404
+ result = self.client.query(self.DELETE_BY_NAME_QUERY.format(collection=self.collection), {"name": name})
405
+ return bool(result)
406
+
407
+ def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
408
+ """Delete documents by their metadata.
409
+
410
+ Args:
411
+ metadata: The metadata to match for deletion.
412
+
413
+ Returns:
414
+ True if documents were deleted, False otherwise.
415
+
416
+ """
417
+ log_debug(f"Deleting documents by metadata: {metadata}")
418
+ conditions = [f"meta_data.{key} = ${key}" for key in metadata.keys()]
419
+ conditions_str = " AND ".join(conditions)
420
+ query = self.DELETE_BY_METADATA_QUERY.format(collection=self.collection, conditions=conditions_str)
421
+ result = self.client.query(query, metadata)
422
+ return bool(result)
423
+
424
+ def delete_by_content_id(self, content_id: str) -> bool:
425
+ """Delete documents by their content ID.
426
+
427
+ Args:
428
+ content_id: The content ID of the documents to delete.
429
+
430
+ Returns:
431
+ True if documents were deleted, False otherwise.
432
+
433
+ """
434
+ log_debug(f"Deleting documents by content ID: {content_id}")
435
+ result = self.client.query(
436
+ self.DELETE_BY_CONTENT_ID_QUERY.format(collection=self.collection), {"content_id": content_id}
437
+ )
438
+ return bool(result)
439
+
440
+ @staticmethod
441
+ def _extract_result(query_result: Union[List[Dict[str, Any]], Dict[str, Any]]) -> Union[List[Any], Dict[str, Any]]:
442
+ """Extract the actual result from SurrealDB query response.
443
+
444
+ Args:
445
+ query_result: The query result from SurrealDB.
446
+
447
+ Returns:
448
+ The actual result from SurrealDB query response.
449
+
450
+ """
451
+ log_debug(f"Query result: {query_result}")
452
+ if isinstance(query_result, dict):
453
+ return query_result
454
+ if isinstance(query_result, list):
455
+ if len(query_result) > 0:
456
+ return query_result[0].get("result", {})
457
+ return []
458
+ return []
459
+
460
+ async def async_create(self) -> None:
461
+ """Create the vector collection and index asynchronously."""
462
+ log_debug(f"Creating collection: {self.collection}")
463
+ await self.async_client.query(
464
+ self.CREATE_TABLE_QUERY.format(
465
+ collection=self.collection,
466
+ distance=self.distance,
467
+ dimensions=self.dimensions,
468
+ efc=self.efc,
469
+ m=self.m,
470
+ ),
471
+ )
472
+
473
+ async def async_name_exists(self, name: str) -> bool:
474
+ """Check if a document exists by its name asynchronously.
475
+
476
+ Returns:
477
+ True if the document exists, False otherwise.
478
+
479
+ """
480
+ response = await self.async_client.query(
481
+ self.NAME_EXISTS_QUERY.format(collection=self.collection),
482
+ {"name": name},
483
+ )
484
+ return bool(self._extract_result(response))
485
+
486
+ async def async_insert(
487
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
488
+ ) -> None:
489
+ """Insert documents into the vector store asynchronously.
490
+
491
+ Args:
492
+ content_hash: The content hash for the documents.
493
+ documents: A list of documents to insert.
494
+ filters: A dictionary of filters to apply to the query.
495
+
496
+ """
497
+ for doc in documents:
498
+ doc.embed(embedder=self.embedder)
499
+ meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
500
+ meta_data["content_hash"] = content_hash
501
+ data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
502
+ if filters:
503
+ data["meta_data"].update(filters)
504
+ log_debug(f"Inserting document asynchronously: {doc.name} ({doc.meta_data})")
505
+ await self.async_client.create(self.collection, data)
506
+
507
+ async def async_upsert(
508
+ self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
509
+ ) -> None:
510
+ """Upsert documents into the vector store asynchronously.
511
+
512
+ Args:
513
+ content_hash: The content hash for the documents.
514
+ documents: A list of documents to upsert.
515
+ filters: A dictionary of filters to apply to the query.
516
+
517
+ """
518
+ for doc in documents:
519
+ doc.embed(embedder=self.embedder)
520
+ meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
521
+ meta_data["content_hash"] = content_hash
522
+ data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
523
+ if filters:
524
+ data["meta_data"].update(filters)
525
+ log_debug(f"Upserting document asynchronously: {doc.name} ({doc.meta_data})")
526
+ thing = f"{self.collection}:{doc.id}" if doc.id else self.collection
527
+ await self.async_client.query(self.UPSERT_QUERY.format(thing=thing), data)
528
+
529
+ async def async_search(
530
+ self,
531
+ query: str,
532
+ limit: int = 5,
533
+ filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
534
+ ) -> List[Document]:
535
+ """Search for similar documents asynchronously.
536
+
537
+ Args:
538
+ query: The query to search for.
539
+ limit: The maximum number of documents to return.
540
+ filters: A dictionary of filters to apply to the query.
541
+
542
+ Returns:
543
+ A list of documents that are similar to the query.
544
+
545
+ """
546
+ if isinstance(filters, List):
547
+ log_warning("Filters Expressions are not supported in SurrealDB. No filters will be applied.")
548
+ filters = None
549
+
550
+ query_embedding = self.embedder.get_embedding(query)
551
+ if query_embedding is None:
552
+ log_error(f"Error getting embedding for Query: {query}")
553
+ return []
554
+
555
+ filter_condition = self._build_filter_condition(filters)
556
+ search_query = self.SEARCH_QUERY.format(
557
+ collection=self.collection,
558
+ limit=limit,
559
+ search_ef=self.search_ef,
560
+ filter_condition=filter_condition,
561
+ distance=self.distance,
562
+ )
563
+ response = await self.async_client.query(
564
+ search_query,
565
+ {"query_embedding": query_embedding, **filters} if filters else {"query_embedding": query_embedding},
566
+ )
567
+ log_debug(f"Search response: {response}")
568
+ documents = []
569
+ for item in response:
570
+ if isinstance(item, dict):
571
+ doc = Document(
572
+ content=item.get("content", ""),
573
+ embedding=item.get("embedding", []),
574
+ meta_data=item.get("meta_data", {}),
575
+ embedder=self.embedder,
576
+ )
577
+ documents.append(doc)
578
+ log_debug(f"Found {len(documents)} documents asynchronously")
579
+ return documents
580
+
581
+ async def async_drop(self) -> None:
582
+ """Drop the vector collection asynchronously."""
583
+ log_debug(f"Dropping collection: {self.collection}")
584
+ await self.async_client.query(self.DROP_TABLE_QUERY.format(collection=self.collection))
585
+
586
+ async def async_exists(self) -> bool:
587
+ """Check if the vector collection exists asynchronously.
588
+
589
+ Returns:
590
+ True if the collection exists, False otherwise.
591
+
592
+ """
593
+ log_debug(f"Checking if collection exists: {self.collection}")
594
+ response = await self.async_client.query(self.INFO_DB_QUERY)
595
+ result = self._extract_result(response)
596
+ if isinstance(result, dict) and "tables" in result:
597
+ return self.collection in result["tables"]
598
+ return False
599
+
600
+ @staticmethod
601
+ def upsert_available() -> bool:
602
+ """Check if upsert is available.
603
+
604
+ Returns:
605
+ True if upsert is available, False otherwise.
606
+
607
+ """
608
+ return True
609
+
610
+ def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
611
+ """
612
+ Update the metadata for documents with the given content_id.
613
+
614
+ Args:
615
+ content_id (str): The content ID to update
616
+ metadata (Dict[str, Any]): The metadata to update
617
+ """
618
+ try:
619
+ # Query for documents with the given content_id
620
+ query = f"SELECT * FROM {self.collection} WHERE content_id = $content_id"
621
+ result = self.client.query(query, {"content_id": content_id})
622
+
623
+ if not result or not result[0].get("result"):
624
+ log_debug(f"No documents found with content_id: {content_id}")
625
+ return
626
+
627
+ documents = result[0]["result"]
628
+ updated_count = 0
629
+
630
+ # Update each matching document
631
+ for doc in documents:
632
+ doc_id = doc["id"]
633
+ current_metadata = doc.get("meta_data", {})
634
+ current_filters = doc.get("filters", {})
635
+
636
+ # Merge existing metadata with new metadata
637
+ if isinstance(current_metadata, dict):
638
+ updated_metadata = current_metadata.copy()
639
+ updated_metadata.update(metadata)
640
+ else:
641
+ updated_metadata = metadata
642
+
643
+ # Merge existing filters with new metadata
644
+ if isinstance(current_filters, dict):
645
+ updated_filters = current_filters.copy()
646
+ updated_filters.update(metadata)
647
+ else:
648
+ updated_filters = metadata
649
+
650
+ # Update the document
651
+ update_query = f"UPDATE {doc_id} SET meta_data = $metadata, filters = $filters"
652
+ self.client.query(update_query, {"metadata": updated_metadata, "filters": updated_filters})
653
+ updated_count += 1
654
+
655
+ log_debug(f"Updated metadata for {updated_count} documents with content_id: {content_id}")
656
+
657
+ except Exception as e:
658
+ log_error(f"Error updating metadata for content_id '{content_id}': {e}")
659
+ raise
660
+
661
+ def get_supported_search_types(self) -> List[str]:
662
+ """Get the supported search types for this vector database."""
663
+ return [] # SurrealDb doesn't use SearchType enum
@@ -0,0 +1,5 @@
1
+ from agno.vectordb.upstashdb.upstashdb import UpstashVectorDb
2
+
3
+ __all__ = [
4
+ "UpstashVectorDb",
5
+ ]