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
agno/os/scopes.py ADDED
@@ -0,0 +1,469 @@
1
+ """AgentOS RBAC Scopes
2
+
3
+ This module defines all available permission scopes for AgentOS RBAC (Role-Based Access Control).
4
+
5
+ Scope Format:
6
+ - Global resource scopes: `resource:action`
7
+ - Per-resource scopes: `resource:<resource-id>:action`
8
+ - Wildcards: `resource:*:action` for any resource
9
+
10
+ The AgentOS ID is verified via the JWT `aud` (audience) claim.
11
+
12
+ Examples:
13
+ - `system:read` - Read system config
14
+ - `agents:read` - List all agents
15
+ - `agents:web-agent:read` - Read specific agent
16
+ - `agents:web-agent:run` - Run specific agent
17
+ - `agents:*:run` - Run any agent (wildcard)
18
+ - `agent_os:admin` - Full access to everything
19
+ """
20
+
21
+ from dataclasses import dataclass
22
+ from enum import Enum
23
+ from typing import Dict, List, Optional, Set
24
+
25
+
26
+ class AgentOSScope(str, Enum):
27
+ """
28
+ Enum of all available AgentOS permission scopes.
29
+
30
+ Special Scopes:
31
+ - ADMIN: Grants full access to all endpoints (agent_os:admin)
32
+
33
+ Scope format:
34
+
35
+ Global Resource Scopes:
36
+ - system:read - System configuration and model information
37
+ - agents:read - List all agents
38
+ - teams:read - List all teams
39
+ - workflows:read - List all workflows
40
+ - sessions:read - View session data
41
+ - sessions:write - Create and update sessions
42
+ - sessions:delete - Delete sessions
43
+ - memories:read - View memories
44
+ - memories:write - Create and update memories
45
+ - memories:delete - Delete memories
46
+ - knowledge:read - View and search knowledge
47
+ - knowledge:write - Add and update knowledge
48
+ - knowledge:delete - Delete knowledge
49
+ - metrics:read - View metrics
50
+ - metrics:write - Refresh metrics
51
+ - evals:read - View evaluation runs
52
+ - evals:write - Create and update evaluation runs
53
+ - evals:delete - Delete evaluation runs
54
+ - traces:read - View traces and trace statistics
55
+
56
+ Per-Resource Scopes (with resource ID):
57
+ - agents:<agent-id>:read - Read specific agent
58
+ - agents:<agent-id>:run - Run specific agent
59
+ - teams:<team-id>:read - Read specific team
60
+ - teams:<team-id>:run - Run specific team
61
+ - workflows:<workflow-id>:read - Read specific workflow
62
+ - workflows:<workflow-id>:run - Run specific workflow
63
+
64
+ Wildcards:
65
+ - agents:*:run - Run any agent
66
+ - teams:*:run - Run any team
67
+ """
68
+
69
+ # Special scopes
70
+ ADMIN = "agent_os:admin"
71
+
72
+
73
+ @dataclass
74
+ class ParsedScope:
75
+ """Represents a parsed scope with its components."""
76
+
77
+ raw: str
78
+ scope_type: str # "admin", "global", "per_resource", or "unknown"
79
+ resource: Optional[str] = None
80
+ resource_id: Optional[str] = None
81
+ action: Optional[str] = None
82
+ is_wildcard_resource: bool = False
83
+
84
+ @property
85
+ def is_global_resource_scope(self) -> bool:
86
+ """Check if this scope targets all resources of a type (no resource_id)."""
87
+ return self.scope_type == "global"
88
+
89
+ @property
90
+ def is_per_resource_scope(self) -> bool:
91
+ """Check if this scope targets a specific resource (has resource_id)."""
92
+ return self.scope_type == "per_resource"
93
+
94
+
95
+ def parse_scope(scope: str, admin_scope: Optional[str] = None) -> ParsedScope:
96
+ """
97
+ Parse a scope string into its components.
98
+
99
+ Args:
100
+ scope: The scope string to parse
101
+ admin_scope: The scope string that grants admin access (default: "agent_os:admin")
102
+
103
+ Returns:
104
+ ParsedScope object with parsed components
105
+
106
+ Examples:
107
+ >>> parse_scope("agent_os:admin")
108
+ ParsedScope(raw="agent_os:admin", scope_type="admin")
109
+
110
+ >>> parse_scope("system:read")
111
+ ParsedScope(raw="system:read", scope_type="global", resource="system", action="read")
112
+
113
+ >>> parse_scope("agents:web-agent:read")
114
+ ParsedScope(raw="...", scope_type="per_resource", resource="agents", resource_id="web-agent", action="read")
115
+
116
+ >>> parse_scope("agents:*:run")
117
+ ParsedScope(raw="...", scope_type="per_resource", resource="agents", resource_id="*", action="run", is_wildcard_resource=True)
118
+ """
119
+ effective_admin_scope = admin_scope or AgentOSScope.ADMIN.value
120
+ if scope == effective_admin_scope:
121
+ return ParsedScope(raw=scope, scope_type="admin")
122
+
123
+ parts = scope.split(":")
124
+
125
+ # Global resource scope: resource:action (2 parts)
126
+ if len(parts) == 2:
127
+ return ParsedScope(
128
+ raw=scope,
129
+ scope_type="global",
130
+ resource=parts[0],
131
+ action=parts[1],
132
+ )
133
+
134
+ # Per-resource scope: resource:<resource-id>:action (3 parts)
135
+ if len(parts) == 3:
136
+ resource_id = parts[1]
137
+ is_wildcard_resource = resource_id == "*"
138
+
139
+ return ParsedScope(
140
+ raw=scope,
141
+ scope_type="per_resource",
142
+ resource=parts[0],
143
+ resource_id=resource_id,
144
+ action=parts[2],
145
+ is_wildcard_resource=is_wildcard_resource,
146
+ )
147
+
148
+ # Invalid format
149
+ return ParsedScope(raw=scope, scope_type="unknown")
150
+
151
+
152
+ def matches_scope(
153
+ user_scope: ParsedScope,
154
+ required_scope: ParsedScope,
155
+ resource_id: Optional[str] = None,
156
+ ) -> bool:
157
+ """
158
+ Check if a user's scope matches a required scope.
159
+
160
+ Args:
161
+ user_scope: The user's parsed scope
162
+ required_scope: The required parsed scope
163
+ resource_id: The specific resource ID being accessed
164
+
165
+ Returns:
166
+ True if the user's scope satisfies the required scope
167
+
168
+ Examples:
169
+ >>> user = parse_scope("system:read")
170
+ >>> required = parse_scope("system:read")
171
+ >>> matches_scope(user, required)
172
+ True
173
+
174
+ >>> user = parse_scope("agents:web-agent:run")
175
+ >>> required = parse_scope("agents:<id>:run")
176
+ >>> matches_scope(user, required, resource_id="web-agent")
177
+ True
178
+
179
+ >>> user = parse_scope("agents:*:run")
180
+ >>> required = parse_scope("agents:<id>:run")
181
+ >>> matches_scope(user, required, resource_id="web-agent")
182
+ True
183
+ """
184
+ # Admin always matches
185
+ if user_scope.scope_type == "admin":
186
+ return True
187
+
188
+ # Unknown scopes don't match anything
189
+ if user_scope.scope_type == "unknown" or required_scope.scope_type == "unknown":
190
+ return False
191
+
192
+ # Resource type must match
193
+ if user_scope.resource != required_scope.resource:
194
+ return False
195
+
196
+ # Action must match
197
+ if user_scope.action != required_scope.action:
198
+ return False
199
+
200
+ # If required scope has a resource_id, check it
201
+ if required_scope.resource_id:
202
+ # User has wildcard resource access
203
+ if user_scope.is_wildcard_resource:
204
+ return True
205
+ # User has global resource access (no resource_id in user scope)
206
+ if not user_scope.resource_id:
207
+ return True
208
+ # User has specific resource access - must match
209
+ return user_scope.resource_id == resource_id
210
+
211
+ # Required scope is global (no resource_id), user scope matches if:
212
+ # - User has global scope (no resource_id), OR
213
+ # - User has wildcard resource scope
214
+ return not user_scope.resource_id or user_scope.is_wildcard_resource
215
+
216
+
217
+ def has_required_scopes(
218
+ user_scopes: List[str],
219
+ required_scopes: List[str],
220
+ resource_type: Optional[str] = None,
221
+ resource_id: Optional[str] = None,
222
+ admin_scope: Optional[str] = None,
223
+ ) -> bool:
224
+ """
225
+ Check if user has all required scopes.
226
+
227
+ Args:
228
+ user_scopes: List of scope strings the user has
229
+ required_scopes: List of scope strings required
230
+ resource_type: Type of resource being accessed ("agents", "teams", "workflows")
231
+ resource_id: Specific resource ID being accessed
232
+ admin_scope: The scope string that grants admin access (default: "agent_os:admin")
233
+
234
+ Returns:
235
+ True if user has all required scopes
236
+
237
+ Examples:
238
+ >>> has_required_scopes(
239
+ ... ["agents:read"],
240
+ ... ["agents:read"],
241
+ ... )
242
+ True
243
+
244
+ >>> has_required_scopes(
245
+ ... ["agents:web-agent:run"],
246
+ ... ["agents:run"],
247
+ ... resource_type="agents",
248
+ ... resource_id="web-agent"
249
+ ... )
250
+ True
251
+
252
+ >>> has_required_scopes(
253
+ ... ["agents:*:run"],
254
+ ... ["agents:run"],
255
+ ... resource_type="agents",
256
+ ... resource_id="any-agent"
257
+ ... )
258
+ True
259
+ """
260
+ if not required_scopes:
261
+ return True
262
+
263
+ # Parse user scopes once
264
+ parsed_user_scopes = [parse_scope(scope, admin_scope=admin_scope) for scope in user_scopes]
265
+
266
+ # Check for admin scope
267
+ if any(s.scope_type == "admin" for s in parsed_user_scopes):
268
+ return True
269
+
270
+ # Check each required scope
271
+ for required_scope_str in required_scopes:
272
+ parts = required_scope_str.split(":")
273
+ if len(parts) == 2:
274
+ resource, action = parts
275
+ # Build the required scope based on context
276
+ if resource_id and resource_type:
277
+ # Per-resource scope required
278
+ full_required_scope = f"{resource_type}:<resource-id>:{action}"
279
+ else:
280
+ # Global resource scope required
281
+ full_required_scope = required_scope_str
282
+
283
+ required = parse_scope(full_required_scope, admin_scope=admin_scope)
284
+ else:
285
+ required = parse_scope(required_scope_str, admin_scope=admin_scope)
286
+
287
+ scope_matched = False
288
+ for user_scope in parsed_user_scopes:
289
+ if matches_scope(user_scope, required, resource_id=resource_id):
290
+ scope_matched = True
291
+ break
292
+
293
+ if not scope_matched:
294
+ return False
295
+
296
+ return True
297
+
298
+
299
+ def get_accessible_resource_ids(
300
+ user_scopes: List[str],
301
+ resource_type: str,
302
+ admin_scope: Optional[str] = None,
303
+ ) -> Set[str]:
304
+ """
305
+ Get the set of resource IDs the user has access to.
306
+
307
+ Args:
308
+ user_scopes: List of scope strings the user has
309
+ resource_type: Type of resource ("agents", "teams", "workflows")
310
+ admin_scope: The scope string that grants admin access (default: "agent_os:admin")
311
+
312
+ Returns:
313
+ Set of resource IDs the user can access. Returns {"*"} for wildcard access.
314
+
315
+ Examples:
316
+ >>> get_accessible_resource_ids(
317
+ ... ["agents:agent-1:read", "agents:agent-2:read"],
318
+ ... "agents"
319
+ ... )
320
+ {'agent-1', 'agent-2'}
321
+
322
+ >>> get_accessible_resource_ids(["agents:*:read"], "agents")
323
+ {'*'}
324
+
325
+ >>> get_accessible_resource_ids(["agents:read"], "agents")
326
+ {'*'}
327
+
328
+ >>> get_accessible_resource_ids(["admin"], "agents")
329
+ {'*'}
330
+ """
331
+ parsed_scopes = [parse_scope(scope, admin_scope=admin_scope) for scope in user_scopes]
332
+
333
+ # Check for admin or global wildcard access
334
+ for scope in parsed_scopes:
335
+ if scope.scope_type == "admin":
336
+ return {"*"}
337
+
338
+ # Check if resource type matches
339
+ if scope.resource == resource_type:
340
+ # Global resource scope (no resource_id) grants access to all
341
+ if not scope.resource_id and scope.action in ["read", "run"]:
342
+ return {"*"}
343
+ # Wildcard resource scope grants access to all
344
+ if scope.is_wildcard_resource and scope.action in ["read", "run"]:
345
+ return {"*"}
346
+
347
+ # Collect specific resource IDs
348
+ accessible_ids: Set[str] = set()
349
+ for scope in parsed_scopes:
350
+ # Check if resource type matches
351
+ if scope.resource == resource_type:
352
+ # Specific resource ID
353
+ if scope.resource_id and not scope.is_wildcard_resource and scope.action in ["read", "run"]:
354
+ accessible_ids.add(scope.resource_id)
355
+
356
+ return accessible_ids
357
+
358
+
359
+ def get_default_scope_mappings() -> Dict[str, List[str]]:
360
+ """
361
+ Get default scope mappings for AgentOS endpoints.
362
+
363
+ Returns a dictionary mapping route patterns (with HTTP methods) to required scope templates.
364
+ Format: "METHOD /path/pattern": ["resource:action"]
365
+ """
366
+ return {
367
+ # System endpoints
368
+ "GET /config": ["system:read"],
369
+ "GET /models": ["system:read"],
370
+ # Agent endpoints
371
+ "GET /agents": ["agents:read"],
372
+ "GET /agents/*": ["agents:read"],
373
+ "POST /agents": ["agents:write"],
374
+ "PATCH /agents/*": ["agents:write"],
375
+ "DELETE /agents/*": ["agents:delete"],
376
+ "POST /agents/*/runs": ["agents:run"],
377
+ "POST /agents/*/runs/*/continue": ["agents:run"],
378
+ "POST /agents/*/runs/*/cancel": ["agents:run"],
379
+ # Team endpoints
380
+ "GET /teams": ["teams:read"],
381
+ "GET /teams/*": ["teams:read"],
382
+ "POST /teams": ["teams:write"],
383
+ "PATCH /teams/*": ["teams:write"],
384
+ "DELETE /teams/*": ["teams:delete"],
385
+ "POST /teams/*/runs": ["teams:run"],
386
+ "POST /teams/*/runs/*/continue": ["teams:run"],
387
+ "POST /teams/*/runs/*/cancel": ["teams:run"],
388
+ # Workflow endpoints
389
+ "GET /workflows": ["workflows:read"],
390
+ "GET /workflows/*": ["workflows:read"],
391
+ "POST /workflows": ["workflows:write"],
392
+ "PATCH /workflows/*": ["workflows:write"],
393
+ "DELETE /workflows/*": ["workflows:delete"],
394
+ "POST /workflows/*/runs": ["workflows:run"],
395
+ "POST /workflows/*/runs/*/continue": ["workflows:run"],
396
+ "POST /workflows/*/runs/*/cancel": ["workflows:run"],
397
+ # Session endpoints
398
+ "GET /sessions": ["sessions:read"],
399
+ "GET /sessions/*": ["sessions:read"],
400
+ "POST /sessions": ["sessions:write"],
401
+ "POST /sessions/*/rename": ["sessions:write"],
402
+ "PATCH /sessions/*": ["sessions:write"],
403
+ "DELETE /sessions": ["sessions:delete"],
404
+ "DELETE /sessions/*": ["sessions:delete"],
405
+ # Memory endpoints
406
+ "GET /memories": ["memories:read"],
407
+ "GET /memories/*": ["memories:read"],
408
+ "GET /memory_topics": ["memories:read"],
409
+ "GET /user_memory_stats": ["memories:read"],
410
+ "POST /memories": ["memories:write"],
411
+ "PATCH /memories/*": ["memories:write"],
412
+ "DELETE /memories": ["memories:delete"],
413
+ "DELETE /memories/*": ["memories:delete"],
414
+ "POST /optimize-memories": ["memories:write"],
415
+ # Knowledge endpoints
416
+ "GET /knowledge/content": ["knowledge:read"],
417
+ "GET /knowledge/content/*": ["knowledge:read"],
418
+ "GET /knowledge/config": ["knowledge:read"],
419
+ "POST /knowledge/content": ["knowledge:write"],
420
+ "PATCH /knowledge/content/*": ["knowledge:write"],
421
+ "POST /knowledge/search": ["knowledge:read"],
422
+ "DELETE /knowledge/content": ["knowledge:delete"],
423
+ "DELETE /knowledge/content/*": ["knowledge:delete"],
424
+ # Metrics endpoints
425
+ "GET /metrics": ["metrics:read"],
426
+ "POST /metrics/refresh": ["metrics:write"],
427
+ # Evaluation endpoints
428
+ "GET /eval-runs": ["evals:read"],
429
+ "GET /eval-runs/*": ["evals:read"],
430
+ "POST /eval-runs": ["evals:write"],
431
+ "PATCH /eval-runs/*": ["evals:write"],
432
+ "DELETE /eval-runs": ["evals:delete"],
433
+ # Trace endpoints
434
+ "GET /traces": ["traces:read"],
435
+ "GET /traces/*": ["traces:read"],
436
+ "GET /trace_session_stats": ["traces:read"],
437
+ }
438
+
439
+
440
+ def get_scope_value(scope: AgentOSScope) -> str:
441
+ """
442
+ Get the string value of a scope.
443
+
444
+ Args:
445
+ scope: The AgentOSScope enum value
446
+
447
+ Returns:
448
+ The string value of the scope
449
+
450
+ Example:
451
+ >>> get_scope_value(AgentOSScope.ADMIN)
452
+ 'admin'
453
+ """
454
+ return scope.value
455
+
456
+
457
+ def get_all_scopes() -> list[str]:
458
+ """
459
+ Get a list of all available scope strings.
460
+
461
+ Returns:
462
+ List of all scope string values
463
+
464
+ Example:
465
+ >>> scopes = get_all_scopes()
466
+ >>> 'admin' in scopes
467
+ True
468
+ """
469
+ return [scope.value for scope in AgentOSScope]
agno/os/settings.py CHANGED
@@ -20,6 +20,9 @@ class AgnoAPISettings(BaseSettings):
20
20
  # Authentication settings
21
21
  os_security_key: Optional[str] = Field(default=None, description="Bearer token for API authentication")
22
22
 
23
+ # Authorization flag - when True, JWT middleware handles auth and security key validation is skipped
24
+ authorization_enabled: bool = Field(default=False, description="Whether JWT authorization is enabled")
25
+
23
26
  # Cors origin list to allow requests from.
24
27
  # This list is set using the set_cors_origin_list validator
25
28
  cors_origin_list: Optional[List[str]] = Field(default=None, validate_default=True)