agno 2.2.13__py3-none-any.whl → 2.4.3__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 (383) hide show
  1. agno/agent/__init__.py +6 -0
  2. agno/agent/agent.py +5252 -3145
  3. agno/agent/remote.py +525 -0
  4. agno/api/api.py +2 -0
  5. agno/client/__init__.py +3 -0
  6. agno/client/a2a/__init__.py +10 -0
  7. agno/client/a2a/client.py +554 -0
  8. agno/client/a2a/schemas.py +112 -0
  9. agno/client/a2a/utils.py +369 -0
  10. agno/client/os.py +2669 -0
  11. agno/compression/__init__.py +3 -0
  12. agno/compression/manager.py +247 -0
  13. agno/culture/manager.py +2 -2
  14. agno/db/base.py +927 -6
  15. agno/db/dynamo/dynamo.py +788 -2
  16. agno/db/dynamo/schemas.py +128 -0
  17. agno/db/dynamo/utils.py +26 -3
  18. agno/db/firestore/firestore.py +674 -50
  19. agno/db/firestore/schemas.py +41 -0
  20. agno/db/firestore/utils.py +25 -10
  21. agno/db/gcs_json/gcs_json_db.py +506 -3
  22. agno/db/gcs_json/utils.py +14 -2
  23. agno/db/in_memory/in_memory_db.py +203 -4
  24. agno/db/in_memory/utils.py +14 -2
  25. agno/db/json/json_db.py +498 -2
  26. agno/db/json/utils.py +14 -2
  27. agno/db/migrations/manager.py +199 -0
  28. agno/db/migrations/utils.py +19 -0
  29. agno/db/migrations/v1_to_v2.py +54 -16
  30. agno/db/migrations/versions/__init__.py +0 -0
  31. agno/db/migrations/versions/v2_3_0.py +977 -0
  32. agno/db/mongo/async_mongo.py +1013 -39
  33. agno/db/mongo/mongo.py +684 -4
  34. agno/db/mongo/schemas.py +48 -0
  35. agno/db/mongo/utils.py +17 -0
  36. agno/db/mysql/__init__.py +2 -1
  37. agno/db/mysql/async_mysql.py +2958 -0
  38. agno/db/mysql/mysql.py +722 -53
  39. agno/db/mysql/schemas.py +77 -11
  40. agno/db/mysql/utils.py +151 -8
  41. agno/db/postgres/async_postgres.py +1254 -137
  42. agno/db/postgres/postgres.py +2316 -93
  43. agno/db/postgres/schemas.py +153 -21
  44. agno/db/postgres/utils.py +22 -7
  45. agno/db/redis/redis.py +531 -3
  46. agno/db/redis/schemas.py +36 -0
  47. agno/db/redis/utils.py +31 -15
  48. agno/db/schemas/evals.py +1 -0
  49. agno/db/schemas/memory.py +20 -9
  50. agno/db/singlestore/schemas.py +70 -1
  51. agno/db/singlestore/singlestore.py +737 -74
  52. agno/db/singlestore/utils.py +13 -3
  53. agno/db/sqlite/async_sqlite.py +1069 -89
  54. agno/db/sqlite/schemas.py +133 -1
  55. agno/db/sqlite/sqlite.py +2203 -165
  56. agno/db/sqlite/utils.py +21 -11
  57. agno/db/surrealdb/models.py +25 -0
  58. agno/db/surrealdb/surrealdb.py +603 -1
  59. agno/db/utils.py +60 -0
  60. agno/eval/__init__.py +26 -3
  61. agno/eval/accuracy.py +25 -12
  62. agno/eval/agent_as_judge.py +871 -0
  63. agno/eval/base.py +29 -0
  64. agno/eval/performance.py +10 -4
  65. agno/eval/reliability.py +22 -13
  66. agno/eval/utils.py +2 -1
  67. agno/exceptions.py +42 -0
  68. agno/hooks/__init__.py +3 -0
  69. agno/hooks/decorator.py +164 -0
  70. agno/integrations/discord/client.py +13 -2
  71. agno/knowledge/__init__.py +4 -0
  72. agno/knowledge/chunking/code.py +90 -0
  73. agno/knowledge/chunking/document.py +65 -4
  74. agno/knowledge/chunking/fixed.py +4 -1
  75. agno/knowledge/chunking/markdown.py +102 -11
  76. agno/knowledge/chunking/recursive.py +2 -2
  77. agno/knowledge/chunking/semantic.py +130 -48
  78. agno/knowledge/chunking/strategy.py +18 -0
  79. agno/knowledge/embedder/azure_openai.py +0 -1
  80. agno/knowledge/embedder/google.py +1 -1
  81. agno/knowledge/embedder/mistral.py +1 -1
  82. agno/knowledge/embedder/nebius.py +1 -1
  83. agno/knowledge/embedder/openai.py +16 -12
  84. agno/knowledge/filesystem.py +412 -0
  85. agno/knowledge/knowledge.py +4261 -1199
  86. agno/knowledge/protocol.py +134 -0
  87. agno/knowledge/reader/arxiv_reader.py +3 -2
  88. agno/knowledge/reader/base.py +9 -7
  89. agno/knowledge/reader/csv_reader.py +91 -42
  90. agno/knowledge/reader/docx_reader.py +9 -10
  91. agno/knowledge/reader/excel_reader.py +225 -0
  92. agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
  93. agno/knowledge/reader/firecrawl_reader.py +3 -2
  94. agno/knowledge/reader/json_reader.py +16 -22
  95. agno/knowledge/reader/markdown_reader.py +15 -14
  96. agno/knowledge/reader/pdf_reader.py +33 -28
  97. agno/knowledge/reader/pptx_reader.py +9 -10
  98. agno/knowledge/reader/reader_factory.py +135 -1
  99. agno/knowledge/reader/s3_reader.py +8 -16
  100. agno/knowledge/reader/tavily_reader.py +3 -3
  101. agno/knowledge/reader/text_reader.py +15 -14
  102. agno/knowledge/reader/utils/__init__.py +17 -0
  103. agno/knowledge/reader/utils/spreadsheet.py +114 -0
  104. agno/knowledge/reader/web_search_reader.py +8 -65
  105. agno/knowledge/reader/website_reader.py +16 -13
  106. agno/knowledge/reader/wikipedia_reader.py +36 -3
  107. agno/knowledge/reader/youtube_reader.py +3 -2
  108. agno/knowledge/remote_content/__init__.py +33 -0
  109. agno/knowledge/remote_content/config.py +266 -0
  110. agno/knowledge/remote_content/remote_content.py +105 -17
  111. agno/knowledge/utils.py +76 -22
  112. agno/learn/__init__.py +71 -0
  113. agno/learn/config.py +463 -0
  114. agno/learn/curate.py +185 -0
  115. agno/learn/machine.py +725 -0
  116. agno/learn/schemas.py +1114 -0
  117. agno/learn/stores/__init__.py +38 -0
  118. agno/learn/stores/decision_log.py +1156 -0
  119. agno/learn/stores/entity_memory.py +3275 -0
  120. agno/learn/stores/learned_knowledge.py +1583 -0
  121. agno/learn/stores/protocol.py +117 -0
  122. agno/learn/stores/session_context.py +1217 -0
  123. agno/learn/stores/user_memory.py +1495 -0
  124. agno/learn/stores/user_profile.py +1220 -0
  125. agno/learn/utils.py +209 -0
  126. agno/media.py +22 -6
  127. agno/memory/__init__.py +14 -1
  128. agno/memory/manager.py +223 -8
  129. agno/memory/strategies/__init__.py +15 -0
  130. agno/memory/strategies/base.py +66 -0
  131. agno/memory/strategies/summarize.py +196 -0
  132. agno/memory/strategies/types.py +37 -0
  133. agno/models/aimlapi/aimlapi.py +17 -0
  134. agno/models/anthropic/claude.py +434 -59
  135. agno/models/aws/bedrock.py +121 -20
  136. agno/models/aws/claude.py +131 -274
  137. agno/models/azure/ai_foundry.py +10 -6
  138. agno/models/azure/openai_chat.py +33 -10
  139. agno/models/base.py +1162 -561
  140. agno/models/cerebras/cerebras.py +120 -24
  141. agno/models/cerebras/cerebras_openai.py +21 -2
  142. agno/models/cohere/chat.py +65 -6
  143. agno/models/cometapi/cometapi.py +18 -1
  144. agno/models/dashscope/dashscope.py +2 -3
  145. agno/models/deepinfra/deepinfra.py +18 -1
  146. agno/models/deepseek/deepseek.py +69 -3
  147. agno/models/fireworks/fireworks.py +18 -1
  148. agno/models/google/gemini.py +959 -89
  149. agno/models/google/utils.py +22 -0
  150. agno/models/groq/groq.py +48 -18
  151. agno/models/huggingface/huggingface.py +17 -6
  152. agno/models/ibm/watsonx.py +16 -6
  153. agno/models/internlm/internlm.py +18 -1
  154. agno/models/langdb/langdb.py +13 -1
  155. agno/models/litellm/chat.py +88 -9
  156. agno/models/litellm/litellm_openai.py +18 -1
  157. agno/models/message.py +24 -5
  158. agno/models/meta/llama.py +40 -13
  159. agno/models/meta/llama_openai.py +22 -21
  160. agno/models/metrics.py +12 -0
  161. agno/models/mistral/mistral.py +8 -4
  162. agno/models/n1n/__init__.py +3 -0
  163. agno/models/n1n/n1n.py +57 -0
  164. agno/models/nebius/nebius.py +6 -7
  165. agno/models/nvidia/nvidia.py +20 -3
  166. agno/models/ollama/__init__.py +2 -0
  167. agno/models/ollama/chat.py +17 -6
  168. agno/models/ollama/responses.py +100 -0
  169. agno/models/openai/__init__.py +2 -0
  170. agno/models/openai/chat.py +117 -26
  171. agno/models/openai/open_responses.py +46 -0
  172. agno/models/openai/responses.py +110 -32
  173. agno/models/openrouter/__init__.py +2 -0
  174. agno/models/openrouter/openrouter.py +67 -2
  175. agno/models/openrouter/responses.py +146 -0
  176. agno/models/perplexity/perplexity.py +19 -1
  177. agno/models/portkey/portkey.py +7 -6
  178. agno/models/requesty/requesty.py +19 -2
  179. agno/models/response.py +20 -2
  180. agno/models/sambanova/sambanova.py +20 -3
  181. agno/models/siliconflow/siliconflow.py +19 -2
  182. agno/models/together/together.py +20 -3
  183. agno/models/vercel/v0.py +20 -3
  184. agno/models/vertexai/claude.py +124 -4
  185. agno/models/vllm/vllm.py +19 -14
  186. agno/models/xai/xai.py +19 -2
  187. agno/os/app.py +467 -137
  188. agno/os/auth.py +253 -5
  189. agno/os/config.py +22 -0
  190. agno/os/interfaces/a2a/a2a.py +7 -6
  191. agno/os/interfaces/a2a/router.py +635 -26
  192. agno/os/interfaces/a2a/utils.py +32 -33
  193. agno/os/interfaces/agui/agui.py +5 -3
  194. agno/os/interfaces/agui/router.py +26 -16
  195. agno/os/interfaces/agui/utils.py +97 -57
  196. agno/os/interfaces/base.py +7 -7
  197. agno/os/interfaces/slack/router.py +16 -7
  198. agno/os/interfaces/slack/slack.py +7 -7
  199. agno/os/interfaces/whatsapp/router.py +35 -7
  200. agno/os/interfaces/whatsapp/security.py +3 -1
  201. agno/os/interfaces/whatsapp/whatsapp.py +11 -8
  202. agno/os/managers.py +326 -0
  203. agno/os/mcp.py +652 -79
  204. agno/os/middleware/__init__.py +4 -0
  205. agno/os/middleware/jwt.py +718 -115
  206. agno/os/middleware/trailing_slash.py +27 -0
  207. agno/os/router.py +105 -1558
  208. agno/os/routers/agents/__init__.py +3 -0
  209. agno/os/routers/agents/router.py +655 -0
  210. agno/os/routers/agents/schema.py +288 -0
  211. agno/os/routers/components/__init__.py +3 -0
  212. agno/os/routers/components/components.py +475 -0
  213. agno/os/routers/database.py +155 -0
  214. agno/os/routers/evals/evals.py +111 -18
  215. agno/os/routers/evals/schemas.py +38 -5
  216. agno/os/routers/evals/utils.py +80 -11
  217. agno/os/routers/health.py +3 -3
  218. agno/os/routers/knowledge/knowledge.py +284 -35
  219. agno/os/routers/knowledge/schemas.py +14 -2
  220. agno/os/routers/memory/memory.py +274 -11
  221. agno/os/routers/memory/schemas.py +44 -3
  222. agno/os/routers/metrics/metrics.py +30 -15
  223. agno/os/routers/metrics/schemas.py +10 -6
  224. agno/os/routers/registry/__init__.py +3 -0
  225. agno/os/routers/registry/registry.py +337 -0
  226. agno/os/routers/session/session.py +143 -14
  227. agno/os/routers/teams/__init__.py +3 -0
  228. agno/os/routers/teams/router.py +550 -0
  229. agno/os/routers/teams/schema.py +280 -0
  230. agno/os/routers/traces/__init__.py +3 -0
  231. agno/os/routers/traces/schemas.py +414 -0
  232. agno/os/routers/traces/traces.py +549 -0
  233. agno/os/routers/workflows/__init__.py +3 -0
  234. agno/os/routers/workflows/router.py +757 -0
  235. agno/os/routers/workflows/schema.py +139 -0
  236. agno/os/schema.py +157 -584
  237. agno/os/scopes.py +469 -0
  238. agno/os/settings.py +3 -0
  239. agno/os/utils.py +574 -185
  240. agno/reasoning/anthropic.py +85 -1
  241. agno/reasoning/azure_ai_foundry.py +93 -1
  242. agno/reasoning/deepseek.py +102 -2
  243. agno/reasoning/default.py +6 -7
  244. agno/reasoning/gemini.py +87 -3
  245. agno/reasoning/groq.py +109 -2
  246. agno/reasoning/helpers.py +6 -7
  247. agno/reasoning/manager.py +1238 -0
  248. agno/reasoning/ollama.py +93 -1
  249. agno/reasoning/openai.py +115 -1
  250. agno/reasoning/vertexai.py +85 -1
  251. agno/registry/__init__.py +3 -0
  252. agno/registry/registry.py +68 -0
  253. agno/remote/__init__.py +3 -0
  254. agno/remote/base.py +581 -0
  255. agno/run/__init__.py +2 -4
  256. agno/run/agent.py +134 -19
  257. agno/run/base.py +49 -1
  258. agno/run/cancel.py +65 -52
  259. agno/run/cancellation_management/__init__.py +9 -0
  260. agno/run/cancellation_management/base.py +78 -0
  261. agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
  262. agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
  263. agno/run/requirement.py +181 -0
  264. agno/run/team.py +111 -19
  265. agno/run/workflow.py +2 -1
  266. agno/session/agent.py +57 -92
  267. agno/session/summary.py +1 -1
  268. agno/session/team.py +62 -115
  269. agno/session/workflow.py +353 -57
  270. agno/skills/__init__.py +17 -0
  271. agno/skills/agent_skills.py +377 -0
  272. agno/skills/errors.py +32 -0
  273. agno/skills/loaders/__init__.py +4 -0
  274. agno/skills/loaders/base.py +27 -0
  275. agno/skills/loaders/local.py +216 -0
  276. agno/skills/skill.py +65 -0
  277. agno/skills/utils.py +107 -0
  278. agno/skills/validator.py +277 -0
  279. agno/table.py +10 -0
  280. agno/team/__init__.py +5 -1
  281. agno/team/remote.py +447 -0
  282. agno/team/team.py +3769 -2202
  283. agno/tools/brandfetch.py +27 -18
  284. agno/tools/browserbase.py +225 -16
  285. agno/tools/crawl4ai.py +3 -0
  286. agno/tools/duckduckgo.py +25 -71
  287. agno/tools/exa.py +0 -21
  288. agno/tools/file.py +14 -13
  289. agno/tools/file_generation.py +12 -6
  290. agno/tools/firecrawl.py +15 -7
  291. agno/tools/function.py +94 -113
  292. agno/tools/google_bigquery.py +11 -2
  293. agno/tools/google_drive.py +4 -3
  294. agno/tools/knowledge.py +9 -4
  295. agno/tools/mcp/mcp.py +301 -18
  296. agno/tools/mcp/multi_mcp.py +269 -14
  297. agno/tools/mem0.py +11 -10
  298. agno/tools/memory.py +47 -46
  299. agno/tools/mlx_transcribe.py +10 -7
  300. agno/tools/models/nebius.py +5 -5
  301. agno/tools/models_labs.py +20 -10
  302. agno/tools/nano_banana.py +151 -0
  303. agno/tools/parallel.py +0 -7
  304. agno/tools/postgres.py +76 -36
  305. agno/tools/python.py +14 -6
  306. agno/tools/reasoning.py +30 -23
  307. agno/tools/redshift.py +406 -0
  308. agno/tools/shopify.py +1519 -0
  309. agno/tools/spotify.py +919 -0
  310. agno/tools/tavily.py +4 -1
  311. agno/tools/toolkit.py +253 -18
  312. agno/tools/websearch.py +93 -0
  313. agno/tools/website.py +1 -1
  314. agno/tools/wikipedia.py +1 -1
  315. agno/tools/workflow.py +56 -48
  316. agno/tools/yfinance.py +12 -11
  317. agno/tracing/__init__.py +12 -0
  318. agno/tracing/exporter.py +161 -0
  319. agno/tracing/schemas.py +276 -0
  320. agno/tracing/setup.py +112 -0
  321. agno/utils/agent.py +251 -10
  322. agno/utils/cryptography.py +22 -0
  323. agno/utils/dttm.py +33 -0
  324. agno/utils/events.py +264 -7
  325. agno/utils/hooks.py +111 -3
  326. agno/utils/http.py +161 -2
  327. agno/utils/mcp.py +49 -8
  328. agno/utils/media.py +22 -1
  329. agno/utils/models/ai_foundry.py +9 -2
  330. agno/utils/models/claude.py +20 -5
  331. agno/utils/models/cohere.py +9 -2
  332. agno/utils/models/llama.py +9 -2
  333. agno/utils/models/mistral.py +4 -2
  334. agno/utils/os.py +0 -0
  335. agno/utils/print_response/agent.py +99 -16
  336. agno/utils/print_response/team.py +223 -24
  337. agno/utils/print_response/workflow.py +0 -2
  338. agno/utils/prompts.py +8 -6
  339. agno/utils/remote.py +23 -0
  340. agno/utils/response.py +1 -13
  341. agno/utils/string.py +91 -2
  342. agno/utils/team.py +62 -12
  343. agno/utils/tokens.py +657 -0
  344. agno/vectordb/base.py +15 -2
  345. agno/vectordb/cassandra/cassandra.py +1 -1
  346. agno/vectordb/chroma/__init__.py +2 -1
  347. agno/vectordb/chroma/chromadb.py +468 -23
  348. agno/vectordb/clickhouse/clickhousedb.py +1 -1
  349. agno/vectordb/couchbase/couchbase.py +6 -2
  350. agno/vectordb/lancedb/lance_db.py +7 -38
  351. agno/vectordb/lightrag/lightrag.py +7 -6
  352. agno/vectordb/milvus/milvus.py +118 -84
  353. agno/vectordb/mongodb/__init__.py +2 -1
  354. agno/vectordb/mongodb/mongodb.py +14 -31
  355. agno/vectordb/pgvector/pgvector.py +120 -66
  356. agno/vectordb/pineconedb/pineconedb.py +2 -19
  357. agno/vectordb/qdrant/__init__.py +2 -1
  358. agno/vectordb/qdrant/qdrant.py +33 -56
  359. agno/vectordb/redis/__init__.py +2 -1
  360. agno/vectordb/redis/redisdb.py +19 -31
  361. agno/vectordb/singlestore/singlestore.py +17 -9
  362. agno/vectordb/surrealdb/surrealdb.py +2 -38
  363. agno/vectordb/weaviate/__init__.py +2 -1
  364. agno/vectordb/weaviate/weaviate.py +7 -3
  365. agno/workflow/__init__.py +5 -1
  366. agno/workflow/agent.py +2 -2
  367. agno/workflow/condition.py +12 -10
  368. agno/workflow/loop.py +28 -9
  369. agno/workflow/parallel.py +21 -13
  370. agno/workflow/remote.py +362 -0
  371. agno/workflow/router.py +12 -9
  372. agno/workflow/step.py +261 -36
  373. agno/workflow/steps.py +12 -8
  374. agno/workflow/types.py +40 -77
  375. agno/workflow/workflow.py +939 -213
  376. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
  377. agno-2.4.3.dist-info/RECORD +677 -0
  378. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
  379. agno/tools/googlesearch.py +0 -98
  380. agno/tools/memori.py +0 -339
  381. agno-2.2.13.dist-info/RECORD +0 -575
  382. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
  383. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,266 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from pydantic import BaseModel, ConfigDict
