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/utils/agent.py CHANGED
@@ -1,14 +1,32 @@
1
+ import asyncio
1
2
  from asyncio import Future, Task
2
- from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, Iterator, List, Optional, Sequence, Union
3
+ from typing import (
4
+ TYPE_CHECKING,
5
+ Any,
6
+ AsyncIterator,
7
+ Awaitable,
8
+ Callable,
9
+ Dict,
10
+ Iterator,
11
+ List,
12
+ Optional,
13
+ Sequence,
14
+ Type,
15
+ Union,
16
+ )
17
+
18
+ from pydantic import BaseModel
3
19
 
4
20
  from agno.media import Audio, File, Image, Video
5
21
  from agno.models.message import Message
6
22
  from agno.models.metrics import Metrics
7
23
  from agno.models.response import ModelResponse
24
+ from agno.run import RunContext
8
25
  from agno.run.agent import RunEvent, RunInput, RunOutput, RunOutputEvent
9
26
  from agno.run.team import RunOutputEvent as TeamRunOutputEvent
10
27
  from agno.run.team import TeamRunOutput
11
28
  from agno.session import AgentSession, TeamSession, WorkflowSession
29
+ from agno.utils.common import is_typed_dict, validate_typed_dict
12
30
  from agno.utils.events import (
13
31
  create_memory_update_completed_event,
14
32
  create_memory_update_started_event,
@@ -23,9 +41,10 @@ if TYPE_CHECKING:
23
41
  from agno.team.team import Team
24
42
 
25
43
 
26
- async def await_for_background_tasks(
44
+ async def await_for_open_threads(
27
45
  memory_task: Optional[Task] = None,
28
46
  cultural_knowledge_task: Optional[Task] = None,
47
+ learning_task: Optional[Task] = None,
29
48
  ) -> None:
30
49
  if memory_task is not None:
31
50
  try:
@@ -39,9 +58,17 @@ async def await_for_background_tasks(
39
58
  except Exception as e:
40
59
  log_warning(f"Error in cultural knowledge creation: {str(e)}")
41
60
 
61
+ if learning_task is not None:
62
+ try:
63
+ await learning_task
64
+ except Exception as e:
65
+ log_warning(f"Error in learning extraction: {str(e)}")
42
66
 
43
- def wait_for_background_tasks(
44
- memory_future: Optional[Future] = None, cultural_knowledge_future: Optional[Future] = None
67
+
68
+ def wait_for_open_threads(
69
+ memory_future: Optional[Future] = None,
70
+ cultural_knowledge_future: Optional[Future] = None,
71
+ learning_future: Optional[Future] = None,
45
72
  ) -> None:
46
73
  if memory_future is not None:
47
74
  try:
@@ -56,14 +83,22 @@ def wait_for_background_tasks(
56
83
  except Exception as e:
57
84
  log_warning(f"Error in cultural knowledge creation: {str(e)}")
58
85
 
86
+ if learning_future is not None:
87
+ try:
88
+ learning_future.result()
89
+ except Exception as e:
90
+ log_warning(f"Error in learning extraction: {str(e)}")
59
91
 
60
- async def await_for_background_tasks_stream(
92
+
93
+ async def await_for_thread_tasks_stream(
61
94
  run_response: Union[RunOutput, TeamRunOutput],
62
95
  memory_task: Optional[Task] = None,
63
96
  cultural_knowledge_task: Optional[Task] = None,
97
+ learning_task: Optional[Task] = None,
64
98
  stream_events: bool = False,
65
99
  events_to_skip: Optional[List[RunEvent]] = None,
66
100
  store_events: bool = False,
101
+ get_memories_callback: Optional[Callable[[], Union[Optional[List[Any]], Awaitable[Optional[List[Any]]]]]] = None,
67
102
  ) -> AsyncIterator[RunOutputEvent]:
68
103
  if memory_task is not None:
69
104
  if stream_events:
@@ -86,16 +121,29 @@ async def await_for_background_tasks_stream(
86
121
  except Exception as e:
87
122
  log_warning(f"Error in memory creation: {str(e)}")
88
123
  if stream_events:
124
+ # Get memories after update if callback provided
125
+ memories = None
126
+ if get_memories_callback is not None:
127
+ try:
128
+ result = get_memories_callback()
129
+ # Handle both sync and async callbacks
130
+ if asyncio.iscoroutine(result):
131
+ memories = await result
132
+ else:
133
+ memories = result
134
+ except Exception as e:
135
+ log_warning(f"Error getting memories: {str(e)}")
136
+
89
137
  if isinstance(run_response, TeamRunOutput):
90
138
  yield handle_event( # type: ignore
91
- create_team_memory_update_completed_event(from_run_response=run_response),
139
+ create_team_memory_update_completed_event(from_run_response=run_response, memories=memories),
92
140
  run_response,
93
141
  events_to_skip=events_to_skip, # type: ignore
94
142
  store_events=store_events,
95
143
  )
96
144
  else:
97
145
  yield handle_event( # type: ignore
98
- create_memory_update_completed_event(from_run_response=run_response),
146
+ create_memory_update_completed_event(from_run_response=run_response, memories=memories),
99
147
  run_response,
100
148
  events_to_skip=events_to_skip, # type: ignore
101
149
  store_events=store_events,
@@ -107,14 +155,22 @@ async def await_for_background_tasks_stream(
107
155
  except Exception as e:
108
156
  log_warning(f"Error in cultural knowledge creation: {str(e)}")
109
157
 
158
+ if learning_task is not None:
159
+ try:
160
+ await learning_task
161
+ except Exception as e:
162
+ log_warning(f"Error in learning extraction: {str(e)}")
163
+
110
164
 
111
- def wait_for_background_tasks_stream(
165
+ def wait_for_thread_tasks_stream(
112
166
  run_response: Union[TeamRunOutput, RunOutput],
113
167
  memory_future: Optional[Future] = None,
114
168
  cultural_knowledge_future: Optional[Future] = None,
169
+ learning_future: Optional[Future] = None,
115
170
  stream_events: bool = False,
116
171
  events_to_skip: Optional[List[RunEvent]] = None,
117
172
  store_events: bool = False,
173
+ get_memories_callback: Optional[Callable[[], Optional[List[Any]]]] = None,
118
174
  ) -> Iterator[Union[RunOutputEvent, TeamRunOutputEvent]]:
119
175
  if memory_future is not None:
120
176
  if stream_events:
@@ -137,16 +193,24 @@ def wait_for_background_tasks_stream(
137
193
  except Exception as e:
138
194
  log_warning(f"Error in memory creation: {str(e)}")
139
195
  if stream_events:
196
+ # Get memories after update if callback provided
197
+ memories = None
198
+ if get_memories_callback is not None:
199
+ try:
200
+ memories = get_memories_callback()
201
+ except Exception as e:
202
+ log_warning(f"Error getting memories: {str(e)}")
203
+
140
204
  if isinstance(run_response, TeamRunOutput):
141
205
  yield handle_event( # type: ignore
142
- create_team_memory_update_completed_event(from_run_response=run_response),
206
+ create_team_memory_update_completed_event(from_run_response=run_response, memories=memories),
143
207
  run_response,
144
208
  events_to_skip=events_to_skip, # type: ignore
145
209
  store_events=store_events,
146
210
  )
147
211
  else:
148
212
  yield handle_event( # type: ignore
149
- create_memory_update_completed_event(from_run_response=run_response),
213
+ create_memory_update_completed_event(from_run_response=run_response, memories=memories),
150
214
  run_response,
151
215
  events_to_skip=events_to_skip, # type: ignore
152
216
  store_events=store_events,
@@ -160,6 +224,12 @@ def wait_for_background_tasks_stream(
160
224
  except Exception as e:
161
225
  log_warning(f"Error in cultural knowledge creation: {str(e)}")
162
226
 
227
+ if learning_future is not None:
228
+ try:
229
+ learning_future.result()
230
+ except Exception as e:
231
+ log_warning(f"Error in learning extraction: {str(e)}")
232
+
163
233
 
164
234
  def collect_joint_images(
165
235
  run_input: Optional[RunInput] = None,
@@ -818,3 +888,174 @@ async def aget_chat_history_util(entity: Union["Agent", "Team"], session_id: str
818
888
  raise Exception("Session not found")
819
889
 
820
890
  return session.get_chat_history() # type: ignore
891
+
892
+
893
+ def execute_instructions(
894
+ instructions: Callable,
895
+ agent: Optional[Union["Agent", "Team"]] = None,
896
+ team: Optional["Team"] = None,
897
+ session_state: Optional[Dict[str, Any]] = None,
898
+ run_context: Optional[RunContext] = None,
899
+ ) -> Union[str, List[str]]:
900
+ """Execute the instructions function."""
901
+ import inspect
902
+
903
+ signature = inspect.signature(instructions)
904
+ instruction_args: Dict[str, Any] = {}
905
+
906
+ # Check for agent parameter
907
+ if "agent" in signature.parameters:
908
+ instruction_args["agent"] = agent
909
+
910
+ if "team" in signature.parameters:
911
+ instruction_args["team"] = team
912
+
913
+ # Check for session_state parameter
914
+ if "session_state" in signature.parameters:
915
+ instruction_args["session_state"] = session_state if session_state is not None else {}
916
+
917
+ # Check for run_context parameter
918
+ if "run_context" in signature.parameters:
919
+ instruction_args["run_context"] = run_context or None
920
+
921
+ # Run the instructions function, await if it's awaitable, otherwise run directly (in thread)
922
+ if inspect.iscoroutinefunction(instructions):
923
+ raise Exception("Instructions function is async, use `agent.arun()` instead")
924
+
925
+ # Run the instructions function
926
+ return instructions(**instruction_args)
927
+
928
+
929
+ def execute_system_message(
930
+ system_message: Callable,
931
+ agent: Optional[Union["Agent", "Team"]] = None,
932
+ team: Optional["Team"] = None,
933
+ session_state: Optional[Dict[str, Any]] = None,
934
+ run_context: Optional[RunContext] = None,
935
+ ) -> str:
936
+ """Execute the system message function."""
937
+ import inspect
938
+
939
+ signature = inspect.signature(system_message)
940
+ system_message_args: Dict[str, Any] = {}
941
+
942
+ # Check for agent parameter
943
+ if "agent" in signature.parameters:
944
+ system_message_args["agent"] = agent
945
+ if "team" in signature.parameters:
946
+ system_message_args["team"] = team
947
+ if inspect.iscoroutinefunction(system_message):
948
+ raise ValueError("System message function is async, use `agent.arun()` instead")
949
+
950
+ return system_message(**system_message_args)
951
+
952
+
953
+ async def aexecute_instructions(
954
+ instructions: Callable,
955
+ agent: Optional[Union["Agent", "Team"]] = None,
956
+ team: Optional["Team"] = None,
957
+ session_state: Optional[Dict[str, Any]] = None,
958
+ run_context: Optional[RunContext] = None,
959
+ ) -> Union[str, List[str]]:
960
+ """Execute the instructions function."""
961
+ import inspect
962
+
963
+ signature = inspect.signature(instructions)
964
+ instruction_args: Dict[str, Any] = {}
965
+
966
+ # Check for agent parameter
967
+ if "agent" in signature.parameters:
968
+ instruction_args["agent"] = agent
969
+ if "team" in signature.parameters:
970
+ instruction_args["team"] = team
971
+
972
+ # Check for session_state parameter
973
+ if "session_state" in signature.parameters:
974
+ instruction_args["session_state"] = session_state if session_state is not None else {}
975
+
976
+ # Check for run_context parameter
977
+ if "run_context" in signature.parameters:
978
+ instruction_args["run_context"] = run_context or None
979
+
980
+ if inspect.iscoroutinefunction(instructions):
981
+ return await instructions(**instruction_args)
982
+ else:
983
+ return instructions(**instruction_args)
984
+
985
+
986
+ async def aexecute_system_message(
987
+ system_message: Callable,
988
+ agent: Optional[Union["Agent", "Team"]] = None,
989
+ team: Optional["Team"] = None,
990
+ session_state: Optional[Dict[str, Any]] = None,
991
+ run_context: Optional[RunContext] = None,
992
+ ) -> str:
993
+ import inspect
994
+
995
+ signature = inspect.signature(system_message)
996
+ system_message_args: Dict[str, Any] = {}
997
+
998
+ # Check for agent parameter
999
+ if "agent" in signature.parameters:
1000
+ system_message_args["agent"] = agent
1001
+ if "team" in signature.parameters:
1002
+ system_message_args["team"] = team
1003
+
1004
+ if inspect.iscoroutinefunction(system_message):
1005
+ return await system_message(**system_message_args)
1006
+ else:
1007
+ return system_message(**system_message_args)
1008
+
1009
+
1010
+ def validate_input(
1011
+ input: Union[str, List, Dict, Message, BaseModel], input_schema: Optional[Type[BaseModel]] = None
1012
+ ) -> Union[str, List, Dict, Message, BaseModel]:
1013
+ """Parse and validate input against input_schema if provided, otherwise return input as-is"""
1014
+ if input_schema is None:
1015
+ return input # Return input unchanged if no schema is set
1016
+
1017
+ if input is None:
1018
+ raise ValueError("Input required when input_schema is set")
1019
+
1020
+ # Handle Message objects - extract content
1021
+ if isinstance(input, Message):
1022
+ input = input.content # type: ignore
1023
+
1024
+ # If input is a string, convert it to a dict
1025
+ if isinstance(input, str):
1026
+ import json
1027
+
1028
+ try:
1029
+ input = json.loads(input)
1030
+ except Exception as e:
1031
+ raise ValueError(f"Failed to parse input. Is it a valid JSON string?: {e}")
1032
+
1033
+ # Case 1: Message is already a BaseModel instance
1034
+ if isinstance(input, BaseModel):
1035
+ if isinstance(input, input_schema):
1036
+ try:
1037
+ return input
1038
+ except Exception as e:
1039
+ raise ValueError(f"BaseModel validation failed: {str(e)}")
1040
+ else:
1041
+ # Different BaseModel types
1042
+ raise ValueError(f"Expected {input_schema.__name__} but got {type(input).__name__}")
1043
+
1044
+ # Case 2: Message is a dict
1045
+ elif isinstance(input, dict):
1046
+ try:
1047
+ # Check if the schema is a TypedDict
1048
+ if is_typed_dict(input_schema):
1049
+ validated_dict = validate_typed_dict(input, input_schema)
1050
+ return validated_dict
1051
+ else:
1052
+ validated_model = input_schema(**input)
1053
+ return validated_model
1054
+ except Exception as e:
1055
+ raise ValueError(f"Failed to parse dict into {input_schema.__name__}: {str(e)}")
1056
+
1057
+ # Case 3: Other types not supported for structured input
1058
+ else:
1059
+ raise ValueError(
1060
+ f"Cannot validate {type(input)} against input_schema. Expected dict or {input_schema.__name__} instance."
1061
+ )
@@ -0,0 +1,22 @@
1
+ from cryptography.hazmat.primitives import serialization
2
+ from cryptography.hazmat.primitives.asymmetric import rsa
3
+
4
+
5
+ def generate_rsa_keys():
6
+ """Generate RSA key pair for RS256 JWT signing/verification."""
7
+ private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
8
+
9
+ # Private key PEM (used by auth server to sign tokens)
10
+ private_pem = private_key.private_bytes(
11
+ encoding=serialization.Encoding.PEM,
12
+ format=serialization.PrivateFormat.PKCS8,
13
+ encryption_algorithm=serialization.NoEncryption(),
14
+ )
15
+
16
+ # Public key PEM (used by AgentOS to verify tokens)
17
+ public_pem = private_key.public_key().public_bytes(
18
+ encoding=serialization.Encoding.PEM,
19
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
20
+ )
21
+
22
+ return private_pem.decode("utf-8"), public_pem.decode("utf-8")
agno/utils/dttm.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from datetime import datetime, timezone
2
+ from typing import Union
2
3
 
3
4
 
4
5
  def current_datetime() -> datetime:
@@ -11,3 +12,35 @@ def current_datetime_utc() -> datetime:
11
12
 
12
13
  def current_datetime_utc_str() -> str:
13
14
  return current_datetime_utc().strftime("%Y-%m-%dT%H:%M:%S")
15
+
16
+
17
+ def now_epoch_s() -> int:
18
+ return int(datetime.now(timezone.utc).timestamp())
19
+
20
+
21
+ def to_epoch_s(value: Union[int, float, str, datetime]) -> int:
22
+ """Normalize various datetime representations to epoch seconds (UTC)."""
23
+
24
+ if isinstance(value, (int, float)):
25
+ # assume value is already in seconds
26
+ return int(value)
27
+
28
+ if isinstance(value, datetime):
29
+ dt = value
30
+ if dt.tzinfo is None:
31
+ dt = dt.replace(tzinfo=timezone.utc)
32
+ return int(dt.timestamp())
33
+
34
+ if isinstance(value, str):
35
+ s = value.strip()
36
+ if s.endswith("Z"):
37
+ s = s[:-1] + "+00:00"
38
+ try:
39
+ dt = datetime.fromisoformat(s)
40
+ except ValueError as e:
41
+ raise ValueError(f"Unsupported datetime string: {value!r}") from e
42
+ if dt.tzinfo is None:
43
+ dt = dt.replace(tzinfo=timezone.utc)
44
+ return int(dt.timestamp())
45
+
46
+ raise TypeError(f"Unsupported datetime value: {type(value)}")