agno 0.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 (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,997 @@
1
+ import logging
2
+ import time
3
+ from typing import Any, List, Optional, Union, cast
4
+ from uuid import uuid4
5
+
6
+ from fastapi import APIRouter, Body, Depends, HTTPException, Path, Query, Request
7
+
8
+ from agno.db.base import AsyncBaseDb, BaseDb, SessionType
9
+ from agno.os.auth import get_authentication_dependency
10
+ from agno.os.schema import (
11
+ AgentSessionDetailSchema,
12
+ BadRequestResponse,
13
+ CreateSessionRequest,
14
+ DeleteSessionRequest,
15
+ InternalServerErrorResponse,
16
+ NotFoundResponse,
17
+ PaginatedResponse,
18
+ PaginationInfo,
19
+ RunSchema,
20
+ SessionSchema,
21
+ SortOrder,
22
+ TeamRunSchema,
23
+ TeamSessionDetailSchema,
24
+ UnauthenticatedResponse,
25
+ UpdateSessionRequest,
26
+ ValidationErrorResponse,
27
+ WorkflowRunSchema,
28
+ WorkflowSessionDetailSchema,
29
+ )
30
+ from agno.os.settings import AgnoAPISettings
31
+ from agno.os.utils import get_db
32
+ from agno.session import AgentSession, TeamSession, WorkflowSession
33
+
34
+ logger = logging.getLogger(__name__)
35
+
36
+
37
+ def get_session_router(
38
+ dbs: dict[str, list[Union[BaseDb, AsyncBaseDb]]], settings: AgnoAPISettings = AgnoAPISettings()
39
+ ) -> APIRouter:
40
+ """Create session router with comprehensive OpenAPI documentation for session management endpoints."""
41
+ session_router = APIRouter(
42
+ dependencies=[Depends(get_authentication_dependency(settings))],
43
+ tags=["Sessions"],
44
+ responses={
45
+ 400: {"description": "Bad Request", "model": BadRequestResponse},
46
+ 401: {"description": "Unauthorized", "model": UnauthenticatedResponse},
47
+ 404: {"description": "Not Found", "model": NotFoundResponse},
48
+ 422: {"description": "Validation Error", "model": ValidationErrorResponse},
49
+ 500: {"description": "Internal Server Error", "model": InternalServerErrorResponse},
50
+ },
51
+ )
52
+ return attach_routes(router=session_router, dbs=dbs)
53
+
54
+
55
+ def attach_routes(router: APIRouter, dbs: dict[str, list[Union[BaseDb, AsyncBaseDb]]]) -> APIRouter:
56
+ @router.get(
57
+ "/sessions",
58
+ response_model=PaginatedResponse[SessionSchema],
59
+ status_code=200,
60
+ operation_id="get_sessions",
61
+ summary="List Sessions",
62
+ description=(
63
+ "Retrieve paginated list of sessions with filtering and sorting options. "
64
+ "Supports filtering by session type (agent, team, workflow), component, user, and name. "
65
+ "Sessions represent conversation histories and execution contexts."
66
+ ),
67
+ responses={
68
+ 200: {
69
+ "description": "Sessions retrieved successfully",
70
+ "content": {
71
+ "application/json": {
72
+ "example": {
73
+ "session_example": {
74
+ "summary": "Example session response",
75
+ "value": {
76
+ "data": [
77
+ {
78
+ "session_id": "6f6cfbfd-9643-479a-ae47-b8f32eb4d710",
79
+ "session_name": "What tools do you have?",
80
+ "session_state": {},
81
+ "created_at": "2025-09-05T16:02:09Z",
82
+ "updated_at": "2025-09-05T16:02:09Z",
83
+ }
84
+ ]
85
+ },
86
+ }
87
+ }
88
+ }
89
+ },
90
+ },
91
+ 400: {"description": "Invalid session type or filter parameters", "model": BadRequestResponse},
92
+ 404: {"description": "Not found", "model": NotFoundResponse},
93
+ 422: {"description": "Validation error in query parameters", "model": ValidationErrorResponse},
94
+ },
95
+ )
96
+ async def get_sessions(
97
+ request: Request,
98
+ session_type: SessionType = Query(
99
+ default=SessionType.AGENT,
100
+ alias="type",
101
+ description="Type of sessions to retrieve (agent, team, or workflow)",
102
+ ),
103
+ component_id: Optional[str] = Query(
104
+ default=None, description="Filter sessions by component ID (agent/team/workflow ID)"
105
+ ),
106
+ user_id: Optional[str] = Query(default=None, description="Filter sessions by user ID"),
107
+ session_name: Optional[str] = Query(default=None, description="Filter sessions by name (partial match)"),
108
+ limit: Optional[int] = Query(default=20, description="Number of sessions to return per page"),
109
+ page: Optional[int] = Query(default=1, description="Page number for pagination"),
110
+ sort_by: Optional[str] = Query(default="created_at", description="Field to sort sessions by"),
111
+ sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
112
+ db_id: Optional[str] = Query(default=None, description="Database ID to query sessions from"),
113
+ table: Optional[str] = Query(default=None, description="The database table to use"),
114
+ ) -> PaginatedResponse[SessionSchema]:
115
+ try:
116
+ db = await get_db(dbs, db_id, table)
117
+ except Exception as e:
118
+ raise HTTPException(status_code=404, detail=f"{e}")
119
+
120
+ if hasattr(request.state, "user_id"):
121
+ user_id = request.state.user_id
122
+
123
+ if isinstance(db, AsyncBaseDb):
124
+ db = cast(AsyncBaseDb, db)
125
+ sessions, total_count = await db.get_sessions(
126
+ session_type=session_type,
127
+ component_id=component_id,
128
+ user_id=user_id,
129
+ session_name=session_name,
130
+ limit=limit,
131
+ page=page,
132
+ sort_by=sort_by,
133
+ sort_order=sort_order,
134
+ deserialize=False,
135
+ )
136
+ else:
137
+ sessions, total_count = db.get_sessions( # type: ignore
138
+ session_type=session_type,
139
+ component_id=component_id,
140
+ user_id=user_id,
141
+ session_name=session_name,
142
+ limit=limit,
143
+ page=page,
144
+ sort_by=sort_by,
145
+ sort_order=sort_order,
146
+ deserialize=False,
147
+ )
148
+
149
+ return PaginatedResponse(
150
+ data=[SessionSchema.from_dict(session) for session in sessions], # type: ignore
151
+ meta=PaginationInfo(
152
+ page=page,
153
+ limit=limit,
154
+ total_count=total_count, # type: ignore
155
+ total_pages=(total_count + limit - 1) // limit if limit is not None and limit > 0 else 0, # type: ignore
156
+ ),
157
+ )
158
+
159
+ @router.post(
160
+ "/sessions",
161
+ response_model=Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema],
162
+ status_code=201,
163
+ operation_id="create_session",
164
+ summary="Create New Session",
165
+ description=(
166
+ "Create a new empty session with optional configuration. "
167
+ "Useful for pre-creating sessions with specific session_state, metadata, or other properties "
168
+ "before running any agent/team/workflow interactions. "
169
+ "The session can later be used by providing its session_id in run requests."
170
+ ),
171
+ responses={
172
+ 201: {
173
+ "description": "Session created successfully",
174
+ "content": {
175
+ "application/json": {
176
+ "examples": {
177
+ "agent_session_example": {
178
+ "summary": "Example created agent session",
179
+ "value": {
180
+ "user_id": "user-123",
181
+ "agent_session_id": "new-session-id",
182
+ "session_id": "new-session-id",
183
+ "session_name": "New Session",
184
+ "session_state": {"key": "value"},
185
+ "metadata": {"key": "value"},
186
+ "agent_id": "agent-1",
187
+ "created_at": "2025-10-21T12:00:00Z",
188
+ "updated_at": "2025-10-21T12:00:00Z",
189
+ },
190
+ }
191
+ }
192
+ }
193
+ },
194
+ },
195
+ 400: {"description": "Invalid request parameters", "model": BadRequestResponse},
196
+ 422: {"description": "Validation error", "model": ValidationErrorResponse},
197
+ 500: {"description": "Failed to create session", "model": InternalServerErrorResponse},
198
+ },
199
+ )
200
+ async def create_session(
201
+ request: Request,
202
+ session_type: SessionType = Query(
203
+ default=SessionType.AGENT, alias="type", description="Type of session to create (agent, team, or workflow)"
204
+ ),
205
+ create_session_request: CreateSessionRequest = Body(
206
+ default=CreateSessionRequest(), description="Session configuration data"
207
+ ),
208
+ db_id: Optional[str] = Query(default=None, description="Database ID to create session in"),
209
+ ) -> Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema]:
210
+ db = await get_db(dbs, db_id)
211
+
212
+ # Get user_id from request state if available (from auth middleware)
213
+ user_id = create_session_request.user_id
214
+ if hasattr(request.state, "user_id"):
215
+ user_id = request.state.user_id
216
+
217
+ # Generate session_id if not provided
218
+ session_id = create_session_request.session_id or str(uuid4())
219
+
220
+ # Prepare session_data with session_state and session_name
221
+ session_data: dict[str, Any] = {}
222
+ if create_session_request.session_state is not None:
223
+ session_data["session_state"] = create_session_request.session_state
224
+ if create_session_request.session_name is not None:
225
+ session_data["session_name"] = create_session_request.session_name
226
+
227
+ current_time = int(time.time())
228
+
229
+ # Create the appropriate session type
230
+ session: Union[AgentSession, TeamSession, WorkflowSession]
231
+ if session_type == SessionType.AGENT:
232
+ session = AgentSession(
233
+ session_id=session_id,
234
+ agent_id=create_session_request.agent_id,
235
+ user_id=user_id,
236
+ session_data=session_data if session_data else None,
237
+ metadata=create_session_request.metadata,
238
+ created_at=current_time,
239
+ updated_at=current_time,
240
+ )
241
+ elif session_type == SessionType.TEAM:
242
+ session = TeamSession(
243
+ session_id=session_id,
244
+ team_id=create_session_request.team_id,
245
+ user_id=user_id,
246
+ session_data=session_data if session_data else None,
247
+ metadata=create_session_request.metadata,
248
+ created_at=current_time,
249
+ updated_at=current_time,
250
+ )
251
+ elif session_type == SessionType.WORKFLOW:
252
+ session = WorkflowSession(
253
+ session_id=session_id,
254
+ workflow_id=create_session_request.workflow_id,
255
+ user_id=user_id,
256
+ session_data=session_data if session_data else None,
257
+ metadata=create_session_request.metadata,
258
+ created_at=current_time,
259
+ updated_at=current_time,
260
+ )
261
+ else:
262
+ raise HTTPException(status_code=400, detail=f"Invalid session type: {session_type}")
263
+
264
+ # Upsert the session to the database
265
+ try:
266
+ if isinstance(db, AsyncBaseDb):
267
+ db = cast(AsyncBaseDb, db)
268
+ created_session = await db.upsert_session(session, deserialize=True)
269
+ else:
270
+ created_session = db.upsert_session(session, deserialize=True)
271
+
272
+ if not created_session:
273
+ raise HTTPException(status_code=500, detail="Failed to create session")
274
+
275
+ # Return appropriate schema based on session type
276
+ if session_type == SessionType.AGENT:
277
+ return AgentSessionDetailSchema.from_session(created_session) # type: ignore
278
+ elif session_type == SessionType.TEAM:
279
+ return TeamSessionDetailSchema.from_session(created_session) # type: ignore
280
+ else:
281
+ return WorkflowSessionDetailSchema.from_session(created_session) # type: ignore
282
+ except Exception as e:
283
+ logger.error(f"Error creating session: {e}")
284
+ raise HTTPException(status_code=500, detail=f"Failed to create session: {str(e)}")
285
+
286
+ @router.get(
287
+ "/sessions/{session_id}",
288
+ response_model=Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema],
289
+ status_code=200,
290
+ operation_id="get_session_by_id",
291
+ summary="Get Session by ID",
292
+ description=(
293
+ "Retrieve detailed information about a specific session including metadata, configuration, "
294
+ "and run history. Response schema varies based on session type (agent, team, or workflow)."
295
+ ),
296
+ responses={
297
+ 200: {
298
+ "description": "Session details retrieved successfully",
299
+ "content": {
300
+ "application/json": {
301
+ "examples": {
302
+ "agent_session_example": {
303
+ "summary": "Example agent session response",
304
+ "value": {
305
+ "user_id": "123",
306
+ "agent_session_id": "6f6cfbfd-9643-479a-ae47-b8f32eb4d710",
307
+ "session_id": "6f6cfbfd-9643-479a-ae47-b8f32eb4d710",
308
+ "session_name": "What tools do you have?",
309
+ "session_summary": {
310
+ "summary": "The user and assistant engaged in a conversation about the tools the agent has available.",
311
+ "updated_at": "2025-09-05T18:02:12.269392",
312
+ },
313
+ "session_state": {},
314
+ "agent_id": "basic-agent",
315
+ "total_tokens": 160,
316
+ "agent_data": {
317
+ "name": "Basic Agent",
318
+ "agent_id": "basic-agent",
319
+ "model": {"provider": "OpenAI", "name": "OpenAIChat", "id": "gpt-4o"},
320
+ },
321
+ "metrics": {
322
+ "input_tokens": 134,
323
+ "output_tokens": 26,
324
+ "total_tokens": 160,
325
+ "audio_input_tokens": 0,
326
+ "audio_output_tokens": 0,
327
+ "audio_total_tokens": 0,
328
+ "cache_read_tokens": 0,
329
+ "cache_write_tokens": 0,
330
+ "reasoning_tokens": 0,
331
+ "timer": None,
332
+ "time_to_first_token": None,
333
+ "duration": None,
334
+ "provider_metrics": None,
335
+ "additional_metrics": None,
336
+ },
337
+ "chat_history": [
338
+ {
339
+ "content": "<additional_information>\n- Use markdown to format your answers.\n- The current time is 2025-09-05 18:02:09.171627.\n</additional_information>\n\nYou have access to memories from previous interactions with the user that you can use:\n\n<memories_from_previous_interactions>\n- User really likes Digimon and Japan.\n- User really likes Japan.\n- User likes coffee.\n</memories_from_previous_interactions>\n\nNote: this information is from previous interactions and may be updated in this conversation. You should always prefer information from this conversation over the past memories.",
340
+ "from_history": False,
341
+ "stop_after_tool_call": False,
342
+ "role": "system",
343
+ "created_at": 1757088129,
344
+ },
345
+ {
346
+ "content": "What tools do you have?",
347
+ "from_history": False,
348
+ "stop_after_tool_call": False,
349
+ "role": "user",
350
+ "created_at": 1757088129,
351
+ },
352
+ {
353
+ "content": "I don't have access to external tools or the internet. However, I can assist you with a wide range of topics by providing information, answering questions, and offering suggestions based on the knowledge I've been trained on. If there's anything specific you need help with, feel free to ask!",
354
+ "from_history": False,
355
+ "stop_after_tool_call": False,
356
+ "role": "assistant",
357
+ "metrics": {"input_tokens": 134, "output_tokens": 26, "total_tokens": 160},
358
+ "created_at": 1757088129,
359
+ },
360
+ ],
361
+ "created_at": "2025-09-05T16:02:09Z",
362
+ "updated_at": "2025-09-05T16:02:09Z",
363
+ },
364
+ }
365
+ }
366
+ }
367
+ },
368
+ },
369
+ 404: {"description": "Session not found", "model": NotFoundResponse},
370
+ 422: {"description": "Invalid session type", "model": ValidationErrorResponse},
371
+ },
372
+ )
373
+ async def get_session_by_id(
374
+ request: Request,
375
+ session_id: str = Path(description="Session ID to retrieve"),
376
+ session_type: SessionType = Query(
377
+ default=SessionType.AGENT, description="Session type (agent, team, or workflow)", alias="type"
378
+ ),
379
+ user_id: Optional[str] = Query(default=None, description="User ID to query session from"),
380
+ db_id: Optional[str] = Query(default=None, description="Database ID to query session from"),
381
+ table: Optional[str] = Query(default=None, description="Table to query session from"),
382
+ ) -> Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema]:
383
+ db = await get_db(dbs, db_id, table)
384
+
385
+ if hasattr(request.state, "user_id"):
386
+ user_id = request.state.user_id
387
+
388
+ if isinstance(db, AsyncBaseDb):
389
+ db = cast(AsyncBaseDb, db)
390
+ session = await db.get_session(session_id=session_id, session_type=session_type, user_id=user_id)
391
+ else:
392
+ session = db.get_session(session_id=session_id, session_type=session_type, user_id=user_id)
393
+ if not session:
394
+ raise HTTPException(
395
+ status_code=404, detail=f"{session_type.value.title()} Session with id '{session_id}' not found"
396
+ )
397
+
398
+ if session_type == SessionType.AGENT:
399
+ return AgentSessionDetailSchema.from_session(session) # type: ignore
400
+ elif session_type == SessionType.TEAM:
401
+ return TeamSessionDetailSchema.from_session(session) # type: ignore
402
+ else:
403
+ return WorkflowSessionDetailSchema.from_session(session) # type: ignore
404
+
405
+ @router.get(
406
+ "/sessions/{session_id}/runs",
407
+ response_model=List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]],
408
+ status_code=200,
409
+ operation_id="get_session_runs",
410
+ summary="Get Session Runs",
411
+ description=(
412
+ "Retrieve all runs (executions) for a specific session with optional timestamp filtering. "
413
+ "Runs represent individual interactions or executions within a session. "
414
+ "Response schema varies based on session type."
415
+ ),
416
+ responses={
417
+ 200: {
418
+ "description": "Session runs retrieved successfully",
419
+ "content": {
420
+ "application/json": {
421
+ "examples": {
422
+ "completed_run": {
423
+ "summary": "Example completed run",
424
+ "value": {
425
+ "run_id": "fcdf50f0-7c32-4593-b2ef-68a558774340",
426
+ "parent_run_id": "80056af0-c7a5-4d69-b6a2-c3eba9f040e0",
427
+ "agent_id": "basic-agent",
428
+ "user_id": "",
429
+ "run_input": "Which tools do you have access to?",
430
+ "content": "I don't have access to external tools or the internet. However, I can assist you with a wide range of topics by providing information, answering questions, and offering suggestions based on the knowledge I've been trained on. If there's anything specific you need help with, feel free to ask!",
431
+ "run_response_format": "text",
432
+ "reasoning_content": "",
433
+ "metrics": {
434
+ "input_tokens": 82,
435
+ "output_tokens": 56,
436
+ "total_tokens": 138,
437
+ "time_to_first_token": 0.047505500027909875,
438
+ "duration": 4.840060166025069,
439
+ },
440
+ "messages": [
441
+ {
442
+ "content": "<additional_information>\n- Use markdown to format your answers.\n- The current time is 2025-09-08 17:52:10.101003.\n</additional_information>\n\nYou have the capability to retain memories from previous interactions with the user, but have not had any interactions with the user yet.",
443
+ "from_history": False,
444
+ "stop_after_tool_call": False,
445
+ "role": "system",
446
+ "created_at": 1757346730,
447
+ },
448
+ {
449
+ "content": "Which tools do you have access to?",
450
+ "from_history": False,
451
+ "stop_after_tool_call": False,
452
+ "role": "user",
453
+ "created_at": 1757346730,
454
+ },
455
+ {
456
+ "content": "I don't have access to external tools or the internet. However, I can assist you with a wide range of topics by providing information, answering questions, and offering suggestions based on the knowledge I've been trained on. If there's anything specific you need help with, feel free to ask!",
457
+ "from_history": False,
458
+ "stop_after_tool_call": False,
459
+ "role": "assistant",
460
+ "metrics": {"input_tokens": 82, "output_tokens": 56, "total_tokens": 138},
461
+ "created_at": 1757346730,
462
+ },
463
+ ],
464
+ "tools": None,
465
+ "events": [
466
+ {
467
+ "created_at": 1757346730,
468
+ "event": "RunStarted",
469
+ "agent_id": "basic-agent",
470
+ "agent_name": "Basic Agent",
471
+ "run_id": "fcdf50f0-7c32-4593-b2ef-68a558774340",
472
+ "session_id": "80056af0-c7a5-4d69-b6a2-c3eba9f040e0",
473
+ "model": "gpt-4o",
474
+ "model_provider": "OpenAI",
475
+ },
476
+ {
477
+ "created_at": 1757346733,
478
+ "event": "MemoryUpdateStarted",
479
+ "agent_id": "basic-agent",
480
+ "agent_name": "Basic Agent",
481
+ "run_id": "fcdf50f0-7c32-4593-b2ef-68a558774340",
482
+ "session_id": "80056af0-c7a5-4d69-b6a2-c3eba9f040e0",
483
+ },
484
+ {
485
+ "created_at": 1757346734,
486
+ "event": "MemoryUpdateCompleted",
487
+ "agent_id": "basic-agent",
488
+ "agent_name": "Basic Agent",
489
+ "run_id": "fcdf50f0-7c32-4593-b2ef-68a558774340",
490
+ "session_id": "80056af0-c7a5-4d69-b6a2-c3eba9f040e0",
491
+ },
492
+ {
493
+ "created_at": 1757346734,
494
+ "event": "RunCompleted",
495
+ "agent_id": "basic-agent",
496
+ "agent_name": "Basic Agent",
497
+ "run_id": "fcdf50f0-7c32-4593-b2ef-68a558774340",
498
+ "session_id": "80056af0-c7a5-4d69-b6a2-c3eba9f040e0",
499
+ "content": "I don't have access to external tools or the internet. However, I can assist you with a wide range of topics by providing information, answering questions, and offering suggestions based on the knowledge I've been trained on. If there's anything specific you need help with, feel free to ask!",
500
+ "content_type": "str",
501
+ "metrics": {
502
+ "input_tokens": 82,
503
+ "output_tokens": 56,
504
+ "total_tokens": 138,
505
+ "time_to_first_token": 0.047505500027909875,
506
+ "duration": 4.840060166025069,
507
+ },
508
+ },
509
+ ],
510
+ "created_at": "2025-09-08T15:52:10Z",
511
+ },
512
+ }
513
+ }
514
+ }
515
+ },
516
+ },
517
+ 404: {"description": "Session not found or has no runs", "model": NotFoundResponse},
518
+ 422: {"description": "Invalid session type", "model": ValidationErrorResponse},
519
+ },
520
+ )
521
+ async def get_session_runs(
522
+ request: Request,
523
+ session_id: str = Path(description="Session ID to get runs from"),
524
+ session_type: SessionType = Query(
525
+ default=SessionType.AGENT, description="Session type (agent, team, or workflow)", alias="type"
526
+ ),
527
+ user_id: Optional[str] = Query(default=None, description="User ID to query runs from"),
528
+ created_after: Optional[int] = Query(
529
+ default=None,
530
+ description="Filter runs created after this Unix timestamp (epoch time in seconds)",
531
+ ),
532
+ created_before: Optional[int] = Query(
533
+ default=None,
534
+ description="Filter runs created before this Unix timestamp (epoch time in seconds)",
535
+ ),
536
+ db_id: Optional[str] = Query(default=None, description="Database ID to query runs from"),
537
+ table: Optional[str] = Query(default=None, description="Table to query runs from"),
538
+ ) -> List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]]:
539
+ db = await get_db(dbs, db_id, table)
540
+
541
+ if hasattr(request.state, "user_id"):
542
+ user_id = request.state.user_id
543
+
544
+ # Use timestamp filters directly (already in epoch format)
545
+ start_timestamp = created_after
546
+ end_timestamp = created_before
547
+
548
+ if isinstance(db, AsyncBaseDb):
549
+ db = cast(AsyncBaseDb, db)
550
+ session = await db.get_session(
551
+ session_id=session_id, session_type=session_type, user_id=user_id, deserialize=False
552
+ )
553
+ else:
554
+ session = db.get_session(
555
+ session_id=session_id, session_type=session_type, user_id=user_id, deserialize=False
556
+ )
557
+
558
+ if not session:
559
+ raise HTTPException(status_code=404, detail=f"Session with ID {session_id} not found")
560
+
561
+ runs = session.get("runs") # type: ignore
562
+ if not runs:
563
+ return []
564
+
565
+ # Filter runs by timestamp if specified
566
+ # TODO: Move this filtering into the DB layer
567
+ filtered_runs = []
568
+ for run in runs:
569
+ if start_timestamp or end_timestamp:
570
+ run_created_at = run.get("created_at")
571
+ if run_created_at:
572
+ # created_at is stored as epoch int
573
+ if start_timestamp and run_created_at < start_timestamp:
574
+ continue
575
+ if end_timestamp and run_created_at > end_timestamp:
576
+ continue
577
+
578
+ filtered_runs.append(run)
579
+
580
+ if not filtered_runs:
581
+ return []
582
+
583
+ run_responses: List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]] = []
584
+
585
+ if session_type == SessionType.AGENT:
586
+ return [RunSchema.from_dict(run) for run in filtered_runs]
587
+
588
+ elif session_type == SessionType.TEAM:
589
+ for run in filtered_runs:
590
+ if run.get("agent_id") is not None:
591
+ run_responses.append(RunSchema.from_dict(run))
592
+ elif run.get("team_id") is not None:
593
+ run_responses.append(TeamRunSchema.from_dict(run))
594
+ return run_responses
595
+
596
+ elif session_type == SessionType.WORKFLOW:
597
+ for run in filtered_runs:
598
+ if run.get("workflow_id") is not None:
599
+ run_responses.append(WorkflowRunSchema.from_dict(run))
600
+ elif run.get("team_id") is not None:
601
+ run_responses.append(TeamRunSchema.from_dict(run))
602
+ else:
603
+ run_responses.append(RunSchema.from_dict(run))
604
+ return run_responses
605
+ else:
606
+ raise HTTPException(status_code=400, detail=f"Invalid session type: {session_type}")
607
+
608
+ @router.get(
609
+ "/sessions/{session_id}/runs/{run_id}",
610
+ response_model=Union[RunSchema, TeamRunSchema, WorkflowRunSchema],
611
+ status_code=200,
612
+ operation_id="get_session_run",
613
+ summary="Get Run by ID",
614
+ description=(
615
+ "Retrieve a specific run by its ID from a session. Response schema varies based on the "
616
+ "run type (agent run, team run, or workflow run)."
617
+ ),
618
+ responses={
619
+ 200: {
620
+ "description": "Run retrieved successfully",
621
+ "content": {
622
+ "application/json": {
623
+ "examples": {
624
+ "agent_run": {
625
+ "summary": "Example agent run",
626
+ "value": {
627
+ "run_id": "fcdf50f0-7c32-4593-b2ef-68a558774340",
628
+ "parent_run_id": "80056af0-c7a5-4d69-b6a2-c3eba9f040e0",
629
+ "agent_id": "basic-agent",
630
+ "user_id": "user_123",
631
+ "run_input": "Which tools do you have access to?",
632
+ "content": "I don't have access to external tools.",
633
+ "created_at": 1728499200,
634
+ },
635
+ }
636
+ }
637
+ }
638
+ },
639
+ },
640
+ 404: {"description": "Session or run not found", "model": NotFoundResponse},
641
+ 422: {"description": "Invalid session type", "model": ValidationErrorResponse},
642
+ },
643
+ )
644
+ async def get_session_run(
645
+ request: Request,
646
+ session_id: str = Path(description="Session ID to get run from"),
647
+ run_id: str = Path(description="Run ID to retrieve"),
648
+ session_type: SessionType = Query(
649
+ default=SessionType.AGENT, description="Session type (agent, team, or workflow)", alias="type"
650
+ ),
651
+ user_id: Optional[str] = Query(default=None, description="User ID to query run from"),
652
+ db_id: Optional[str] = Query(default=None, description="Database ID to query run from"),
653
+ ) -> Union[RunSchema, TeamRunSchema, WorkflowRunSchema]:
654
+ db = await get_db(dbs, db_id)
655
+
656
+ if hasattr(request.state, "user_id"):
657
+ user_id = request.state.user_id
658
+
659
+ if isinstance(db, AsyncBaseDb):
660
+ db = cast(AsyncBaseDb, db)
661
+ session = await db.get_session(
662
+ session_id=session_id, session_type=session_type, user_id=user_id, deserialize=False
663
+ )
664
+ else:
665
+ session = db.get_session(
666
+ session_id=session_id, session_type=session_type, user_id=user_id, deserialize=False
667
+ )
668
+
669
+ if not session:
670
+ raise HTTPException(status_code=404, detail=f"Session with ID {session_id} not found")
671
+
672
+ runs = session.get("runs") # type: ignore
673
+ if not runs:
674
+ raise HTTPException(status_code=404, detail=f"Session with ID {session_id} has no runs")
675
+
676
+ # Find the specific run
677
+ # TODO: Move this filtering into the DB layer
678
+ target_run = None
679
+ for run in runs:
680
+ if run.get("run_id") == run_id:
681
+ target_run = run
682
+ break
683
+
684
+ if not target_run:
685
+ raise HTTPException(status_code=404, detail=f"Run with ID {run_id} not found in session {session_id}")
686
+
687
+ # Return the appropriate schema based on run type
688
+ if target_run.get("workflow_id") is not None:
689
+ return WorkflowRunSchema.from_dict(target_run)
690
+ elif target_run.get("team_id") is not None:
691
+ return TeamRunSchema.from_dict(target_run)
692
+ else:
693
+ return RunSchema.from_dict(target_run)
694
+
695
+ @router.delete(
696
+ "/sessions/{session_id}",
697
+ status_code=204,
698
+ operation_id="delete_session",
699
+ summary="Delete Session",
700
+ description=(
701
+ "Permanently delete a specific session and all its associated runs. "
702
+ "This action cannot be undone and will remove all conversation history."
703
+ ),
704
+ responses={
705
+ 204: {},
706
+ 500: {"description": "Failed to delete session", "model": InternalServerErrorResponse},
707
+ },
708
+ )
709
+ async def delete_session(
710
+ session_id: str = Path(description="Session ID to delete"),
711
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for deletion"),
712
+ table: Optional[str] = Query(default=None, description="Table to use for deletion"),
713
+ ) -> None:
714
+ db = await get_db(dbs, db_id, table)
715
+ if isinstance(db, AsyncBaseDb):
716
+ db = cast(AsyncBaseDb, db)
717
+ await db.delete_session(session_id=session_id)
718
+ else:
719
+ db.delete_session(session_id=session_id)
720
+
721
+ @router.delete(
722
+ "/sessions",
723
+ status_code=204,
724
+ operation_id="delete_sessions",
725
+ summary="Delete Multiple Sessions",
726
+ description=(
727
+ "Delete multiple sessions by their IDs in a single operation. "
728
+ "This action cannot be undone and will permanently remove all specified sessions and their runs."
729
+ ),
730
+ responses={
731
+ 204: {"description": "Sessions deleted successfully"},
732
+ 400: {
733
+ "description": "Invalid request - session IDs and types length mismatch",
734
+ "model": BadRequestResponse,
735
+ },
736
+ 500: {"description": "Failed to delete sessions", "model": InternalServerErrorResponse},
737
+ },
738
+ )
739
+ async def delete_sessions(
740
+ request: DeleteSessionRequest,
741
+ session_type: SessionType = Query(
742
+ default=SessionType.AGENT, description="Default session type filter", alias="type"
743
+ ),
744
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for deletion"),
745
+ table: Optional[str] = Query(default=None, description="Table to use for deletion"),
746
+ ) -> None:
747
+ if len(request.session_ids) != len(request.session_types):
748
+ raise HTTPException(status_code=400, detail="Session IDs and session types must have the same length")
749
+
750
+ db = await get_db(dbs, db_id, table)
751
+ if isinstance(db, AsyncBaseDb):
752
+ db = cast(AsyncBaseDb, db)
753
+ await db.delete_sessions(session_ids=request.session_ids)
754
+ else:
755
+ db.delete_sessions(session_ids=request.session_ids)
756
+
757
+ @router.post(
758
+ "/sessions/{session_id}/rename",
759
+ response_model=Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema],
760
+ status_code=200,
761
+ operation_id="rename_session",
762
+ summary="Rename Session",
763
+ description=(
764
+ "Update the name of an existing session. Useful for organizing and categorizing "
765
+ "sessions with meaningful names for better identification and management."
766
+ ),
767
+ responses={
768
+ 200: {
769
+ "description": "Session renamed successfully",
770
+ "content": {
771
+ "application/json": {
772
+ "examples": {
773
+ "agent_session_example": {
774
+ "summary": "Example agent session response",
775
+ "value": {
776
+ "user_id": "123",
777
+ "agent_session_id": "6f6cfbfd-9643-479a-ae47-b8f32eb4d710",
778
+ "session_id": "6f6cfbfd-9643-479a-ae47-b8f32eb4d710",
779
+ "session_name": "What tools do you have?",
780
+ "session_summary": {
781
+ "summary": "The user and assistant engaged in a conversation about the tools the agent has available.",
782
+ "updated_at": "2025-09-05T18:02:12.269392",
783
+ },
784
+ "session_state": {},
785
+ "agent_id": "basic-agent",
786
+ "total_tokens": 160,
787
+ "agent_data": {
788
+ "name": "Basic Agent",
789
+ "agent_id": "basic-agent",
790
+ "model": {"provider": "OpenAI", "name": "OpenAIChat", "id": "gpt-4o"},
791
+ },
792
+ "metrics": {
793
+ "input_tokens": 134,
794
+ "output_tokens": 26,
795
+ "total_tokens": 160,
796
+ "audio_input_tokens": 0,
797
+ "audio_output_tokens": 0,
798
+ "audio_total_tokens": 0,
799
+ "cache_read_tokens": 0,
800
+ "cache_write_tokens": 0,
801
+ "reasoning_tokens": 0,
802
+ "timer": None,
803
+ "time_to_first_token": None,
804
+ "duration": None,
805
+ "provider_metrics": None,
806
+ "additional_metrics": None,
807
+ },
808
+ "chat_history": [
809
+ {
810
+ "content": "<additional_information>\n- Use markdown to format your answers.\n- The current time is 2025-09-05 18:02:09.171627.\n</additional_information>\n\nYou have access to memories from previous interactions with the user that you can use:\n\n<memories_from_previous_interactions>\n- User really likes Digimon and Japan.\n- User really likes Japan.\n- User likes coffee.\n</memories_from_previous_interactions>\n\nNote: this information is from previous interactions and may be updated in this conversation. You should always prefer information from this conversation over the past memories.",
811
+ "from_history": False,
812
+ "stop_after_tool_call": False,
813
+ "role": "system",
814
+ "created_at": 1757088129,
815
+ },
816
+ {
817
+ "content": "What tools do you have?",
818
+ "from_history": False,
819
+ "stop_after_tool_call": False,
820
+ "role": "user",
821
+ "created_at": 1757088129,
822
+ },
823
+ {
824
+ "content": "I don't have access to external tools or the internet. However, I can assist you with a wide range of topics by providing information, answering questions, and offering suggestions based on the knowledge I've been trained on. If there's anything specific you need help with, feel free to ask!",
825
+ "from_history": False,
826
+ "stop_after_tool_call": False,
827
+ "role": "assistant",
828
+ "metrics": {"input_tokens": 134, "output_tokens": 26, "total_tokens": 160},
829
+ "created_at": 1757088129,
830
+ },
831
+ ],
832
+ "created_at": "2025-09-05T16:02:09Z",
833
+ "updated_at": "2025-09-05T16:02:09Z",
834
+ },
835
+ }
836
+ }
837
+ }
838
+ },
839
+ },
840
+ 400: {"description": "Invalid session name", "model": BadRequestResponse},
841
+ 404: {"description": "Session not found", "model": NotFoundResponse},
842
+ 422: {"description": "Invalid session type or validation error", "model": ValidationErrorResponse},
843
+ },
844
+ )
845
+ async def rename_session(
846
+ session_id: str = Path(description="Session ID to rename"),
847
+ session_type: SessionType = Query(
848
+ default=SessionType.AGENT, description="Session type (agent, team, or workflow)", alias="type"
849
+ ),
850
+ session_name: str = Body(embed=True, description="New name for the session"),
851
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for rename operation"),
852
+ table: Optional[str] = Query(default=None, description="Table to use for rename operation"),
853
+ ) -> Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema]:
854
+ db = await get_db(dbs, db_id, table)
855
+ if isinstance(db, AsyncBaseDb):
856
+ db = cast(AsyncBaseDb, db)
857
+ session = await db.rename_session(
858
+ session_id=session_id, session_type=session_type, session_name=session_name
859
+ )
860
+ else:
861
+ session = db.rename_session(session_id=session_id, session_type=session_type, session_name=session_name)
862
+ if not session:
863
+ raise HTTPException(status_code=404, detail=f"Session with id '{session_id}' not found")
864
+
865
+ if session_type == SessionType.AGENT:
866
+ return AgentSessionDetailSchema.from_session(session) # type: ignore
867
+ elif session_type == SessionType.TEAM:
868
+ return TeamSessionDetailSchema.from_session(session) # type: ignore
869
+ else:
870
+ return WorkflowSessionDetailSchema.from_session(session) # type: ignore
871
+
872
+ @router.patch(
873
+ "/sessions/{session_id}",
874
+ response_model=Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema],
875
+ status_code=200,
876
+ operation_id="update_session",
877
+ summary="Update Session",
878
+ description=(
879
+ "Update session properties such as session_name, session_state, metadata, or summary. "
880
+ "Use this endpoint to modify the session name, update state, add metadata, or update the session summary."
881
+ ),
882
+ responses={
883
+ 200: {
884
+ "description": "Session updated successfully",
885
+ "content": {
886
+ "application/json": {
887
+ "examples": {
888
+ "update_summary": {
889
+ "summary": "Update session summary",
890
+ "value": {
891
+ "summary": {
892
+ "summary": "The user discussed project planning with the agent.",
893
+ "updated_at": "2025-10-21T14:30:00Z",
894
+ }
895
+ },
896
+ },
897
+ "update_metadata": {
898
+ "summary": "Update session metadata",
899
+ "value": {
900
+ "metadata": {
901
+ "tags": ["planning", "project"],
902
+ "priority": "high",
903
+ }
904
+ },
905
+ },
906
+ "update_session_name": {
907
+ "summary": "Update session name",
908
+ "value": {"session_name": "Updated Session Name"},
909
+ },
910
+ "update_session_state": {
911
+ "summary": "Update session state",
912
+ "value": {
913
+ "session_state": {
914
+ "step": "completed",
915
+ "context": "Project planning finished",
916
+ "progress": 100,
917
+ }
918
+ },
919
+ },
920
+ }
921
+ }
922
+ },
923
+ },
924
+ 404: {"description": "Session not found", "model": NotFoundResponse},
925
+ 422: {"description": "Invalid request", "model": ValidationErrorResponse},
926
+ 500: {"description": "Failed to update session", "model": InternalServerErrorResponse},
927
+ },
928
+ )
929
+ async def update_session(
930
+ request: Request,
931
+ session_id: str = Path(description="Session ID to update"),
932
+ session_type: SessionType = Query(
933
+ default=SessionType.AGENT, description="Session type (agent, team, or workflow)", alias="type"
934
+ ),
935
+ update_data: UpdateSessionRequest = Body(description="Session update data"),
936
+ user_id: Optional[str] = Query(default=None, description="User ID"),
937
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for update operation"),
938
+ ) -> Union[AgentSessionDetailSchema, TeamSessionDetailSchema, WorkflowSessionDetailSchema]:
939
+ db = await get_db(dbs, db_id)
940
+
941
+ if hasattr(request.state, "user_id"):
942
+ user_id = request.state.user_id
943
+
944
+ # Get the existing session
945
+ if isinstance(db, AsyncBaseDb):
946
+ db = cast(AsyncBaseDb, db)
947
+ existing_session = await db.get_session(
948
+ session_id=session_id, session_type=session_type, user_id=user_id, deserialize=True
949
+ )
950
+ else:
951
+ existing_session = db.get_session(
952
+ session_id=session_id, session_type=session_type, user_id=user_id, deserialize=True
953
+ )
954
+
955
+ if not existing_session:
956
+ raise HTTPException(status_code=404, detail=f"Session with id '{session_id}' not found")
957
+
958
+ # Update session properties
959
+ # Handle session_name - stored in session_data
960
+ if update_data.session_name is not None:
961
+ if existing_session.session_data is None: # type: ignore
962
+ existing_session.session_data = {} # type: ignore
963
+ existing_session.session_data["session_name"] = update_data.session_name # type: ignore
964
+
965
+ # Handle session_state - stored in session_data
966
+ if update_data.session_state is not None:
967
+ if existing_session.session_data is None: # type: ignore
968
+ existing_session.session_data = {} # type: ignore
969
+ existing_session.session_data["session_state"] = update_data.session_state # type: ignore
970
+
971
+ if update_data.metadata is not None:
972
+ existing_session.metadata = update_data.metadata # type: ignore
973
+
974
+ if update_data.summary is not None:
975
+ from agno.session.summary import SessionSummary
976
+
977
+ existing_session.summary = SessionSummary.from_dict(update_data.summary) # type: ignore
978
+
979
+ # Upsert the updated session
980
+ if isinstance(db, AsyncBaseDb):
981
+ db = cast(AsyncBaseDb, db)
982
+ updated_session = await db.upsert_session(existing_session, deserialize=True) # type: ignore
983
+ else:
984
+ updated_session = db.upsert_session(existing_session, deserialize=True) # type: ignore
985
+
986
+ if not updated_session:
987
+ raise HTTPException(status_code=500, detail="Failed to update session")
988
+
989
+ # Return appropriate schema based on session type
990
+ if session_type == SessionType.AGENT:
991
+ return AgentSessionDetailSchema.from_session(updated_session) # type: ignore
992
+ elif session_type == SessionType.TEAM:
993
+ return TeamSessionDetailSchema.from_session(updated_session) # type: ignore
994
+ else:
995
+ return WorkflowSessionDetailSchema.from_session(updated_session) # type: ignore
996
+
997
+ return router