6
+
7
+ if TYPE_CHECKING:
8
+ from agno.knowledge.remote_content.remote_content import (
9
+ AzureBlobContent,
10
+ GCSContent,
11
+ GitHubContent,
12
+ S3Content,
13
+ SharePointContent,
14
+ )
15
+
16
+
17
+ class RemoteContentConfig(BaseModel):
18
+ """Base configuration for remote content sources."""
19
+
20
+ id: str
21
+ name: str
22
+ metadata: Optional[dict] = None
23
+
24
+ model_config = ConfigDict(extra="allow")
25
+
26
+
27
+ class S3Config(RemoteContentConfig):
28
+ """Configuration for AWS S3 content source."""
29
+
30
+ bucket_name: str
31
+ region: Optional[str] = None
32
+ aws_access_key_id: Optional[str] = None
33
+ aws_secret_access_key: Optional[str] = None
34
+ prefix: Optional[str] = None
35
+
36
+ def file(self, key: str) -> "S3Content":
37
+ """Create a content reference for a specific file.
38
+
39
+ Args:
40
+ key: The S3 object key (path to file).
41
+
42
+ Returns:
43
+ S3Content configured with this source's credentials.
44
+ """
45
+ from agno.knowledge.remote_content.remote_content import S3Content
46
+
47
+ return S3Content(
48
+ bucket_name=self.bucket_name,
49
+ key=key,
50
+ config_id=self.id,
51
+ )
52
+
53
+ def folder(self, prefix: str) -> "S3Content":
54
+ """Create a content reference for a folder (prefix).
55
+
56
+ Args:
57
+ prefix: The S3 prefix (folder path).
58
+
59
+ Returns:
60
+ S3Content configured with this source's credentials.
61
+ """
62
+ from agno.knowledge.remote_content.remote_content import S3Content
63
+
64
+ return S3Content(
65
+ bucket_name=self.bucket_name,
66
+ prefix=prefix,
67
+ config_id=self.id,
68
+ )
69
+
70
+
71
+ class GcsConfig(RemoteContentConfig):
72
+ """Configuration for Google Cloud Storage content source."""
73
+
74
+ bucket_name: str
75
+ project: Optional[str] = None
76
+ credentials_path: Optional[str] = None
77
+ prefix: Optional[str] = None
78
+
79
+ def file(self, blob_name: str) -> "GCSContent":
80
+ """Create a content reference for a specific file.
81
+
82
+ Args:
83
+ blob_name: The GCS blob name (path to file).
84
+
85
+ Returns:
86
+ GCSContent configured with this source's credentials.
87
+ """
88
+ from agno.knowledge.remote_content.remote_content import GCSContent
89
+
90
+ return GCSContent(
91
+ bucket_name=self.bucket_name,
92
+ blob_name=blob_name,
93
+ config_id=self.id,
94
+ )
95
+
96
+ def folder(self, prefix: str) -> "GCSContent":
97
+ """Create a content reference for a folder (prefix).
98
+
99
+ Args:
100
+ prefix: The GCS prefix (folder path).
101
+
102
+ Returns:
103
+ GCSContent configured with this source's credentials.
104
+ """
105
+ from agno.knowledge.remote_content.remote_content import GCSContent
106
+
107
+ return GCSContent(
108
+ bucket_name=self.bucket_name,
109
+ prefix=prefix,
110
+ config_id=self.id,
111
+ )
112
+
113
+
114
+ class SharePointConfig(RemoteContentConfig):
115
+ """Configuration for SharePoint content source."""
116
+
117
+ tenant_id: str
118
+ client_id: str
119
+ client_secret: str
120
+ hostname: str
121
+ site_path: Optional[str] = None
122
+ site_id: Optional[str] = None # Full site ID (e.g., "contoso.sharepoint.com,guid1,guid2")
123
+ folder_path: Optional[str] = None
124
+
125
+ def file(self, file_path: str, site_path: Optional[str] = None) -> "SharePointContent":
126
+ """Create a content reference for a specific file.
127
+
128
+ Args:
129
+ file_path: Path to the file in SharePoint.
130
+ site_path: Optional site path override.
131
+
132
+ Returns:
133
+ SharePointContent configured with this source's credentials.
134
+ """
135
+ from agno.knowledge.remote_content.remote_content import SharePointContent
136
+
137
+ return SharePointContent(
138
+ config_id=self.id,
139
+ file_path=file_path,
140
+ site_path=site_path or self.site_path,
141
+ )
142
+
143
+ def folder(self, folder_path: str, site_path: Optional[str] = None) -> "SharePointContent":
144
+ """Create a content reference for a folder.
145
+
146
+ Args:
147
+ folder_path: Path to the folder in SharePoint.
148
+ site_path: Optional site path override.
149
+
150
+ Returns:
151
+ SharePointContent configured with this source's credentials.
152
+ """
153
+ from agno.knowledge.remote_content.remote_content import SharePointContent
154
+
155
+ return SharePointContent(
156
+ config_id=self.id,
157
+ folder_path=folder_path,
158
+ site_path=site_path or self.site_path,
159
+ )
160
+
161
+
162
+ class GitHubConfig(RemoteContentConfig):
163
+ """Configuration for GitHub content source."""
164
+
165
+ repo: str
166
+ token: Optional[str] = None
167
+ branch: Optional[str] = None
168
+ path: Optional[str] = None
169
+
170
+ def file(self, file_path: str, branch: Optional[str] = None) -> "GitHubContent":
171
+ """Create a content reference for a specific file.
172
+
173
+ Args:
174
+ file_path: Path to the file in the repository.
175
+ branch: Optional branch override.
176
+
177
+ Returns:
178
+ GitHubContent configured with this source's credentials.
179
+ """
180
+ from agno.knowledge.remote_content.remote_content import GitHubContent
181
+
182
+ return GitHubContent(
183
+ config_id=self.id,
184
+ file_path=file_path,
185
+ branch=branch or self.branch,
186
+ )
187
+
188
+ def folder(self, folder_path: str, branch: Optional[str] = None) -> "GitHubContent":
189
+ """Create a content reference for a folder.
190
+
191
+ Args:
192
+ folder_path: Path to the folder in the repository.
193
+ branch: Optional branch override.
194
+
195
+ Returns:
196
+ GitHubContent configured with this source's credentials.
197
+ """
198
+ from agno.knowledge.remote_content.remote_content import GitHubContent
199
+
200
+ return GitHubContent(
201
+ config_id=self.id,
202
+ folder_path=folder_path,
203
+ branch=branch or self.branch,
204
+ )
205
+
206
+
207
+ class AzureBlobConfig(RemoteContentConfig):
208
+ """Configuration for Azure Blob Storage content source.
209
+
210
+ Uses Azure AD client credentials flow for authentication.
211
+
212
+ Required Azure AD App Registration permissions:
213
+ - Storage Blob Data Reader (or Contributor) role on the storage account
214
+
215
+ Example:
216
+ ```python
217
+ config = AzureBlobConfig(
218
+ id="company-docs",
219
+ name="Company Documents",
220
+ tenant_id=os.getenv("AZURE_TENANT_ID"),
221
+ client_id=os.getenv("AZURE_CLIENT_ID"),
222
+ client_secret=os.getenv("AZURE_CLIENT_SECRET"),
223
+ storage_account=os.getenv("AZURE_STORAGE_ACCOUNT_NAME"),
224
+ container=os.getenv("AZURE_CONTAINER_NAME"),
225
+ )
226
+ ```
227
+ """
228
+
229
+ tenant_id: str
230
+ client_id: str
231
+ client_secret: str
232
+ storage_account: str
233
+ container: str
234
+ prefix: Optional[str] = None
235
+
236
+ def file(self, blob_name: str) -> "AzureBlobContent":
237
+ """Create a content reference for a specific blob (file).
238
+
239
+ Args:
240
+ blob_name: The blob name (path to file in container).
241
+
242
+ Returns:
243
+ AzureBlobContent configured with this source's credentials.
244
+ """
245
+ from agno.knowledge.remote_content.remote_content import AzureBlobContent
246
+
247
+ return AzureBlobContent(
248
+ config_id=self.id,
249
+ blob_name=blob_name,
250
+ )
251
+
252
+ def folder(self, prefix: str) -> "AzureBlobContent":
253
+ """Create a content reference for a folder (prefix).
254
+
255
+ Args:
256
+ prefix: The blob prefix (folder path).
257
+
258
+ Returns:
259
+ AzureBlobContent configured with this source's credentials.
260
+ """
261
+ from agno.knowledge.remote_content.remote_content import AzureBlobContent
262
+
263
+ return AzureBlobContent(
264
+ config_id=self.id,
265
+ prefix=prefix,
266
+ )
@@ -14,21 +14,23 @@ class S3Content:
14
14
  key: Optional[str] = None,
