agno 1.8.0__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 (583) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2781 -4126
  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/media.py +2 -2
  137. agno/memory/__init__.py +2 -10
  138. agno/memory/manager.py +1003 -148
  139. agno/models/aimlapi/__init__.py +2 -2
  140. agno/models/aimlapi/aimlapi.py +6 -6
  141. agno/models/anthropic/claude.py +129 -82
  142. agno/models/aws/bedrock.py +107 -175
  143. agno/models/aws/claude.py +64 -18
  144. agno/models/azure/ai_foundry.py +73 -23
  145. agno/models/base.py +347 -287
  146. agno/models/cerebras/cerebras.py +84 -27
  147. agno/models/cohere/chat.py +106 -98
  148. agno/models/dashscope/dashscope.py +14 -5
  149. agno/models/google/gemini.py +123 -53
  150. agno/models/groq/groq.py +97 -35
  151. agno/models/huggingface/huggingface.py +92 -27
  152. agno/models/ibm/watsonx.py +72 -13
  153. agno/models/litellm/chat.py +85 -13
  154. agno/models/message.py +38 -144
  155. agno/models/meta/llama.py +85 -49
  156. agno/models/metrics.py +120 -0
  157. agno/models/mistral/mistral.py +90 -21
  158. agno/models/ollama/__init__.py +0 -2
  159. agno/models/ollama/chat.py +84 -46
  160. agno/models/openai/chat.py +135 -27
  161. agno/models/openai/responses.py +233 -115
  162. agno/models/perplexity/perplexity.py +26 -2
  163. agno/models/portkey/portkey.py +0 -7
  164. agno/models/response.py +14 -8
  165. agno/models/utils.py +20 -0
  166. agno/models/vercel/__init__.py +2 -2
  167. agno/models/vercel/v0.py +1 -1
  168. agno/models/vllm/__init__.py +2 -2
  169. agno/models/vllm/vllm.py +3 -3
  170. agno/models/xai/xai.py +10 -10
  171. agno/os/__init__.py +3 -0
  172. agno/os/app.py +393 -0
  173. agno/os/auth.py +47 -0
  174. agno/os/config.py +103 -0
  175. agno/os/interfaces/agui/__init__.py +3 -0
  176. agno/os/interfaces/agui/agui.py +31 -0
  177. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  178. agno/{app → os/interfaces}/agui/utils.py +65 -28
  179. agno/os/interfaces/base.py +21 -0
  180. agno/os/interfaces/slack/__init__.py +3 -0
  181. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  182. agno/os/interfaces/slack/slack.py +33 -0
  183. agno/os/interfaces/whatsapp/__init__.py +3 -0
  184. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  185. agno/os/interfaces/whatsapp/whatsapp.py +30 -0
  186. agno/os/router.py +843 -0
  187. agno/os/routers/__init__.py +3 -0
  188. agno/os/routers/evals/__init__.py +3 -0
  189. agno/os/routers/evals/evals.py +204 -0
  190. agno/os/routers/evals/schemas.py +142 -0
  191. agno/os/routers/evals/utils.py +161 -0
  192. agno/os/routers/knowledge/__init__.py +3 -0
  193. agno/os/routers/knowledge/knowledge.py +413 -0
  194. agno/os/routers/knowledge/schemas.py +118 -0
  195. agno/os/routers/memory/__init__.py +3 -0
  196. agno/os/routers/memory/memory.py +179 -0
  197. agno/os/routers/memory/schemas.py +58 -0
  198. agno/os/routers/metrics/__init__.py +3 -0
  199. agno/os/routers/metrics/metrics.py +58 -0
  200. agno/os/routers/metrics/schemas.py +47 -0
  201. agno/os/routers/session/__init__.py +3 -0
  202. agno/os/routers/session/session.py +163 -0
  203. agno/os/schema.py +892 -0
  204. agno/{app/playground → os}/settings.py +8 -15
  205. agno/os/utils.py +270 -0
  206. agno/reasoning/azure_ai_foundry.py +4 -4
  207. agno/reasoning/deepseek.py +4 -4
  208. agno/reasoning/default.py +6 -11
  209. agno/reasoning/groq.py +4 -4
  210. agno/reasoning/helpers.py +4 -6
  211. agno/reasoning/ollama.py +4 -4
  212. agno/reasoning/openai.py +4 -4
  213. agno/run/{response.py → agent.py} +144 -72
  214. agno/run/base.py +44 -58
  215. agno/run/cancel.py +83 -0
  216. agno/run/team.py +133 -77
  217. agno/run/workflow.py +537 -12
  218. agno/session/__init__.py +10 -0
  219. agno/session/agent.py +244 -0
  220. agno/session/summary.py +225 -0
  221. agno/session/team.py +262 -0
  222. agno/{storage/session/v2 → session}/workflow.py +47 -24
  223. agno/team/__init__.py +15 -16
  224. agno/team/team.py +2967 -4243
  225. agno/tools/agentql.py +14 -5
  226. agno/tools/airflow.py +9 -4
  227. agno/tools/api.py +7 -3
  228. agno/tools/apify.py +2 -46
  229. agno/tools/arxiv.py +8 -3
  230. agno/tools/aws_lambda.py +7 -5
  231. agno/tools/aws_ses.py +7 -1
  232. agno/tools/baidusearch.py +4 -1
  233. agno/tools/bitbucket.py +4 -4
  234. agno/tools/brandfetch.py +14 -11
  235. agno/tools/bravesearch.py +4 -1
  236. agno/tools/brightdata.py +42 -22
  237. agno/tools/browserbase.py +13 -4
  238. agno/tools/calcom.py +12 -10
  239. agno/tools/calculator.py +10 -27
  240. agno/tools/cartesia.py +18 -13
  241. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  242. agno/tools/confluence.py +71 -18
  243. agno/tools/crawl4ai.py +7 -1
  244. agno/tools/csv_toolkit.py +9 -8
  245. agno/tools/dalle.py +18 -11
  246. agno/tools/daytona.py +13 -16
  247. agno/tools/decorator.py +6 -3
  248. agno/tools/desi_vocal.py +16 -7
  249. agno/tools/discord.py +11 -8
  250. agno/tools/docker.py +30 -42
  251. agno/tools/duckdb.py +34 -53
  252. agno/tools/duckduckgo.py +8 -7
  253. agno/tools/e2b.py +62 -62
  254. agno/tools/eleven_labs.py +35 -28
  255. agno/tools/email.py +4 -1
  256. agno/tools/evm.py +7 -1
  257. agno/tools/exa.py +19 -14
  258. agno/tools/fal.py +29 -29
  259. agno/tools/file.py +9 -8
  260. agno/tools/financial_datasets.py +25 -44
  261. agno/tools/firecrawl.py +22 -22
  262. agno/tools/function.py +68 -17
  263. agno/tools/giphy.py +22 -10
  264. agno/tools/github.py +48 -126
  265. agno/tools/gmail.py +46 -62
  266. agno/tools/google_bigquery.py +7 -6
  267. agno/tools/google_maps.py +11 -26
  268. agno/tools/googlesearch.py +7 -2
  269. agno/tools/googlesheets.py +21 -17
  270. agno/tools/hackernews.py +9 -5
  271. agno/tools/jina.py +5 -4
  272. agno/tools/jira.py +18 -9
  273. agno/tools/knowledge.py +31 -32
  274. agno/tools/linear.py +18 -33
  275. agno/tools/linkup.py +5 -1
  276. agno/tools/local_file_system.py +8 -5
  277. agno/tools/lumalab.py +31 -19
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +32 -14
  282. agno/tools/models/gemini.py +58 -31
  283. agno/tools/models/groq.py +29 -20
  284. agno/tools/models/nebius.py +27 -11
  285. agno/tools/models_labs.py +39 -15
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +134 -0
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +57 -26
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +62 -46
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +54 -41
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +95 -118
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/location.py +2 -2
  337. agno/utils/log.py +2 -2
  338. agno/utils/mcp.py +11 -5
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/claude.py +6 -4
  342. agno/utils/models/mistral.py +8 -7
  343. agno/utils/models/schema_utils.py +3 -3
  344. agno/utils/pprint.py +33 -32
  345. agno/utils/print_response/agent.py +779 -0
  346. agno/utils/print_response/team.py +1565 -0
  347. agno/utils/print_response/workflow.py +1451 -0
  348. agno/utils/prompts.py +14 -14
  349. agno/utils/reasoning.py +87 -0
  350. agno/utils/response.py +42 -42
  351. agno/utils/string.py +8 -22
  352. agno/utils/team.py +50 -0
  353. agno/utils/timer.py +2 -2
  354. agno/vectordb/base.py +33 -21
  355. agno/vectordb/cassandra/cassandra.py +287 -23
  356. agno/vectordb/chroma/chromadb.py +482 -59
  357. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  358. agno/vectordb/couchbase/couchbase.py +309 -29
  359. agno/vectordb/lancedb/lance_db.py +360 -21
  360. agno/vectordb/langchaindb/__init__.py +5 -0
  361. agno/vectordb/langchaindb/langchaindb.py +145 -0
  362. agno/vectordb/lightrag/__init__.py +5 -0
  363. agno/vectordb/lightrag/lightrag.py +374 -0
  364. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  365. agno/vectordb/milvus/milvus.py +242 -32
  366. agno/vectordb/mongodb/mongodb.py +200 -24
  367. agno/vectordb/pgvector/pgvector.py +319 -37
  368. agno/vectordb/pineconedb/pineconedb.py +221 -27
  369. agno/vectordb/qdrant/qdrant.py +356 -14
  370. agno/vectordb/singlestore/singlestore.py +286 -29
  371. agno/vectordb/surrealdb/surrealdb.py +187 -7
  372. agno/vectordb/upstashdb/upstashdb.py +342 -26
  373. agno/vectordb/weaviate/weaviate.py +227 -165
  374. agno/workflow/__init__.py +17 -13
  375. agno/workflow/{v2/condition.py → condition.py} +135 -32
  376. agno/workflow/{v2/loop.py → loop.py} +115 -28
  377. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  378. agno/workflow/{v2/router.py → router.py} +133 -32
  379. agno/workflow/{v2/step.py → step.py} +200 -42
  380. agno/workflow/{v2/steps.py → steps.py} +147 -66
  381. agno/workflow/types.py +482 -0
  382. agno/workflow/workflow.py +2394 -696
  383. agno-2.0.0a1.dist-info/METADATA +355 -0
  384. agno-2.0.0a1.dist-info/RECORD +514 -0
  385. agno/agent/metrics.py +0 -107
  386. agno/api/app.py +0 -35
  387. agno/api/playground.py +0 -92
  388. agno/api/schemas/app.py +0 -12
  389. agno/api/schemas/playground.py +0 -22
  390. agno/api/schemas/user.py +0 -35
  391. agno/api/schemas/workspace.py +0 -46
  392. agno/api/user.py +0 -160
  393. agno/api/workflows.py +0 -33
  394. agno/api/workspace.py +0 -175
  395. agno/app/agui/__init__.py +0 -3
  396. agno/app/agui/app.py +0 -17
  397. agno/app/agui/sync_router.py +0 -120
  398. agno/app/base.py +0 -186
  399. agno/app/discord/__init__.py +0 -3
  400. agno/app/fastapi/__init__.py +0 -3
  401. agno/app/fastapi/app.py +0 -107
  402. agno/app/fastapi/async_router.py +0 -457
  403. agno/app/fastapi/sync_router.py +0 -448
  404. agno/app/playground/app.py +0 -228
  405. agno/app/playground/async_router.py +0 -1050
  406. agno/app/playground/deploy.py +0 -249
  407. agno/app/playground/operator.py +0 -183
  408. agno/app/playground/schemas.py +0 -220
  409. agno/app/playground/serve.py +0 -55
  410. agno/app/playground/sync_router.py +0 -1042
  411. agno/app/playground/utils.py +0 -46
  412. agno/app/settings.py +0 -15
  413. agno/app/slack/__init__.py +0 -3
  414. agno/app/slack/app.py +0 -19
  415. agno/app/slack/sync_router.py +0 -92
  416. agno/app/utils.py +0 -54
  417. agno/app/whatsapp/__init__.py +0 -3
  418. agno/app/whatsapp/app.py +0 -15
  419. agno/app/whatsapp/sync_router.py +0 -197
  420. agno/cli/auth_server.py +0 -249
  421. agno/cli/config.py +0 -274
  422. agno/cli/console.py +0 -88
  423. agno/cli/credentials.py +0 -23
  424. agno/cli/entrypoint.py +0 -571
  425. agno/cli/operator.py +0 -357
  426. agno/cli/settings.py +0 -96
  427. agno/cli/ws/ws_cli.py +0 -817
  428. agno/constants.py +0 -13
  429. agno/document/__init__.py +0 -5
  430. agno/document/chunking/semantic.py +0 -45
  431. agno/document/chunking/strategy.py +0 -31
  432. agno/document/reader/__init__.py +0 -5
  433. agno/document/reader/base.py +0 -47
  434. agno/document/reader/docx_reader.py +0 -60
  435. agno/document/reader/gcs/pdf_reader.py +0 -44
  436. agno/document/reader/s3/pdf_reader.py +0 -59
  437. agno/document/reader/s3/text_reader.py +0 -63
  438. agno/document/reader/url_reader.py +0 -59
  439. agno/document/reader/youtube_reader.py +0 -58
  440. agno/embedder/__init__.py +0 -5
  441. agno/embedder/langdb.py +0 -80
  442. agno/embedder/mistral.py +0 -82
  443. agno/embedder/openai.py +0 -78
  444. agno/file/__init__.py +0 -5
  445. agno/file/file.py +0 -16
  446. agno/file/local/csv.py +0 -32
  447. agno/file/local/txt.py +0 -19
  448. agno/infra/app.py +0 -240
  449. agno/infra/base.py +0 -144
  450. agno/infra/context.py +0 -20
  451. agno/infra/db_app.py +0 -52
  452. agno/infra/resource.py +0 -205
  453. agno/infra/resources.py +0 -55
  454. agno/knowledge/agent.py +0 -698
  455. agno/knowledge/arxiv.py +0 -33
  456. agno/knowledge/combined.py +0 -36
  457. agno/knowledge/csv.py +0 -144
  458. agno/knowledge/csv_url.py +0 -124
  459. agno/knowledge/document.py +0 -223
  460. agno/knowledge/docx.py +0 -137
  461. agno/knowledge/firecrawl.py +0 -34
  462. agno/knowledge/gcs/__init__.py +0 -0
  463. agno/knowledge/gcs/base.py +0 -39
  464. agno/knowledge/gcs/pdf.py +0 -125
  465. agno/knowledge/json.py +0 -137
  466. agno/knowledge/langchain.py +0 -71
  467. agno/knowledge/light_rag.py +0 -273
  468. agno/knowledge/llamaindex.py +0 -66
  469. agno/knowledge/markdown.py +0 -154
  470. agno/knowledge/pdf.py +0 -164
  471. agno/knowledge/pdf_bytes.py +0 -42
  472. agno/knowledge/pdf_url.py +0 -148
  473. agno/knowledge/s3/__init__.py +0 -0
  474. agno/knowledge/s3/base.py +0 -64
  475. agno/knowledge/s3/pdf.py +0 -33
  476. agno/knowledge/s3/text.py +0 -34
  477. agno/knowledge/text.py +0 -141
  478. agno/knowledge/url.py +0 -46
  479. agno/knowledge/website.py +0 -179
  480. agno/knowledge/wikipedia.py +0 -32
  481. agno/knowledge/youtube.py +0 -35
  482. agno/memory/agent.py +0 -423
  483. agno/memory/classifier.py +0 -104
  484. agno/memory/db/__init__.py +0 -5
  485. agno/memory/db/base.py +0 -42
  486. agno/memory/db/mongodb.py +0 -189
  487. agno/memory/db/postgres.py +0 -203
  488. agno/memory/db/sqlite.py +0 -193
  489. agno/memory/memory.py +0 -22
  490. agno/memory/row.py +0 -36
  491. agno/memory/summarizer.py +0 -201
  492. agno/memory/summary.py +0 -19
  493. agno/memory/team.py +0 -415
  494. agno/memory/v2/__init__.py +0 -2
  495. agno/memory/v2/db/__init__.py +0 -1
  496. agno/memory/v2/db/base.py +0 -42
  497. agno/memory/v2/db/firestore.py +0 -339
  498. agno/memory/v2/db/mongodb.py +0 -196
  499. agno/memory/v2/db/postgres.py +0 -214
  500. agno/memory/v2/db/redis.py +0 -187
  501. agno/memory/v2/db/schema.py +0 -54
  502. agno/memory/v2/db/sqlite.py +0 -209
  503. agno/memory/v2/manager.py +0 -437
  504. agno/memory/v2/memory.py +0 -1097
  505. agno/memory/v2/schema.py +0 -55
  506. agno/memory/v2/summarizer.py +0 -215
  507. agno/memory/workflow.py +0 -38
  508. agno/models/ollama/tools.py +0 -430
  509. agno/models/qwen/__init__.py +0 -5
  510. agno/playground/__init__.py +0 -10
  511. agno/playground/deploy.py +0 -3
  512. agno/playground/playground.py +0 -3
  513. agno/playground/serve.py +0 -3
  514. agno/playground/settings.py +0 -3
  515. agno/reranker/__init__.py +0 -0
  516. agno/run/v2/__init__.py +0 -0
  517. agno/run/v2/workflow.py +0 -567
  518. agno/storage/__init__.py +0 -0
  519. agno/storage/agent/__init__.py +0 -0
  520. agno/storage/agent/dynamodb.py +0 -1
  521. agno/storage/agent/json.py +0 -1
  522. agno/storage/agent/mongodb.py +0 -1
  523. agno/storage/agent/postgres.py +0 -1
  524. agno/storage/agent/singlestore.py +0 -1
  525. agno/storage/agent/sqlite.py +0 -1
  526. agno/storage/agent/yaml.py +0 -1
  527. agno/storage/base.py +0 -60
  528. agno/storage/dynamodb.py +0 -673
  529. agno/storage/firestore.py +0 -297
  530. agno/storage/gcs_json.py +0 -261
  531. agno/storage/in_memory.py +0 -234
  532. agno/storage/json.py +0 -237
  533. agno/storage/mongodb.py +0 -328
  534. agno/storage/mysql.py +0 -685
  535. agno/storage/postgres.py +0 -682
  536. agno/storage/redis.py +0 -336
  537. agno/storage/session/__init__.py +0 -16
  538. agno/storage/session/agent.py +0 -64
  539. agno/storage/session/team.py +0 -63
  540. agno/storage/session/v2/__init__.py +0 -5
  541. agno/storage/session/workflow.py +0 -61
  542. agno/storage/singlestore.py +0 -606
  543. agno/storage/sqlite.py +0 -646
  544. agno/storage/workflow/__init__.py +0 -0
  545. agno/storage/workflow/mongodb.py +0 -1
  546. agno/storage/workflow/postgres.py +0 -1
  547. agno/storage/workflow/sqlite.py +0 -1
  548. agno/storage/yaml.py +0 -241
  549. agno/tools/thinking.py +0 -73
  550. agno/utils/defaults.py +0 -57
  551. agno/utils/filesystem.py +0 -39
  552. agno/utils/git.py +0 -52
  553. agno/utils/json_io.py +0 -30
  554. agno/utils/load_env.py +0 -19
  555. agno/utils/py_io.py +0 -19
  556. agno/utils/pyproject.py +0 -18
  557. agno/utils/resource_filter.py +0 -31
  558. agno/workflow/v2/__init__.py +0 -21
  559. agno/workflow/v2/types.py +0 -357
  560. agno/workflow/v2/workflow.py +0 -3312
  561. agno/workspace/__init__.py +0 -0
  562. agno/workspace/config.py +0 -325
  563. agno/workspace/enums.py +0 -6
  564. agno/workspace/helpers.py +0 -52
  565. agno/workspace/operator.py +0 -757
  566. agno/workspace/settings.py +0 -158
  567. agno-1.8.0.dist-info/METADATA +0 -979
  568. agno-1.8.0.dist-info/RECORD +0 -565
  569. agno-1.8.0.dist-info/entry_points.txt +0 -3
  570. /agno/{app → db/migrations}/__init__.py +0 -0
  571. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  572. /agno/{cli → integrations}/__init__.py +0 -0
  573. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  574. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  575. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  576. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  577. /agno/{app → os/interfaces}/slack/security.py +0 -0
  578. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  579. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  580. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  581. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  582. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  583. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,413 @@
