agno 2.2.13__py3-none-any.whl → 2.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. agno/agent/__init__.py +6 -0
  2. agno/agent/agent.py +5252 -3145
  3. agno/agent/remote.py +525 -0
  4. agno/api/api.py +2 -0
  5. agno/client/__init__.py +3 -0
  6. agno/client/a2a/__init__.py +10 -0
  7. agno/client/a2a/client.py +554 -0
  8. agno/client/a2a/schemas.py +112 -0
  9. agno/client/a2a/utils.py +369 -0
  10. agno/client/os.py +2669 -0
  11. agno/compression/__init__.py +3 -0
  12. agno/compression/manager.py +247 -0
  13. agno/culture/manager.py +2 -2
  14. agno/db/base.py +927 -6
  15. agno/db/dynamo/dynamo.py +788 -2
  16. agno/db/dynamo/schemas.py +128 -0
  17. agno/db/dynamo/utils.py +26 -3
  18. agno/db/firestore/firestore.py +674 -50
  19. agno/db/firestore/schemas.py +41 -0
  20. agno/db/firestore/utils.py +25 -10
  21. agno/db/gcs_json/gcs_json_db.py +506 -3
  22. agno/db/gcs_json/utils.py +14 -2
  23. agno/db/in_memory/in_memory_db.py +203 -4
  24. agno/db/in_memory/utils.py +14 -2
  25. agno/db/json/json_db.py +498 -2
  26. agno/db/json/utils.py +14 -2
  27. agno/db/migrations/manager.py +199 -0
  28. agno/db/migrations/utils.py +19 -0
  29. agno/db/migrations/v1_to_v2.py +54 -16
  30. agno/db/migrations/versions/__init__.py +0 -0
  31. agno/db/migrations/versions/v2_3_0.py +977 -0
  32. agno/db/mongo/async_mongo.py +1013 -39
  33. agno/db/mongo/mongo.py +684 -4
  34. agno/db/mongo/schemas.py +48 -0
  35. agno/db/mongo/utils.py +17 -0
  36. agno/db/mysql/__init__.py +2 -1
  37. agno/db/mysql/async_mysql.py +2958 -0
  38. agno/db/mysql/mysql.py +722 -53
  39. agno/db/mysql/schemas.py +77 -11
  40. agno/db/mysql/utils.py +151 -8
  41. agno/db/postgres/async_postgres.py +1254 -137
  42. agno/db/postgres/postgres.py +2316 -93
  43. agno/db/postgres/schemas.py +153 -21
  44. agno/db/postgres/utils.py +22 -7
  45. agno/db/redis/redis.py +531 -3
  46. agno/db/redis/schemas.py +36 -0
  47. agno/db/redis/utils.py +31 -15
  48. agno/db/schemas/evals.py +1 -0
  49. agno/db/schemas/memory.py +20 -9
  50. agno/db/singlestore/schemas.py +70 -1
  51. agno/db/singlestore/singlestore.py +737 -74
  52. agno/db/singlestore/utils.py +13 -3
  53. agno/db/sqlite/async_sqlite.py +1069 -89
  54. agno/db/sqlite/schemas.py +133 -1
  55. agno/db/sqlite/sqlite.py +2203 -165
  56. agno/db/sqlite/utils.py +21 -11
  57. agno/db/surrealdb/models.py +25 -0
  58. agno/db/surrealdb/surrealdb.py +603 -1
  59. agno/db/utils.py +60 -0
  60. agno/eval/__init__.py +26 -3
  61. agno/eval/accuracy.py +25 -12
  62. agno/eval/agent_as_judge.py +871 -0
  63. agno/eval/base.py +29 -0
  64. agno/eval/performance.py +10 -4
  65. agno/eval/reliability.py +22 -13
  66. agno/eval/utils.py +2 -1
  67. agno/exceptions.py +42 -0
  68. agno/hooks/__init__.py +3 -0
  69. agno/hooks/decorator.py +164 -0
  70. agno/integrations/discord/client.py +13 -2
  71. agno/knowledge/__init__.py +4 -0
  72. agno/knowledge/chunking/code.py +90 -0
  73. agno/knowledge/chunking/document.py +65 -4
  74. agno/knowledge/chunking/fixed.py +4 -1
  75. agno/knowledge/chunking/markdown.py +102 -11
  76. agno/knowledge/chunking/recursive.py +2 -2
  77. agno/knowledge/chunking/semantic.py +130 -48
  78. agno/knowledge/chunking/strategy.py +18 -0
  79. agno/knowledge/embedder/azure_openai.py +0 -1
  80. agno/knowledge/embedder/google.py +1 -1
  81. agno/knowledge/embedder/mistral.py +1 -1
  82. agno/knowledge/embedder/nebius.py +1 -1
  83. agno/knowledge/embedder/openai.py +16 -12
  84. agno/knowledge/filesystem.py +412 -0
  85. agno/knowledge/knowledge.py +4261 -1199
  86. agno/knowledge/protocol.py +134 -0
  87. agno/knowledge/reader/arxiv_reader.py +3 -2
  88. agno/knowledge/reader/base.py +9 -7
  89. agno/knowledge/reader/csv_reader.py +91 -42
  90. agno/knowledge/reader/docx_reader.py +9 -10
  91. agno/knowledge/reader/excel_reader.py +225 -0
  92. agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
  93. agno/knowledge/reader/firecrawl_reader.py +3 -2
  94. agno/knowledge/reader/json_reader.py +16 -22
  95. agno/knowledge/reader/markdown_reader.py +15 -14
  96. agno/knowledge/reader/pdf_reader.py +33 -28
  97. agno/knowledge/reader/pptx_reader.py +9 -10
  98. agno/knowledge/reader/reader_factory.py +135 -1
  99. agno/knowledge/reader/s3_reader.py +8 -16
  100. agno/knowledge/reader/tavily_reader.py +3 -3
  101. agno/knowledge/reader/text_reader.py +15 -14
  102. agno/knowledge/reader/utils/__init__.py +17 -0
  103. agno/knowledge/reader/utils/spreadsheet.py +114 -0
  104. agno/knowledge/reader/web_search_reader.py +8 -65
  105. agno/knowledge/reader/website_reader.py +16 -13
  106. agno/knowledge/reader/wikipedia_reader.py +36 -3
  107. agno/knowledge/reader/youtube_reader.py +3 -2
  108. agno/knowledge/remote_content/__init__.py +33 -0
  109. agno/knowledge/remote_content/config.py +266 -0
  110. agno/knowledge/remote_content/remote_content.py +105 -17
  111. agno/knowledge/utils.py +76 -22
  112. agno/learn/__init__.py +71 -0
  113. agno/learn/config.py +463 -0
  114. agno/learn/curate.py +185 -0
  115. agno/learn/machine.py +725 -0
  116. agno/learn/schemas.py +1114 -0
  117. agno/learn/stores/__init__.py +38 -0
  118. agno/learn/stores/decision_log.py +1156 -0
  119. agno/learn/stores/entity_memory.py +3275 -0
  120. agno/learn/stores/learned_knowledge.py +1583 -0
  121. agno/learn/stores/protocol.py +117 -0
  122. agno/learn/stores/session_context.py +1217 -0
  123. agno/learn/stores/user_memory.py +1495 -0
  124. agno/learn/stores/user_profile.py +1220 -0
  125. agno/learn/utils.py +209 -0
  126. agno/media.py +22 -6
  127. agno/memory/__init__.py +14 -1
  128. agno/memory/manager.py +223 -8
  129. agno/memory/strategies/__init__.py +15 -0
  130. agno/memory/strategies/base.py +66 -0
  131. agno/memory/strategies/summarize.py +196 -0
  132. agno/memory/strategies/types.py +37 -0
  133. agno/models/aimlapi/aimlapi.py +17 -0
  134. agno/models/anthropic/claude.py +434 -59
  135. agno/models/aws/bedrock.py +121 -20
  136. agno/models/aws/claude.py +131 -274
  137. agno/models/azure/ai_foundry.py +10 -6
  138. agno/models/azure/openai_chat.py +33 -10
  139. agno/models/base.py +1162 -561
  140. agno/models/cerebras/cerebras.py +120 -24
  141. agno/models/cerebras/cerebras_openai.py +21 -2
  142. agno/models/cohere/chat.py +65 -6
  143. agno/models/cometapi/cometapi.py +18 -1
  144. agno/models/dashscope/dashscope.py +2 -3
  145. agno/models/deepinfra/deepinfra.py +18 -1
  146. agno/models/deepseek/deepseek.py +69 -3
  147. agno/models/fireworks/fireworks.py +18 -1
  148. agno/models/google/gemini.py +959 -89
  149. agno/models/google/utils.py +22 -0
  150. agno/models/groq/groq.py +48 -18
  151. agno/models/huggingface/huggingface.py +17 -6
  152. agno/models/ibm/watsonx.py +16 -6
  153. agno/models/internlm/internlm.py +18 -1
  154. agno/models/langdb/langdb.py +13 -1
  155. agno/models/litellm/chat.py +88 -9
  156. agno/models/litellm/litellm_openai.py +18 -1
  157. agno/models/message.py +24 -5
  158. agno/models/meta/llama.py +40 -13
  159. agno/models/meta/llama_openai.py +22 -21
  160. agno/models/metrics.py +12 -0
  161. agno/models/mistral/mistral.py +8 -4
  162. agno/models/n1n/__init__.py +3 -0
  163. agno/models/n1n/n1n.py +57 -0
  164. agno/models/nebius/nebius.py +6 -7
  165. agno/models/nvidia/nvidia.py +20 -3
  166. agno/models/ollama/__init__.py +2 -0
  167. agno/models/ollama/chat.py +17 -6
  168. agno/models/ollama/responses.py +100 -0
  169. agno/models/openai/__init__.py +2 -0
  170. agno/models/openai/chat.py +117 -26
  171. agno/models/openai/open_responses.py +46 -0
  172. agno/models/openai/responses.py +110 -32
  173. agno/models/openrouter/__init__.py +2 -0
  174. agno/models/openrouter/openrouter.py +67 -2
  175. agno/models/openrouter/responses.py +146 -0
  176. agno/models/perplexity/perplexity.py +19 -1
  177. agno/models/portkey/portkey.py +7 -6
  178. agno/models/requesty/requesty.py +19 -2
  179. agno/models/response.py +20 -2
  180. agno/models/sambanova/sambanova.py +20 -3
  181. agno/models/siliconflow/siliconflow.py +19 -2
  182. agno/models/together/together.py +20 -3
  183. agno/models/vercel/v0.py +20 -3
  184. agno/models/vertexai/claude.py +124 -4
  185. agno/models/vllm/vllm.py +19 -14
  186. agno/models/xai/xai.py +19 -2
  187. agno/os/app.py +467 -137
  188. agno/os/auth.py +253 -5
  189. agno/os/config.py +22 -0
  190. agno/os/interfaces/a2a/a2a.py +7 -6
  191. agno/os/interfaces/a2a/router.py +635 -26
  192. agno/os/interfaces/a2a/utils.py +32 -33
  193. agno/os/interfaces/agui/agui.py +5 -3
  194. agno/os/interfaces/agui/router.py +26 -16
  195. agno/os/interfaces/agui/utils.py +97 -57
  196. agno/os/interfaces/base.py +7 -7
  197. agno/os/interfaces/slack/router.py +16 -7
  198. agno/os/interfaces/slack/slack.py +7 -7
  199. agno/os/interfaces/whatsapp/router.py +35 -7
  200. agno/os/interfaces/whatsapp/security.py +3 -1
  201. agno/os/interfaces/whatsapp/whatsapp.py +11 -8
  202. agno/os/managers.py +326 -0
  203. agno/os/mcp.py +652 -79
  204. agno/os/middleware/__init__.py +4 -0
  205. agno/os/middleware/jwt.py +718 -115
  206. agno/os/middleware/trailing_slash.py +27 -0
  207. agno/os/router.py +105 -1558
  208. agno/os/routers/agents/__init__.py +3 -0
  209. agno/os/routers/agents/router.py +655 -0
  210. agno/os/routers/agents/schema.py +288 -0
  211. agno/os/routers/components/__init__.py +3 -0
  212. agno/os/routers/components/components.py +475 -0
  213. agno/os/routers/database.py +155 -0
  214. agno/os/routers/evals/evals.py +111 -18
  215. agno/os/routers/evals/schemas.py +38 -5
  216. agno/os/routers/evals/utils.py +80 -11
  217. agno/os/routers/health.py +3 -3
  218. agno/os/routers/knowledge/knowledge.py +284 -35
  219. agno/os/routers/knowledge/schemas.py +14 -2
  220. agno/os/routers/memory/memory.py +274 -11
  221. agno/os/routers/memory/schemas.py +44 -3
  222. agno/os/routers/metrics/metrics.py +30 -15
  223. agno/os/routers/metrics/schemas.py +10 -6
  224. agno/os/routers/registry/__init__.py +3 -0
  225. agno/os/routers/registry/registry.py +337 -0
  226. agno/os/routers/session/session.py +143 -14
  227. agno/os/routers/teams/__init__.py +3 -0
  228. agno/os/routers/teams/router.py +550 -0
  229. agno/os/routers/teams/schema.py +280 -0
  230. agno/os/routers/traces/__init__.py +3 -0
  231. agno/os/routers/traces/schemas.py +414 -0
  232. agno/os/routers/traces/traces.py +549 -0
  233. agno/os/routers/workflows/__init__.py +3 -0
  234. agno/os/routers/workflows/router.py +757 -0
  235. agno/os/routers/workflows/schema.py +139 -0
  236. agno/os/schema.py +157 -584
  237. agno/os/scopes.py +469 -0
  238. agno/os/settings.py +3 -0
  239. agno/os/utils.py +574 -185
  240. agno/reasoning/anthropic.py +85 -1
  241. agno/reasoning/azure_ai_foundry.py +93 -1
  242. agno/reasoning/deepseek.py +102 -2
  243. agno/reasoning/default.py +6 -7
  244. agno/reasoning/gemini.py +87 -3
  245. agno/reasoning/groq.py +109 -2
  246. agno/reasoning/helpers.py +6 -7
  247. agno/reasoning/manager.py +1238 -0
  248. agno/reasoning/ollama.py +93 -1
  249. agno/reasoning/openai.py +115 -1
  250. agno/reasoning/vertexai.py +85 -1
  251. agno/registry/__init__.py +3 -0
  252. agno/registry/registry.py +68 -0
  253. agno/remote/__init__.py +3 -0
  254. agno/remote/base.py +581 -0
  255. agno/run/__init__.py +2 -4
  256. agno/run/agent.py +134 -19
  257. agno/run/base.py +49 -1
  258. agno/run/cancel.py +65 -52
  259. agno/run/cancellation_management/__init__.py +9 -0
  260. agno/run/cancellation_management/base.py +78 -0
  261. agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
  262. agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
  263. agno/run/requirement.py +181 -0
  264. agno/run/team.py +111 -19
  265. agno/run/workflow.py +2 -1
  266. agno/session/agent.py +57 -92
  267. agno/session/summary.py +1 -1
  268. agno/session/team.py +62 -115
  269. agno/session/workflow.py +353 -57
  270. agno/skills/__init__.py +17 -0
  271. agno/skills/agent_skills.py +377 -0
  272. agno/skills/errors.py +32 -0
  273. agno/skills/loaders/__init__.py +4 -0
  274. agno/skills/loaders/base.py +27 -0
  275. agno/skills/loaders/local.py +216 -0
  276. agno/skills/skill.py +65 -0
  277. agno/skills/utils.py +107 -0
  278. agno/skills/validator.py +277 -0
  279. agno/table.py +10 -0
  280. agno/team/__init__.py +5 -1
  281. agno/team/remote.py +447 -0
  282. agno/team/team.py +3769 -2202
  283. agno/tools/brandfetch.py +27 -18
  284. agno/tools/browserbase.py +225 -16
  285. agno/tools/crawl4ai.py +3 -0
  286. agno/tools/duckduckgo.py +25 -71
  287. agno/tools/exa.py +0 -21
  288. agno/tools/file.py +14 -13
  289. agno/tools/file_generation.py +12 -6
  290. agno/tools/firecrawl.py +15 -7
  291. agno/tools/function.py +94 -113
  292. agno/tools/google_bigquery.py +11 -2
  293. agno/tools/google_drive.py +4 -3
  294. agno/tools/knowledge.py +9 -4
  295. agno/tools/mcp/mcp.py +301 -18
  296. agno/tools/mcp/multi_mcp.py +269 -14
  297. agno/tools/mem0.py +11 -10
  298. agno/tools/memory.py +47 -46
  299. agno/tools/mlx_transcribe.py +10 -7
  300. agno/tools/models/nebius.py +5 -5
  301. agno/tools/models_labs.py +20 -10
  302. agno/tools/nano_banana.py +151 -0
  303. agno/tools/parallel.py +0 -7
  304. agno/tools/postgres.py +76 -36
  305. agno/tools/python.py +14 -6
  306. agno/tools/reasoning.py +30 -23
  307. agno/tools/redshift.py +406 -0
  308. agno/tools/shopify.py +1519 -0
  309. agno/tools/spotify.py +919 -0
  310. agno/tools/tavily.py +4 -1
  311. agno/tools/toolkit.py +253 -18
  312. agno/tools/websearch.py +93 -0
  313. agno/tools/website.py +1 -1
  314. agno/tools/wikipedia.py +1 -1
  315. agno/tools/workflow.py +56 -48
  316. agno/tools/yfinance.py +12 -11
  317. agno/tracing/__init__.py +12 -0
  318. agno/tracing/exporter.py +161 -0
  319. agno/tracing/schemas.py +276 -0
  320. agno/tracing/setup.py +112 -0
  321. agno/utils/agent.py +251 -10
  322. agno/utils/cryptography.py +22 -0
  323. agno/utils/dttm.py +33 -0
  324. agno/utils/events.py +264 -7
  325. agno/utils/hooks.py +111 -3
  326. agno/utils/http.py +161 -2
  327. agno/utils/mcp.py +49 -8
  328. agno/utils/media.py +22 -1
  329. agno/utils/models/ai_foundry.py +9 -2
  330. agno/utils/models/claude.py +20 -5
  331. agno/utils/models/cohere.py +9 -2
  332. agno/utils/models/llama.py +9 -2
  333. agno/utils/models/mistral.py +4 -2
  334. agno/utils/os.py +0 -0
  335. agno/utils/print_response/agent.py +99 -16
  336. agno/utils/print_response/team.py +223 -24
  337. agno/utils/print_response/workflow.py +0 -2
  338. agno/utils/prompts.py +8 -6
  339. agno/utils/remote.py +23 -0
  340. agno/utils/response.py +1 -13
  341. agno/utils/string.py +91 -2
  342. agno/utils/team.py +62 -12
  343. agno/utils/tokens.py +657 -0
  344. agno/vectordb/base.py +15 -2
  345. agno/vectordb/cassandra/cassandra.py +1 -1
  346. agno/vectordb/chroma/__init__.py +2 -1
  347. agno/vectordb/chroma/chromadb.py +468 -23
  348. agno/vectordb/clickhouse/clickhousedb.py +1 -1
  349. agno/vectordb/couchbase/couchbase.py +6 -2
  350. agno/vectordb/lancedb/lance_db.py +7 -38
  351. agno/vectordb/lightrag/lightrag.py +7 -6
  352. agno/vectordb/milvus/milvus.py +118 -84
  353. agno/vectordb/mongodb/__init__.py +2 -1
  354. agno/vectordb/mongodb/mongodb.py +14 -31
  355. agno/vectordb/pgvector/pgvector.py +120 -66
  356. agno/vectordb/pineconedb/pineconedb.py +2 -19
  357. agno/vectordb/qdrant/__init__.py +2 -1
  358. agno/vectordb/qdrant/qdrant.py +33 -56
  359. agno/vectordb/redis/__init__.py +2 -1
  360. agno/vectordb/redis/redisdb.py +19 -31
  361. agno/vectordb/singlestore/singlestore.py +17 -9
  362. agno/vectordb/surrealdb/surrealdb.py +2 -38
  363. agno/vectordb/weaviate/__init__.py +2 -1
  364. agno/vectordb/weaviate/weaviate.py +7 -3
  365. agno/workflow/__init__.py +5 -1
  366. agno/workflow/agent.py +2 -2
  367. agno/workflow/condition.py +12 -10
  368. agno/workflow/loop.py +28 -9
  369. agno/workflow/parallel.py +21 -13
  370. agno/workflow/remote.py +362 -0
  371. agno/workflow/router.py +12 -9
  372. agno/workflow/step.py +261 -36
  373. agno/workflow/steps.py +12 -8
  374. agno/workflow/types.py +40 -77
  375. agno/workflow/workflow.py +939 -213
  376. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
  377. agno-2.4.3.dist-info/RECORD +677 -0
  378. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
  379. agno/tools/googlesearch.py +0 -98
  380. agno/tools/memori.py +0 -339
  381. agno-2.2.13.dist-info/RECORD +0 -575
  382. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
  383. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/os/schema.py CHANGED