15
15
  object: Optional[S3Object] = None,
16
16
  prefix: Optional[str] = None,
17
+ config_id: Optional[str] = None,
17
18
  ):
18
19
  self.bucket_name = bucket_name
19
20
  self.bucket = bucket
20
21
  self.key = key
21
22
  self.object = object
22
23
  self.prefix = prefix
24
+ self.config_id = config_id
23
25
 
24
26
  if bucket_name is None and bucket is None:
25
27
  raise ValueError("Either bucket_name or bucket must be provided")
26
- if key is None and object is None:
27
- raise ValueError("Either key or object must be provided")
28
+ if key is None and object is None and prefix is None:
29
+ raise ValueError("Either key, object, or prefix must be provided")
28
30
  if bucket_name is not None and bucket is not None:
29
31
  raise ValueError("Either bucket_name or bucket must be provided, not both")
30
- if key is not None and object is not None:
31
- raise ValueError("Either key or object must be provided, not both")
32
+ if sum(x is not None for x in [key, object, prefix]) > 1:
33
+ raise ValueError("Only one of key, object, or prefix should be provided")
32
34
 
33
35
  if self.bucket_name is not None:
34
36
  self.bucket = S3Bucket(name=self.bucket_name)
@@ -40,6 +42,7 @@ class S3Content:
40
42
  "key": self.key,
