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,164 @@
1
+ from functools import wraps
2
+ from typing import Any, Callable, TypeVar, Union, overload
3
+
4
+ # Type variable for better type hints
5
+ F = TypeVar("F", bound=Callable[..., Any])
6
+
7
+ # Attribute name used to mark hooks for background execution
8
+ HOOK_RUN_IN_BACKGROUND_ATTR = "_agno_run_in_background"
9
+
10
+
11
+ def _is_async_function(func: Callable) -> bool:
12
+ """
13
+ Check if a function is async, even when wrapped by decorators like @staticmethod.
14
+ Traverses the full wrapper chain to find the original function.
15
+ """
16
+ from inspect import iscoroutinefunction, unwrap
17
+
18
+ # First, try the standard inspect function on the wrapper
19
+ if iscoroutinefunction(func):
20
+ return True
21
+
22
+ # Use unwrap to traverse the full __wrapped__ chain to the original function
23
+ try:
24
+ original_func = unwrap(func)
25
+ if original_func is not func and iscoroutinefunction(original_func):
26
+ return True
27
+ except ValueError:
28
+ # unwrap raises ValueError if it hits a cycle
29
+ pass
30
+
31
+ # Check if the function has CO_COROUTINE flag in its code object
32
+ try:
33
+ if hasattr(func, "__code__") and func.__code__.co_flags & 0x80: # CO_COROUTINE flag
34
+ return True
35
+ except (AttributeError, TypeError):
36
+ pass
37
+
38
+ return False
39
+
40
+
41
+ @overload
42
+ def hook() -> Callable[[F], F]: ...
43
+
44
+
45
+ @overload
46
+ def hook(
47
+ *,
48
+ run_in_background: bool = False,
49
+ ) -> Callable[[F], F]: ...
50
+
51
+
52
+ @overload
53
+ def hook(func: F) -> F: ...
54
+
55
+
56
+ def hook(*args, **kwargs) -> Union[F, Callable[[F], F]]:
57
+ """Decorator to configure hook behavior.
58
+
59
+ Args:
60
+ run_in_background: If True, this hook will be scheduled as a FastAPI background task
61
+ when background_tasks is available, regardless of the agent/team's
62
+ run_hooks_in_background setting. This allows per-hook control over
63
+ background execution. This is only use-able when running with AgentOS.
64
+
65
+ Returns:
66
+ Union[F, Callable[[F], F]]: Decorated function or decorator
67
+
68
+ Examples:
69
+ @hook
70
+ def my_hook(run_output, agent):
71
+ # This runs normally (blocking)
72
+ process_output(run_output.content)
73
+
74
+ @hook()
75
+ def another_hook(run_output, agent):
76
+ # Same as above - runs normally
77
+ process_output(run_output.content)
78
+
79
+ @hook(run_in_background=True)
80
+ def my_background_hook(run_output, agent):
81
+ # This will run in the background when background_tasks is available
82
+ send_notification(run_output.content)
83
+
84
+ @hook(run_in_background=True)
85
+ async def my_async_background_hook(run_output, agent):
86
+ # Async hooks also supported
87
+ await send_async_notification(run_output.content)
88
+
89
+ agent = Agent(
90
+ model=OpenAIChat(id="gpt-4o"),
91
+ post_hooks=[my_hook, my_background_hook],
92
+ )
93
+ """
94
+ # Valid kwargs for the hook decorator
95
+ VALID_KWARGS = frozenset({"run_in_background"})
96
+
97
+ # Validate kwargs
98
+ invalid_kwargs = set(kwargs.keys()) - VALID_KWARGS
99
+ if invalid_kwargs:
100
+ raise ValueError(
101
+ f"Invalid hook configuration arguments: {invalid_kwargs}. Valid arguments are: {sorted(VALID_KWARGS)}"
102
+ )
103
+
104
+ def decorator(func: F) -> F:
105
+ run_in_background = kwargs.get("run_in_background", False)
106
+
107
+ # Preserve existing hook attributes from previously applied decorators
108
+ # Use OR logic: if any decorator sets run_in_background=True, it stays True
109
+ existing_run_in_background = should_run_in_background(func)
110
+ final_run_in_background = run_in_background or existing_run_in_background
111
+
112
+ @wraps(func)
113
+ def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
114
+ return func(*args, **kwargs)
115
+
116
+ @wraps(func)
117
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
118
+ return await func(*args, **kwargs)
119
+
120
+ # Choose appropriate wrapper based on function type
121
+ if _is_async_function(func):
122
+ wrapper = async_wrapper
123
+ else:
124
+ wrapper = sync_wrapper
125
+
126
+ # Set the background execution attribute (combined from all decorators)
127
+ setattr(wrapper, HOOK_RUN_IN_BACKGROUND_ATTR, final_run_in_background)
128
+
129
+ return wrapper # type: ignore
130
+
131
+ # Handle both @hook and @hook() cases
132
+ if len(args) == 1 and callable(args[0]) and not kwargs:
133
+ return decorator(args[0])
134
+
135
+ return decorator
136
+
137
+
138
+ def should_run_in_background(hook_func: Callable) -> bool:
139
+ """
140
+ Check if a hook function is marked to run in background.
141
+ Traverses the wrapper chain to find the attribute when multiple decorators are stacked.
142
+
143
+ Args:
144
+ hook_func: The hook function to check
145
+
146
+ Returns:
147
+ True if the hook is decorated with @hook(run_in_background=True)
148
+ """
149
+ # Check the function directly first
150
+ if hasattr(hook_func, HOOK_RUN_IN_BACKGROUND_ATTR):
151
+ return getattr(hook_func, HOOK_RUN_IN_BACKGROUND_ATTR)
152
+
153
+ # Traverse the wrapper chain to find the attribute
154
+ current = hook_func
155
+ seen: set[int] = set()
156
+ while hasattr(current, "__wrapped__"):
157
+ if id(current) in seen:
158
+ break
159
+ seen.add(id(current))
160
+ current = current.__wrapped__
161
+ if hasattr(current, HOOK_RUN_IN_BACKGROUND_ATTR):
162
+ return getattr(current, HOOK_RUN_IN_BACKGROUND_ATTR)
163
+
164
+ return False
@@ -0,0 +1,3 @@
1
+ from agno.integrations.discord.client import DiscordClient
2
+
3
+ __all__ = ["DiscordClient"]
@@ -0,0 +1,203 @@
1
+ from os import getenv
2
+ from textwrap import dedent
3
+ from typing import Optional, Union
4
+
5
+ import requests
6
+
7
+ from agno.agent.agent import Agent, RunOutput
8
+ from agno.media import Audio, File, Image, Video
9
+ from agno.team.team import Team, TeamRunOutput
10
+ from agno.utils.log import log_info, log_warning
11
+ from agno.utils.message import get_text_from_message
12
+
13
+ try:
14
+ import discord
15
+
16
+ except (ImportError, ModuleNotFoundError):
17
+ raise ImportError("`discord.py` not installed. Please install using `pip install discord.py`")
18
+
19
+
20
+ class RequiresConfirmationView(discord.ui.View):
21
+ def __init__(self):
22
+ super().__init__()
23
+ self.value = None
24
+
25
+ @discord.ui.button(label="Confirm", style=discord.ButtonStyle.primary)
26
+ async def confirm(
27
+ self,
28
+ interaction: discord.Interaction,
29
+ button: discord.ui.Button,
30
+ ):
31
+ self.value = True
32
+ button.disabled = True
33
+ await interaction.response.edit_message(view=self)
34
+ self.clear_items()
35
+ self.stop()
36
+
37
+ @discord.ui.button(label="Cancel", style=discord.ButtonStyle.secondary)
38
+ async def cancel(
39
+ self,
40
+ interaction: discord.Interaction,
41
+ button: discord.ui.Button,
42
+ ):
43
+ self.value = False
44
+ button.disabled = True
45
+ await interaction.response.edit_message(view=self)
46
+ self.clear_items()
47
+ self.stop()
48
+
49
+ async def on_timeout(self):
50
+ log_warning("Agent Timeout Error")
51
+
52
+
53
+ class DiscordClient:
54
+ def __init__(
55
+ self, agent: Optional[Agent] = None, team: Optional[Team] = None, client: Optional[discord.Client] = None
56
+ ):
57
+ self.agent = agent
58
+ self.team = team
59
+ if client is None:
60
+ self.intents = discord.Intents.all()
61
+ self.client = discord.Client(intents=self.intents)
62
+ else:
63
+ self.client = client
64
+ self._setup_events()
65
+
66
+ def _setup_events(self):
67
+ @self.client.event
68
+ async def on_message(message):
69
+ if message.author == self.client.user:
70
+ log_info(f"sent {message.content}")
71
+ return
72
+
73
+ message_image = None
74
+ message_video = None
75
+ message_audio = None
76
+ message_file = None
77
+ media_url = None
78
+ message_text = message.content
79
+ message_url = message.jump_url
80
+ message_user = message.author.name
81
+ message_user_id = message.author.id
82
+
83
+ if message.attachments:
84
+ media = message.attachments[0]
85
+ media_type = media.content_type
86
+ media_url = media.url
87
+ if media_type.startswith("image/"):
88
+ message_image = media_url
89
+ elif media_type.startswith("video/"):
90
+ req = requests.get(media_url)
91
+ video = req.content
92
+ message_video = video
93
+ elif media_type.startswith("application/"):
94
+ req = requests.get(media_url)
95
+ document = req.content
96
+ message_file = document
97
+ elif media_type.startswith("audio/"):
98
+ message_audio = media_url
99
+
100
+ log_info(f"processing message:{message_text} \n with media: {media_url} \n url:{message_url}")
101
+ if isinstance(message.channel, discord.Thread):
102
+ thread = message.channel
103
+ elif isinstance(message.channel, discord.channel.DMChannel):
104
+ thread = message.channel # type: ignore
105
+ elif isinstance(message.channel, discord.TextChannel):
106
+ thread = await message.create_thread(name=f"{message_user}'s thread")
107
+ else:
108
+ log_info(f"received {message.content} but not in a supported channel")
109
+ return
110
+
111
+ async with thread.typing():
112
+ # TODO Unhappy with the duplication here but it keeps MyPy from complaining
113
+ additional_context = dedent(f"""
114
+ Discord username: {message_user}
115
+ Discord userid: {message_user_id}
116
+ Discord url: {message_url}
117
+ """)
118
+ if self.agent:
119
+ self.agent.additional_context = additional_context
120
+ agent_response: RunOutput = await self.agent.arun(
121
+ input=message_text,
122
+ user_id=message_user_id,
123
+ session_id=str(thread.id),
124
+ images=[Image(url=message_image)] if message_image else None,
125
+ videos=[Video(content=message_video)] if message_video else None,
126
+ audio=[Audio(url=message_audio)] if message_audio else None,
127
+ files=[File(content=message_file)] if message_file else None,
128
+ )
129
+ await self._handle_response_in_thread(agent_response, thread)
130
+ elif self.team:
131
+ self.team.additional_context = additional_context
132
+ team_response: TeamRunOutput = await self.team.arun(
133
+ input=message_text,
134
+ user_id=message_user_id,
135
+ session_id=str(thread.id),
136
+ images=[Image(url=message_image)] if message_image else None,
137
+ videos=[Video(content=message_video)] if message_video else None,
138
+ audio=[Audio(url=message_audio)] if message_audio else None,
139
+ files=[File(content=message_file)] if message_file else None,
140
+ )
141
+ await self._handle_response_in_thread(team_response, thread)
142
+
143
+ async def handle_hitl(
144
+ self, run_response: RunOutput, thread: Union[discord.Thread, discord.TextChannel]
145
+ ) -> RunOutput:
146
+ """Handles optional Human-In-The-Loop interaction."""
147
+ if run_response.is_paused:
148
+ for tool in run_response.tools_requiring_confirmation:
149
+ view = RequiresConfirmationView()
150
+ await thread.send(f"Tool requiring confirmation: {tool.tool_name}", view=view)
151
+ await view.wait()
152
+ tool.confirmed = view.value if view.value is not None else False
153
+
154
+ if self.agent:
155
+ run_response = await self.agent.acontinue_run(
156
+ run_response=run_response,
157
+ )
158
+
159
+ return run_response
160
+
161
+ async def _handle_response_in_thread(
162
+ self, response: Union[RunOutput, TeamRunOutput], thread: Union[discord.TextChannel, discord.Thread]
163
+ ):
164
+ if isinstance(response, RunOutput):
165
+ response = await self.handle_hitl(response, thread)
166
+
167
+ if response.reasoning_content:
168
+ await self._send_discord_messages(
169
+ thread=thread, message=f"Reasoning: \n{response.reasoning_content}", italics=True
170
+ )
171
+
172
+ # Handle structured outputs properly
173
+ content_message = get_text_from_message(response.content) if response.content is not None else ""
174
+
175
+ await self._send_discord_messages(thread=thread, message=content_message)
176
+
177
+ async def _send_discord_messages(self, thread: discord.channel, message: str, italics: bool = False): # type: ignore
178
+ if len(message) < 1500:
179
+ if italics:
180
+ formatted_message = "\n".join([f"_{line}_" for line in message.split("\n")])
181
+ await thread.send(formatted_message) # type: ignore
182
+ else:
183
+ await thread.send(message) # type: ignore
184
+ return
185
+
186
+ message_batches = [message[i : i + 1500] for i in range(0, len(message), 1500)]
187
+
188
+ for i, batch in enumerate(message_batches, 1):
189
+ batch_message = f"[{i}/{len(message_batches)}] {batch}"
190
+ if italics:
191
+ formatted_batch = "\n".join([f"_{line}_" for line in batch_message.split("\n")])
192
+ await thread.send(formatted_batch) # type: ignore
193
+ else:
194
+ await thread.send(batch_message) # type: ignore
195
+
196
+ def serve(self):
197
+ try:
198
+ token = getenv("DISCORD_BOT_TOKEN")
199
+ if not token:
200
+ raise ValueError("DISCORD_BOT_TOKEN NOT SET")
201
+ return self.client.run(token)
202
+ except Exception as e:
203
+ raise ValueError(f"Failed to run Discord client: {str(e)}")
@@ -1 +1,5 @@
1
- from agno.knowledge.agent import AgentKnowledge
1
+ from agno.knowledge.knowledge import Knowledge
2
+
3
+ __all__ = [
4
+ "Knowledge",
5
+ ]
@@ -1,23 +1,31 @@
1
- from typing import List, Optional
1
+ from typing import List, Optional, Union
2
2
 