@@ -1,30 +1,26 @@
1
1
  from datetime import datetime, timezone
2
2
  from enum import Enum
3
3
  from typing import Any, Dict, Generic, List, Optional, TypeVar, Union
4
- from uuid import uuid4
5
4
 
6
5
  from pydantic import BaseModel, ConfigDict, Field
7
6
 
8
7
  from agno.agent import Agent
8
+ from agno.agent.remote import RemoteAgent
9
9
  from agno.db.base import SessionType
10
- from agno.models.message import Message
11
- from agno.os.config import ChatConfig, EvalsConfig, KnowledgeConfig, MemoryConfig, MetricsConfig, SessionConfig
12
- from agno.os.utils import (
13
- extract_input_media,
14
- format_team_tools,
15
- format_tools,
16
- get_agent_input_schema_dict,
17
- get_run_input,
18
- get_session_name,
19
- get_team_input_schema_dict,
20
- get_workflow_input_schema_dict,
10
+ from agno.os.config import (
11
+ ChatConfig,
12
+ EvalsConfig,
13
+ KnowledgeConfig,
14
+ MemoryConfig,
15
+ MetricsConfig,
16
+ SessionConfig,
17
+ TracesConfig,
21
18
  )
22
- from agno.run import RunContext
23
- from agno.run.agent import RunOutput
24
- from agno.run.team import TeamRunOutput
19
+ from agno.os.utils import extract_input_media, get_run_input, get_session_name, to_utc_datetime
25
20
  from agno.session import AgentSession, TeamSession, WorkflowSession
21
+ from agno.team.remote import RemoteTeam
26
22
  from agno.team.team import Team
27
- from agno.workflow.agent import WorkflowAgent
23
+ from agno.workflow.remote import RemoteWorkflow
28
24
  from agno.workflow.workflow import Workflow
29
25
 
30
26
 
@@ -79,10 +75,12 @@ class InternalServerErrorResponse(BaseModel):
79
75
 
80
76
 
81
77
  class HealthResponse(BaseModel):
82
- model_config = ConfigDict(json_schema_extra={"example": {"status": "ok", "instantiated_at": "1760169236.778903"}})
78
+ model_config = ConfigDict(
79
+ json_schema_extra={"example": {"status": "ok", "instantiated_at": "2025-06-10T12:00:00Z"}}
80
+ )
83
81
 
84
82
  status: str = Field(..., description="Health status of the service")
85
- instantiated_at: str = Field(..., description="Unix timestamp when service was instantiated")
83
+ instantiated_at: datetime = Field(..., description="Timestamp when service was instantiated")
86
84
 
87
85
 
88
86
  class InterfaceResponse(BaseModel):
@@ -105,7 +103,7 @@ class AgentSummaryResponse(BaseModel):
105
103
  db_id: Optional[str] = Field(None, description="Database identifier")
106
104
 
107
105
  @classmethod
108
- def from_agent(cls, agent: Agent) -> "AgentSummaryResponse":
106
+ def from_agent(cls, agent: Union[Agent, RemoteAgent]) -> "AgentSummaryResponse":
109
107
  return cls(id=agent.id, name=agent.name, description=agent.description, db_id=agent.db.id if agent.db else None)
110
108
 
111
109
 
@@ -116,8 +114,9 @@ class TeamSummaryResponse(BaseModel):
116
114
  db_id: Optional[str] = Field(None, description="Database identifier")
117
115
 
118
116
  @classmethod
119
- def from_team(cls, team: Team) -> "TeamSummaryResponse":
120
- return cls(id=team.id, name=team.name, description=team.description, db_id=team.db.id if team.db else None)
117
+ def from_team(cls, team: Union[Team, RemoteTeam]) -> "TeamSummaryResponse":
118
+ db_id = team.db.id if team.db else None
119
+ return cls(id=team.id, name=team.name, description=team.description, db_id=db_id)
121
120
 
122
121
 
123
122
  class WorkflowSummaryResponse(BaseModel):
@@ -127,12 +126,13 @@ class WorkflowSummaryResponse(BaseModel):
127
126
  db_id: Optional[str] = Field(None, description="Database identifier")
128
127
 
129
128
  @classmethod
130
- def from_workflow(cls, workflow: Workflow) -> "WorkflowSummaryResponse":
129
+ def from_workflow(cls, workflow: Union[Workflow, RemoteWorkflow]) -> "WorkflowSummaryResponse":
130
+ db_id = workflow.db.id if workflow.db else None
131
131
  return cls(
132
132
  id=workflow.id,
133
133
  name=workflow.name,
134
134
  description=workflow.description,
135
- db_id=workflow.db.id if workflow.db else None,
135
+ db_id=db_id,
136
136
  )
137
137
 
138
138
 
@@ -143,7 +143,8 @@ class ConfigResponse(BaseModel):
143
143
  name: Optional[str] = Field(None, description="Name of the OS instance")
144
144
  description: Optional[str] = Field(None, description="Description of the OS instance")
145
145
  available_models: Optional[List[str]] = Field(None, description="List of available models")
146
- databases: List[str] = Field(..., description="List of database IDs")
146
+ os_database: Optional[str] = Field(None, description="ID of the database used for the OS instance")
147
+ databases: List[str] = Field(..., description="List of database IDs used by the components of the OS instance")
147
148
  chat: Optional[ChatConfig] = Field(None, description="Chat configuration")
148
149
 
149
150
  session: Optional[SessionConfig] = Field(None, description="Session configuration")
@@ -151,6 +152,7 @@ class ConfigResponse(BaseModel):
151
152
  memory: Optional[MemoryConfig] = Field(None, description="Memory configuration")
152
153
  knowledge: Optional[KnowledgeConfig] = Field(None, description="Knowledge configuration")
153
154
  evals: Optional[EvalsConfig] = Field(None, description="Evaluations configuration")
155
+ traces: Optional[TracesConfig] = Field(None, description="Traces configuration")
154
156
 
155
157
  agents: List[AgentSummaryResponse] = Field(..., description="List of registered agents")
156
158
  teams: List[TeamSummaryResponse] = Field(..., description="List of registered teams")
@@ -169,539 +171,6 @@ class ModelResponse(BaseModel):
169
171
  provider: Optional[str] = Field(None, description="Model provider name")
170
172
 
171
173
 
172
- class AgentResponse(BaseModel):
173
- id: Optional[str] = None
174
- name: Optional[str] = None
175
- db_id: Optional[str] = None
176
- model: Optional[ModelResponse] = None
177
- tools: Optional[Dict[str, Any]] = None
178
- sessions: Optional[Dict[str, Any]] = None
179
- knowledge: Optional[Dict[str, Any]] = None
180
- memory: Optional[Dict[str, Any]] = None
181
- reasoning: Optional[Dict[str, Any]] = None
182
- default_tools: Optional[Dict[str, Any]] = None
183
- system_message: Optional[Dict[str, Any]] = None
184
- extra_messages: Optional[Dict[str, Any]] = None
185
- response_settings: Optional[Dict[str, Any]] = None
186
- streaming: Optional[Dict[str, Any]] = None
187
- metadata: Optional[Dict[str, Any]] = None
188
- input_schema: Optional[Dict[str, Any]] = None
189
-
190
- @classmethod
191
- async def from_agent(cls, agent: Agent) -> "AgentResponse":
192
- def filter_meaningful_config(d: Dict[str, Any], defaults: Dict[str, Any]) -> Optional[Dict[str, Any]]:
193
- """Filter out fields that match their default values, keeping only meaningful user configurations"""
194
- filtered = {}
195
- for key, value in d.items():
196
- if value is None:
197
- continue
198
- # Skip if value matches the default exactly
199
- if key in defaults and value == defaults[key]:
200
- continue
201
- # Keep non-default values
202
- filtered[key] = value
203
- return filtered if filtered else None
204
-
205
- # Define default values for filtering
206
- agent_defaults = {
207
- # Sessions defaults
208
- "add_history_to_context": False,
209
- "num_history_runs": 3,
210
- "enable_session_summaries": False,
211
- "search_session_history": False,
212
- "cache_session": False,
213
- # Knowledge defaults
214
- "add_references": False,
215
- "references_format": "json",
216
- "enable_agentic_knowledge_filters": False,
217
- # Memory defaults
218
- "enable_agentic_memory": False,
219
- "enable_user_memories": False,
220
- # Reasoning defaults
221
- "reasoning": False,
222
- "reasoning_min_steps": 1,
223
- "reasoning_max_steps": 10,
224
- # Default tools defaults
225
- "read_chat_history": False,
226
- "search_knowledge": True,
227
- "update_knowledge": False,
228
- "read_tool_call_history": False,
229
- # System message defaults
230
- "system_message_role": "system",
231
- "build_context": True,
232
- "markdown": False,
233
- "add_name_to_context": False,
234
- "add_datetime_to_context": False,
235
- "add_location_to_context": False,
236
- "resolve_in_context": True,
237
- # Extra messages defaults
238
- "user_message_role": "user",
239
- "build_user_context": True,
240
- # Response settings defaults
241
- "retries": 0,
242
- "delay_between_retries": 1,
243
- "exponential_backoff": False,
244
- "parse_response": True,
245
- "use_json_mode": False,
246
- # Streaming defaults
247
- "stream_events": False,
248
- "stream_intermediate_steps": False,
249
- }
250
-
251
- session_id = str(uuid4())
252
- run_id = str(uuid4())
253
- agent_tools = await agent.aget_tools(
254
- session=AgentSession(session_id=session_id, session_data={}),
255
- run_response=RunOutput(run_id=run_id, session_id=session_id),
256
- run_context=RunContext(run_id=run_id, session_id=session_id, user_id=agent.user_id),
257
- check_mcp_tools=False,
258
- )
259
- formatted_tools = format_tools(agent_tools) if agent_tools else None
260
-
261
- additional_input = agent.additional_input
262
- if additional_input and isinstance(additional_input[0], Message):
263
- additional_input = [message.to_dict() for message in additional_input] # type: ignore
264
-
265
- # Build model only if it has at least one non-null field
266
- model_name = agent.model.name if (agent.model and agent.model.name) else None
267
- model_provider = agent.model.provider if (agent.model and agent.model.provider) else None
268
- model_id = agent.model.id if (agent.model and agent.model.id) else None
269
- _agent_model_data: Dict[str, Any] = {}
270
- if model_name is not None:
271
- _agent_model_data["name"] = model_name
272
- if model_id is not None:
273
- _agent_model_data["model"] = model_id
274
- if model_provider is not None:
275
- _agent_model_data["provider"] = model_provider
276
-
277
- session_table = agent.db.session_table_name if agent.db else None
278
- knowledge_table = agent.db.knowledge_table_name if agent.db and agent.knowledge else None
279
-
280
- tools_info = {
281
- "tools": formatted_tools,
282
- "tool_call_limit": agent.tool_call_limit,
283
- "tool_choice": agent.tool_choice,
284
- }
285
-
286
- sessions_info = {
287
- "session_table": session_table,
288
- "add_history_to_context": agent.add_history_to_context,
289
- "enable_session_summaries": agent.enable_session_summaries,
290
- "num_history_runs": agent.num_history_runs,
291
- "search_session_history": agent.search_session_history,
292
- "num_history_sessions": agent.num_history_sessions,
293
- "cache_session": agent.cache_session,
294
- }
295
-
296
- knowledge_info = {
297
- "knowledge_table": knowledge_table,
298
- "enable_agentic_knowledge_filters": agent.enable_agentic_knowledge_filters,
299
- "knowledge_filters": agent.knowledge_filters,
300
- "references_format": agent.references_format,
301
- }
302
-
303
- memory_info: Optional[Dict[str, Any]] = None
304
- if agent.memory_manager is not None:
305
- memory_info = {
306
- "enable_agentic_memory": agent.enable_agentic_memory,
307
- "enable_user_memories": agent.enable_user_memories,
308
- "metadata": agent.metadata,
309
- "memory_table": agent.db.memory_table_name if agent.db and agent.enable_user_memories else None,
310
- }
311
-
312
- if agent.memory_manager.model is not None:
313
- memory_info["model"] = ModelResponse(
314
- name=agent.memory_manager.model.name,
315
- model=agent.memory_manager.model.id,
316
- provider=agent.memory_manager.model.provider,
317
- ).model_dump()
318
-
319
- reasoning_info: Dict[str, Any] = {
320
- "reasoning": agent.reasoning,
321
- "reasoning_agent_id": agent.reasoning_agent.id if agent.reasoning_agent else None,
322
- "reasoning_min_steps": agent.reasoning_min_steps,
323
- "reasoning_max_steps": agent.reasoning_max_steps,
324
- }
325
-
326
- if agent.reasoning_model:
327
- reasoning_info["reasoning_model"] = ModelResponse(
328
- name=agent.reasoning_model.name,
329
- model=agent.reasoning_model.id,
330
- provider=agent.reasoning_model.provider,
331
- ).model_dump()
332
-
333
- default_tools_info = {
334
- "read_chat_history": agent.read_chat_history,
335
- "search_knowledge": agent.search_knowledge,
336
- "update_knowledge": agent.update_knowledge,
337
- "read_tool_call_history": agent.read_tool_call_history,
338
- }
339
-
340
- system_message_info = {
341
- "system_message": str(agent.system_message) if agent.system_message else None,
342
- "system_message_role": agent.system_message_role,
343
- "build_context": agent.build_context,
344
- "description": agent.description,
345
- "instructions": agent.instructions if agent.instructions else None,
346
- "expected_output": agent.expected_output,
347
- "additional_context": agent.additional_context,
348
- "markdown": agent.markdown,
349
- "add_name_to_context": agent.add_name_to_context,
350
- "add_datetime_to_context": agent.add_datetime_to_context,
351
- "add_location_to_context": agent.add_location_to_context,
352
- "timezone_identifier": agent.timezone_identifier,
353
- "resolve_in_context": agent.resolve_in_context,
354
- }
355
-
356
- extra_messages_info = {
357
- "additional_input": additional_input, # type: ignore
358
- "user_message_role": agent.user_message_role,
359
- "build_user_context": agent.build_user_context,
360
- }
361
-
362
- response_settings_info: Dict[str, Any] = {
363
- "retries": agent.retries,
364
- "delay_between_retries": agent.delay_between_retries,
365
- "exponential_backoff": agent.exponential_backoff,
366
- "output_schema_name": agent.output_schema.__name__ if agent.output_schema else None,
367
- "parser_model_prompt": agent.parser_model_prompt,
368
- "parse_response": agent.parse_response,
369
- "structured_outputs": agent.structured_outputs,
370
- "use_json_mode": agent.use_json_mode,
371
- "save_response_to_file": agent.save_response_to_file,
372
- }
373
-
374
- if agent.parser_model:
375
- response_settings_info["parser_model"] = ModelResponse(
376
- name=agent.parser_model.name,
377
- model=agent.parser_model.id,
378
- provider=agent.parser_model.provider,
379
- ).model_dump()
380
-
381
- streaming_info = {
382
- "stream": agent.stream,
383
- "stream_events": agent.stream_events,
384
- "stream_intermediate_steps": agent.stream_intermediate_steps,
385
- }
386
-
387
- return AgentResponse(
388
- id=agent.id,
389
- name=agent.name,
390
- db_id=agent.db.id if agent.db else None,
391
- model=ModelResponse(**_agent_model_data) if _agent_model_data else None,
392
- tools=filter_meaningful_config(tools_info, {}),
393
- sessions=filter_meaningful_config(sessions_info, agent_defaults),
394
- knowledge=filter_meaningful_config(knowledge_info, agent_defaults),
395
- memory=filter_meaningful_config(memory_info, agent_defaults) if memory_info else None,
396
- reasoning=filter_meaningful_config(reasoning_info, agent_defaults),
397
- default_tools=filter_meaningful_config(default_tools_info, agent_defaults),
398
- system_message=filter_meaningful_config(system_message_info, agent_defaults),
399
- extra_messages=filter_meaningful_config(extra_messages_info, agent_defaults),
400
- response_settings=filter_meaningful_config(response_settings_info, agent_defaults),
401
- streaming=filter_meaningful_config(streaming_info, agent_defaults),
402
- metadata=agent.metadata,
403
- input_schema=get_agent_input_schema_dict(agent),
404
- )
405
-
406
-
407
- class TeamResponse(BaseModel):
408
- id: Optional[str] = None
409
- name: Optional[str] = None
410
- db_id: Optional[str] = None
411
- description: Optional[str] = None
412
- model: Optional[ModelResponse] = None
413
- tools: Optional[Dict[str, Any]] = None
414
- sessions: Optional[Dict[str, Any]] = None
415
- knowledge: Optional[Dict[str, Any]] = None
416
- memory: Optional[Dict[str, Any]] = None
417
- reasoning: Optional[Dict[str, Any]] = None
418
- default_tools: Optional[Dict[str, Any]] = None
419
- system_message: Optional[Dict[str, Any]] = None
420
- response_settings: Optional[Dict[str, Any]] = None
421
- streaming: Optional[Dict[str, Any]] = None
422
- members: Optional[List[Union[AgentResponse, "TeamResponse"]]] = None
423
- metadata: Optional[Dict[str, Any]] = None
424
- input_schema: Optional[Dict[str, Any]] = None
425
-
426
- @classmethod
427
- async def from_team(cls, team: Team) -> "TeamResponse":
428
- def filter_meaningful_config(d: Dict[str, Any], defaults: Dict[str, Any]) -> Optional[Dict[str, Any]]:
429
- """Filter out fields that match their default values, keeping only meaningful user configurations"""
430
- filtered = {}
431
- for key, value in d.items():
432
- if value is None:
433
- continue
434
- # Skip if value matches the default exactly
435
- if key in defaults and value == defaults[key]:
436
- continue
437
- # Keep non-default values
438
- filtered[key] = value
439
- return filtered if filtered else None
440
-
441
- # Define default values for filtering (similar to agent defaults)
442
- team_defaults = {
443
- # Sessions defaults
444
- "add_history_to_context": False,
445
- "num_history_runs": 3,
446
- "enable_session_summaries": False,
447
- "cache_session": False,
448
- # Knowledge defaults
449
- "add_references": False,
450
- "references_format": "json",
451
- "enable_agentic_knowledge_filters": False,
452
- # Memory defaults
453
- "enable_agentic_memory": False,
454
- "enable_user_memories": False,
455
- # Reasoning defaults
456
- "reasoning": False,
457
- "reasoning_min_steps": 1,
458
- "reasoning_max_steps": 10,
459
- # Default tools defaults
460
- "search_knowledge": True,
461
- "read_team_history": False,
462
- "get_member_information_tool": False,
463
- # System message defaults
464
- "system_message_role": "system",
465
- "markdown": False,
466
- "add_datetime_to_context": False,
467
- "add_location_to_context": False,
468
- "resolve_in_context": True,
469
- # Response settings defaults
470
- "parse_response": True,
471
- "use_json_mode": False,
472
- # Streaming defaults
473
- "stream_events": False,
474
- "stream_intermediate_steps": False,
475
- "stream_member_events": False,
476
- }
477
-
478
- run_id = str(uuid4())
479
- session_id = str(uuid4())
480
- _tools = team._determine_tools_for_model(
481
- model=team.model, # type: ignore
482
- session=TeamSession(session_id=session_id, session_data={}),
483
- run_response=TeamRunOutput(run_id=run_id),
484
- run_context=RunContext(run_id=run_id, session_id=session_id, session_state={}),
485
- async_mode=True,
486
- team_run_context={},
487
- check_mcp_tools=False,
488
- )
489
- team_tools = _tools
490
- formatted_tools = format_team_tools(team_tools) if team_tools else None
491
-
492
- model_name = team.model.name or team.model.__class__.__name__ if team.model else None
493
- model_provider = team.model.provider or team.model.__class__.__name__ if team.model else ""
494
- model_id = team.model.id if team.model else None
495
-
496
- if model_provider and model_id:
497
- model_provider = f"{model_provider} {model_id}"
498
- elif model_name and model_id:
499
- model_provider = f"{model_name} {model_id}"
500
- elif model_id:
501
- model_provider = model_id
502
-
503
- session_table = team.db.session_table_name if team.db else None
504
- knowledge_table = team.db.knowledge_table_name if team.db and team.knowledge else None
505
-
506
- tools_info = {
507
- "tools": formatted_tools,
508
- "tool_call_limit": team.tool_call_limit,
509
- "tool_choice": team.tool_choice,
510
- }
511
-
512
- sessions_info = {
513
- "session_table": session_table,
514
- "add_history_to_context": team.add_history_to_context,
515
- "enable_session_summaries": team.enable_session_summaries,
516
- "num_history_runs": team.num_history_runs,
517
- "cache_session": team.cache_session,
518
- }
519
-
520
- knowledge_info = {
521
- "knowledge_table": knowledge_table,
522
- "enable_agentic_knowledge_filters": team.enable_agentic_knowledge_filters,
523
- "knowledge_filters": team.knowledge_filters,
524
- "references_format": team.references_format,
525
- }
526
-
527
- memory_info: Optional[Dict[str, Any]] = None
528
- if team.memory_manager is not None:
529
- memory_info = {
530
- "enable_agentic_memory": team.enable_agentic_memory,
531
- "enable_user_memories": team.enable_user_memories,
532
- "metadata": team.metadata,
533
- "memory_table": team.db.memory_table_name if team.db and team.enable_user_memories else None,
534
- }
535
-
536
- if team.memory_manager.model is not None:
537
- memory_info["model"] = ModelResponse(
538
- name=team.memory_manager.model.name,
539
- model=team.memory_manager.model.id,
540
- provider=team.memory_manager.model.provider,
541
- ).model_dump()
542
-
543
- reasoning_info: Dict[str, Any] = {
544
- "reasoning": team.reasoning,
545
- "reasoning_agent_id": team.reasoning_agent.id if team.reasoning_agent else None,
546
- "reasoning_min_steps": team.reasoning_min_steps,
547
- "reasoning_max_steps": team.reasoning_max_steps,
548
- }
549
-
550
- if team.reasoning_model:
551
- reasoning_info["reasoning_model"] = ModelResponse(
552
- name=team.reasoning_model.name,
553
- model=team.reasoning_model.id,
554
- provider=team.reasoning_model.provider,
555
- ).model_dump()
556
-
557
- default_tools_info = {
558
- "search_knowledge": team.search_knowledge,
559
- "read_team_history": team.read_team_history,
560
- "get_member_information_tool": team.get_member_information_tool,
561
- }
562
-
563
- team_instructions = (
564
- team.instructions() if team.instructions and callable(team.instructions) else team.instructions
565
- )
566
-
567
- system_message_info = {
568
- "system_message": str(team.system_message) if team.system_message else None,
569
- "system_message_role": team.system_message_role,
570
- "description": team.description,
571
- "instructions": team_instructions,
572
- "expected_output": team.expected_output,
573
- "additional_context": team.additional_context,
574
- "markdown": team.markdown,
575
- "add_datetime_to_context": team.add_datetime_to_context,
576
- "add_location_to_context": team.add_location_to_context,
577
- "resolve_in_context": team.resolve_in_context,
578
- }
579
-
580
- response_settings_info: Dict[str, Any] = {
581
- "output_schema_name": team.output_schema.__name__ if team.output_schema else None,
582
- "parser_model_prompt": team.parser_model_prompt,
583
- "parse_response": team.parse_response,
584
- "use_json_mode": team.use_json_mode,
585
- }
586
-
587
- if team.parser_model:
588
- response_settings_info["parser_model"] = ModelResponse(
589
- name=team.parser_model.name,
590
- model=team.parser_model.id,
591
- provider=team.parser_model.provider,
592
- ).model_dump()
593
-
594
- streaming_info = {
595
- "stream": team.stream,
596
- "stream_events": team.stream_events,
597
- "stream_intermediate_steps": team.stream_intermediate_steps,
598
- "stream_member_events": team.stream_member_events,
599
- }
600
-
601
- # Build team model only if it has at least one non-null field
602
- _team_model_data: Dict[str, Any] = {}
603
- if team.model and team.model.name is not None:
604
- _team_model_data["name"] = team.model.name
605
- if team.model and team.model.id is not None:
606
- _team_model_data["model"] = team.model.id
607
- if team.model and team.model.provider is not None:
608
- _team_model_data["provider"] = team.model.provider
609
-
610
- members: List[Union[AgentResponse, TeamResponse]] = []
611
- for member in team.members:
612
- if isinstance(member, Agent):
613
- agent_response = await AgentResponse.from_agent(member)
614
- members.append(agent_response)
615
- if isinstance(member, Team):
616
- team_response = await TeamResponse.from_team(member)
617
- members.append(team_response)
618
-
619
- return TeamResponse(
620
- id=team.id,
621
- name=team.name,
622
- db_id=team.db.id if team.db else None,
623
- model=ModelResponse(**_team_model_data) if _team_model_data else None,
624
- tools=filter_meaningful_config(tools_info, {}),
625
- sessions=filter_meaningful_config(sessions_info, team_defaults),
626
- knowledge=filter_meaningful_config(knowledge_info, team_defaults),
627
- memory=filter_meaningful_config(memory_info, team_defaults) if memory_info else None,
628
- reasoning=filter_meaningful_config(reasoning_info, team_defaults),
629
- default_tools=filter_meaningful_config(default_tools_info, team_defaults),
630
- system_message=filter_meaningful_config(system_message_info, team_defaults),
631
- response_settings=filter_meaningful_config(response_settings_info, team_defaults),
632
- streaming=filter_meaningful_config(streaming_info, team_defaults),
633
- members=members if members else None,
634
- metadata=team.metadata,
635
- input_schema=get_team_input_schema_dict(team),
636
- )
637
-
638
-
639
- class WorkflowResponse(BaseModel):
640
- id: Optional[str] = Field(None, description="Unique identifier for the workflow")
641
- name: Optional[str] = Field(None, description="Name of the workflow")
642
- db_id: Optional[str] = Field(None, description="Database identifier")
643
- description: Optional[str] = Field(None, description="Description of the workflow")
644
- input_schema: Optional[Dict[str, Any]] = Field(None, description="Input schema for the workflow")
645
- steps: Optional[List[Dict[str, Any]]] = Field(None, description="List of workflow steps")
646
- agent: Optional[AgentResponse] = Field(None, description="Agent configuration if used")
647
- team: Optional[TeamResponse] = Field(None, description="Team configuration if used")
648
- metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")
649
- workflow_agent: bool = Field(False, description="Whether this workflow uses a WorkflowAgent")
650
-
651
- @classmethod
652
- async def _resolve_agents_and_teams_recursively(cls, steps: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
653
- """Parse Agents and Teams into AgentResponse and TeamResponse objects.
654
-
655
- If the given steps have nested steps, recursively work on those."""
656
- if not steps:
657
- return steps
658
-
659
- def _prune_none(value: Any) -> Any:
660
- # Recursively remove None values from dicts and lists
661
- if isinstance(value, dict):
662
- return {k: _prune_none(v) for k, v in value.items() if v is not None}
663
- if isinstance(value, list):
664
- return [_prune_none(v) for v in value]
665
- return value
666
-
667
- for idx, step in enumerate(steps):
668
- if step.get("agent"):
669
- # Convert to dict and exclude fields that are None
670
- agent_response = await AgentResponse.from_agent(step.get("agent")) # type: ignore
671
- step["agent"] = agent_response.model_dump(exclude_none=True)
672
-
673
- if step.get("team"):
674
- team_response = await TeamResponse.from_team(step.get("team")) # type: ignore
675
- step["team"] = team_response.model_dump(exclude_none=True)
676
-
677
- if step.get("steps"):
678
- step["steps"] = await cls._resolve_agents_and_teams_recursively(step["steps"])
679
-
680
- # Prune None values in the entire step
681
- steps[idx] = _prune_none(step)
682
-
683
- return steps
684
-
685
- @classmethod
686
- async def from_workflow(cls, workflow: Workflow) -> "WorkflowResponse":
687
- workflow_dict = workflow.to_dict()
688
- steps = workflow_dict.get("steps")
689
-
690
- if steps:
691
- steps = await cls._resolve_agents_and_teams_recursively(steps)
692
-
693
- return cls(
694
- id=workflow.id,
695
- name=workflow.name,
696
- db_id=workflow.db.id if workflow.db else None,
697
- description=workflow.description,
698
- steps=steps,
699
- input_schema=get_workflow_input_schema_dict(workflow),
700
- metadata=workflow.metadata,
701
- workflow_agent=isinstance(workflow.agent, WorkflowAgent) if workflow.agent else False,
702
- )
703
-
704
-
705
174
  class WorkflowRunRequest(BaseModel):
706
175
  input: Dict[str, Any] = Field(..., description="Input parameters for the workflow run")
707
176
  user_id: Optional[str] = Field(None, description="User identifier for the workflow run")
@@ -717,17 +186,39 @@ class SessionSchema(BaseModel):
717
186
 
718
187
  @classmethod
719
188
  def from_dict(cls, session: Dict[str, Any]) -> "SessionSchema":
720
- session_name = get_session_name(session)
189
+ session_name = session.get("session_name")
190
+ if not session_name:
191
+ session_name = get_session_name(session)
192
+ session_data = session.get("session_data", {}) or {}
193
+
194
+ created_at = session.get("created_at", 0)
195
+ updated_at = session.get("updated_at", created_at)
196
+
197
+ # Handle created_at and updated_at as either ISO 8601 string or timestamp
198
+ def parse_datetime(val):
199
+ if isinstance(val, str):
200
+ try:
201
+ # Accept both with and without Z
202
+ if val.endswith("Z"):
203
+ val = val[:-1] + "+00:00"
204
+ return datetime.fromisoformat(val)
205
+ except Exception:
206
+ return None
207
+ elif isinstance(val, (int, float)):
208
+ try:
209
+ return datetime.fromtimestamp(val, tz=timezone.utc)
210
+ except Exception:
211
+ return None
212
+ return None
213
+
214
+ created_at = to_utc_datetime(session.get("created_at", 0))
215
+ updated_at = to_utc_datetime(session.get("updated_at", created_at))
721
216
  return cls(
722
217
  session_id=session.get("session_id", ""),
723
218
  session_name=session_name,
724
- session_state=session.get("session_data", {}).get("session_state", None),
725
- created_at=datetime.fromtimestamp(session.get("created_at", 0), tz=timezone.utc)
726
- if session.get("created_at")
727
- else None,
728
- updated_at=datetime.fromtimestamp(session.get("updated_at", 0), tz=timezone.utc)
729
- if session.get("updated_at")
730
- else None,
219
+ session_state=session_data.get("session_state", None),
220
+ created_at=created_at,
221
+ updated_at=updated_at,
731
222
  )
732
223
 
733
224
 
@@ -773,6 +264,8 @@ class AgentSessionDetailSchema(BaseModel):
773
264
  @classmethod
774
265
  def from_session(cls, session: AgentSession) -> "AgentSessionDetailSchema":
775
266
  session_name = get_session_name({**session.to_dict(), "session_type": "agent"})
267
+ created_at = datetime.fromtimestamp(session.created_at, tz=timezone.utc) if session.created_at else None
268
+ updated_at = datetime.fromtimestamp(session.updated_at, tz=timezone.utc) if session.updated_at else created_at
776
269
  return cls(
777
270
  user_id=session.user_id,
778
271
  agent_session_id=session.session_id,
@@ -788,8 +281,8 @@ class AgentSessionDetailSchema(BaseModel):
788
281
  metrics=session.session_data.get("session_metrics", {}) if session.session_data else None, # type: ignore
789
282
  metadata=session.metadata,
790
283
  chat_history=[message.to_dict() for message in session.get_chat_history()],
791
- created_at=datetime.fromtimestamp(session.created_at, tz=timezone.utc) if session.created_at else None,
792
- updated_at=datetime.fromtimestamp(session.updated_at, tz=timezone.utc) if session.updated_at else None,
284
+ created_at=to_utc_datetime(created_at),
285
+ updated_at=to_utc_datetime(updated_at),
793
286
  )
794
287
 
795
288
 
@@ -812,7 +305,8 @@ class TeamSessionDetailSchema(BaseModel):
812
305
  def from_session(cls, session: TeamSession) -> "TeamSessionDetailSchema":
813
306
  session_dict = session.to_dict()
814
307
  session_name = get_session_name({**session_dict, "session_type": "team"})
815
-
308
+ created_at = datetime.fromtimestamp(session.created_at, tz=timezone.utc) if session.created_at else None
309
+ updated_at = datetime.fromtimestamp(session.updated_at, tz=timezone.utc) if session.updated_at else created_at
816
310
  return cls(
817
311
  session_id=session.session_id,
818
312
  team_id=session.team_id,
@@ -827,8 +321,8 @@ class TeamSessionDetailSchema(BaseModel):
827
321
  metrics=session.session_data.get("session_metrics", {}) if session.session_data else None,
828
322
  metadata=session.metadata,
829
323
  chat_history=[message.to_dict() for message in session.get_chat_history()],
830
- created_at=datetime.fromtimestamp(session.created_at, tz=timezone.utc) if session.created_at else None,
831
- updated_at=datetime.fromtimestamp(session.updated_at, tz=timezone.utc) if session.updated_at else None,
324
+ created_at=to_utc_datetime(created_at),
325
+ updated_at=to_utc_datetime(updated_at),
832
326
  )
833
327
 
834
328
 
@@ -844,14 +338,15 @@ class WorkflowSessionDetailSchema(BaseModel):
844
338
  workflow_data: Optional[dict] = Field(None, description="Workflow-specific data")
845
339
  metadata: Optional[dict] = Field(None, description="Additional metadata")
846
340
 
847
- created_at: Optional[int] = Field(None, description="Unix timestamp of session creation")
848
- updated_at: Optional[int] = Field(None, description="Unix timestamp of last update")
341
+ created_at: Optional[datetime] = Field(None, description="Session creation timestamp")
342
+ updated_at: Optional[datetime] = Field(None, description="Last update timestamp")
849
343
 
850
344
  @classmethod
851
345
  def from_session(cls, session: WorkflowSession) -> "WorkflowSessionDetailSchema":
852
346
  session_dict = session.to_dict()
853
347
  session_name = get_session_name({**session_dict, "session_type": "workflow"})
854
-
348
+ created_at = datetime.fromtimestamp(session.created_at, tz=timezone.utc) if session.created_at else None
349
+ updated_at = datetime.fromtimestamp(session.updated_at, tz=timezone.utc) if session.updated_at else created_at
855
350
  return cls(
856
351
  session_id=session.session_id,
857
352
  user_id=session.user_id,
@@ -862,8 +357,8 @@ class WorkflowSessionDetailSchema(BaseModel):
862
357
  session_state=session.session_data.get("session_state", None) if session.session_data else None,
863
358
  workflow_data=session.workflow_data,
864
359
  metadata=session.metadata,
865
- created_at=session.created_at,
866
- updated_at=session.updated_at,
360
+ created_at=to_utc_datetime(created_at),
361
+ updated_at=to_utc_datetime(updated_at),
867
362
  )
868
363
 
869
364
 
@@ -883,6 +378,9 @@ class RunSchema(BaseModel):
883
378
  events: Optional[List[dict]] = Field(None, description="Events generated during the run")
884
379
  created_at: Optional[datetime] = Field(None, description="Run creation timestamp")
885
380
  references: Optional[List[dict]] = Field(None, description="References cited in the run")
381
+ citations: Optional[Dict[str, Any]] = Field(
382
+ None, description="Citations from the model (e.g., from Gemini grounding/search)"
383
+ )
886
384
  reasoning_messages: Optional[List[dict]] = Field(None, description="Reasoning process messages")
887
385
  session_state: Optional[dict] = Field(None, description="Session state at the end of the run")
888
386
  images: Optional[List[dict]] = Field(None, description="Images included in the run")
@@ -896,6 +394,7 @@ class RunSchema(BaseModel):
896
394
  def from_dict(cls, run_dict: Dict[str, Any]) -> "RunSchema":
897
395
  run_input = get_run_input(run_dict)
898
396
  run_response_format = "text" if run_dict.get("content_type", "str") == "str" else "json"
397
+
899
398
  return cls(
900
399
  run_id=run_dict.get("run_id", ""),
901
400
  parent_run_id=run_dict.get("parent_run_id", ""),
@@ -911,6 +410,7 @@ class RunSchema(BaseModel):
911
410
  tools=[tool for tool in run_dict.get("tools", [])] if run_dict.get("tools") else None,
912
411
  events=[event for event in run_dict["events"]] if run_dict.get("events") else None,
913
412
  references=run_dict.get("references", []),
413
+ citations=run_dict.get("citations", None),
914
414
  reasoning_messages=run_dict.get("reasoning_messages", []),
915
415
  session_state=run_dict.get("session_state"),
916
416
  images=run_dict.get("images", []),
@@ -919,9 +419,7 @@ class RunSchema(BaseModel):
919
419
  files=run_dict.get("files", []),
920
420
  response_audio=run_dict.get("response_audio", None),
921
421
  input_media=extract_input_media(run_dict),
922
- created_at=datetime.fromtimestamp(run_dict.get("created_at", 0), tz=timezone.utc)
923
- if run_dict.get("created_at") is not None
924
- else None,
422
+ created_at=to_utc_datetime(run_dict.get("created_at")),
925
423
  )
926
424
 
927
425
 
@@ -940,6 +438,9 @@ class TeamRunSchema(BaseModel):
940
438
  events: Optional[List[dict]] = Field(None, description="Events generated during the run")
941
439
  created_at: Optional[datetime] = Field(None, description="Run creation timestamp")
942
440
  references: Optional[List[dict]] = Field(None, description="References cited in the run")
441
+ citations: Optional[Dict[str, Any]] = Field(
442
+ None, description="Citations from the model (e.g., from Gemini grounding/search)"
443
+ )
943
444
  reasoning_messages: Optional[List[dict]] = Field(None, description="Reasoning process messages")
944
445
  session_state: Optional[dict] = Field(None, description="Session state at the end of the run")
945
446
  input_media: Optional[Dict[str, Any]] = Field(None, description="Input media attachments")
@@ -966,10 +467,9 @@ class TeamRunSchema(BaseModel):
966
467
  messages=[message for message in run_dict.get("messages", [])] if run_dict.get("messages") else None,
967
468
  tools=[tool for tool in run_dict.get("tools", [])] if run_dict.get("tools") else None,
968
469
  events=[event for event in run_dict["events"]] if run_dict.get("events") else None,
969
- created_at=datetime.fromtimestamp(run_dict.get("created_at", 0), tz=timezone.utc)
970
- if run_dict.get("created_at") is not None
971
- else None,
470
+ created_at=to_utc_datetime(run_dict.get("created_at")),
972
471
  references=run_dict.get("references", []),
472
+ citations=run_dict.get("citations", None),
973
473
  reasoning_messages=run_dict.get("reasoning_messages", []),
974
474
  session_state=run_dict.get("session_state"),
975
475
  images=run_dict.get("images", []),
@@ -993,10 +493,13 @@ class WorkflowRunSchema(BaseModel):
993
493
  step_results: Optional[list[dict]] = Field(None, description="Results from each workflow step")
994
494
  step_executor_runs: Optional[list[dict]] = Field(None, description="Executor runs for each step")
995
495
  metrics: Optional[dict] = Field(None, description="Performance and usage metrics")
996
- created_at: Optional[int] = Field(None, description="Unix timestamp of run creation")
496
+ created_at: Optional[datetime] = Field(None, description="Run creation timestamp")
997
497
  reasoning_content: Optional[str] = Field(None, description="Reasoning content if reasoning was enabled")
998
498
  reasoning_steps: Optional[List[dict]] = Field(None, description="List of reasoning steps")
999
499
  references: Optional[List[dict]] = Field(None, description="References cited in the workflow")
500
+ citations: Optional[Dict[str, Any]] = Field(
501
+ None, description="Citations from the model (e.g., from Gemini grounding/search)"
502
+ )
1000
503
  reasoning_messages: Optional[List[dict]] = Field(None, description="Reasoning process messages")
1001
504
  images: Optional[List[dict]] = Field(None, description="Images included in the workflow")
1002
505
  videos: Optional[List[dict]] = Field(None, description="Videos included in the workflow")
@@ -1019,10 +522,11 @@ class WorkflowRunSchema(BaseModel):
1019
522
  metrics=run_response.get("metrics", {}),
1020
523
  step_results=run_response.get("step_results", []),
1021
524
  step_executor_runs=run_response.get("step_executor_runs", []),
1022
- created_at=run_response["created_at"],
525
+ created_at=to_utc_datetime(run_response.get("created_at")),
1023
526
  reasoning_content=run_response.get("reasoning_content", ""),
1024
527
  reasoning_steps=run_response.get("reasoning_steps", []),
1025
528
  references=run_response.get("references", []),
529
+ citations=run_response.get("citations", None),
1026
530
  reasoning_messages=run_response.get("reasoning_messages", []),
1027
531
  images=run_response.get("images", []),
1028
532
  videos=run_response.get("videos", []),
@@ -1042,7 +546,7 @@ class SortOrder(str, Enum):
1042
546
 
1043
547
  class PaginationInfo(BaseModel):
1044
548
  page: int = Field(0, description="Current page number (0-indexed)", ge=0)
1045
- limit: int = Field(20, description="Number of items per page", ge=1, le=100)
549
+ limit: int = Field(20, description="Number of items per page", ge=1)
1046
550
  total_pages: int = Field(0, description="Total number of pages", ge=0)
1047
551
  total_count: int = Field(0, description="Total count of items", ge=0)
1048
552
  search_time_ms: float = Field(0, description="Search execution time in milliseconds", ge=0)
@@ -1053,3 +557,72 @@ class PaginatedResponse(BaseModel, Generic[T]):
1053
557
 
1054
558
  data: List[T] = Field(..., description="List of items for the current page")
1055
559
  meta: PaginationInfo = Field(..., description="Pagination metadata")
560
+
561
+
562
+ class ComponentType(str, Enum):
563
+ AGENT = "agent"
564
+ TEAM = "team"
565
+ WORKFLOW = "workflow"
566
+
567
+
568
+ class ComponentCreate(BaseModel):
569
+ name: str = Field(..., description="Display name")
570
+ component_id: Optional[str] = Field(
571
+ None, description="Unique identifier for the entity. Auto-generated from name if not provided."
572
+ )
573
+ component_type: ComponentType = Field(..., description="Type of entity: agent, team, or workflow")
574
+ description: Optional[str] = Field(None, description="Optional description")
575
+ metadata: Optional[Dict[str, Any]] = Field(None, description="Optional metadata")
576
+ # Config parameters are optional, but if provided, they will be used to create the initial config
577
+ config: Optional[Dict[str, Any]] = Field(None, description="Optional configuration")
578
+ label: Optional[str] = Field(None, description="Optional label (e.g., 'stable')")
579
+ stage: str = Field("draft", description="Stage: 'draft' or 'published'")
580
+ notes: Optional[str] = Field(None, description="Optional notes")
581
+ set_current: bool = Field(True, description="Set as current version")
582
+
583
+
584
+ class ComponentResponse(BaseModel):
585
+ component_id: str
586
+ component_type: ComponentType
587
+ name: Optional[str] = None
588
+ description: Optional[str] = None
589
+ current_version: Optional[int] = None
590
+ metadata: Optional[Dict[str, Any]] = None
591
+ created_at: int
592
+ updated_at: Optional[int] = None
593
+
594
+
595
+ class ConfigCreate(BaseModel):
596
+ config: Dict[str, Any] = Field(..., description="The configuration data")
597
+ version: Optional[int] = Field(None, description="Optional version number")
598
+ label: Optional[str] = Field(None, description="Optional label (e.g., 'stable')")
599
+ stage: str = Field("draft", description="Stage: 'draft' or 'published'")
600
+ notes: Optional[str] = Field(None, description="Optional notes")
601
+ links: Optional[List[Dict[str, Any]]] = Field(None, description="Optional links to child components")
602
+ set_current: bool = Field(True, description="Set as current version")
603
+
604
+
605
+ class ComponentConfigResponse(BaseModel):
606
+ component_id: str
607
+ version: int
608
+ label: Optional[str] = None
609
+ stage: str
610
+ config: Dict[str, Any]
611
+ notes: Optional[str] = None
612
+ created_at: int
613
+ updated_at: Optional[int] = None
614
+
615
+
616
+ class ComponentUpdate(BaseModel):
617
+ name: Optional[str] = None
618
+ description: Optional[str] = None
619
+ component_type: Optional[str] = None
620
+ metadata: Optional[Dict[str, Any]] = None
621
+
622
+
623
+ class ConfigUpdate(BaseModel):
624
+ config: Optional[Dict[str, Any]] = None
625
+ label: Optional[str] = None
626
+ stage: Optional[str] = None
627
+ notes: Optional[str] = None
628
+ links: Optional[List[Dict[str, Any]]] = None