41
43
  "object": self.object,
42
44
  "prefix": self.prefix,
45
+ "config_id": self.config_id,
43
46
  }
44
47
 
45
48
 
@@ -51,19 +54,13 @@ class GCSContent:
51
54
  bucket_name: Optional[str] = None,
52
55
  blob_name: Optional[str] = None,
53
56
  prefix: Optional[str] = None,
57
+ config_id: Optional[str] = None,
54
58
  ):
55
- # Import Google Cloud Storage only when actually needed
56
- try:
57
- from google.cloud import storage # type: ignore
58
- except ImportError:
59
- raise ImportError(
60
- "The `google-cloud-storage` package is not installed. Please install it via `pip install google-cloud-storage`."
61
- )
62
-
63
59
  self.bucket = bucket
64
60
  self.bucket_name = bucket_name
65
61
  self.blob_name = blob_name
66
62
  self.prefix = prefix
63
+ self.config_id = config_id
67
64
 
68
65
  if self.bucket is None and self.bucket_name is None:
69
66
  raise ValueError("No bucket or bucket_name provided")
@@ -72,17 +69,108 @@ class GCSContent:
72
69
  if self.blob_name is None and self.prefix is None:
73
70
  raise ValueError("Either blob_name or prefix must be provided")
74
71
 