3
- from agno.document.base import Document
4
- from agno.document.chunking.strategy import ChunkingStrategy
3
+ from agno.knowledge.chunking.strategy import ChunkingStrategy
4
+ from agno.knowledge.document.base import Document
5
5
  from agno.models.base import Model
6
6
  from agno.models.defaults import DEFAULT_OPENAI_MODEL_ID
7
7
  from agno.models.message import Message
8
- from agno.models.openai import OpenAIChat
8
+ from agno.models.utils import get_model
9
9
 
10
10
 
11
11
  class AgenticChunking(ChunkingStrategy):
12
12
  """Chunking strategy that uses an LLM to determine natural breakpoints in the text"""
13
13
 
14
- def __init__(self, model: Optional[Model] = None, max_chunk_size: int = 5000):
15
- self.model = model or OpenAIChat(DEFAULT_OPENAI_MODEL_ID)
16
- self.max_chunk_size = max_chunk_size
14
+ def __init__(self, model: Optional[Union[Model, str]] = None, max_chunk_size: int = 5000):
15
+ # Convert model string to Model instance
16
+ model = get_model(model)
17
+ if model is None:
18
+ try:
19
+ from agno.models.openai import OpenAIChat
20
+ except Exception:
21
+ raise ValueError("`openai` isn't installed. Please install it with `pip install openai`")
22
+ model = OpenAIChat(DEFAULT_OPENAI_MODEL_ID)
23
+ self.chunk_size = max_chunk_size
24
+ self.model = model
17
25
 
