agno 1.8.2__py3-none-any.whl → 2.0.0__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 (589) hide show
  1. agno/agent/__init__.py +19 -27
  2. agno/agent/agent.py +3143 -4170
  3. agno/api/agent.py +11 -67
  4. agno/api/api.py +5 -46
  5. agno/api/evals.py +8 -19
  6. agno/api/os.py +17 -0
  7. agno/api/routes.py +6 -41
  8. agno/api/schemas/__init__.py +9 -0
  9. agno/api/schemas/agent.py +5 -21
  10. agno/api/schemas/evals.py +7 -16
  11. agno/api/schemas/os.py +14 -0
  12. agno/api/schemas/team.py +5 -21
  13. agno/api/schemas/utils.py +21 -0
  14. agno/api/schemas/workflows.py +11 -7
  15. agno/api/settings.py +53 -0
  16. agno/api/team.py +11 -66
  17. agno/api/workflow.py +28 -0
  18. agno/cloud/aws/base.py +214 -0
  19. agno/cloud/aws/s3/__init__.py +2 -0
  20. agno/cloud/aws/s3/api_client.py +43 -0
  21. agno/cloud/aws/s3/bucket.py +195 -0
  22. agno/cloud/aws/s3/object.py +57 -0
  23. agno/db/__init__.py +24 -0
  24. agno/db/base.py +245 -0
  25. agno/db/dynamo/__init__.py +3 -0
  26. agno/db/dynamo/dynamo.py +1743 -0
  27. agno/db/dynamo/schemas.py +278 -0
  28. agno/db/dynamo/utils.py +684 -0
  29. agno/db/firestore/__init__.py +3 -0
  30. agno/db/firestore/firestore.py +1432 -0
  31. agno/db/firestore/schemas.py +130 -0
  32. agno/db/firestore/utils.py +278 -0
  33. agno/db/gcs_json/__init__.py +3 -0
  34. agno/db/gcs_json/gcs_json_db.py +1001 -0
  35. agno/db/gcs_json/utils.py +194 -0
  36. agno/db/in_memory/__init__.py +3 -0
  37. agno/db/in_memory/in_memory_db.py +882 -0
  38. agno/db/in_memory/utils.py +172 -0
  39. agno/db/json/__init__.py +3 -0
  40. agno/db/json/json_db.py +1045 -0
  41. agno/db/json/utils.py +196 -0
  42. agno/db/migrations/v1_to_v2.py +162 -0
  43. agno/db/mongo/__init__.py +3 -0
  44. agno/db/mongo/mongo.py +1416 -0
  45. agno/db/mongo/schemas.py +77 -0
  46. agno/db/mongo/utils.py +204 -0
  47. agno/db/mysql/__init__.py +3 -0
  48. agno/db/mysql/mysql.py +1719 -0
  49. agno/db/mysql/schemas.py +124 -0
  50. agno/db/mysql/utils.py +297 -0
  51. agno/db/postgres/__init__.py +3 -0
  52. agno/db/postgres/postgres.py +1710 -0
  53. agno/db/postgres/schemas.py +124 -0
  54. agno/db/postgres/utils.py +280 -0
  55. agno/db/redis/__init__.py +3 -0
  56. agno/db/redis/redis.py +1367 -0
  57. agno/db/redis/schemas.py +109 -0
  58. agno/db/redis/utils.py +288 -0
  59. agno/db/schemas/__init__.py +3 -0
  60. agno/db/schemas/evals.py +33 -0
  61. agno/db/schemas/knowledge.py +40 -0
  62. agno/db/schemas/memory.py +46 -0
  63. agno/db/singlestore/__init__.py +3 -0
  64. agno/db/singlestore/schemas.py +116 -0
  65. agno/db/singlestore/singlestore.py +1712 -0
  66. agno/db/singlestore/utils.py +326 -0
  67. agno/db/sqlite/__init__.py +3 -0
  68. agno/db/sqlite/schemas.py +119 -0
  69. agno/db/sqlite/sqlite.py +1676 -0
  70. agno/db/sqlite/utils.py +268 -0
  71. agno/db/utils.py +88 -0
  72. agno/eval/__init__.py +14 -0
  73. agno/eval/accuracy.py +154 -48
  74. agno/eval/performance.py +88 -23
  75. agno/eval/reliability.py +73 -20
  76. agno/eval/utils.py +23 -13
  77. agno/integrations/discord/__init__.py +3 -0
  78. agno/{app → integrations}/discord/client.py +10 -10
  79. agno/knowledge/__init__.py +2 -2
  80. agno/{document → knowledge}/chunking/agentic.py +2 -2
  81. agno/{document → knowledge}/chunking/document.py +2 -2
  82. agno/{document → knowledge}/chunking/fixed.py +3 -3
  83. agno/{document → knowledge}/chunking/markdown.py +2 -2
  84. agno/{document → knowledge}/chunking/recursive.py +2 -2
  85. agno/{document → knowledge}/chunking/row.py +2 -2
  86. agno/knowledge/chunking/semantic.py +59 -0
  87. agno/knowledge/chunking/strategy.py +121 -0
  88. agno/knowledge/content.py +74 -0
  89. agno/knowledge/document/__init__.py +5 -0
  90. agno/{document → knowledge/document}/base.py +12 -2
  91. agno/knowledge/embedder/__init__.py +5 -0
  92. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  93. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  94. agno/{embedder → knowledge/embedder}/base.py +6 -0
  95. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  96. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  97. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  98. agno/{embedder → knowledge/embedder}/google.py +74 -1
  99. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  100. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  101. agno/knowledge/embedder/langdb.py +22 -0
  102. agno/knowledge/embedder/mistral.py +139 -0
  103. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  104. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  105. agno/knowledge/embedder/openai.py +223 -0
  106. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  107. agno/{embedder → knowledge/embedder}/together.py +1 -1
  108. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  109. agno/knowledge/knowledge.py +1551 -0
  110. agno/knowledge/reader/__init__.py +7 -0
  111. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  112. agno/knowledge/reader/base.py +88 -0
  113. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  114. agno/knowledge/reader/docx_reader.py +83 -0
  115. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  116. agno/{document → knowledge}/reader/json_reader.py +30 -9
  117. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  118. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  119. agno/knowledge/reader/reader_factory.py +268 -0
  120. agno/knowledge/reader/s3_reader.py +101 -0
  121. agno/{document → knowledge}/reader/text_reader.py +31 -10
  122. agno/knowledge/reader/url_reader.py +128 -0
  123. agno/knowledge/reader/web_search_reader.py +366 -0
  124. agno/{document → knowledge}/reader/website_reader.py +37 -10
  125. agno/knowledge/reader/wikipedia_reader.py +59 -0
  126. agno/knowledge/reader/youtube_reader.py +78 -0
  127. agno/knowledge/remote_content/remote_content.py +88 -0
  128. agno/{reranker → knowledge/reranker}/base.py +1 -1
  129. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  130. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  131. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  132. agno/knowledge/types.py +30 -0
  133. agno/knowledge/utils.py +169 -0
  134. agno/media.py +269 -268
  135. agno/memory/__init__.py +2 -10
  136. agno/memory/manager.py +1003 -148
  137. agno/models/aimlapi/__init__.py +2 -2
  138. agno/models/aimlapi/aimlapi.py +6 -6
  139. agno/models/anthropic/claude.py +128 -72
  140. agno/models/aws/bedrock.py +107 -175
  141. agno/models/aws/claude.py +64 -18
  142. agno/models/azure/ai_foundry.py +73 -23
  143. agno/models/base.py +346 -290
  144. agno/models/cerebras/cerebras.py +84 -27
  145. agno/models/cohere/chat.py +106 -98
  146. agno/models/google/gemini.py +105 -46
  147. agno/models/groq/groq.py +97 -35
  148. agno/models/huggingface/huggingface.py +92 -27
  149. agno/models/ibm/watsonx.py +72 -13
  150. agno/models/litellm/chat.py +85 -13
  151. agno/models/message.py +46 -151
  152. agno/models/meta/llama.py +85 -49
  153. agno/models/metrics.py +120 -0
  154. agno/models/mistral/mistral.py +90 -21
  155. agno/models/ollama/__init__.py +0 -2
  156. agno/models/ollama/chat.py +85 -47
  157. agno/models/openai/chat.py +154 -37
  158. agno/models/openai/responses.py +178 -105
  159. agno/models/perplexity/perplexity.py +26 -2
  160. agno/models/portkey/portkey.py +0 -7
  161. agno/models/response.py +15 -9
  162. agno/models/utils.py +20 -0
  163. agno/models/vercel/__init__.py +2 -2
  164. agno/models/vercel/v0.py +1 -1
  165. agno/models/vllm/__init__.py +2 -2
  166. agno/models/vllm/vllm.py +3 -3
  167. agno/models/xai/xai.py +10 -10
  168. agno/os/__init__.py +3 -0
  169. agno/os/app.py +497 -0
  170. agno/os/auth.py +47 -0
  171. agno/os/config.py +103 -0
  172. agno/os/interfaces/agui/__init__.py +3 -0
  173. agno/os/interfaces/agui/agui.py +31 -0
  174. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  175. agno/{app → os/interfaces}/agui/utils.py +65 -28
  176. agno/os/interfaces/base.py +21 -0
  177. agno/os/interfaces/slack/__init__.py +3 -0
  178. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  179. agno/os/interfaces/slack/slack.py +32 -0
  180. agno/os/interfaces/whatsapp/__init__.py +3 -0
  181. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  182. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  183. agno/os/mcp.py +235 -0
  184. agno/os/router.py +1400 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +393 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +850 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +410 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +178 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +536 -0
  201. agno/os/schema.py +945 -0
  202. agno/{app/playground → os}/settings.py +7 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/agent.py +633 -0
  212. agno/run/base.py +53 -77
  213. agno/run/cancel.py +81 -0
  214. agno/run/team.py +243 -96
  215. agno/run/workflow.py +550 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +3260 -4824
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +43 -23
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +20 -17
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +22 -12
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +17 -8
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +62 -62
  252. agno/tools/eleven_labs.py +36 -29
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +30 -30
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +17 -18
  260. agno/tools/function.py +127 -18
  261. agno/tools/giphy.py +23 -11
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +32 -20
  276. agno/tools/mcp.py +1 -2
  277. agno/tools/mem0.py +18 -12
  278. agno/tools/memori.py +14 -10
  279. agno/tools/mlx_transcribe.py +3 -2
  280. agno/tools/models/azure_openai.py +33 -15
  281. agno/tools/models/gemini.py +59 -32
  282. agno/tools/models/groq.py +30 -23
  283. agno/tools/models/nebius.py +28 -12
  284. agno/tools/models_labs.py +40 -16
  285. agno/tools/moviepy_video.py +7 -6
  286. agno/tools/neo4j.py +10 -8
  287. agno/tools/newspaper.py +7 -2
  288. agno/tools/newspaper4k.py +8 -3
  289. agno/tools/openai.py +58 -32
  290. agno/tools/openbb.py +12 -11
  291. agno/tools/opencv.py +63 -47
  292. agno/tools/openweather.py +14 -12
  293. agno/tools/pandas.py +11 -3
  294. agno/tools/postgres.py +4 -12
  295. agno/tools/pubmed.py +4 -1
  296. agno/tools/python.py +9 -22
  297. agno/tools/reasoning.py +35 -27
  298. agno/tools/reddit.py +11 -26
  299. agno/tools/replicate.py +55 -42
  300. agno/tools/resend.py +4 -1
  301. agno/tools/scrapegraph.py +15 -14
  302. agno/tools/searxng.py +10 -23
  303. agno/tools/serpapi.py +6 -3
  304. agno/tools/serper.py +13 -4
  305. agno/tools/shell.py +9 -2
  306. agno/tools/slack.py +12 -11
  307. agno/tools/sleep.py +3 -2
  308. agno/tools/spider.py +24 -4
  309. agno/tools/sql.py +7 -6
  310. agno/tools/tavily.py +6 -4
  311. agno/tools/telegram.py +12 -4
  312. agno/tools/todoist.py +11 -31
  313. agno/tools/toolkit.py +1 -1
  314. agno/tools/trafilatura.py +22 -6
  315. agno/tools/trello.py +9 -22
  316. agno/tools/twilio.py +10 -3
  317. agno/tools/user_control_flow.py +6 -1
  318. agno/tools/valyu.py +34 -5
  319. agno/tools/visualization.py +19 -28
  320. agno/tools/webbrowser.py +4 -3
  321. agno/tools/webex.py +11 -7
  322. agno/tools/website.py +15 -46
  323. agno/tools/webtools.py +12 -4
  324. agno/tools/whatsapp.py +5 -9
  325. agno/tools/wikipedia.py +20 -13
  326. agno/tools/x.py +14 -13
  327. agno/tools/yfinance.py +13 -40
  328. agno/tools/youtube.py +26 -20
  329. agno/tools/zendesk.py +7 -2
  330. agno/tools/zep.py +10 -7
  331. agno/tools/zoom.py +10 -9
  332. agno/utils/common.py +1 -19
  333. agno/utils/events.py +100 -123
  334. agno/utils/gemini.py +1 -1
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/log.py +54 -4
  337. agno/utils/mcp.py +68 -10
  338. agno/utils/media.py +39 -0
  339. agno/utils/message.py +12 -1
  340. agno/utils/models/aws_claude.py +1 -1
  341. agno/utils/models/claude.py +6 -12
  342. agno/utils/models/cohere.py +1 -1
  343. agno/utils/models/mistral.py +8 -7
  344. agno/utils/models/schema_utils.py +3 -3
  345. agno/utils/models/watsonx.py +1 -1
  346. agno/utils/openai.py +1 -1
  347. agno/utils/pprint.py +33 -32
  348. agno/utils/print_response/agent.py +779 -0
  349. agno/utils/print_response/team.py +1669 -0
  350. agno/utils/print_response/workflow.py +1451 -0
  351. agno/utils/prompts.py +14 -14
  352. agno/utils/reasoning.py +87 -0
  353. agno/utils/response.py +42 -42
  354. agno/utils/streamlit.py +481 -0
  355. agno/utils/string.py +8 -22
  356. agno/utils/team.py +50 -0
  357. agno/utils/timer.py +2 -2
  358. agno/vectordb/base.py +33 -21
  359. agno/vectordb/cassandra/cassandra.py +287 -23
  360. agno/vectordb/chroma/chromadb.py +482 -59
  361. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  362. agno/vectordb/couchbase/couchbase.py +309 -29
  363. agno/vectordb/lancedb/lance_db.py +360 -21
  364. agno/vectordb/langchaindb/__init__.py +5 -0
  365. agno/vectordb/langchaindb/langchaindb.py +145 -0
  366. agno/vectordb/lightrag/__init__.py +5 -0
  367. agno/vectordb/lightrag/lightrag.py +374 -0
  368. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  369. agno/vectordb/milvus/milvus.py +242 -32
  370. agno/vectordb/mongodb/mongodb.py +200 -24
  371. agno/vectordb/pgvector/pgvector.py +319 -37
  372. agno/vectordb/pineconedb/pineconedb.py +221 -27
  373. agno/vectordb/qdrant/qdrant.py +334 -14
  374. agno/vectordb/singlestore/singlestore.py +286 -29
  375. agno/vectordb/surrealdb/surrealdb.py +187 -7
  376. agno/vectordb/upstashdb/upstashdb.py +342 -26
  377. agno/vectordb/weaviate/weaviate.py +227 -165
  378. agno/workflow/__init__.py +17 -13
  379. agno/workflow/{v2/condition.py → condition.py} +135 -32
  380. agno/workflow/{v2/loop.py → loop.py} +115 -28
  381. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  382. agno/workflow/{v2/router.py → router.py} +133 -32
  383. agno/workflow/{v2/step.py → step.py} +207 -49
  384. agno/workflow/{v2/steps.py → steps.py} +147 -66
  385. agno/workflow/types.py +482 -0
  386. agno/workflow/workflow.py +2410 -696
  387. agno-2.0.0.dist-info/METADATA +494 -0
  388. agno-2.0.0.dist-info/RECORD +515 -0
  389. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  390. agno/agent/metrics.py +0 -110
  391. agno/api/app.py +0 -35
  392. agno/api/playground.py +0 -92
  393. agno/api/schemas/app.py +0 -12
  394. agno/api/schemas/playground.py +0 -22
  395. agno/api/schemas/user.py +0 -35
  396. agno/api/schemas/workspace.py +0 -46
  397. agno/api/user.py +0 -160
  398. agno/api/workflows.py +0 -33
  399. agno/api/workspace.py +0 -175
  400. agno/app/agui/__init__.py +0 -3
  401. agno/app/agui/app.py +0 -17
  402. agno/app/agui/sync_router.py +0 -120
  403. agno/app/base.py +0 -186
  404. agno/app/discord/__init__.py +0 -3
  405. agno/app/fastapi/__init__.py +0 -3
  406. agno/app/fastapi/app.py +0 -107
  407. agno/app/fastapi/async_router.py +0 -457
  408. agno/app/fastapi/sync_router.py +0 -448
  409. agno/app/playground/app.py +0 -228
  410. agno/app/playground/async_router.py +0 -1053
  411. agno/app/playground/deploy.py +0 -249
  412. agno/app/playground/operator.py +0 -183
  413. agno/app/playground/schemas.py +0 -223
  414. agno/app/playground/serve.py +0 -55
  415. agno/app/playground/sync_router.py +0 -1045
  416. agno/app/playground/utils.py +0 -46
  417. agno/app/settings.py +0 -15
  418. agno/app/slack/__init__.py +0 -3
  419. agno/app/slack/app.py +0 -19
  420. agno/app/slack/sync_router.py +0 -92
  421. agno/app/utils.py +0 -54
  422. agno/app/whatsapp/__init__.py +0 -3
  423. agno/app/whatsapp/app.py +0 -15
  424. agno/app/whatsapp/sync_router.py +0 -197
  425. agno/cli/auth_server.py +0 -249
  426. agno/cli/config.py +0 -274
  427. agno/cli/console.py +0 -88
  428. agno/cli/credentials.py +0 -23
  429. agno/cli/entrypoint.py +0 -571
  430. agno/cli/operator.py +0 -357
  431. agno/cli/settings.py +0 -96
  432. agno/cli/ws/ws_cli.py +0 -817
  433. agno/constants.py +0 -13
  434. agno/document/__init__.py +0 -5
  435. agno/document/chunking/semantic.py +0 -45
  436. agno/document/chunking/strategy.py +0 -31
  437. agno/document/reader/__init__.py +0 -5
  438. agno/document/reader/base.py +0 -47
  439. agno/document/reader/docx_reader.py +0 -60
  440. agno/document/reader/gcs/pdf_reader.py +0 -44
  441. agno/document/reader/s3/pdf_reader.py +0 -59
  442. agno/document/reader/s3/text_reader.py +0 -63
  443. agno/document/reader/url_reader.py +0 -59
  444. agno/document/reader/youtube_reader.py +0 -58
  445. agno/embedder/__init__.py +0 -5
  446. agno/embedder/langdb.py +0 -80
  447. agno/embedder/mistral.py +0 -82
  448. agno/embedder/openai.py +0 -78
  449. agno/file/__init__.py +0 -5
  450. agno/file/file.py +0 -16
  451. agno/file/local/csv.py +0 -32
  452. agno/file/local/txt.py +0 -19
  453. agno/infra/app.py +0 -240
  454. agno/infra/base.py +0 -144
  455. agno/infra/context.py +0 -20
  456. agno/infra/db_app.py +0 -52
  457. agno/infra/resource.py +0 -205
  458. agno/infra/resources.py +0 -55
  459. agno/knowledge/agent.py +0 -702
  460. agno/knowledge/arxiv.py +0 -33
  461. agno/knowledge/combined.py +0 -36
  462. agno/knowledge/csv.py +0 -144
  463. agno/knowledge/csv_url.py +0 -124
  464. agno/knowledge/document.py +0 -223
  465. agno/knowledge/docx.py +0 -137
  466. agno/knowledge/firecrawl.py +0 -34
  467. agno/knowledge/gcs/__init__.py +0 -0
  468. agno/knowledge/gcs/base.py +0 -39
  469. agno/knowledge/gcs/pdf.py +0 -125
  470. agno/knowledge/json.py +0 -137
  471. agno/knowledge/langchain.py +0 -71
  472. agno/knowledge/light_rag.py +0 -273
  473. agno/knowledge/llamaindex.py +0 -66
  474. agno/knowledge/markdown.py +0 -154
  475. agno/knowledge/pdf.py +0 -164
  476. agno/knowledge/pdf_bytes.py +0 -42
  477. agno/knowledge/pdf_url.py +0 -148
  478. agno/knowledge/s3/__init__.py +0 -0
  479. agno/knowledge/s3/base.py +0 -64
  480. agno/knowledge/s3/pdf.py +0 -33
  481. agno/knowledge/s3/text.py +0 -34
  482. agno/knowledge/text.py +0 -141
  483. agno/knowledge/url.py +0 -46
  484. agno/knowledge/website.py +0 -179
  485. agno/knowledge/wikipedia.py +0 -32
  486. agno/knowledge/youtube.py +0 -35
  487. agno/memory/agent.py +0 -423
  488. agno/memory/classifier.py +0 -104
  489. agno/memory/db/__init__.py +0 -5
  490. agno/memory/db/base.py +0 -42
  491. agno/memory/db/mongodb.py +0 -189
  492. agno/memory/db/postgres.py +0 -203
  493. agno/memory/db/sqlite.py +0 -193
  494. agno/memory/memory.py +0 -22
  495. agno/memory/row.py +0 -36
  496. agno/memory/summarizer.py +0 -201
  497. agno/memory/summary.py +0 -19
  498. agno/memory/team.py +0 -415
  499. agno/memory/v2/__init__.py +0 -2
  500. agno/memory/v2/db/__init__.py +0 -1
  501. agno/memory/v2/db/base.py +0 -42
  502. agno/memory/v2/db/firestore.py +0 -339
  503. agno/memory/v2/db/mongodb.py +0 -196
  504. agno/memory/v2/db/postgres.py +0 -214
  505. agno/memory/v2/db/redis.py +0 -187
  506. agno/memory/v2/db/schema.py +0 -54
  507. agno/memory/v2/db/sqlite.py +0 -209
  508. agno/memory/v2/manager.py +0 -437
  509. agno/memory/v2/memory.py +0 -1097
  510. agno/memory/v2/schema.py +0 -55
  511. agno/memory/v2/summarizer.py +0 -215
  512. agno/memory/workflow.py +0 -38
  513. agno/models/ollama/tools.py +0 -430
  514. agno/models/qwen/__init__.py +0 -5
  515. agno/playground/__init__.py +0 -10
  516. agno/playground/deploy.py +0 -3
  517. agno/playground/playground.py +0 -3
  518. agno/playground/serve.py +0 -3
  519. agno/playground/settings.py +0 -3
  520. agno/reranker/__init__.py +0 -0
  521. agno/run/response.py +0 -467
  522. agno/run/v2/__init__.py +0 -0
  523. agno/run/v2/workflow.py +0 -567
  524. agno/storage/__init__.py +0 -0
  525. agno/storage/agent/__init__.py +0 -0
  526. agno/storage/agent/dynamodb.py +0 -1
  527. agno/storage/agent/json.py +0 -1
  528. agno/storage/agent/mongodb.py +0 -1
  529. agno/storage/agent/postgres.py +0 -1
  530. agno/storage/agent/singlestore.py +0 -1
  531. agno/storage/agent/sqlite.py +0 -1
  532. agno/storage/agent/yaml.py +0 -1
  533. agno/storage/base.py +0 -60
  534. agno/storage/dynamodb.py +0 -673
  535. agno/storage/firestore.py +0 -297
  536. agno/storage/gcs_json.py +0 -261
  537. agno/storage/in_memory.py +0 -234
  538. agno/storage/json.py +0 -237
  539. agno/storage/mongodb.py +0 -328
  540. agno/storage/mysql.py +0 -685
  541. agno/storage/postgres.py +0 -682
  542. agno/storage/redis.py +0 -336
  543. agno/storage/session/__init__.py +0 -16
  544. agno/storage/session/agent.py +0 -64
  545. agno/storage/session/team.py +0 -63
  546. agno/storage/session/v2/__init__.py +0 -5
  547. agno/storage/session/workflow.py +0 -61
  548. agno/storage/singlestore.py +0 -606
  549. agno/storage/sqlite.py +0 -646
  550. agno/storage/workflow/__init__.py +0 -0
  551. agno/storage/workflow/mongodb.py +0 -1
  552. agno/storage/workflow/postgres.py +0 -1
  553. agno/storage/workflow/sqlite.py +0 -1
  554. agno/storage/yaml.py +0 -241
  555. agno/tools/thinking.py +0 -73
  556. agno/utils/defaults.py +0 -57
  557. agno/utils/filesystem.py +0 -39
  558. agno/utils/git.py +0 -52
  559. agno/utils/json_io.py +0 -30
  560. agno/utils/load_env.py +0 -19
  561. agno/utils/py_io.py +0 -19
  562. agno/utils/pyproject.py +0 -18
  563. agno/utils/resource_filter.py +0 -31
  564. agno/workflow/v2/__init__.py +0 -21
  565. agno/workflow/v2/types.py +0 -357
  566. agno/workflow/v2/workflow.py +0 -3313
  567. agno/workspace/__init__.py +0 -0
  568. agno/workspace/config.py +0 -325
  569. agno/workspace/enums.py +0 -6
  570. agno/workspace/helpers.py +0 -52
  571. agno/workspace/operator.py +0 -757
  572. agno/workspace/settings.py +0 -158
  573. agno-1.8.2.dist-info/METADATA +0 -982
  574. agno-1.8.2.dist-info/RECORD +0 -566
  575. agno-1.8.2.dist-info/entry_points.txt +0 -3
  576. agno-1.8.2.dist-info/licenses/LICENSE +0 -375
  577. /agno/{app → db/migrations}/__init__.py +0 -0
  578. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  579. /agno/{cli → integrations}/__init__.py +0 -0
  580. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  581. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  582. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  583. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  584. /agno/{app → os/interfaces}/slack/security.py +0 -0
  585. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  586. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  587. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  588. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  589. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