75
- if self.bucket is None:
76
- client = storage.Client()
77
- self.bucket = client.bucket(self.bucket_name)
78
-
79
72
  def get_config(self):
80
73
  return {
81
74
  "bucket": self.bucket,
82
75
  "bucket_name": self.bucket_name,
83
76
  "blob_name": self.blob_name,
84
77
  "prefix": self.prefix,
78
+ "config_id": self.config_id,
79
+ }
80
+
81
+
82
+ @dataclass
83
+ class SharePointContent:
84
+ """Content reference for SharePoint files."""
85
+
86
+ def __init__(
87
+ self,
88
+ config_id: str,
89
+ file_path: Optional[str] = None,
90
+ folder_path: Optional[str] = None,
91
+ site_path: Optional[str] = None,
92
+ drive_id: Optional[str] = None,
93
+ ):
94
+ self.config_id = config_id
95
+ self.file_path = file_path
96
+ self.folder_path = folder_path
97
+ self.site_path = site_path
98
+ self.drive_id = drive_id
99
+
100
+ if self.file_path is None and self.folder_path is None:
101
+ raise ValueError("Either file_path or folder_path must be provided")
102
+ if self.file_path is not None and self.folder_path is not None:
103
+ raise ValueError("Provide either file_path or folder_path, not both")
104
+
105
+ def get_config(self):
106
+ return {
107
+ "config_id": self.config_id,
108
+ "file_path": self.file_path,
109
+ "folder_path": self.folder_path,
110
+ "site_path": self.site_path,
111
+ "drive_id": self.drive_id,
112
+ }
113
+
114
+
115
+ @dataclass
116
+ class GitHubContent:
117
+ """Content reference for GitHub files."""
118
+
119
+ def __init__(
120
+ self,
121
+ config_id: str,
122
+ file_path: Optional[str] = None,
123
+ folder_path: Optional[str] = None,
124
+ branch: Optional[str] = None,
125
+ ):
126
+ self.config_id = config_id
127
+ self.file_path = file_path
128
+ self.folder_path = folder_path
129
+ self.branch = branch
130
+
131
+ if self.file_path is None and self.folder_path is None:
132
+ raise ValueError("Either file_path or folder_path must be provided")
133
+ if self.file_path is not None and self.folder_path is not None:
134
+ raise ValueError("Provide either file_path or folder_path, not both")
135
+
136
+ def get_config(self):
137
+ return {
138
+ "config_id": self.config_id,
139
+ "file_path": self.file_path,
140
+ "folder_path": self.folder_path,
141
+ "branch": self.branch,
142
+ }
143
+
144
+
145
+ @dataclass
146
+ class AzureBlobContent:
147
+ """Content reference for Azure Blob Storage files.
148
+
149
+ Used with AzureBlobConfig to load files from Azure Blob Storage containers.
150
+ Supports loading single blobs or entire prefixes (folders).
151
+ """
152
+
153
+ def __init__(
154
+ self,
155
+ config_id: str,
156
+ blob_name: Optional[str] = None,
157
+ prefix: Optional[str] = None,
158
+ ):
159
+ self.config_id = config_id
160
+ self.blob_name = blob_name
161
+ self.prefix = prefix
162
+
163
+ if self.blob_name is None and self.prefix is None:
164
+ raise ValueError("Either blob_name or prefix must be provided")
165
+ if self.blob_name is not None and self.prefix is not None:
166
+ raise ValueError("Provide either blob_name or prefix, not both")
167
+
168
+ def get_config(self):
169
+ return {
170
+ "config_id": self.config_id,
171
+ "blob_name": self.blob_name,
172
+ "prefix": self.prefix,
85
173
  }