18
26
  def chunk(self, document: Document) -> List[Document]:
19
27
  """Split text into chunks using LLM to determine natural breakpoints based on context"""
20
- if len(document.content) <= self.max_chunk_size:
28
+ if len(document.content) <= self.chunk_size:
21
29
  return [document]
22
30
 
23
31
  chunks: List[Document] = []
@@ -26,22 +34,22 @@ class AgenticChunking(ChunkingStrategy):
26
34
  chunk_number = 1
27
35
 
28
36
  while remaining_text:
29
- # Ask model to find a good breakpoint within max_chunk_size
30
- prompt = f"""Analyze this text and determine a natural breakpoint within the first {self.max_chunk_size} characters.
37
+ # Ask model to find a good breakpoint within chunk_size
38
+ prompt = f"""Analyze this text and determine a natural breakpoint within the first {self.chunk_size} characters.
31
39
  Consider semantic completeness, paragraph boundaries, and topic transitions.
32
40
  Return only the character position number of where to break the text:
33
41
 
34
- {remaining_text[: self.max_chunk_size]}"""
42
+ {remaining_text[: self.chunk_size]}"""
35
43
 
36
44
  try:
37
45
  response = self.model.response([Message(role="user", content=prompt)])
38
46
  if response and response.content:
39
- break_point = min(int(response.content.strip()), self.max_chunk_size)
47
+ break_point = min(int(response.content.strip()), self.chunk_size)
40
48
  else:
41
- break_point = self.max_chunk_size
49
+ break_point = self.chunk_size
42
50
  except Exception:
43
51
  # Fallback to max size if model fails
44
- break_point = self.max_chunk_size
52
+ break_point = self.chunk_size
45
53
 
46
54
  # Extract chunk and update remaining text
47
55
  chunk = remaining_text[:break_point].strip()
@@ -1,7 +1,7 @@
1
1
  from typing import List
2
2
 
3
- from agno.document.base import Document
4
- from agno.document.chunking.strategy import ChunkingStrategy
3
+ from agno.knowledge.chunking.strategy import ChunkingStrategy
4
+ from agno.knowledge.document.base import Document
5
5
 
6
6
 
7
7
  class DocumentChunking(ChunkingStrategy):
@@ -1,7 +1,7 @@
1
1
  from typing import List
2
2
 
3
- from agno.document.base import Document
4
- from agno.document.chunking.strategy import ChunkingStrategy
3
+ from agno.knowledge.chunking.strategy import ChunkingStrategy
4
+ from agno.knowledge.document.base import Document
5
5
 
6
6
 
7
7
  class FixedSizeChunking(ChunkingStrategy):
@@ -22,9 +22,8 @@ class FixedSizeChunking(ChunkingStrategy):
22
22
  chunked_documents: List[Document] = []
