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,290 @@
1
+ import asyncio
2
+ import csv
3
+ import io
4
+ from pathlib import Path
5
+ from typing import IO, Any, List, Optional, Union
6
+
7
+ try:
8
+ import aiofiles
9
+ except ImportError:
10
+ raise ImportError("`aiofiles` not installed. Please install it with `pip install aiofiles`")
11
+
12
+ from agno.knowledge.chunking.strategy import ChunkingStrategyType
13
+ from agno.knowledge.document.base import Document
14
+ from agno.knowledge.reader.base import Reader
15
+ from agno.knowledge.types import ContentType
16
+ from agno.utils.log import log_debug, log_error, log_warning
17
+
18
+
19
+ class FieldLabeledCSVReader(Reader):
20
+ """Reader for CSV files that converts each row to a field-labeled document."""
21
+
22
+ def __init__(
23
+ self,
24
+ chunk_title: Optional[Union[str, List[str]]] = None,
25
+ field_names: Optional[List[str]] = None,
26
+ format_headers: bool = True,
27
+ skip_empty_fields: bool = True,
28
+ **kwargs,
29
+ ):
30
+ super().__init__(chunk=False, chunking_strategy=None, **kwargs)
31
+ self.chunk_title = chunk_title
32
+ self.field_names = field_names or []
33
+ self.format_headers = format_headers
34
+ self.skip_empty_fields = skip_empty_fields
35
+
36
+ @classmethod
37
+ def get_supported_chunking_strategies(cls) -> List[ChunkingStrategyType]:
38
+ """Chunking is not supported - each row is already a logical document unit."""
39
+ return []
40
+
41
+ @classmethod
42
+ def get_supported_content_types(cls) -> List[ContentType]:
43
+ """Get the list of supported content types."""
44
+ return [ContentType.CSV, ContentType.XLSX, ContentType.XLS]
45
+
46
+ def _format_field_name(self, field_name: str) -> str:
47
+ """Format field name to be more readable."""
48
+ if not self.format_headers:
49
+ return field_name.strip()
50
+
51
+ # Replace underscores with spaces and title case
52
+ formatted = field_name.replace("_", " ").strip().title()
53
+ return formatted
54
+
55
+ def _get_title_for_entry(self, entry_index: int) -> Optional[str]:
56
+ """Get title for a specific entry."""
57
+ if self.chunk_title is None:
58
+ return None
59
+
60
+ if isinstance(self.chunk_title, str):
61
+ return self.chunk_title
62
+
63
+ if isinstance(self.chunk_title, list) and self.chunk_title:
64
+ return self.chunk_title[entry_index % len(self.chunk_title)]
65
+
66
+ return None
67
+
68
+ def _convert_row_to_labeled_text(self, headers: List[str], row: List[str], entry_index: int) -> str:
69
+ """
70
+ Convert a CSV row to field-labeled text format.
71
+
72
+ Args:
73
+ headers: Column headers
74
+ row: Data row values
75
+ entry_index: Index of this entry (for title rotation)
76
+
77
+ Returns:
78
+ Formatted text with field labels
79
+ """
80
+ lines = []
81
+
82
+ title = self._get_title_for_entry(entry_index)
83
+ if title:
84
+ lines.append(title)
85
+
86
+ for i, (header, value) in enumerate(zip(headers, row)):
87
+ clean_value = value.strip() if value else ""
88
+
89
+ if self.skip_empty_fields and not clean_value:
90
+ continue
91
+
92
+ if self.field_names and i < len(self.field_names):
93
+ field_name = self.field_names[i]
94
+ else:
95
+ field_name = self._format_field_name(header)
96
+
97
+ lines.append(f"{field_name}: {clean_value}")
98
+
99
+ return "\n".join(lines)
100
+
101
+ def read(
102
+ self, file: Union[Path, IO[Any]], delimiter: str = ",", quotechar: str = '"', name: Optional[str] = None
103
+ ) -> List[Document]:
104
+ try:
105
+ if isinstance(file, Path):
106
+ if not file.exists():
107
+ raise FileNotFoundError(f"Could not find file: {file}")
108
+ log_debug(f"Reading: {file}")
109
+ file_content = file.open(newline="", mode="r", encoding=self.encoding or "utf-8")
110
+ else:
111
+ log_debug(f"Reading retrieved file: {name or file.name}")
112
+ file.seek(0)
113
+ file_content = io.StringIO(file.read().decode("utf-8")) # type: ignore
114
+
115
+ csv_name = name or (
116
+ Path(file.name).stem
117
+ if isinstance(file, Path)
118
+ else (getattr(file, "name", "csv_file").split(".")[0] if hasattr(file, "name") else "csv_file")
119
+ )
120
+
121
+ documents = []
122
+
123
+ with file_content as csvfile:
124
+ csv_reader = csv.reader(csvfile, delimiter=delimiter, quotechar=quotechar)
125
+
126
+ # Read all rows
127
+ rows = list(csv_reader)
128
+
129
+ if not rows:
130
+ log_warning("CSV file is empty")
131
+ return []
132
+
133
+ # First row is headers
134
+ headers = [header.strip() for header in rows[0]]
135
+ log_debug(f"Found {len(headers)} headers: {headers}")
136
+
137
+ data_rows = rows[1:] if len(rows) > 1 else []
138
+ log_debug(f"Processing {len(data_rows)} data rows")
139
+
140
+ for row_index, row in enumerate(data_rows):
141
+ # Ensure row has same length as headers (pad or truncate)
142
+ normalized_row = row[: len(headers)] # Truncate if too long
143
+ while len(normalized_row) < len(headers): # Pad if too short
144
+ normalized_row.append("")
145
+
146
+ # Convert row to labeled text
147
+ labeled_text = self._convert_row_to_labeled_text(headers, normalized_row, row_index)
148
+
149
+ if labeled_text.strip():
150
+ # Create document for this row
151
+ doc_id = f"{csv_name}_row_{row_index + 1}"
152
+
153
+ document = Document(
154
+ id=doc_id,
155
+ name=csv_name,
156
+ meta_data={
157
+ "row_index": row_index,
158
+ "headers": headers,
159
+ "total_rows": len(data_rows),
160
+ "source": "field_labeled_csv_reader",
161
+ },
162
+ content=labeled_text,
163
+ )
164
+
165
+ documents.append(document)
166
+ log_debug(f"Created document for row {row_index + 1}: {len(labeled_text)} chars")
167
+
168
+ log_debug(f"Successfully created {len(documents)} labeled documents from CSV")
169
+ return documents
170
+
171
+ except Exception as e:
172
+ log_error(f"Error reading: {getattr(file, 'name', str(file)) if isinstance(file, IO) else file}: {e}")
173
+ return []
174
+
175
+ async def async_read(
176
+ self,
177
+ file: Union[Path, IO[Any]],
178
+ delimiter: str = ",",
179
+ quotechar: str = '"',
180
+ page_size: int = 1000,
181
+ name: Optional[str] = None,
182
+ ) -> List[Document]:
183
+ try:
184
+ # Handle file input
185
+ if isinstance(file, Path):
186
+ if not file.exists():
187
+ raise FileNotFoundError(f"Could not find file: {file}")
188
+ log_debug(f"Reading async: {file}")
189
+ async with aiofiles.open(file, mode="r", encoding=self.encoding or "utf-8", newline="") as file_content:
190
+ content = await file_content.read()
191
+ file_content_io = io.StringIO(content)
192
+ else:
193
+ log_debug(f"Reading retrieved file async: {name or file.name}")
194
+ file.seek(0)
195
+ file_content_io = io.StringIO(file.read().decode("utf-8")) # type: ignore
196
+
197
+ csv_name = name or (
198
+ Path(file.name).stem
199
+ if isinstance(file, Path)
200
+ else (getattr(file, "name", "csv_file").split(".")[0] if hasattr(file, "name") else "csv_file")
201
+ )
202
+
203
+ file_content_io.seek(0)
204
+ csv_reader = csv.reader(file_content_io, delimiter=delimiter, quotechar=quotechar)
205
+ rows = list(csv_reader)
206
+
207
+ if not rows:
208
+ log_warning("CSV file is empty")
209
+ return []
210
+
211
+ # First row is headers
212
+ headers = [header.strip() for header in rows[0]]
213
+ log_debug(f"Found {len(headers)} headers: {headers}")
214
+
215
+ # Process data rows
216
+ data_rows = rows[1:] if len(rows) > 1 else []
217
+ total_rows = len(data_rows)
218
+ log_debug(f"Processing {total_rows} data rows")
219
+
220
+ # For small files, process all at once
221
+ if total_rows <= 10:
222
+ documents = []
223
+ for row_index, row in enumerate(data_rows):
224
+ normalized_row = row[: len(headers)]
225
+ while len(normalized_row) < len(headers):
226
+ normalized_row.append("")
227
+
228
+ labeled_text = self._convert_row_to_labeled_text(headers, normalized_row, row_index)
229
+
230
+ if labeled_text.strip():
231
+ document = Document(
232
+ id=f"{csv_name}_row_{row_index + 1}",
233
+ name=csv_name,
234
+ meta_data={
235
+ "row_index": row_index,
236
+ "headers": headers,
237
+ "total_rows": total_rows,
238
+ "source": "field_labeled_csv_reader",
239
+ },
240
+ content=labeled_text,
241
+ )
242
+ documents.append(document)
243
+ else:
244
+ pages = []
245
+ for i in range(0, total_rows, page_size):
246
+ pages.append(data_rows[i : i + page_size])
247
+
248
+ async def _process_page(page_number: int, page_rows: List[List[str]]) -> List[Document]:
249
+ """Process a page of rows into documents"""
250
+ page_documents = []
251
+ start_row_index = (page_number - 1) * page_size
252
+
253
+ for i, row in enumerate(page_rows):
254
+ row_index = start_row_index + i
255
+
256
+ normalized_row = row[: len(headers)]
257
+ while len(normalized_row) < len(headers):
258
+ normalized_row.append("")
259
+
260
+ labeled_text = self._convert_row_to_labeled_text(headers, normalized_row, row_index)
261
+
262
+ if labeled_text.strip():
263
+ document = Document(
264
+ id=f"{csv_name}_row_{row_index + 1}",
265
+ name=csv_name,
266
+ meta_data={
267
+ "row_index": row_index,
268
+ "headers": headers,
269
+ "total_rows": total_rows,
270
+ "page": page_number,
271
+ "source": "field_labeled_csv_reader",
272
+ },
273
+ content=labeled_text,
274
+ )
275
+ page_documents.append(document)
276
+
277
+ return page_documents
278
+
279
+ page_results = await asyncio.gather(
280
+ *[_process_page(page_number, page) for page_number, page in enumerate(pages, start=1)]
281
+ )
282
+
283
+ documents = [doc for page_docs in page_results for doc in page_docs]
284
+
285
+ log_debug(f"Successfully created {len(documents)} labeled documents from CSV")
286
+ return documents
287
+
288
+ except Exception as e:
289
+ log_error(f"Error reading async: {getattr(file, 'name', str(file)) if isinstance(file, IO) else file}: {e}")
290
+ return []
@@ -0,0 +1,201 @@
1
+ import asyncio
2
+ from dataclasses import dataclass
3
+ from typing import Dict, List, Literal, Optional
4
+
5
+ from agno.knowledge.chunking.semantic import SemanticChunking
6
+ from agno.knowledge.chunking.strategy import ChunkingStrategy, ChunkingStrategyType
7
+ from agno.knowledge.document.base import Document
8
+ from agno.knowledge.reader.base import Reader
9
+ from agno.knowledge.types import ContentType
10
+ from agno.utils.log import log_debug, logger
11
+
12
+ try:
13
+ from firecrawl import FirecrawlApp # type: ignore[attr-defined]
14
+ except ImportError:
15
+ raise ImportError("The `firecrawl` package is not installed. Please install it via `pip install firecrawl-py`.")
16
+
17
+
18
+ @dataclass
19
+ class FirecrawlReader(Reader):
20
+ api_key: Optional[str] = None
21
+ params: Optional[Dict] = None
22
+ mode: Literal["scrape", "crawl"] = "scrape"
23
+
24
+ def __init__(
25
+ self,
26
+ api_key: Optional[str] = None,
27
+ params: Optional[Dict] = None,
28
+ mode: Literal["scrape", "crawl"] = "scrape",
29
+ chunk: bool = True,
30
+ chunk_size: int = 5000,
31
+ chunking_strategy: Optional[ChunkingStrategy] = SemanticChunking(),
32
+ name: Optional[str] = None,
33
+ description: Optional[str] = None,
34
+ ) -> None:
35
+ # Initialise base Reader (handles chunk_size / strategy)
36
+ super().__init__(
37
+ chunk=chunk, chunk_size=chunk_size, chunking_strategy=chunking_strategy, name=name, description=description
38
+ )
39
+
40
+ # Firecrawl-specific attributes
41
+ self.api_key = api_key
42
+ self.params = params
43
+ self.mode = mode
44
+
45
+ @classmethod
46
+ def get_supported_chunking_strategies(self) -> List[ChunkingStrategyType]:
47
+ """Get the list of supported chunking strategies for Firecrawl readers."""
48
+ return [
49
+ ChunkingStrategyType.SEMANTIC_CHUNKER,
50
+ ChunkingStrategyType.FIXED_SIZE_CHUNKER,
51
+ ChunkingStrategyType.AGENTIC_CHUNKER,
52
+ ChunkingStrategyType.DOCUMENT_CHUNKER,
53
+ ChunkingStrategyType.RECURSIVE_CHUNKER,
54
+ ]
55
+
56
+ @classmethod
57
+ def get_supported_content_types(self) -> List[ContentType]:
58
+ return [ContentType.URL]
59
+
60
+ def scrape(self, url: str, name: Optional[str] = None) -> List[Document]:
61
+ """
62
+ Scrapes a website and returns a list of documents.
63
+
64
+ Args:
65
+ url: The URL of the website to scrape
66
+
67
+ Returns:
68
+ A list of documents
69
+ """
70
+
71
+ log_debug(f"Scraping: {url}")
72
+
73
+ app = FirecrawlApp(api_key=self.api_key)
74
+
75
+ if self.params:
76
+ scraped_data = app.scrape_url(url, **self.params)
77
+ else:
78
+ scraped_data = app.scrape_url(url)
79
+ if isinstance(scraped_data, dict):
80
+ content = scraped_data.get("markdown", "")
81
+ else:
82
+ content = getattr(scraped_data, "markdown", "")
83
+
84
+ # Debug logging
85
+ log_debug(f"Received content type: {type(content)}")
86
+ log_debug(f"Content empty: {not bool(content)}")
87
+
88
+ # Ensure content is a string
89
+ if content is None:
90
+ content = "" # or you could use metadata to create a meaningful message
91
+ logger.warning(f"No content received for URL: {url}")
92
+
93
+ documents = []
94
+ if self.chunk and content: # Only chunk if there's content
95
+ documents.extend(self.chunk_document(Document(name=name or url, id=url, content=content)))
96
+ else:
97
+ documents.append(Document(name=name or url, id=url, content=content))
98
+ return documents
99
+
100
+ async def async_scrape(self, url: str, name: Optional[str] = None) -> List[Document]:
101
+ """
102
+ Asynchronously scrapes a website and returns a list of documents.
103
+
104
+ Args:
105
+ url: The URL of the website to scrape
106
+
107
+ Returns:
108
+ A list of documents
109
+ """
110
+ log_debug(f"Async scraping: {url}")
111
+
112
+ # Use asyncio.to_thread to run the synchronous scrape in a thread
113
+ return await asyncio.to_thread(self.scrape, url, name)
114
+
115
+ def crawl(self, url: str, name: Optional[str] = None) -> List[Document]:
116
+ """
117
+ Crawls a website and returns a list of documents.
118
+
119
+ Args:
120
+ url: The URL of the website to crawl
121
+
122
+ Returns:
123
+ A list of documents
124
+ """
125
+ log_debug(f"Crawling: {url}")
126
+
127
+ app = FirecrawlApp(api_key=self.api_key)
128
+
129
+ if self.params:
130
+ crawl_result = app.crawl_url(url, **self.params)
131
+ else:
132
+ crawl_result = app.crawl_url(url)
133
+ documents = []
134
+
135
+ if isinstance(crawl_result, dict):
136
+ results_data = crawl_result.get("data", [])
137
+ else:
138
+ results_data = getattr(crawl_result, "data", [])
139
+ for result in results_data:
140
+ # Get markdown content, default to empty string if not found
141
+ if isinstance(result, dict):
142
+ content = result.get("markdown", "")
143
+ else:
144
+ content = getattr(result, "markdown", "")
145
+
146
+ if content: # Only create document if content exists
147
+ if self.chunk:
148
+ documents.extend(self.chunk_document(Document(name=name or url, id=url, content=content)))
149
+ else:
150
+ documents.append(Document(name=name or url, id=url, content=content))
151
+
152
+ return documents
153
+
154
+ async def async_crawl(self, url: str, name: Optional[str] = None) -> List[Document]:
155
+ """
156
+ Asynchronously crawls a website and returns a list of documents.
157
+
158
+ Args:
159
+ url: The URL of the website to crawl
160
+
161
+ Returns:
162
+ A list of documents
163
+ """
164
+ log_debug(f"Async crawling: {url}")
165
+
166
+ # Use asyncio.to_thread to run the synchronous crawl in a thread
167
+ return await asyncio.to_thread(self.crawl, url, name)
168
+
169
+ def read(self, url: str, name: Optional[str] = None) -> List[Document]:
170
+ """
171
+ Reads from a URL based on the mode setting.
172
+
173
+ Args:
174
+ url: The URL of the website to process
175
+
176
+ Returns:
177
+ A list of documents
178
+ """
179
+ if self.mode == "scrape":
180
+ return self.scrape(url, name)
181
+ elif self.mode == "crawl":
182
+ return self.crawl(url, name)
183
+ else:
184
+ raise NotImplementedError(f"Mode {self.mode} not implemented")
185
+
186
+ async def async_read(self, url: str, name: Optional[str] = None) -> List[Document]:
187
+ """
188
+ Asynchronously reads from a URL based on the mode setting.
189
+
190
+ Args:
191
+ url: The URL of the website to process
192
+
193
+ Returns:
194
+ A list of documents
195
+ """
196
+ if self.mode == "scrape":
197
+ return await self.async_scrape(url, name)
198
+ elif self.mode == "crawl":
199
+ return await self.async_crawl(url, name)
200
+ else:
201
+ raise NotImplementedError(f"Mode {self.mode} not implemented")
@@ -0,0 +1,88 @@
1
+ import asyncio
2
+ import json
3
+ from io import BytesIO
4
+ from pathlib import Path
5
+ from typing import IO, Any, List, Optional, Union
6
+ from uuid import uuid4
7
+
8
+ from agno.knowledge.chunking.fixed import FixedSizeChunking
9
+ from agno.knowledge.chunking.strategy import ChunkingStrategy, ChunkingStrategyType
10
+ from agno.knowledge.document.base import Document
11
+ from agno.knowledge.reader.base import Reader
12
+ from agno.knowledge.types import ContentType
13
+ from agno.utils.log import log_debug, log_error
14
+
15
+
16
+ class JSONReader(Reader):
17
+ """Reader for JSON files"""
18
+
19
+ chunk: bool = False
20
+
21
+ def __init__(self, chunking_strategy: Optional[ChunkingStrategy] = FixedSizeChunking(), **kwargs):
22
+ super().__init__(chunking_strategy=chunking_strategy, **kwargs)
23
+
24
+ @classmethod
25
+ def get_supported_chunking_strategies(self) -> List[ChunkingStrategyType]:
26
+ """Get the list of supported chunking strategies for JSON readers."""
27
+ return [
28
+ ChunkingStrategyType.FIXED_SIZE_CHUNKER,
29
+ ChunkingStrategyType.AGENTIC_CHUNKER,
30
+ ChunkingStrategyType.DOCUMENT_CHUNKER,
31
+ ChunkingStrategyType.RECURSIVE_CHUNKER,
32
+ ChunkingStrategyType.SEMANTIC_CHUNKER,
33
+ ]
34
+
35
+ @classmethod
36
+ def get_supported_content_types(self) -> List[ContentType]:
37
+ return [ContentType.JSON]
38
+
39
+ def read(self, path: Union[Path, IO[Any]], name: Optional[str] = None) -> List[Document]:
40
+ try:
41
+ if isinstance(path, Path):
42
+ if not path.exists():
43
+ raise FileNotFoundError(f"Could not find file: {path}")
44
+ log_debug(f"Reading: {path}")
45
+ json_name = name or path.name.split(".")[0]
46
+ json_contents = json.loads(path.read_text(self.encoding or "utf-8"))
47
+
48
+ elif isinstance(path, BytesIO):
49
+ json_name = name or path.name.split(".")[0]
50
+ log_debug(f"Reading uploaded file: {json_name}")
51
+ path.seek(0)
52
+ json_contents = json.load(path)
53
+
54
+ else:
55
+ raise ValueError("Unsupported file type. Must be Path or BytesIO.")
56
+
57
+ if isinstance(json_contents, dict):
58
+ json_contents = [json_contents]
59
+
60
+ documents = [
61
+ Document(
62
+ name=json_name,
63
+ id=str(uuid4()),
64
+ meta_data={"page": page_number},
65
+ content=json.dumps(content),
66
+ )
67
+ for page_number, content in enumerate(json_contents, start=1)
68
+ ]
69
+ if self.chunk:
70
+ chunked_documents = []
71
+ for document in documents:
72
+ chunked_documents.extend(self.chunk_document(document))
73
+ return chunked_documents
74
+ return documents
75
+ except Exception as e:
76
+ log_error(f"Error reading: {path}: {e}")
77
+ raise
78
+
79
+ async def async_read(self, path: Union[Path, IO[Any]], name: Optional[str] = None) -> List[Document]:
80
+ """Asynchronously read JSON files.
81
+
82
+ Args:
83
+ path (Union[Path, IO[Any]]): Path to a JSON file or a file-like object
84
+
85
+ Returns:
86
+ List[Document]: List of documents from the JSON file
87
+ """
88
+ return await asyncio.to_thread(self.read, path, name)