86
174
 
87
175
 
88
- RemoteContent = Union[S3Content, GCSContent]
176
+ RemoteContent = Union[S3Content, GCSContent, SharePointContent, GitHubContent, AzureBlobContent]
agno/knowledge/utils.py CHANGED
@@ -1,5 +1,6 @@
1
- from typing import Dict, List
1
+ from typing import Any, Dict, List, Optional
2
2
 
3
+ from agno.knowledge.reader.base import Reader
3
4
  from agno.knowledge.reader.reader_factory import ReaderFactory
4
5
  from agno.knowledge.types import ContentType
5
6
  from agno.utils.log import log_debug
@@ -14,6 +15,7 @@ def _get_chunker_class(strategy_type):
14
15
  ChunkingStrategyType.AGENTIC_CHUNKER: lambda: _import_class(
15
16
  "agno.knowledge.chunking.agentic", "AgenticChunking"
16
17
  ),
18
+ ChunkingStrategyType.CODE_CHUNKER: lambda: _import_class("agno.knowledge.chunking.code", "CodeChunking"),
17
19
  ChunkingStrategyType.DOCUMENT_CHUNKER: lambda: _import_class(
18
20
  "agno.knowledge.chunking.document", "DocumentChunking"
19
21
  ),
@@ -47,26 +49,28 @@ def _import_class(module_name: str, class_name: str):
47
49
 