23
23
  chunk_number = 1
24
24
  chunk_meta_data = document.meta_data
25
-
26
25
  start = 0
27
- while start < content_length:
26
+ while start + self.overlap < content_length:
28
27
  end = min(start + self.chunk_size, content_length)
29
28
 
30
29
  # Ensure we're not splitting a word in half
@@ -54,6 +53,8 @@ class FixedSizeChunking(ChunkingStrategy):
54
53
  )
55
54
  )
56
55
  chunk_number += 1
57
- start = end - self.overlap
58
-
56
+ # Ensure start always advances by at least 1 to prevent infinite loops
57
+ # when overlap is large relative to chunk_size
58
+ new_start = max(start + 1, end - self.overlap)
59
+ start = new_start
59
60
  return chunked_documents
@@ -0,0 +1,151 @@
1
+ import os
2
+ import tempfile
3
+ from typing import List
4
+
5
+ try:
6
+ from unstructured.chunking.title import chunk_by_title # type: ignore
7
+ from unstructured.partition.md import partition_md # type: ignore
8
+ except ImportError:
9
+ raise ImportError("`unstructured` not installed. Please install it using `pip install unstructured markdown`")
10
+
11
+ from agno.knowledge.chunking.strategy import ChunkingStrategy
12
+ from agno.knowledge.document.base import Document
13
+
14
+
15
+ class MarkdownChunking(ChunkingStrategy):
16
+ """A chunking strategy that splits markdown based on structure like headers, paragraphs and sections"""
17
+
18
+ def __init__(self, chunk_size: int = 5000, overlap: int = 0):
19
+ self.chunk_size = chunk_size
20
+ self.overlap = overlap
21
+
22
+ def _partition_markdown_content(self, content: str) -> List[str]:
23
+ """
24
+ Partition markdown content and return a list of text chunks.
25
+ Falls back to paragraph splitting if the markdown chunking fails.
26
+ """
27
+ try:
28
+ # Create a temporary file with the markdown content.
29
+ # This is the recommended usage of the unstructured library.
30
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False, encoding="utf-8") as temp_file:
31
+ temp_file.write(content)
32
+ temp_file_path = temp_file.name
33
+
34
+ try:
35
+ elements = partition_md(filename=temp_file_path)
36
+
37
+ if not elements:
38
+ return self.clean_text(content).split("\n\n")
39
+
40
+ # Chunk by title with some default values
41
+ chunked_elements = chunk_by_title(
42
+ elements=elements,
43
+ max_characters=self.chunk_size,
44
+ new_after_n_chars=int(self.chunk_size * 0.8),
45
+ combine_text_under_n_chars=self.chunk_size,
46
+ overlap=0,
47
+ )
48
+
49
+ # Generate the final text chunks
50
+ text_chunks = []
51
+ for chunk_group in chunked_elements:
52
+ if isinstance(chunk_group, list):
53
+ chunk_text = "\n\n".join([elem.text for elem in chunk_group if hasattr(elem, "text")])
54
+ else:
55
+ chunk_text = chunk_group.text if hasattr(chunk_group, "text") else str(chunk_group)
56
+
57
+ if chunk_text.strip():
58
+ text_chunks.append(chunk_text.strip())
59
+
60
+ return text_chunks if text_chunks else self.clean_text(content).split("\n\n")
61
+
62
+ # Always clean up the temporary file
63
+ finally:
64
+ os.unlink(temp_file_path)
65
+
66
+ # Fallback to simple paragraph splitting if the markdown chunking fails
67
+ except Exception:
68
+ return self.clean_text(content).split("\n\n")
69
+
70
+ def chunk(self, document: Document) -> List[Document]:
71
+ """Split markdown document into chunks based on markdown structure"""
72
+ if not document.content or len(document.content) <= self.chunk_size:
73
+ return [document]
74
+
75
+ # Split using markdown chunking logic, or fallback to paragraphs
76
+ sections = self._partition_markdown_content(document.content)
77
+
78
+ chunks: List[Document] = []
79
+ current_chunk = []
80
+ current_size = 0
81
+ chunk_meta_data = document.meta_data
82
+ chunk_number = 1
83
+
84
+ for section in sections:
85
+ section = section.strip()
86
+ section_size = len(section)
87
+
88
+ if current_size + section_size <= self.chunk_size:
89
+ current_chunk.append(section)
90
+ current_size += section_size
91
+ else:
92
+ meta_data = chunk_meta_data.copy()
93
+ meta_data["chunk"] = chunk_number
94
+ chunk_id = None
95
+ if document.id:
96
+ chunk_id = f"{document.id}_{chunk_number}"
97
+ elif document.name:
98
+ chunk_id = f"{document.name}_{chunk_number}"
99
+ meta_data["chunk_size"] = len("\n\n".join(current_chunk))
100
+
101
+ if current_chunk:
102
+ chunks.append(
103
+ Document(
104
+ id=chunk_id, name=document.name, meta_data=meta_data, content="\n\n".join(current_chunk)
105
+ )
106
+ )
107
+ chunk_number += 1
108
+
109
+ current_chunk = [section]
110
+ current_size = section_size
111
+
112
+ if current_chunk:
113
+ meta_data = chunk_meta_data.copy()
114
+ meta_data["chunk"] = chunk_number
115
+ chunk_id = None
116
+ if document.id:
117
+ chunk_id = f"{document.id}_{chunk_number}"
118
+ elif document.name:
119
+ chunk_id = f"{document.name}_{chunk_number}"
120
+ meta_data["chunk_size"] = len("\n\n".join(current_chunk))
121
+ chunks.append(
122
+ Document(id=chunk_id, name=document.name, meta_data=meta_data, content="\n\n".join(current_chunk))
123
+ )
124
+
125
+ # Handle overlap if specified
126
+ if self.overlap > 0:
127
+ overlapped_chunks = []
128
+ for i in range(len(chunks)):
129
+ if i > 0:
130
+ # Add overlap from previous chunk
131
+ prev_text = chunks[i - 1].content[-self.overlap :]
132
+ meta_data = chunk_meta_data.copy()
133
+ meta_data["chunk"] = chunks[i].meta_data["chunk"]
134
+ chunk_id = chunks[i].id
135
+ meta_data["chunk_size"] = len(prev_text + chunks[i].content)
136
+
137
+ if prev_text:
138
+ overlapped_chunks.append(
139
+ Document(
140
+ id=chunk_id,
141
+ name=document.name,
142
+ meta_data=meta_data,
143
+ content=prev_text + chunks[i].content,
144
+ )
145
+ )
146
+ else:
147
+ overlapped_chunks.append(chunks[i])
148
+ else:
149
+ overlapped_chunks.append(chunks[i])
150
+ chunks = overlapped_chunks
151
+ return chunks
@@ -1,7 +1,8 @@
1
+ import warnings
1
2
  from typing import List
