agno 2.1.2__py3-none-any.whl → 2.3.13__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 (314) hide show
  1. agno/agent/agent.py +5540 -2273
  2. agno/api/api.py +2 -0
  3. agno/api/os.py +1 -1
  4. agno/compression/__init__.py +3 -0
  5. agno/compression/manager.py +247 -0
  6. agno/culture/__init__.py +3 -0
  7. agno/culture/manager.py +956 -0
  8. agno/db/async_postgres/__init__.py +3 -0
  9. agno/db/base.py +689 -6
  10. agno/db/dynamo/dynamo.py +933 -37
  11. agno/db/dynamo/schemas.py +174 -10
  12. agno/db/dynamo/utils.py +63 -4
  13. agno/db/firestore/firestore.py +831 -9
  14. agno/db/firestore/schemas.py +51 -0
  15. agno/db/firestore/utils.py +102 -4
  16. agno/db/gcs_json/gcs_json_db.py +660 -12
  17. agno/db/gcs_json/utils.py +60 -26
  18. agno/db/in_memory/in_memory_db.py +287 -14
  19. agno/db/in_memory/utils.py +60 -2
  20. agno/db/json/json_db.py +590 -14
  21. agno/db/json/utils.py +60 -26
  22. agno/db/migrations/manager.py +199 -0
  23. agno/db/migrations/v1_to_v2.py +43 -13
  24. agno/db/migrations/versions/__init__.py +0 -0
  25. agno/db/migrations/versions/v2_3_0.py +938 -0
  26. agno/db/mongo/__init__.py +15 -1
  27. agno/db/mongo/async_mongo.py +2760 -0
  28. agno/db/mongo/mongo.py +879 -11
  29. agno/db/mongo/schemas.py +42 -0
  30. agno/db/mongo/utils.py +80 -8
  31. agno/db/mysql/__init__.py +2 -1
  32. agno/db/mysql/async_mysql.py +2912 -0
  33. agno/db/mysql/mysql.py +946 -68
  34. agno/db/mysql/schemas.py +72 -10
  35. agno/db/mysql/utils.py +198 -7
  36. agno/db/postgres/__init__.py +2 -1
  37. agno/db/postgres/async_postgres.py +2579 -0
  38. agno/db/postgres/postgres.py +942 -57
  39. agno/db/postgres/schemas.py +81 -18
  40. agno/db/postgres/utils.py +164 -2
  41. agno/db/redis/redis.py +671 -7
  42. agno/db/redis/schemas.py +50 -0
  43. agno/db/redis/utils.py +65 -7
  44. agno/db/schemas/__init__.py +2 -1
  45. agno/db/schemas/culture.py +120 -0
  46. agno/db/schemas/evals.py +1 -0
  47. agno/db/schemas/memory.py +17 -2
  48. agno/db/singlestore/schemas.py +63 -0
  49. agno/db/singlestore/singlestore.py +949 -83
  50. agno/db/singlestore/utils.py +60 -2
  51. agno/db/sqlite/__init__.py +2 -1
  52. agno/db/sqlite/async_sqlite.py +2911 -0
  53. agno/db/sqlite/schemas.py +62 -0
  54. agno/db/sqlite/sqlite.py +965 -46
  55. agno/db/sqlite/utils.py +169 -8
  56. agno/db/surrealdb/__init__.py +3 -0
  57. agno/db/surrealdb/metrics.py +292 -0
  58. agno/db/surrealdb/models.py +334 -0
  59. agno/db/surrealdb/queries.py +71 -0
  60. agno/db/surrealdb/surrealdb.py +1908 -0
  61. agno/db/surrealdb/utils.py +147 -0
  62. agno/db/utils.py +2 -0
  63. agno/eval/__init__.py +10 -0
  64. agno/eval/accuracy.py +75 -55
  65. agno/eval/agent_as_judge.py +861 -0
  66. agno/eval/base.py +29 -0
  67. agno/eval/performance.py +16 -7
  68. agno/eval/reliability.py +28 -16
  69. agno/eval/utils.py +35 -17
  70. agno/exceptions.py +27 -2
  71. agno/filters.py +354 -0
  72. agno/guardrails/prompt_injection.py +1 -0
  73. agno/hooks/__init__.py +3 -0
  74. agno/hooks/decorator.py +164 -0
  75. agno/integrations/discord/client.py +1 -1
  76. agno/knowledge/chunking/agentic.py +13 -10
  77. agno/knowledge/chunking/fixed.py +4 -1
  78. agno/knowledge/chunking/semantic.py +9 -4
  79. agno/knowledge/chunking/strategy.py +59 -15
  80. agno/knowledge/embedder/fastembed.py +1 -1
  81. agno/knowledge/embedder/nebius.py +1 -1
  82. agno/knowledge/embedder/ollama.py +8 -0
  83. agno/knowledge/embedder/openai.py +8 -8
  84. agno/knowledge/embedder/sentence_transformer.py +6 -2
  85. agno/knowledge/embedder/vllm.py +262 -0
  86. agno/knowledge/knowledge.py +1618 -318
  87. agno/knowledge/reader/base.py +6 -2
  88. agno/knowledge/reader/csv_reader.py +8 -10
  89. agno/knowledge/reader/docx_reader.py +5 -6
  90. agno/knowledge/reader/field_labeled_csv_reader.py +16 -20
  91. agno/knowledge/reader/json_reader.py +5 -4
  92. agno/knowledge/reader/markdown_reader.py +8 -8
  93. agno/knowledge/reader/pdf_reader.py +17 -19
  94. agno/knowledge/reader/pptx_reader.py +101 -0
  95. agno/knowledge/reader/reader_factory.py +32 -3
  96. agno/knowledge/reader/s3_reader.py +3 -3
  97. agno/knowledge/reader/tavily_reader.py +193 -0
  98. agno/knowledge/reader/text_reader.py +22 -10
  99. agno/knowledge/reader/web_search_reader.py +1 -48
  100. agno/knowledge/reader/website_reader.py +10 -10
  101. agno/knowledge/reader/wikipedia_reader.py +33 -1
  102. agno/knowledge/types.py +1 -0
  103. agno/knowledge/utils.py +72 -7
  104. agno/media.py +22 -6
  105. agno/memory/__init__.py +14 -1
  106. agno/memory/manager.py +544 -83
  107. agno/memory/strategies/__init__.py +15 -0
  108. agno/memory/strategies/base.py +66 -0
  109. agno/memory/strategies/summarize.py +196 -0
  110. agno/memory/strategies/types.py +37 -0
  111. agno/models/aimlapi/aimlapi.py +17 -0
  112. agno/models/anthropic/claude.py +515 -40
  113. agno/models/aws/bedrock.py +102 -21
  114. agno/models/aws/claude.py +131 -274
  115. agno/models/azure/ai_foundry.py +41 -19
  116. agno/models/azure/openai_chat.py +39 -8
  117. agno/models/base.py +1249 -525
  118. agno/models/cerebras/cerebras.py +91 -21
  119. agno/models/cerebras/cerebras_openai.py +21 -2
  120. agno/models/cohere/chat.py +40 -6
  121. agno/models/cometapi/cometapi.py +18 -1
  122. agno/models/dashscope/dashscope.py +2 -3
  123. agno/models/deepinfra/deepinfra.py +18 -1
  124. agno/models/deepseek/deepseek.py +69 -3
  125. agno/models/fireworks/fireworks.py +18 -1
  126. agno/models/google/gemini.py +877 -80
  127. agno/models/google/utils.py +22 -0
  128. agno/models/groq/groq.py +51 -18
  129. agno/models/huggingface/huggingface.py +17 -6
  130. agno/models/ibm/watsonx.py +16 -6
  131. agno/models/internlm/internlm.py +18 -1
  132. agno/models/langdb/langdb.py +13 -1
  133. agno/models/litellm/chat.py +44 -9
  134. agno/models/litellm/litellm_openai.py +18 -1
  135. agno/models/message.py +28 -5
  136. agno/models/meta/llama.py +47 -14
  137. agno/models/meta/llama_openai.py +22 -17
  138. agno/models/mistral/mistral.py +8 -4
  139. agno/models/nebius/nebius.py +6 -7
  140. agno/models/nvidia/nvidia.py +20 -3
  141. agno/models/ollama/chat.py +24 -8
  142. agno/models/openai/chat.py +104 -29
  143. agno/models/openai/responses.py +101 -81
  144. agno/models/openrouter/openrouter.py +60 -3
  145. agno/models/perplexity/perplexity.py +17 -1
  146. agno/models/portkey/portkey.py +7 -6
  147. agno/models/requesty/requesty.py +24 -4
  148. agno/models/response.py +73 -2
  149. agno/models/sambanova/sambanova.py +20 -3
  150. agno/models/siliconflow/siliconflow.py +19 -2
  151. agno/models/together/together.py +20 -3
  152. agno/models/utils.py +254 -8
  153. agno/models/vercel/v0.py +20 -3
  154. agno/models/vertexai/__init__.py +0 -0
  155. agno/models/vertexai/claude.py +190 -0
  156. agno/models/vllm/vllm.py +19 -14
  157. agno/models/xai/xai.py +19 -2
  158. agno/os/app.py +549 -152
  159. agno/os/auth.py +190 -3
  160. agno/os/config.py +23 -0
  161. agno/os/interfaces/a2a/router.py +8 -11
  162. agno/os/interfaces/a2a/utils.py +1 -1
  163. agno/os/interfaces/agui/router.py +18 -3
  164. agno/os/interfaces/agui/utils.py +152 -39
  165. agno/os/interfaces/slack/router.py +55 -37
  166. agno/os/interfaces/slack/slack.py +9 -1
  167. agno/os/interfaces/whatsapp/router.py +0 -1
  168. agno/os/interfaces/whatsapp/security.py +3 -1
  169. agno/os/mcp.py +110 -52
  170. agno/os/middleware/__init__.py +2 -0
  171. agno/os/middleware/jwt.py +676 -112
  172. agno/os/router.py +40 -1478
  173. agno/os/routers/agents/__init__.py +3 -0
  174. agno/os/routers/agents/router.py +599 -0
  175. agno/os/routers/agents/schema.py +261 -0
  176. agno/os/routers/evals/evals.py +96 -39
  177. agno/os/routers/evals/schemas.py +65 -33
  178. agno/os/routers/evals/utils.py +80 -10
  179. agno/os/routers/health.py +10 -4
  180. agno/os/routers/knowledge/knowledge.py +196 -38
  181. agno/os/routers/knowledge/schemas.py +82 -22
  182. agno/os/routers/memory/memory.py +279 -52
  183. agno/os/routers/memory/schemas.py +46 -17
  184. agno/os/routers/metrics/metrics.py +20 -8
  185. agno/os/routers/metrics/schemas.py +16 -16
  186. agno/os/routers/session/session.py +462 -34
  187. agno/os/routers/teams/__init__.py +3 -0
  188. agno/os/routers/teams/router.py +512 -0
  189. agno/os/routers/teams/schema.py +257 -0
  190. agno/os/routers/traces/__init__.py +3 -0
  191. agno/os/routers/traces/schemas.py +414 -0
  192. agno/os/routers/traces/traces.py +499 -0
  193. agno/os/routers/workflows/__init__.py +3 -0
  194. agno/os/routers/workflows/router.py +624 -0
  195. agno/os/routers/workflows/schema.py +75 -0
  196. agno/os/schema.py +256 -693
  197. agno/os/scopes.py +469 -0
  198. agno/os/utils.py +514 -36
  199. agno/reasoning/anthropic.py +80 -0
  200. agno/reasoning/gemini.py +73 -0
  201. agno/reasoning/openai.py +5 -0
  202. agno/reasoning/vertexai.py +76 -0
  203. agno/run/__init__.py +6 -0
  204. agno/run/agent.py +155 -32
  205. agno/run/base.py +55 -3
  206. agno/run/requirement.py +181 -0
  207. agno/run/team.py +125 -38
  208. agno/run/workflow.py +72 -18
  209. agno/session/agent.py +102 -89
  210. agno/session/summary.py +56 -15
  211. agno/session/team.py +164 -90
  212. agno/session/workflow.py +405 -40
  213. agno/table.py +10 -0
  214. agno/team/team.py +3974 -1903
  215. agno/tools/dalle.py +2 -4
  216. agno/tools/eleven_labs.py +23 -25
  217. agno/tools/exa.py +21 -16
  218. agno/tools/file.py +153 -23
  219. agno/tools/file_generation.py +16 -10
  220. agno/tools/firecrawl.py +15 -7
  221. agno/tools/function.py +193 -38
  222. agno/tools/gmail.py +238 -14
  223. agno/tools/google_drive.py +271 -0
  224. agno/tools/googlecalendar.py +36 -8
  225. agno/tools/googlesheets.py +20 -5
  226. agno/tools/jira.py +20 -0
  227. agno/tools/mcp/__init__.py +10 -0
  228. agno/tools/mcp/mcp.py +331 -0
  229. agno/tools/mcp/multi_mcp.py +347 -0
  230. agno/tools/mcp/params.py +24 -0
  231. agno/tools/mcp_toolbox.py +3 -3
  232. agno/tools/models/nebius.py +5 -5
  233. agno/tools/models_labs.py +20 -10
  234. agno/tools/nano_banana.py +151 -0
  235. agno/tools/notion.py +204 -0
  236. agno/tools/parallel.py +314 -0
  237. agno/tools/postgres.py +76 -36
  238. agno/tools/redshift.py +406 -0
  239. agno/tools/scrapegraph.py +1 -1
  240. agno/tools/shopify.py +1519 -0
  241. agno/tools/slack.py +18 -3
  242. agno/tools/spotify.py +919 -0
  243. agno/tools/tavily.py +146 -0
  244. agno/tools/toolkit.py +25 -0
  245. agno/tools/workflow.py +8 -1
  246. agno/tools/yfinance.py +12 -11
  247. agno/tracing/__init__.py +12 -0
  248. agno/tracing/exporter.py +157 -0
  249. agno/tracing/schemas.py +276 -0
  250. agno/tracing/setup.py +111 -0
  251. agno/utils/agent.py +938 -0
  252. agno/utils/cryptography.py +22 -0
  253. agno/utils/dttm.py +33 -0
  254. agno/utils/events.py +151 -3
  255. agno/utils/gemini.py +15 -5
  256. agno/utils/hooks.py +118 -4
  257. agno/utils/http.py +113 -2
  258. agno/utils/knowledge.py +12 -5
  259. agno/utils/log.py +1 -0
  260. agno/utils/mcp.py +92 -2
  261. agno/utils/media.py +187 -1
  262. agno/utils/merge_dict.py +3 -3
  263. agno/utils/message.py +60 -0
  264. agno/utils/models/ai_foundry.py +9 -2
  265. agno/utils/models/claude.py +49 -14
  266. agno/utils/models/cohere.py +9 -2
  267. agno/utils/models/llama.py +9 -2
  268. agno/utils/models/mistral.py +4 -2
  269. agno/utils/print_response/agent.py +109 -16
  270. agno/utils/print_response/team.py +223 -30
  271. agno/utils/print_response/workflow.py +251 -34
  272. agno/utils/streamlit.py +1 -1
  273. agno/utils/team.py +98 -9
  274. agno/utils/tokens.py +657 -0
  275. agno/vectordb/base.py +39 -7
  276. agno/vectordb/cassandra/cassandra.py +21 -5
  277. agno/vectordb/chroma/chromadb.py +43 -12
  278. agno/vectordb/clickhouse/clickhousedb.py +21 -5
  279. agno/vectordb/couchbase/couchbase.py +29 -5
  280. agno/vectordb/lancedb/lance_db.py +92 -181
  281. agno/vectordb/langchaindb/langchaindb.py +24 -4
  282. agno/vectordb/lightrag/lightrag.py +17 -3
  283. agno/vectordb/llamaindex/llamaindexdb.py +25 -5
  284. agno/vectordb/milvus/milvus.py +50 -37
  285. agno/vectordb/mongodb/__init__.py +7 -1
  286. agno/vectordb/mongodb/mongodb.py +36 -30
  287. agno/vectordb/pgvector/pgvector.py +201 -77
  288. agno/vectordb/pineconedb/pineconedb.py +41 -23
  289. agno/vectordb/qdrant/qdrant.py +67 -54
  290. agno/vectordb/redis/__init__.py +9 -0
  291. agno/vectordb/redis/redisdb.py +682 -0
  292. agno/vectordb/singlestore/singlestore.py +50 -29
  293. agno/vectordb/surrealdb/surrealdb.py +31 -41
  294. agno/vectordb/upstashdb/upstashdb.py +34 -6
  295. agno/vectordb/weaviate/weaviate.py +53 -14
  296. agno/workflow/__init__.py +2 -0
  297. agno/workflow/agent.py +299 -0
  298. agno/workflow/condition.py +120 -18
  299. agno/workflow/loop.py +77 -10
  300. agno/workflow/parallel.py +231 -143
  301. agno/workflow/router.py +118 -17
  302. agno/workflow/step.py +609 -170
  303. agno/workflow/steps.py +73 -6
  304. agno/workflow/types.py +96 -21
  305. agno/workflow/workflow.py +2039 -262
  306. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/METADATA +201 -66
  307. agno-2.3.13.dist-info/RECORD +613 -0
  308. agno/tools/googlesearch.py +0 -98
  309. agno/tools/mcp.py +0 -679
  310. agno/tools/memori.py +0 -339
  311. agno-2.1.2.dist-info/RECORD +0 -543
  312. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +0 -0
  313. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/licenses/LICENSE +0 -0
  314. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ from typing import Optional, Union