48
50
 
49
51
  def get_reader_info(reader_key: str) -> Dict:
50
- """Get information about a reader without instantiating it."""
51
- # Try to create the reader to get its info, but don't cache it
52
+ """Get information about a reader without instantiating it.
53
+
54
+ Uses class methods and static metadata from ReaderFactory to avoid
55
+ the overhead of creating reader instances.
56
+ """
52
57
  try:
53
- reader_factory_method = ReaderFactory._get_reader_method(reader_key)
58
+ # Get the reader CLASS without instantiation
59
+ reader_class = ReaderFactory.get_reader_class(reader_key)
54
60
 
55
- # Create an instance to get the class, then call class methods
56
- reader_instance = reader_factory_method()
57
- reader_class = reader_instance.__class__
61
+ # Get metadata from static registry (no instantiation needed)
62
+ metadata = ReaderFactory.READER_METADATA.get(reader_key, {})
58
63
 
59
- supported_strategies = reader_class.get_supported_chunking_strategies()
60
- supported_content_types = reader_class.get_supported_content_types()
64
+ # Call class methods directly (no instance needed)
65
+ supported_strategies = reader_class.get_supported_chunking_strategies() # type: ignore[attr-defined]
66
+ supported_content_types = reader_class.get_supported_content_types() # type: ignore[attr-defined]
61
67
 
62
68
  return {
63
69
  "id": reader_key,
64
- "name": "".join(word.capitalize() for word in reader_key.split("_")) + "Reader",
65
- "description": reader_instance.description,
66
- "chunking_strategies": [
67
- strategy.value for strategy in supported_strategies
68
- ], # Convert enums to string values
69
- "content_types": [ct.value for ct in supported_content_types], # Convert enums to string values
70
+ "name": metadata.get("name", reader_class.__name__),
71
+ "description": metadata.get("description", f"{reader_class.__name__} reader"),
72
+ "chunking_strategies": [strategy.value for strategy in supported_strategies],
73
+ "content_types": [ct.value for ct in supported_content_types],
70
74
  }
71
75
  except ImportError as e:
72
76
  # Skip readers with missing dependencies
@@ -75,31 +79,79 @@ def get_reader_info(reader_key: str) -> Dict:
75
79
  raise ValueError(f"Unknown reader: {reader_key}. Error: {str(e)}")
76
80
 
77
81
 
78
- def get_all_readers_info() -> List[Dict]:
79
- """Get information about all available readers."""
82
+ def get_reader_info_from_instance(reader: Reader, reader_id: str) -> Dict:
83
+ """Get information about a reader instance."""
84
+ try:
85
+ reader_class = reader.__class__
86
+ supported_strategies = reader_class.get_supported_chunking_strategies()
87
+ supported_content_types = reader_class.get_supported_content_types()
88
+
89
+ return {
90
+ "id": reader_id,
91
+ "name": getattr(reader, "name", reader_class.__name__),
92
+ "description": getattr(reader, "description", f"Custom {reader_class.__name__}"),
93
+ "chunking_strategies": [strategy.value for strategy in supported_strategies],
94
+ "content_types": [ct.value for ct in supported_content_types],
95
+ }
96
+ except Exception as e:
97
+ raise ValueError(f"Failed to get info for reader '{reader_id}': {str(e)}")
98
+
99
+
100
+ def get_all_readers_info(knowledge_instance: Optional[Any] = None) -> List[Dict]:
101
+ """Get information about all available readers, including custom readers from a Knowledge instance.
102
+
103
+ Custom readers are added first and take precedence over factory readers with the same ID.
104
+
105
+ Args:
106
+ knowledge_instance: Optional Knowledge instance to include custom readers from.
107
+
108
+ Returns:
109
+ List of reader info dictionaries (custom readers first, then factory readers).
110
+ """
80
111
  readers_info = []