1
+ import json
2
+ import logging
3
+ import math
4
+ from typing import Dict, List, Optional
5
+ from uuid import uuid4
6
+
7
+ from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, Path, Query, UploadFile
8
+
9
+ from agno.knowledge.content import Content, FileData
10
+ from agno.knowledge.knowledge import Knowledge
11
+ from agno.knowledge.reader import ReaderFactory
12
+ from agno.knowledge.reader.base import Reader
13
+ from agno.knowledge.utils import get_all_chunkers_info, get_all_readers_info, get_content_types_to_readers_mapping
14
+ from agno.os.auth import get_authentication_dependency
15
+ from agno.os.routers.knowledge.schemas import (
16
+ ChunkerSchema,
17
+ ConfigResponseSchema,
18
+ ContentResponseSchema,
19
+ ContentStatus,
20
+ ContentStatusResponse,
21
+ ContentUpdateSchema,
22
+ ReaderSchema,
23
+ )
24
+ from agno.os.schema import PaginatedResponse, PaginationInfo, SortOrder
25
+ from agno.os.settings import AgnoAPISettings
26
+ from agno.os.utils import get_knowledge_instance_by_db_id
27
+ from agno.utils.log import log_debug, log_info
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ def get_knowledge_router(
33
+ knowledge_instances: List[Knowledge], settings: AgnoAPISettings = AgnoAPISettings()
34
+ ) -> APIRouter:
35
+ router = APIRouter(dependencies=[Depends(get_authentication_dependency(settings))], tags=["Knowledge"])
36
+ return attach_routes(router=router, knowledge_instances=knowledge_instances)
37
+
38
+
39
+ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> APIRouter:
40
+ @router.post("/knowledge/content", response_model=ContentResponseSchema, status_code=202)
41
+ async def upload_content(
42
+ background_tasks: BackgroundTasks,
43
+ name: Optional[str] = Form(None),
44
+ description: Optional[str] = Form(None),
45
+ url: Optional[str] = Form(None),
46
+ metadata: Optional[str] = Form(None, description="JSON metadata"),
47
+ file: Optional[UploadFile] = File(None),
48
+ text_content: Optional[str] = Form(None),
49
+ reader_id: Optional[str] = Form(None),
50
+ chunker: Optional[str] = Form(None),
51
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
52
+ ):
53
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
54
+ content_id = str(uuid4())
55
+ log_info(f"Adding content: {name}, {description}, {url}, {metadata} with ID: {content_id}")
56
+
57
+ parsed_metadata = None
58
+ if metadata:
59
+ try:
60
+ parsed_metadata = json.loads(metadata)
61
+ except json.JSONDecodeError:
62
+ # If it's not valid JSON, treat as a simple key-value pair
63
+ parsed_metadata = {"value": metadata} if metadata != "string" else None
64
+ if file:
65
+ content_bytes = await file.read()
66
+ elif text_content:
67
+ content_bytes = text_content.encode("utf-8")
68
+ else:
69
+ content_bytes = None
70
+
71
+ parsed_urls = None
72
+ if url and url.strip():
73
+ try:
74
+ parsed_urls = json.loads(url)
75
+ log_debug(f"Parsed URLs: {parsed_urls}")
76
+ except json.JSONDecodeError:
77
+ # If it's not valid JSON, treat as a single URL string
78
+ parsed_urls = url
79
+
80
+ # # Parse metadata with proper error handling
81
+ parsed_metadata = None
82
+ if metadata:
83
+ try:
84
+ parsed_metadata = json.loads(metadata)
85
+ except json.JSONDecodeError:
86
+ # If it's not valid JSON, treat as a simple key-value pair
87
+ parsed_metadata = {"value": metadata}
88
+
89
+ if text_content:
90
+ file_data = FileData(
91
+ content=content_bytes,
92
+ type="manual",
93
+ )
94
+ elif file:
95
+ file_data = FileData(
96
+ content=content_bytes,
97
+ type=file.content_type if file.content_type else None,
98
+ filename=file.filename,
99
+ size=file.size,
100
+ )
101
+ else:
102
+ file_data = None
103
+
104
+ if not name:
105
+ if file and file.filename:
106
+ name = file.filename
107
+ elif url:
108
+ name = parsed_urls
109
+
110
+ content = Content(
111
+ name=name,
112
+ description=description,
113
+ url=parsed_urls,
114
+ metadata=parsed_metadata,
115
+ file_data=file_data,
116
+ size=file.size if file else None if text_content else None,
117
+ )
118
+ background_tasks.add_task(process_content, knowledge, content_id, content, reader_id, chunker)
119
+
120
+ response = ContentResponseSchema(
121
+ id=content_id,
122
+ name=name,
123
+ description=description,
124
+ metadata=parsed_metadata,
125
+ status=ContentStatus.PROCESSING,
126
+ )
127
+ return response
128
+
129
+ @router.patch("/knowledge/content/{content_id}", response_model=ContentResponseSchema, status_code=200)
130
+ async def update_content(
131
+ content_id: str = Path(..., description="Content ID"),
132
+ name: Optional[str] = Form(None, description="Content name"),
133
+ description: Optional[str] = Form(None, description="Content description"),
134
+ metadata: Optional[str] = Form(None, description="Content metadata as JSON string"),
135
+ reader_id: Optional[str] = Form(None, description="ID of the reader to use for processing"),
136
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
137
+ ) -> Optional[ContentResponseSchema]:
138
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
139
+
140
+ # Parse metadata JSON string if provided
141
+ parsed_metadata = None
142
+ if metadata and metadata.strip():
143
+ try:
144
+ parsed_metadata = json.loads(metadata)
145
+ except json.JSONDecodeError:
146
+ raise HTTPException(status_code=400, detail="Invalid JSON format for metadata")
147
+
148
+ # Create ContentUpdateSchema object from form data
149
+ update_data = ContentUpdateSchema(
150
+ name=name if name and name.strip() else None,
151
+ description=description if description and description.strip() else None,
152
+ metadata=parsed_metadata,
153
+ reader_id=reader_id if reader_id and reader_id.strip() else None,
154
+ )
155
+
156
+ content = Content(
157
+ id=content_id,
158
+ name=update_data.name,
159
+ description=update_data.description,
160
+ metadata=update_data.metadata,
161
+ )
162
+
163
+ if update_data.reader_id:
164
+ if knowledge.readers and update_data.reader_id in knowledge.readers:
165
+ content.reader = knowledge.readers[update_data.reader_id]
166
+ else:
167
+ raise HTTPException(status_code=400, detail=f"Invalid reader_id: {update_data.reader_id}")
168
+
169
+ updated_content_dict = knowledge.patch_content(content)
170
+ if not updated_content_dict:
171
+ raise HTTPException(status_code=404, detail=f"Content not found: {content_id}")
172
+
173
+ return ContentResponseSchema.from_dict(updated_content_dict)
174
+
175
+ @router.get("/knowledge/content", response_model=PaginatedResponse[ContentResponseSchema], status_code=200)
176
+ def get_content(
177
+ limit: Optional[int] = Query(default=20, description="Number of content entries to return"),
178
+ page: Optional[int] = Query(default=1, description="Page number"),
179
+ sort_by: Optional[str] = Query(default="created_at", description="Field to sort by"),
180
+ sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
181
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
182
+ ) -> PaginatedResponse[ContentResponseSchema]:
183
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
184
+ contents, count = knowledge.get_content(limit=limit, page=page, sort_by=sort_by, sort_order=sort_order)
185
+
186
+ return PaginatedResponse(
187
+ data=[
188
+ ContentResponseSchema.from_dict(
189
+ {
190
+ "id": content.id,
191
+ "name": content.name,
192
+ "description": content.description,
193
+ "file_type": content.file_type,
194
+ "size": content.size,
195
+ "metadata": content.metadata,
196
+ "status": content.status,
197
+ "status_message": content.status_message,
198
+ "created_at": content.created_at,
199
+ "updated_at": content.updated_at,
200
+ }
201
+ )
202
+ for content in contents
203
+ ],
204
+ meta=PaginationInfo(
205
+ page=page,
206
+ limit=limit,
207
+ total_count=count,
208
+ total_pages=math.ceil(count / limit) if limit is not None and limit > 0 else 0,
209
+ ),
210
+ )
211
+
212
+ @router.get("/knowledge/content/{content_id}", response_model=ContentResponseSchema, status_code=200)
213
+ def get_content_by_id(
214
+ content_id: str,
215
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
216
+ ) -> ContentResponseSchema:
217
+ log_info(f"Getting content by id: {content_id}")
218
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
219
+ content = knowledge.get_content_by_id(content_id=content_id)
220
+ if not content:
221
+ raise HTTPException(status_code=404, detail=f"Content not found: {content_id}")
222
+ response = ContentResponseSchema.from_dict(
223
+ {
224
+ "id": content_id,
225
+ "name": content.name,
226
+ "description": content.description,
227
+ "file_type": content.file_type,
228
+ "size": len(content.file_data.content) if content.file_data and content.file_data.content else 0,
229
+ "metadata": content.metadata,
230
+ "status": content.status,
231
+ "status_message": content.status_message,
232
+ "created_at": content.created_at,
233
+ "updated_at": content.updated_at,
234
+ }
235
+ )
236
+
237
+ return response
238
+
239
+ @router.delete(
240
+ "/knowledge/content/{content_id}",
241
+ response_model=ContentResponseSchema,
242
+ status_code=200,
243
+ response_model_exclude_none=True,
244
+ )
245
+ def delete_content_by_id(
246
+ content_id: str,
247
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
248
+ ) -> ContentResponseSchema:
249
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
250
+ knowledge.remove_content_by_id(content_id=content_id)
251
+ log_info(f"Deleting content by id: {content_id}")
252
+
253
+ return ContentResponseSchema(
254
+ id=content_id,
255
+ )
256
+
257
+ @router.delete("/knowledge/content", status_code=200)
258
+ def delete_all_content(
259
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
260
+ ):
261
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
262
+ log_info("Deleting all content")
263
+ knowledge.remove_all_content()
264
+ return "success"
265
+
266
+ @router.get("/knowledge/content/{content_id}/status", status_code=200, response_model=ContentStatusResponse)
267
+ def get_content_status(
268
+ content_id: str,
269
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
270
+ ) -> ContentStatusResponse:
271
+ log_info(f"Getting content status: {content_id}")
272
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
273
+ knowledge_status, status_message = knowledge.get_content_status(content_id=content_id)
274
+
275
+ # Handle the case where content is not found
276
+ if knowledge_status is None:
277
+ return ContentStatusResponse(
278
+ status=ContentStatus.FAILED, status_message=status_message or "Content not found"
279
+ )
280
+
281
+ # Convert knowledge ContentStatus to schema ContentStatus (they have same values)
282
+ if hasattr(knowledge_status, "value"):
283
+ status_value = knowledge_status.value
284
+ else:
285
+ status_value = str(knowledge_status)
286
+
287
+ # Convert string status to ContentStatus enum if needed (for backward compatibility and mocks)
288
+ if isinstance(status_value, str):
289
+ try:
290
+ status = ContentStatus(status_value.lower())
291
+ except ValueError:
292
+ # Handle legacy or unknown statuses gracefully
293
+ if "failed" in status_value.lower():
294
+ status = ContentStatus.FAILED
295
+ elif "completed" in status_value.lower():
296
+ status = ContentStatus.COMPLETED
297
+ else:
298
+ status = ContentStatus.PROCESSING
299
+ else:
300
+ status = ContentStatus.PROCESSING
301
+
302
+ return ContentStatusResponse(status=status, status_message=status_message or "")
303
+
304
+ @router.get("/knowledge/config", status_code=200)
305
+ def get_config(
306
+ db_id: Optional[str] = Query(default=None, description="The ID of the database to use"),
307
+ ) -> ConfigResponseSchema:
308
+ knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
309
+
310
+ # Get factory readers info
311
+ readers_info = get_all_readers_info()
312
+ reader_schemas = {}
313
+ # Add factory readers
314
+ for reader_info in readers_info:
315
+ reader_schemas[reader_info["id"]] = ReaderSchema(
316
+ id=reader_info["id"],
317
+ name=reader_info["name"],
318
+ description=reader_info.get("description"),
319
+ chunkers=reader_info.get("chunking_strategies", []),
320
+ )
321
+
322
+ # Add custom readers from knowledge.readers
323
+ readers_dict: Dict[str, Reader] = knowledge.get_readers() or {}
324
+ if readers_dict:
325
+ for reader_id, reader in readers_dict.items():
326
+ # Get chunking strategies from the reader
327
+ chunking_strategies = []
328
+ try:
329
+ strategies = reader.get_supported_chunking_strategies()
330
+ chunking_strategies = [strategy.value for strategy in strategies]
331
+ except Exception:
332
+ chunking_strategies = []
333
+
334
+ # Check if this reader ID already exists in factory readers
335
+ if reader_id not in reader_schemas:
336
+ reader_schemas[reader_id] = ReaderSchema(
337
+ id=reader_id,
338
+ name=getattr(reader, "name", reader.__class__.__name__),
339
+ description=getattr(reader, "description", f"Custom {reader.__class__.__name__}"),
340
+ chunkers=chunking_strategies,
341
+ )
342
+
343
+ # Get content types to readers mapping
344
+ types_of_readers = get_content_types_to_readers_mapping()
345
+ chunkers_list = get_all_chunkers_info()
346
+
347
+ # Convert chunkers list to dictionary format expected by schema
348
+ chunkers_dict = {}
349
+ for chunker_info in chunkers_list:
350
+ chunker_key = chunker_info.get("key")
351
+ if chunker_key:
352
+ chunkers_dict[chunker_key] = ChunkerSchema(
353
+ key=chunker_key, name=chunker_info.get("name"), description=chunker_info.get("description")
354
+ )
355
+
356
+ return ConfigResponseSchema(
357
+ readers=reader_schemas,
358
+ readersForType=types_of_readers,
359
+ chunkers=chunkers_dict,
360
+ filters=knowledge.get_filters(),
361
+ )
362
+
363
+ return router
364
+
365
+
366
+ async def process_content(
367
+ knowledge: Knowledge,
368
+ content_id: str,
369
+ content: Content,
370
+ reader_id: Optional[str] = None,
371
+ chunker: Optional[str] = None,
372
+ ):
373
+ """Background task to process the content"""
374
+ log_info(f"Processing content {content_id}")
375
+ try:
376
+ content.id = content_id
377
+ if reader_id:
378
+ reader = None
379
+ if knowledge.readers and reader_id in knowledge.readers:
380
+ reader = knowledge.readers[reader_id]
381
+ else:
382
+ key = reader_id.lower().strip().replace("-", "_").replace(" ", "_")
383
+ candidates = [key] + ([key[:-6]] if key.endswith("reader") else [])
384
+ for cand in candidates:
385
+ try:
386
+ reader = ReaderFactory.create_reader(cand)
387
+ log_debug(f"Resolved reader: {reader.__class__.__name__}")
388
+ break
389
+ except Exception:
390
+ continue
391
+ if reader:
392
+ content.reader = reader
393
+ if chunker and content.reader:
394
+ # Set the chunker name on the reader - let the reader handle it internally
395
+ content.reader.set_chunking_strategy_from_string(chunker)
396
+ log_debug(f"Set chunking strategy: {chunker}")
397
+
398
+ log_debug(f"Using reader: {content.reader.__class__.__name__}")
399
+ await knowledge._load_content(content, upsert=False, skip_if_exists=True)
400
+ log_info(f"Content {content_id} processed successfully")
401
+ except Exception as e:
402
+ log_info(f"Error processing content {content_id}: {e}")
403
+ # Mark content as failed in the contents DB
404
+ try:
405
+ from agno.knowledge.content import ContentStatus as KnowledgeContentStatus
406
+
407
+ content.status = KnowledgeContentStatus.FAILED
408
+ content.status_message = str(e)
409
+ content.id = content_id
410
+ knowledge.patch_content(content)
411
+ except Exception:
412
+ # Swallow any secondary errors to avoid crashing the background task
413
+ pass
@@ -0,0 +1,118 @@
1
+ from datetime import datetime, timezone
2
+ from enum import Enum
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class ContentStatus(str, Enum):
9
+ """Enumeration of possible content processing statuses."""
10
+
11
+ PROCESSING = "processing"
12
+ COMPLETED = "completed"
13
+ FAILED = "failed"
14
+
15
+
16
+ class ContentStatusResponse(BaseModel):
17
+ """Response model for content status endpoint."""
18
+
19
+ status: ContentStatus
20
+ status_message: str = ""
21
+
22
+
23
+ class ContentResponseSchema(BaseModel):
24
+ id: str
25
+ name: Optional[str] = None
26
+ description: Optional[str] = None
27
+ type: Optional[str] = None
28
+ size: Optional[str] = None
29
+ linked_to: Optional[str] = None
30
+ metadata: Optional[dict] = None
31
+ access_count: Optional[int] = None
32
+ status: Optional[ContentStatus] = None
33
+ status_message: Optional[str] = None
34
+ created_at: Optional[datetime] = None
35
+ updated_at: Optional[datetime] = None
36
+
37
+ @classmethod
38
+ def from_dict(cls, content: Dict[str, Any]) -> "ContentResponseSchema":
39
+ status = content.get("status")
40
+ if isinstance(status, str):
41
+ try:
42
+ status = ContentStatus(status.lower())
43
+ except ValueError:
44
+ # Handle legacy or unknown statuses gracefully
45
+ if "failed" in status.lower():
46
+ status = ContentStatus.FAILED
47
+ elif "completed" in status.lower():
48
+ status = ContentStatus.COMPLETED
49
+ else:
50
+ status = ContentStatus.PROCESSING
51
+ elif status is None:
52
+ status = ContentStatus.PROCESSING # Default for None values
53
+
54
+ # Helper function to safely parse timestamps
55
+ def parse_timestamp(timestamp_value):
56
+ if timestamp_value is None:
57
+ return None
58
+ try:
59
+ # If it's already a datetime object, return it
60
+ if isinstance(timestamp_value, datetime):
61
+ return timestamp_value
62
+ # If it's a string, try to parse it as ISO format first
63
+ if isinstance(timestamp_value, str):
64
+ try:
65
+ return datetime.fromisoformat(timestamp_value.replace("Z", "+00:00"))
66
+ except ValueError:
67
+ # Try to parse as float/int timestamp
68
+ timestamp_value = float(timestamp_value)
69
+ # If it's a number, use fromtimestamp
70
+ return datetime.fromtimestamp(timestamp_value, tz=timezone.utc)
71
+ except (ValueError, TypeError, OSError):
72
+ # If all parsing fails, return None
73
+ return None
74
+
75
+ return cls(
76
+ id=content.get("id"), # type: ignore
77
+ name=content.get("name"),
78
+ description=content.get("description"),
79
+ type=content.get("file_type"),
80
+ size=str(content.get("size")) if content.get("size") else "0",
81
+ metadata=content.get("metadata"),
82
+ status=status,
83
+ status_message=content.get("status_message"),
84
+ created_at=parse_timestamp(content.get("created_at")),
85
+ updated_at=parse_timestamp(content.get("updated_at")),
86
+ # TODO: These fields are not available in the Content class. Fix the inconsistency
87
+ access_count=None,
88
+ linked_to=None,
89
+ )
90
+
91
+
92
+ class ContentUpdateSchema(BaseModel):
93
+ """Schema for updating content."""
94
+
95
+ name: Optional[str] = Field(None, description="Content name", min_length=1, max_length=255)
96
+ description: Optional[str] = Field(None, description="Content description", max_length=1000)
97
+ metadata: Optional[Dict[str, Any]] = Field(None, description="Content metadata as key-value pairs")
98
+ reader_id: Optional[str] = Field(None, description="ID of the reader to use for processing", min_length=1)
99
+
100
+
101
+ class ReaderSchema(BaseModel):
102
+ id: str
103
+ name: Optional[str] = None
104
+ description: Optional[str] = None
105
+ chunkers: Optional[List[str]] = None
106
+
107
+
108
+ class ChunkerSchema(BaseModel):
109
+ key: str
110
+ name: Optional[str] = None
111
+ description: Optional[str] = None
112
+
113
+
114
+ class ConfigResponseSchema(BaseModel):
115
+ readers: Optional[Dict[str, ReaderSchema]] = None
116
+ readersForType: Optional[Dict[str, List[str]]] = None
117
+ chunkers: Optional[Dict[str, ChunkerSchema]] = None
118
+ filters: Optional[List[str]] = None
@@ -0,0 +1,3 @@
1
+ from agno.os.routers.memory.memory import get_memory_router
2
+
3
+ __all__ = ["get_memory_router"]