2
2
 
3
3
  from fastapi import APIRouter, BackgroundTasks, HTTPException, Request
4
4
  from pydantic import BaseModel, Field
@@ -24,19 +24,21 @@ class SlackChallengeResponse(BaseModel):
24
24
 
25
25
 
26
26
  def attach_routes(
27
- router: APIRouter, agent: Optional[Agent] = None, team: Optional[Team] = None, workflow: Optional[Workflow] = None
27
+ router: APIRouter,
28
+ agent: Optional[Agent] = None,
29
+ team: Optional[Team] = None,
30
+ workflow: Optional[Workflow] = None,
31
+ reply_to_mentions_only: bool = True,
28
32
  ) -> APIRouter:
29
33
  # Determine entity type for documentation
30
34
  entity_type = "agent" if agent else "team" if team else "workflow" if workflow else "unknown"
31
- entity_name = getattr(agent or team or workflow, "name", f"Unnamed {entity_type}")
32
35
 
33
36
  @router.post(
34
37
  "/events",
35
38
  operation_id=f"slack_events_{entity_type}",
36
- summary=f"Process Slack Events for {entity_type.title()}",
37
- description=f"Process incoming Slack events and route them to the configured {entity_type}: {entity_name}",
38
- tags=["Slack", f"Slack-{entity_type.title()}"],
39
- response_model=SlackEventResponse,
39
+ name="slack_events",
40
+ description="Process incoming Slack events",
41
+ response_model=Union[SlackChallengeResponse, SlackEventResponse],
40
42
  response_model_exclude_none=True,
41
43
  responses={
42
44
  200: {"description": "Event processed successfully"},
@@ -73,36 +75,52 @@ def attach_routes(
73
75
  return SlackEventResponse(status="ok")
74
76
 
75
77
  async def _process_slack_event(event: dict):
76
- if event.get("type") == "message":
77
- user = None
78
- message_text = event.get("text", "")
79
- channel_id = event.get("channel", "")
80
- user = event.get("user")
81
- if event.get("thread_ts"):
82
- ts = event.get("thread_ts", "")
83
- else:
84
- ts = event.get("ts", "")
85
-
86
- # Use the timestamp as the session id, so that each thread is a separate session
87
- session_id = ts
88
-
89
- if agent:
90
- response = await agent.arun(message_text, user_id=user if user else None, session_id=session_id)
91
- elif team:
92
- response = await team.arun(message_text, user_id=user if user else None, session_id=session_id) # type: ignore
93
- elif workflow:
94
- response = await workflow.arun(message_text, user_id=user if user else None, session_id=session_id) # type: ignore
95
-
96
- if response:
97
- if hasattr(response, "reasoning_content") and response.reasoning_content:
98
- _send_slack_message(
99
- channel=channel_id,
100
- message=f"Reasoning: \n{response.reasoning_content}",
101
- thread_ts=ts,
102
- italics=True,
103
- )
104
-
105
- _send_slack_message(channel=channel_id, message=response.content or "", thread_ts=ts)
78
+ event_type = event.get("type")
79
+
80
+ # Only handle app_mention and message events
81
+ if event_type not in ("app_mention", "message"):
82
+ return
83
+
84
+ channel_type = event.get("channel_type", "")
85
+
86
+ # Handle duplicate replies
87
+ if not reply_to_mentions_only and event_type == "app_mention":
88
+ return
89
+
90
+ # If reply_to_mentions_only is True, ignore every message that is not a DM
91
+ if reply_to_mentions_only and event_type == "message" and channel_type != "im":
92
+ return
93
+
94
+ # Extract event data
95
+ user = None
96
+ message_text = event.get("text", "")
97
+ channel_id = event.get("channel", "")
98
+ user = event.get("user")
99
+ if event.get("thread_ts"):
100
+ ts = event.get("thread_ts", "")
101
+ else:
102
+ ts = event.get("ts", "")
103
+
104
+ # Use the timestamp as the session id, so that each thread is a separate session
105
+ session_id = ts
106
+
107
+ if agent:
108
+ response = await agent.arun(message_text, user_id=user, session_id=session_id)
109
+ elif team:
110
+ response = await team.arun(message_text, user_id=user, session_id=session_id) # type: ignore
111
+ elif workflow:
112
+ response = await workflow.arun(message_text, user_id=user, session_id=session_id) # type: ignore
113
+
114
+ if response:
115
+ if hasattr(response, "reasoning_content") and response.reasoning_content:
116
+ _send_slack_message(
117
+ channel=channel_id,
118
+ message=f"Reasoning: \n{response.reasoning_content}",
119
+ thread_ts=ts,
120
+ italics=True,
121
+ )
122
+
123
+ _send_slack_message(channel=channel_id, message=response.content or "", thread_ts=ts)
106
124
 
107
125
  def _send_slack_message(channel: str, thread_ts: str, message: str, italics: bool = False):
108
126
  if len(message) <= 40000:
@@ -21,12 +21,14 @@ class Slack(BaseInterface):
21
21
  workflow: Optional[Workflow] = None,
22
22
  prefix: str = "/slack",
23
23
  tags: Optional[List[str]] = None,
24
+ reply_to_mentions_only: bool = True,
24
25
  ):
25
26
  self.agent = agent
26
27
  self.team = team
27
28
  self.workflow = workflow
28
29
  self.prefix = prefix
29
30
  self.tags = tags or ["Slack"]
31
+ self.reply_to_mentions_only = reply_to_mentions_only
30
32
 
31
33
  if not (self.agent or self.team or self.workflow):
32
34
  raise ValueError("Slack requires an agent, team or workflow")
@@ -34,6 +36,12 @@ class Slack(BaseInterface):
34
36
  def get_router(self) -> APIRouter:
35
37
  self.router = APIRouter(prefix=self.prefix, tags=self.tags) # type: ignore
36
38
 
37
- self.router = attach_routes(router=self.router, agent=self.agent, team=self.team, workflow=self.workflow)
39
+ self.router = attach_routes(
40
+ router=self.router,
41
+ agent=self.agent,
42
+ team=self.team,
43
+ workflow=self.workflow,
44
+ reply_to_mentions_only=self.reply_to_mentions_only,
45
+ )
38
46
 
39
47
  return self.router
@@ -171,7 +171,6 @@ def attach_routes(router: APIRouter, agent: Optional[Agent] = None, team: Option
171
171
  f"Could not process image content for user {phone_number}. Type: {type(image_content)}"
172
172
  )
173
173
  await _send_whatsapp_message(phone_number, response.content) # type: ignore
174
- await _send_whatsapp_message(phone_number, response.content) # type: ignore
175
174
  else:
176
175
  await _send_whatsapp_message(phone_number, response.content) # type: ignore
177
176
 
@@ -3,6 +3,8 @@ import hmac
3
3
  import os
4
4
  from typing import Optional
5
5
 
6
+ from agno.utils.log import log_warning
7
+
6
8
 
7
9
  def is_development_mode() -> bool:
8
10
  """Check if the application is running in development mode."""
@@ -36,7 +38,7 @@ def validate_webhook_signature(payload: bytes, signature_header: Optional[str])
36
38
  """
37
39
  # In development mode, we can bypass signature validation
38
40
  if is_development_mode():
39
- print("WARNING: Bypassing signature validation in development mode")
41
+ log_warning("Bypassing signature validation in development mode")
40
42
  return True
41
43
 
42
44
  if not signature_header or not signature_header.startswith("sha256="):
agno/os/mcp.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Router for MCP interface providing Model Context Protocol endpoints."""
2
2
 
3
3
  import logging
4
- from typing import TYPE_CHECKING, List, Optional
4
+ from typing import TYPE_CHECKING, List, Optional, cast
5
5
  from uuid import uuid4
6
6
 
7
7
  from fastmcp import FastMCP
@@ -9,7 +9,7 @@ from fastmcp.server.http import (
9
9
  StarletteWithLifespan,
10
10
  )
11
11
 
12
- from agno.db.base import SessionType
12
+ from agno.db.base import AsyncBaseDb, SessionType
13
13
  from agno.db.schemas import UserMemory
14
14
  from agno.os.routers.memory.schemas import (
15
15
  UserMemorySchema,
@@ -57,13 +57,14 @@ def get_mcp_server(
57
57
  os_id=os.id or "AgentOS",
58
58
  description=os.description,
59
59
  available_models=os.config.available_models if os.config else [],
60
- databases=[db.id for db in os.dbs.values()],
60
+ databases=[db.id for db_list in os.dbs.values() for db in db_list],
61
61
  chat=os.config.chat if os.config else None,
62
62
  session=os._get_session_config(),
63
63
  memory=os._get_memory_config(),
64
64
  knowledge=os._get_knowledge_config(),
65
65
  evals=os._get_evals_config(),
66
66
  metrics=os._get_metrics_config(),
67
+ traces=os._get_traces_config(),
67
68
  agents=[AgentSummaryResponse.from_agent(agent) for agent in os.agents] if os.agents else [],
68
69
  teams=[TeamSummaryResponse.from_team(team) for team in os.teams] if os.teams else [],
69
70
  workflows=[WorkflowSummaryResponse.from_workflow(w) for w in os.workflows] if os.workflows else [],
@@ -78,21 +79,21 @@ def get_mcp_server(
78
79
  agent = get_agent_by_id(agent_id, os.agents)
79
80
  if agent is None:
80
81
  raise Exception(f"Agent {agent_id} not found")
81
- return agent.run(message)
82
+ return await agent.arun(message)
82
83
 
83
84
  @mcp.tool(name="run_team", description="Run a team", tags={"core"}) # type: ignore
84
85
  async def run_team(team_id: str, message: str) -> TeamRunOutput:
85
86
  team = get_team_by_id(team_id, os.teams)
86
87
  if team is None:
87
88
  raise Exception(f"Team {team_id} not found")
88
- return team.run(message)
89
+ return await team.arun(message)
89
90
 
90
91
  @mcp.tool(name="run_workflow", description="Run a workflow", tags={"core"}) # type: ignore
91
92
  async def run_workflow(workflow_id: str, message: str) -> WorkflowRunOutput:
92
93
  workflow = get_workflow_by_id(workflow_id, os.workflows)
93
94
  if workflow is None:
94
95
  raise Exception(f"Workflow {workflow_id} not found")
95
- return workflow.run(message)
96
+ return await workflow.arun(message)
96
97
 
97
98
  # Session Management Tools
98
99
  @mcp.tool(name="get_sessions_for_agent", description="Get list of sessions for an agent", tags={"session"}) # type: ignore
@@ -103,15 +104,26 @@ def get_mcp_server(
103
104
  sort_by: str = "created_at",
104
105
  sort_order: str = "desc",
105
106
  ):
106
- db = get_db(os.dbs, db_id)
107
- sessions, _ = db.get_sessions(
108
- session_type=SessionType.AGENT,
109
- component_id=agent_id,
110
- user_id=user_id,
111
- sort_by=sort_by,
112
- sort_order=sort_order,
113
- deserialize=False,
114
- )
107
+ db = await get_db(os.dbs, db_id)
108
+ if isinstance(db, AsyncBaseDb):
109
+ db = cast(AsyncBaseDb, db)
110
+ sessions = await db.get_sessions(
111
+ session_type=SessionType.AGENT,
112
+ component_id=agent_id,
113
+ user_id=user_id,
114
+ sort_by=sort_by,
115
+ sort_order=sort_order,
116
+ deserialize=False,
117
+ )
118
+ else:
119
+ sessions = db.get_sessions(
120
+ session_type=SessionType.AGENT,
121
+ component_id=agent_id,
122
+ user_id=user_id,
123
+ sort_by=sort_by,
124
+ sort_order=sort_order,
125
+ deserialize=False,
126
+ )
115
127
 
116
128
  return {
117
129
  "data": [SessionSchema.from_dict(session) for session in sessions], # type: ignore
@@ -125,15 +137,26 @@ def get_mcp_server(
125
137
  sort_by: str = "created_at",
126
138
  sort_order: str = "desc",
127
139
  ):
128
- db = get_db(os.dbs, db_id)
129
- sessions, _ = db.get_sessions(
130
- session_type=SessionType.TEAM,
131
- component_id=team_id,
132
- user_id=user_id,
133
- sort_by=sort_by,
134
- sort_order=sort_order,
135
- deserialize=False,
136
- )
140
+ db = await get_db(os.dbs, db_id)
141
+ if isinstance(db, AsyncBaseDb):
142
+ db = cast(AsyncBaseDb, db)
143
+ sessions = await db.get_sessions(
144
+ session_type=SessionType.TEAM,
145
+ component_id=team_id,
146
+ user_id=user_id,
147
+ sort_by=sort_by,
148
+ sort_order=sort_order,
149
+ deserialize=False,
150
+ )
151
+ else:
152
+ sessions = db.get_sessions(
153
+ session_type=SessionType.TEAM,
154
+ component_id=team_id,
155
+ user_id=user_id,
156
+ sort_by=sort_by,
157
+ sort_order=sort_order,
158
+ deserialize=False,
159
+ )
137
160
 
138
161
  return {
139
162
  "data": [SessionSchema.from_dict(session) for session in sessions], # type: ignore
@@ -147,15 +170,26 @@ def get_mcp_server(
147
170
  sort_by: str = "created_at",
148
171
  sort_order: str = "desc",
149
172
  ):
150
- db = get_db(os.dbs, db_id)
151
- sessions, _ = db.get_sessions(
152
- session_type=SessionType.WORKFLOW,
153
- component_id=workflow_id,
154
- user_id=user_id,
155
- sort_by=sort_by,
156
- sort_order=sort_order,
157
- deserialize=False,
158
- )
173
+ db = await get_db(os.dbs, db_id)
174
+ if isinstance(db, AsyncBaseDb):
175
+ db = cast(AsyncBaseDb, db)
176
+ sessions = await db.get_sessions(
177
+ session_type=SessionType.WORKFLOW,
178
+ component_id=workflow_id,
179
+ user_id=user_id,
180
+ sort_by=sort_by,
181
+ sort_order=sort_order,
182
+ deserialize=False,
183
+ )
184
+ else:
185
+ sessions = db.get_sessions(
186
+ session_type=SessionType.WORKFLOW,
187
+ component_id=workflow_id,
188
+ user_id=user_id,
189
+ sort_by=sort_by,
190
+ sort_order=sort_order,
191
+ deserialize=False,
192
+ )
159
193
 
160
194
  return {
161
195
  "data": [SessionSchema.from_dict(session) for session in sessions], # type: ignore
@@ -169,7 +203,7 @@ def get_mcp_server(
169
203
  user_id: str,
170
204
  topics: Optional[List[str]] = None,
171
205
  ) -> UserMemorySchema:
172
- db = get_db(os.dbs, db_id)
206
+ db = await get_db(os.dbs, db_id)
173
207
  user_memory = db.upsert_user_memory(
174
208
  memory=UserMemory(
175
209
  memory_id=str(uuid4()),
@@ -191,13 +225,22 @@ def get_mcp_server(
191
225
  sort_order: str = "desc",
192
226
  db_id: Optional[str] = None,
193
227
  ):
194
- db = get_db(os.dbs, db_id)
195
- user_memories, _ = db.get_user_memories(
196
- user_id=user_id,
197
- sort_by=sort_by,
198
- sort_order=sort_order,
199
- deserialize=False,
200
- )
228
+ db = await get_db(os.dbs, db_id)
229
+ if isinstance(db, AsyncBaseDb):
230
+ db = cast(AsyncBaseDb, db)
231
+ user_memories = await db.get_user_memories(
232
+ user_id=user_id,
233
+ sort_by=sort_by,
234
+ sort_order=sort_order,
235
+ deserialize=False,
236
+ )
237
+ else:
238
+ user_memories = db.get_user_memories(
239
+ user_id=user_id,
240
+ sort_by=sort_by,
241
+ sort_order=sort_order,
242
+ deserialize=False,
243
+ )
201
244
  return {
202
245
  "data": [UserMemorySchema.from_dict(user_memory) for user_memory in user_memories], # type: ignore
203
246
  }
@@ -209,15 +252,26 @@ def get_mcp_server(
209
252
  memory: str,
210
253
  user_id: str,
211
254
  ) -> UserMemorySchema:
212
- db = get_db(os.dbs, db_id)
213
- user_memory = db.upsert_user_memory(
214
- memory=UserMemory(
215
- memory_id=memory_id,
216
- memory=memory,
217
- user_id=user_id,
218
- ),
219
- deserialize=False,
220
- )
255
+ db = await get_db(os.dbs, db_id)
256
+ if isinstance(db, AsyncBaseDb):
257
+ db = cast(AsyncBaseDb, db)
258
+ user_memory = await db.upsert_user_memory(
259
+ memory=UserMemory(
260
+ memory_id=memory_id,
261
+ memory=memory,
262
+ user_id=user_id,
263
+ ),
264
+ deserialize=False,
265
+ )
266
+ else:
267
+ user_memory = db.upsert_user_memory(
268
+ memory=UserMemory(
269
+ memory_id=memory_id,
270
+ memory=memory,
271
+ user_id=user_id,
272
+ ),
273
+ deserialize=False,
274
+ )
221
275
  if not user_memory:
222
276
  raise Exception("Failed to update memory")
223
277
 
@@ -228,8 +282,12 @@ def get_mcp_server(
228
282
  db_id: str,
229
283
  memory_id: str,
230
284
  ) -> None:
231
- db = get_db(os.dbs, db_id)
232
- db.delete_user_memory(memory_id=memory_id)
285
+ db = await get_db(os.dbs, db_id)
286
+ if isinstance(db, AsyncBaseDb):
287
+ db = cast(AsyncBaseDb, db)
288
+ await db.delete_user_memory(memory_id=memory_id)
289
+ else:
290
+ db.delete_user_memory(memory_id=memory_id)
233
291
 
234
292
  mcp_app = mcp.http_app(path="/mcp")
235
293
  return mcp_app
@@ -1,7 +1,9 @@
1
1
  from agno.os.middleware.jwt import (
2
2
  JWTMiddleware,
3
+ TokenSource,
3
4
  )
4
5
 
5
6
  __all__ = [
6
7
  "JWTMiddleware",
8
+ "TokenSource",
7
9
  ]