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

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