2
3
 
3
- from agno.document.base import Document
4
- from agno.document.chunking.strategy import ChunkingStrategy
4
+ from agno.knowledge.chunking.strategy import ChunkingStrategy
5
+ from agno.knowledge.document.base import Document
5
6
 
6
7
 
7
8
  class RecursiveChunking(ChunkingStrategy):
@@ -12,6 +13,12 @@ class RecursiveChunking(ChunkingStrategy):
12
13
  if overlap >= chunk_size:
13
14
  raise ValueError(f"Invalid parameters: overlap ({overlap}) must be less than chunk size ({chunk_size}).")
14
15
 
16
+ if overlap > chunk_size * 0.15:
17
+ warnings.warn(
18
+ f"High overlap: {overlap} > 15% of chunk size ({chunk_size}). May cause slow processing.",
19
+ RuntimeWarning,
20
+ )
21
+
15
22
  self.chunk_size = chunk_size
16
23
  self.overlap = overlap
17
24
 
@@ -46,6 +53,11 @@ class RecursiveChunking(ChunkingStrategy):
46
53
  meta_data["chunk_size"] = len(chunk)
47
54
  chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk))
48
55
 
49
- start = max(start, end - self.overlap)
56
+ new_start = end - self.overlap
57
+ if new_start <= start: # Prevent infinite loop
58
+ new_start = min(
59
+ len(content), start + max(1, self.chunk_size // 10)
60
+ ) # Move forward by at least 10% of chunk size
61
+ start = new_start
50
62
 
51
63
  return chunks