@@ -1,273 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pathlib import Path
4
- from typing import Any, ClassVar, Dict, Iterator, List, Optional, Union
5
-
6
- import textract
7
- from pydantic import Field
8
-
9
- from agno.document import Document
10
- from agno.document.reader.markdown_reader import MarkdownReader
11
- from agno.document.reader.pdf_reader import PDFUrlReader
12
- from agno.document.reader.url_reader import URLReader
13
- from agno.knowledge.agent import AgentKnowledge
14
- from agno.utils.log import log_debug, log_info, logger
15
-
16
-
17
- class LightRagKnowledgeBase(AgentKnowledge):
18
- """LightRAG-based knowledge base for document processing and retrieval."""
19
-
20
- # Constants
21
- DEFAULT_SERVER_URL: ClassVar[str] = "http://localhost:9621"
22
- SUPPORTED_EXTENSIONS: ClassVar[List[str]] = [".pdf", ".md", ".txt"]
23
-
24
- lightrag_server_url: str = DEFAULT_SERVER_URL
25
- path: Optional[Union[str, Path, List[Dict[str, Union[str, Dict[str, Any]]]]]] = None
26
- urls: Optional[Union[List[str], List[Dict[str, Union[str, Dict[str, Any]]]]]] = None
27
- exclude_files: List[str] = Field(default_factory=list)
28
-
29
- pdf_url_reader: PDFUrlReader = PDFUrlReader()
30
- markdown_reader: MarkdownReader = MarkdownReader()
31
- url_reader: URLReader = URLReader()
32
-
33
- @property
34
- def document_lists(self) -> Iterator[List[Document]]:
35
- """Iterate over documents and yield lists of Document objects."""
36
- # Convert text lists to Document objects to match parent class signature
37
- for text_list in self._text_document_lists():
38
- documents = [Document(content=text) for text in text_list]
39
- yield documents
40
-
41
- def _text_document_lists(self) -> Iterator[List[str]]:
42
- """Internal method to iterate over documents and yield lists of text content."""
43
- if self.path is not None:
44
- yield from self._process_paths()
45
-
46
- if self.urls is not None:
47
- yield from self._process_urls()
48
-
49
- if self.urls is None and self.path is None:
50
- raise ValueError("Path or URLs are not set")
51
-
52
- def _process_paths(self) -> Iterator[List[str]]:
53
- """Process path-based documents."""
54
- if self.path is None:
55
- return
56
-
57
- if isinstance(self.path, list):
58
- for item in self.path:
59
- if isinstance(item, dict) and "path" in item:
60
- path_value = item["path"]
61
- if isinstance(path_value, (str, Path)):
62
- yield from self._process_single_path(Path(path_value))
63
- else:
64
- yield from self._process_single_path(Path(self.path))
65
-
66
- def _process_single_path(self, path: Path) -> Iterator[List[str]]:
67
- """Process a single path (file or directory)."""
68
- if path.is_dir():
69
- for file_path in path.glob("**/*"):
70
- if file_path.is_file():
71
- text_str = textract.process(str(file_path)).decode("utf-8")
72
- yield [text_str]
73
- elif path.exists() and path.is_file():
74
- if path.suffix == ".md":
75
- documents = self.markdown_reader.read(file=path)
76
- text_contents = [doc.content for doc in documents]
77
- yield text_contents
78
- elif path.suffix == ".pdf":
79
- text_str = textract.process(str(path)).decode("utf-8")
80
- yield [text_str]
81
- else:
82
- text_str = textract.process(str(path)).decode("utf-8")
83
- yield [text_str]
84
-
85
- def _process_urls(self) -> Iterator[List[str]]:
86
- """Process URL-based documents."""
87
- if self.urls is None:
88
- return
89
-
90
- log_info(f"Processing URLs: {self.urls}")
91
- for item in self.urls:
92
- if isinstance(item, dict) and "url" in item:
93
- url = item["url"]
94
- config = item.get("metadata", {})
95
- if isinstance(url, str) and isinstance(config, dict):
96
- yield from self._process_url_with_metadata(url, config)
97
- elif isinstance(item, str):
98
- yield from self._process_simple_url(item)
99
-
100
- def _process_url_with_metadata(self, url: str, config: Dict[str, Any]) -> Iterator[List[str]]:
101
- """Process URL with metadata configuration."""
102
- log_debug(f"Processing URL with metadata - URL: {url}, Config: {config}")
103
- if self._is_valid_url(url):
104
- if url.endswith(".pdf"):
105
- log_info(f"READING PDF URL: {url}")
106
- documents = self.pdf_url_reader.read(url=url)
107
- text_contents = [doc.content for doc in documents]
108
- yield text_contents
109
- else:
110
- log_debug(f"URL is valid, reading documents from: {url}")
111
- documents = self.url_reader.read(url=url)
112
- text_contents = []
113
- for doc in documents:
114
- if config:
115
- log_debug(f"Adding metadata {config} to document from URL: {url}")
116
- doc.meta_data.update(config)
117
- text_contents.append(doc.content)
118
- yield text_contents
119
-
120
- def _process_simple_url(self, url: str) -> Iterator[List[str]]:
121
- """Process a simple URL without metadata."""
122
- log_info(f"Processing simple URL: {url}")
123
- if self._is_valid_url(url):
124
- log_info(f"Simple URL is valid, reading documents from: {url}")
125
- if url.endswith(".pdf"):
126
- documents = self.pdf_url_reader.read(url=url)
127
- text_contents = [doc.content for doc in documents]
128
- yield text_contents
129
- else:
130
- documents = self.url_reader.read(url=url)
131
- text_contents = [doc.content for doc in documents]
132
- yield text_contents
133
-
134
- async def load(
135
- self,
136
- recreate: bool = False,
137
- upsert: bool = False,
138
- skip_existing: bool = True,
139
- ) -> None:
140
- """Load the knowledge base to the LightRAG server asynchronously.
141
-
142
- Note: The LightRAG implementation is inherently async.
143
- """
144
- logger.debug("Loading LightRagKnowledgeBase")
145
- for text_list in self._text_document_lists():
146
- for text in text_list:
147
- await self._insert_text(text)
148
-
149
- async def aload(
150
- self,
151
- recreate: bool = False,
152
- upsert: bool = False,
153
- skip_existing: bool = True,
154
- ) -> None:
155
- """Load all documents into the LightRAG server asynchronously."""
156
- # Delegate to load() since both are async for LightRAG
157
- await self.load(recreate=recreate, upsert=upsert, skip_existing=skip_existing)
158
-
159
- async def load_text(
160
- self, text: str, upsert: bool = False, skip_existing: bool = True, filters: Optional[Dict[str, Any]] = None
161
- ) -> None:
162
- """Load a single text into the LightRAG server asynchronously."""
163
- await self._insert_text(text)
164
-
165
- async def async_search(
166
- self, query: str, num_documents: Optional[int] = None, filters: Optional[Dict[str, Any]] = None
167
- ) -> List[Document]:
168
- """Override the async_search method from AgentKnowledge to query the LightRAG server."""
169
- import httpx
170
-
171
- logger.info(f"Querying LightRAG server with query: {query}")
172
- mode = "hybrid" # Default mode, can be "local", "global", or "hybrid"
173
-
174
- async with httpx.AsyncClient() as client:
175
- response = await client.post(
176
- f"{self.lightrag_server_url}/query",
177
- json={"query": query, "mode": mode},
178
- headers={"Content-Type": "application/json"},
179
- )
180
- response.raise_for_status()
181
- result = response.json()
182
- logger.info(f"Query result: {result}")
183
-
184
- # Convert result to Document objects to match parent class signature
185
- if isinstance(result, dict) and "response" in result:
186
- return [Document(content=result["response"], meta_data={"query": query, "mode": mode})]
187
- elif isinstance(result, list):
188
- return [Document(content=str(item), meta_data={"query": query, "mode": mode}) for item in result]
189
- else:
190
- return [Document(content=str(result), meta_data={"query": query, "mode": mode})]
191
-
192
- async def _insert_text(self, text: str) -> Dict[str, Any]:
193
- """Insert text into the LightRAG server."""
194
- import httpx
195
-
196
- async with httpx.AsyncClient() as client:
197
- response = await client.post(
198
- f"{self.lightrag_server_url}/documents/text",
199
- json={"text": text},
200
- headers={"Content-Type": "application/json"},
201
- )
202
- response.raise_for_status()
203
- result = response.json()
204
- logger.debug(f"Text insertion result: {result}")
205
- return result
206
-
207
- def _is_valid_url(self, url: str) -> bool:
208
- """Helper to check if URL is valid."""
209
- if not any(url.endswith(ext) for ext in self.SUPPORTED_EXTENSIONS):
210
- logger.error(f"Unsupported URL: {url}. Supported file types: {', '.join(self.SUPPORTED_EXTENSIONS)}")
211
- return False
212
- return True
213
-
214
-
215
- async def lightrag_retriever(
216
- query: str,
217
- num_documents: int = 5,
218
- mode: str = "hybrid", # Default mode, can be "local", "global", or "hybrid"
219
- lightrag_server_url: str = "http://localhost:9621",
220
- ) -> Optional[List[Dict[str, Any]]]:
221
- """
222
- Custom retriever function to search the LightRAG server for relevant documents.
223
-
224
- Args:
225
- query: The search query string
226
- num_documents: Number of documents to retrieve (currently unused by LightRAG)
227
- mode: Query mode - "local", "global", or "hybrid"
228
- lightrag_server_url: URL of the LightRAG server
229
-
230
- Returns:
231
- List of retrieved documents or None if search fails
232
- """
233
- try:
234
- import httpx
235
-
236
- async with httpx.AsyncClient(timeout=30.0) as client:
237
- response = await client.post(
238
- f"{lightrag_server_url}/query",
239
- json={"query": query, "mode": mode},
240
- headers={"Content-Type": "application/json"},
241
- )
242
-
243
- response.raise_for_status()
244
- result = response.json()
245
-
246
- return _format_lightrag_response(result, query, mode)
247
-
248
- except httpx.RequestError as e:
249
- logger.error(f"HTTP Request Error: {type(e).__name__}: {str(e)}")
250
- return None
251
- except httpx.HTTPStatusError as e:
252
- logger.error(f"HTTP Status Error: {e.response.status_code} - {e.response.text}")
253
- return None
254
- except Exception as e:
255
- logger.error(f"Unexpected error during LightRAG server search: {type(e).__name__}: {str(e)}")
256
- import traceback
257
-
258
- logger.error(f"Full traceback: {traceback.format_exc()}")
259
- return None
260
-
261
-
262
- def _format_lightrag_response(result: Any, query: str, mode: str) -> List[Dict[str, Any]]:
263
- """Format LightRAG server response to expected document format."""
264
- # LightRAG server returns a dict with 'response' key, but we expect a list of documents
265
- # Convert the response to the expected format
266
- if isinstance(result, dict) and "response" in result:
267
- # Wrap the response in a document-like structure
268
- return [{"content": result["response"], "source": "lightrag", "metadata": {"query": query, "mode": mode}}]
269
- elif isinstance(result, list):
270
- return result
271
- else:
272
- # If it's a string or other format, wrap it
273
- return [{"content": str(result), "source": "lightrag", "metadata": {"query": query, "mode": mode}}]
@@ -1,66 +0,0 @@
1
- from typing import Any, Callable, Dict, List, Optional
2
-
3
- from agno.document import Document
4
- from agno.knowledge.agent import AgentKnowledge
5
- from agno.utils.log import logger
6
-
7
- try:
8
- from llama_index.core.retrievers import BaseRetriever
9
- from llama_index.core.schema import NodeWithScore
10
- except ImportError:
11
- raise ImportError(
12
- "The `llama-index-core` package is not installed. Please install it via `pip install llama-index-core`."
13
- )
14
-
15
-
16
- class LlamaIndexKnowledgeBase(AgentKnowledge):
17
- retriever: BaseRetriever
18
- loader: Optional[Callable] = None
19
-
20
- def search(
21
- self, query: str, num_documents: Optional[int] = None, filters: Optional[Dict[str, Any]] = None
22
- ) -> List[Document]:
23
- """
24
- Returns relevant documents matching the query.
25
-
26
- Args:
27
- query (str): The query string to search for.
28
- num_documents (Optional[int]): The maximum number of documents to return. Defaults to None.
29
- filters (Optional[Dict[str, Any]]): Filters to apply to the search. Defaults to None.
30
-
31
- Returns:
32
- List[Document]: A list of relevant documents matching the query.
33
- Raises:
34
- ValueError: If the retriever is not of type BaseRetriever.
35
- """
36
- if not isinstance(self.retriever, BaseRetriever):
37
- raise ValueError(f"Retriever is not of type BaseRetriever: {self.retriever}")
38
-
39
- lc_documents: List[NodeWithScore] = self.retriever.retrieve(query)
40
- if num_documents is not None:
41
- lc_documents = lc_documents[:num_documents]
42
- documents = []
43
- for lc_doc in lc_documents:
44
- documents.append(
45
- Document(
46
- content=lc_doc.text,
47
- meta_data=lc_doc.metadata,
48
- )
49
- )
50
- return documents
51
-
52
- def load(
53
- self,
54
- recreate: bool = False,
55
- upsert: bool = True,
56
- skip_existing: bool = True,
57
- filters: Optional[Dict[str, Any]] = None,
58
- ) -> None:
59
- if self.loader is None:
60
- logger.error("No loader provided for LlamaIndexKnowledgeBase")
61
- return
62
- self.loader()
63
-
64
- def exists(self) -> bool:
65
- logger.warning("LlamaIndexKnowledgeBase.exists() not supported - please check the vectorstore manually.")
66
- return True
@@ -1,154 +0,0 @@
1
- from pathlib import Path
2
- from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Union, cast
3
-
4
- from pydantic import model_validator
5
-
6
- from agno.document import Document
7
- from agno.document.chunking.markdown import MarkdownChunking
8
- from agno.document.reader.markdown_reader import MarkdownReader
9
- from agno.knowledge.agent import AgentKnowledge
10
- from agno.utils.log import log_info, logger
11
-
12
-
13
- class MarkdownKnowledgeBase(AgentKnowledge):
14
- path: Optional[Union[str, Path, List[Dict[str, Union[str, Dict[str, Any]]]]]] = None
15
- formats: List[str] = [".md"]
16
- reader: Optional[MarkdownReader] = None
17
-
18
- @model_validator(mode="after")
19
- def set_reader(self) -> "MarkdownKnowledgeBase":
20
- if self.reader is None:
21
- self.reader = MarkdownReader(chunking_strategy=self.chunking_strategy or MarkdownChunking())
22
- return self
23
-
24
- @property
25
- def document_lists(self) -> Iterator[List[Document]]:
26
- """Iterate over text files and yield lists of documents."""
27
- self.reader = cast(MarkdownReader, self.reader)
28
- if self.path is None:
29
- raise ValueError("Path is not set")
30
-
31
- if isinstance(self.path, list):
32
- for item in self.path:
33
- if isinstance(item, dict) and "path" in item:
34
- # Handle path with metadata
35
- file_path = item["path"]
36
- config = item.get("metadata", {})
37
- _file_path = Path(file_path) # type: ignore
38
- if self._is_valid_text(_file_path):
39
- documents = self.reader.read(file=_file_path)
40
- if config:
41
- for doc in documents:
42
- log_info(f"Adding metadata {config} to document: {doc.name}")
43
- doc.meta_data.update(config) # type: ignore
44
- yield documents
45
- else:
46
- # Handle single path
47
- _file_path = Path(self.path)
48
- if _file_path.is_dir():
49
- for _file in _file_path.glob("**/*"):
50
- if self._is_valid_text(_file):
51
- yield self.reader.read(file=_file)
52
- elif self._is_valid_text(_file_path):
53
- yield self.reader.read(file=_file_path)
54
-
55
- def _is_valid_text(self, path: Path) -> bool:
56
- """Helper to check if path is a valid text file."""
57
- return path.exists() and path.is_file() and path.suffix in self.formats
58
-
59
- @property
60
- async def async_document_lists(self) -> AsyncIterator[List[Document]]:
61
- """Iterate over text files and yield lists of documents asynchronously."""
62
- self.reader = cast(MarkdownReader, self.reader)
63
- if self.path is None:
64
- raise ValueError("Path is not set")
65
-
66
- if isinstance(self.path, list):
67
- for item in self.path:
68
- if isinstance(item, dict) and "path" in item:
69
- # Handle path with metadata
70
- file_path = item["path"]
71
- config = item.get("metadata", {})
72
- _file_path = Path(file_path) # type: ignore
73
- if self._is_valid_text(_file_path):
74
- documents = await self.reader.async_read(file=_file_path)
75
- if config:
76
- for doc in documents:
77
- log_info(f"Adding metadata {config} to document: {doc.name}")
78
- doc.meta_data.update(config) # type: ignore
79
- yield documents
80
- else:
81
- # Handle single path
82
- _file_path = Path(self.path)
83
- if _file_path.is_dir():
84
- for _file in _file_path.glob("**/*"):
85
- if self._is_valid_text(_file):
86
- yield await self.reader.async_read(file=_file)
87
- elif self._is_valid_text(_file_path):
88
- yield await self.reader.async_read(file=_file_path)
89
-
90
- def load_document(
91
- self,
92
- path: Union[str, Path],
93
- metadata: Optional[Dict[str, Any]] = None,
94
- recreate: bool = False,
95
- upsert: bool = False,
96
- skip_existing: bool = True,
97
- ) -> None:
98
- """Load documents from a single text file with specific metadata into the vector DB."""
99
- self.reader = cast(MarkdownReader, self.reader)
100
-
101
- _file_path = Path(path) if isinstance(path, str) else path
102
-
103
- # Validate file and prepare collection in one step
104
- if not self.prepare_load(_file_path, self.formats, metadata, recreate):
105
- return
106
-
107
- # Read documents
108
- try:
109
- documents = self.reader.read(file=_file_path)
110
- except Exception as e:
111
- logger.exception(f"Failed to read documents from file {_file_path}: {e}")
112
- return
113
-
114
- # Process documents
115
- self.process_documents(
116
- documents=documents,
117
- metadata=metadata,
118
- upsert=upsert,
119
- skip_existing=skip_existing,
120
- source_info=str(_file_path),
121
- )
122
-
123
- async def aload_document(
124
- self,
125
- path: Union[str, Path],
126
- metadata: Optional[Dict[str, Any]] = None,
127
- recreate: bool = False,
128
- upsert: bool = False,
129
- skip_existing: bool = True,
130
- ) -> None:
131
- """Load documents from a single text file with specific metadata into the vector DB."""
132
- self.reader = cast(MarkdownReader, self.reader)
133
-
134
- _file_path = Path(path) if isinstance(path, str) else path
135
-
136
- # Validate file and prepare collection in one step
137
- if not await self.aprepare_load(_file_path, self.formats, metadata, recreate):
138
- return
139
-
140
- # Read documents
141
- try:
142
- documents = await self.reader.async_read(file=_file_path)
143
- except Exception as e:
144
- logger.exception(f"Failed to read documents from file {_file_path}: {e}")
145
- return
146
-
147
- # Process documents
148
- await self.aprocess_documents(
149
- documents=documents,
150
- metadata=metadata,
151
- upsert=upsert,
152
- skip_existing=skip_existing,
153
- source_info=str(_file_path),
154
- )
agno/knowledge/pdf.py DELETED
@@ -1,164 +0,0 @@
1
- from pathlib import Path
2
- from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Union
3
-
4
- from pydantic import Field
5
- from typing_extensions import TypedDict
6
-
7
- from agno.document import Document
8
- from agno.document.reader.pdf_reader import PDFImageReader, PDFReader
9
- from agno.knowledge.agent import AgentKnowledge
10
- from agno.utils.log import log_error, log_info, logger
11
-
12
-
13
- class PDFConfig(TypedDict, total=False):
14
- path: str
15
- password: Optional[str]
16
- metadata: Optional[Dict[str, Any]]
17
-
18
-
19
- class PDFKnowledgeBase(AgentKnowledge):
20
- path: Optional[Union[str, Path, List[PDFConfig]]] = None
21
- formats: List[str] = [".pdf"]
22
- exclude_files: List[str] = Field(default_factory=list)
23
- reader: Union[PDFReader, PDFImageReader] = PDFReader()
24
-
25
- @property
26
- def document_lists(self) -> Iterator[List[Document]]:
27
- """Iterate over PDFs and yield lists of documents."""
28
- if self.path is None:
29
- raise ValueError("Path is not set")
30
-
31
- if isinstance(self.path, list):
32
- for item in self.path:
33
- if isinstance(item, dict) and "path" in item:
34
- file_path = item["path"]
35
- config = item.get("metadata", {})
36
- file_password = item.get("password")
37
- if file_password is not None and not isinstance(file_password, str):
38
- file_password = None
39
-
40
- _pdf_path = Path(file_path) # type: ignore
41
- if self._is_valid_pdf(_pdf_path):
42
- documents = self.reader.read(pdf=_pdf_path, password=file_password)
43
- if config:
44
- for doc in documents:
45
- log_info(f"Adding metadata {config} to document: {doc.name}")
46
- doc.meta_data.update(config) # type: ignore
47
- yield documents
48
- else:
49
- _pdf_path = Path(self.path)
50
- if _pdf_path.is_dir():
51
- for _pdf in _pdf_path.glob("**/*.pdf"):
52
- if _pdf.name not in self.exclude_files:
53
- yield self.reader.read(pdf=_pdf)
54
- elif self._is_valid_pdf(_pdf_path):
55
- yield self.reader.read(pdf=_pdf_path)
56
-
57
- def _is_valid_pdf(self, path: Path) -> bool:
58
- """Helper to check if path is a valid PDF file."""
59
- if not path.exists():
60
- log_error(f"PDF file not found: {path}")
61
- return False
62
- if not path.is_file():
63
- log_error(f"Path is not a file: {path}")
64
- return False
65
- if path.suffix != ".pdf":
66
- log_error(f"File is not a PDF: {path}")
67
- return False
68
- if path.name in self.exclude_files:
69
- log_error(f"PDF file excluded: {path}")
70
- return False
71
- return True
72
-
73
- @property
74
- async def async_document_lists(self) -> AsyncIterator[List[Document]]:
75
- """Iterate over PDFs and yield lists of documents asynchronously."""
76
- if self.path is None:
77
- raise ValueError("Path is not set")
78
-
79
- if isinstance(self.path, list):
80
- for item in self.path:
81
- if isinstance(item, dict) and "path" in item:
82
- file_path = item["path"]
83
- config = item.get("metadata", {})
84
- file_password = item.get("password")
85
- if file_password is not None and not isinstance(file_password, str):
86
- file_password = None
87
-
88
- _pdf_path = Path(file_path) # type: ignore
89
- if self._is_valid_pdf(_pdf_path):
90
- documents = await self.reader.async_read(pdf=_pdf_path, password=file_password)
91
- if config:
92
- for doc in documents:
93
- log_info(f"Adding metadata {config} to document: {doc.name}")
94
- doc.meta_data.update(config) # type: ignore
95
- yield documents
96
- else:
97
- # Handle single path
98
- _pdf_path = Path(self.path)
99
- if _pdf_path.is_dir():
100
- for _pdf in _pdf_path.glob("**/*.pdf"):
101
- if _pdf.name not in self.exclude_files:
102
- yield await self.reader.async_read(pdf=_pdf)
103
- elif self._is_valid_pdf(_pdf_path):
104
- yield await self.reader.async_read(pdf=_pdf_path)
105
-
106
- def load_document(
107
- self,
108
- path: Union[str, Path],
109
- metadata: Optional[Dict[str, Any]] = None,
110
- recreate: bool = False,
111
- upsert: bool = False,
112
- skip_existing: bool = True,
113
- ) -> None:
114
- _file_path = Path(path) if isinstance(path, str) else path
115
-
116
- # Validate file and prepare collection in one step
117
- if not self.prepare_load(_file_path, self.formats, metadata, recreate):
118
- return
119
-
120
- # Read documents
121
- try:
122
- documents = self.reader.read(pdf=_file_path)
123
- except Exception as e:
124
- logger.exception(f"Failed to read documents from file {_file_path}: {e}")
125
- return
126
-
127
- # Process documents
128
- self.process_documents(
129
- documents=documents,
130
- metadata=metadata,
131
- upsert=upsert,
132
- skip_existing=skip_existing,
133
- source_info=str(_file_path),
134
- )
135
-
136
- async def aload_document(
137
- self,
138
- path: Union[str, Path],
139
- metadata: Optional[Dict[str, Any]] = None,
140
- recreate: bool = False,
141
- upsert: bool = False,
142
- skip_existing: bool = True,
143
- ) -> None:
144
- _file_path = Path(path) if isinstance(path, str) else path
145
-
146
- # Validate file and prepare collection in one step
147
- if not await self.aprepare_load(_file_path, self.formats, metadata, recreate):
148
- return
149
-
150
- # Read documents
151
- try:
152
- documents = await self.reader.async_read(pdf=_file_path)
153
- except Exception as e:
154
- logger.exception(f"Failed to read documents from file {_file_path}: {e}")
155
- return
156
-
157
- # Process documents
158
- await self.aprocess_documents(
159
- documents=documents,
160
- metadata=metadata,
161
- upsert=upsert,
162
- skip_existing=skip_existing,
163
- source_info=str(_file_path),
164
- )