112
+ seen_ids: set = set()
113
+
114
+ # 1. Add custom readers FIRST (they take precedence over factory readers)
115
+ if knowledge_instance is not None:
116
+ custom_readers = knowledge_instance.get_readers()
117
+ if isinstance(custom_readers, dict):
118
+ for reader_id, reader in custom_readers.items():
119
+ try:
120
+ reader_info = get_reader_info_from_instance(reader, reader_id)
121
+ readers_info.append(reader_info)
122
+ seen_ids.add(reader_id)
123
+ except ValueError as e:
124
+ log_debug(f"Skipping custom reader '{reader_id}': {e}")
125
+ continue
126
+
127
+ # 2. Add factory readers (skip if custom reader with same ID already exists)
81
128
  keys = ReaderFactory.get_all_reader_keys()
82
129
  for key in keys:
130
+ if key in seen_ids:
131
+ # Custom reader with this ID already added, skip factory version
132
+ continue
83
133
  try:
84
134
  reader_info = get_reader_info(key)
85
135
  readers_info.append(reader_info)
86
136
  except ValueError as e:
87
137
  # Skip readers with missing dependencies or other issues
88
- # Log the error but don't fail the entire request
89
138
  log_debug(f"Skipping reader '{key}': {e}")
90
139
  continue
140
+
91
141
  return readers_info
92
142
 
93
143
 
94
- def get_content_types_to_readers_mapping() -> Dict[str, List[str]]:
144
+ def get_content_types_to_readers_mapping(knowledge_instance: Optional[Any] = None) -> Dict[str, List[str]]:
95
145
  """Get mapping of content types to list of reader IDs that support them.
96
146
 
147
+ Args:
148
+ knowledge_instance: Optional Knowledge instance to include custom readers from.
149
+
97
150
  Returns:
98
151
  Dictionary mapping content type strings (ContentType enum values) to list of reader IDs.
99
152
  """
100
153
  content_type_mapping: Dict[str, List[str]] = {}
101
- readers_info = get_all_readers_info()
102
-
154
+ readers_info = get_all_readers_info(knowledge_instance)
103
155
  for reader_info in readers_info:
104
156
  reader_id = reader_info["id"]
105
157
  content_types = reader_info.get("content_types", [])
@@ -107,7 +159,9 @@ def get_content_types_to_readers_mapping() -> Dict[str, List[str]]:
107
159
  for content_type in content_types:
108
160
  if content_type not in content_type_mapping:
109
161
  content_type_mapping[content_type] = []
110
- content_type_mapping[content_type].append(reader_id)
162
+ # Avoid duplicates
163
+ if reader_id not in content_type_mapping[content_type]:
164
+ content_type_mapping[content_type].append(reader_id)
111
165
 
112
166
  return content_type_mapping
113
167
 
agno/learn/__init__.py ADDED
@@ -0,0 +1,71 @@
1
+ """
2
+ Agno Learning Module
3
+ ====================
4
+ Gives agents the ability to learn and remember.
5
+
6
+ Main Components:
7
+ - LearningMachine: Unified learning system
8
+ - Config: Configuration for learning types
9
+ - Schemas: Data structures for learning types
10
+ - Stores: Storage backends for learning types
11
+ """
12
+
13
+ from agno.learn.config import (
14
+ DecisionLogConfig,
15
+ EntityMemoryConfig,
16
+ LearnedKnowledgeConfig,
17
+ LearningMode,
18
+ MemoriesConfig,
19
+ SessionContextConfig,
20
+ UserMemoryConfig,
21
+ UserProfileConfig,
22
+ )
23
+ from agno.learn.machine import LearningMachine
24
+ from agno.learn.schemas import (
25
+ DecisionLog,
26
+ EntityMemory,
27
+ LearnedKnowledge,
28
+ Memories,
29
+ SessionContext,
30
+ UserProfile,
31
+ )
32
+ from agno.learn.stores import (
33
+ DecisionLogStore,
34
+ EntityMemoryStore,
35
+ LearnedKnowledgeStore,
36
+ LearningStore,
37
+ MemoriesStore,
38
+ SessionContextStore,
39
+ UserMemoryStore,
40
+ UserProfileStore,
41
+ )
42
+
43
+ __all__ = [
44
+ # Main class
45
+ "LearningMachine",
46
+ # Configs
47
+ "LearningMode",
48
+ "UserProfileConfig",
49
+ "UserMemoryConfig",
50
+ "MemoriesConfig", # Backwards compatibility alias
51
+ "EntityMemoryConfig",
52
+ "SessionContextConfig",
53
+ "LearnedKnowledgeConfig",
54
+ "DecisionLogConfig", # Phase 2
55
+ # Schemas
56
+ "UserProfile",
57
+ "Memories",
58
+ "EntityMemory",
59
+ "SessionContext",
60
+ "LearnedKnowledge",
61
+ "DecisionLog", # Phase 2
62
+ # Stores
63
+ "LearningStore",
64
+ "UserProfileStore",
65
+ "UserMemoryStore",
66
+ "MemoriesStore", # Backwards compatibility alias
67
+ "SessionContextStore",
68
+ "LearnedKnowledgeStore",
69
+ "EntityMemoryStore",
70
+ "DecisionLogStore", # Phase 2
71
+ ]