agno 2.0.0rc1__py3-none-any.whl → 2.0.0rc2__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 (49) hide show
  1. agno/agent/agent.py +32 -14
  2. agno/db/mongo/mongo.py +8 -3
  3. agno/eval/accuracy.py +12 -5
  4. agno/knowledge/chunking/strategy.py +14 -14
  5. agno/knowledge/knowledge.py +156 -120
  6. agno/knowledge/reader/arxiv_reader.py +5 -5
  7. agno/knowledge/reader/csv_reader.py +6 -77
  8. agno/knowledge/reader/docx_reader.py +5 -5
  9. agno/knowledge/reader/firecrawl_reader.py +5 -5
  10. agno/knowledge/reader/json_reader.py +5 -5
  11. agno/knowledge/reader/markdown_reader.py +31 -9
  12. agno/knowledge/reader/pdf_reader.py +10 -123
  13. agno/knowledge/reader/reader_factory.py +65 -72
  14. agno/knowledge/reader/s3_reader.py +44 -114
  15. agno/knowledge/reader/text_reader.py +5 -5
  16. agno/knowledge/reader/url_reader.py +75 -31
  17. agno/knowledge/reader/web_search_reader.py +6 -29
  18. agno/knowledge/reader/website_reader.py +5 -5
  19. agno/knowledge/reader/wikipedia_reader.py +5 -5
  20. agno/knowledge/reader/youtube_reader.py +6 -6
  21. agno/knowledge/utils.py +10 -10
  22. agno/models/aws/bedrock.py +3 -7
  23. agno/models/base.py +37 -6
  24. agno/os/app.py +32 -24
  25. agno/os/mcp.py +39 -59
  26. agno/os/router.py +547 -16
  27. agno/os/routers/evals/evals.py +197 -12
  28. agno/os/routers/knowledge/knowledge.py +428 -14
  29. agno/os/routers/memory/memory.py +250 -28
  30. agno/os/routers/metrics/metrics.py +125 -7
  31. agno/os/routers/session/session.py +393 -25
  32. agno/os/schema.py +55 -2
  33. agno/run/agent.py +9 -0
  34. agno/run/team.py +93 -2
  35. agno/run/workflow.py +25 -12
  36. agno/team/team.py +861 -1051
  37. agno/tools/mcp.py +1 -2
  38. agno/utils/log.py +52 -2
  39. agno/utils/mcp.py +55 -3
  40. agno/utils/models/claude.py +0 -8
  41. agno/utils/print_response/team.py +177 -73
  42. agno/utils/streamlit.py +27 -0
  43. agno/workflow/workflow.py +9 -0
  44. {agno-2.0.0rc1.dist-info → agno-2.0.0rc2.dist-info}/METADATA +1 -1
  45. {agno-2.0.0rc1.dist-info → agno-2.0.0rc2.dist-info}/RECORD +48 -49
  46. agno/knowledge/reader/gcs_reader.py +0 -67
  47. {agno-2.0.0rc1.dist-info → agno-2.0.0rc2.dist-info}/WHEEL +0 -0
  48. {agno-2.0.0rc1.dist-info → agno-2.0.0rc2.dist-info}/licenses/LICENSE +0 -0
  49. {agno-2.0.0rc1.dist-info → agno-2.0.0rc2.dist-info}/top_level.txt +0 -0
agno/os/router.py CHANGED
@@ -21,11 +21,17 @@ from agno.os.auth import get_authentication_dependency
21
21
  from agno.os.schema import (
22
22
  AgentResponse,
23
23
  AgentSummaryResponse,
24
+ BadRequestResponse,
24
25
  ConfigResponse,
26
+ HealthResponse,
25
27
  InterfaceResponse,
28
+ InternalServerErrorResponse,
26
29
  Model,
30
+ NotFoundResponse,
27
31
  TeamResponse,
28
32
  TeamSummaryResponse,
33
+ UnauthenticatedResponse,
34
+ ValidationErrorResponse,
29
35
  WorkflowResponse,
30
36
  WorkflowSummaryResponse,
31
37
  )
@@ -307,13 +313,47 @@ def get_base_router(
307
313
  os: "AgentOS",
308
314
  settings: AgnoAPISettings = AgnoAPISettings(),
309
315
  ) -> APIRouter:
310
- router = APIRouter(dependencies=[Depends(get_authentication_dependency(settings))])
316
+ """
317
+ Create the base FastAPI router with comprehensive OpenAPI documentation.
318
+
319
+ This router provides endpoints for:
320
+ - Core system operations (health, config, models)
321
+ - Agent management and execution
322
+ - Team collaboration and coordination
323
+ - Workflow automation and orchestration
324
+ - Real-time WebSocket communications
325
+
326
+ All endpoints include detailed documentation, examples, and proper error handling.
327
+ """
328
+ router = APIRouter(
329
+ dependencies=[Depends(get_authentication_dependency(settings))],
330
+ responses={
331
+ 400: {"description": "Bad Request", "model": BadRequestResponse},
332
+ 401: {"description": "Unauthorized", "model": UnauthenticatedResponse},
333
+ 404: {"description": "Not Found", "model": NotFoundResponse},
334
+ 422: {"description": "Validation Error", "model": ValidationErrorResponse},
335
+ 500: {"description": "Internal Server Error", "model": InternalServerErrorResponse},
336
+ },
337
+ )
311
338
 
312
339
  # -- Main Routes ---
313
340
 
314
- @router.get("/health", tags=["Core"], operation_id="health_check")
315
- async def health_check():
316
- return JSONResponse(content={"status": "ok"})
341
+ @router.get(
342
+ "/health",
343
+ tags=["Core"],
344
+ operation_id="health_check",
345
+ summary="Health Check",
346
+ description="Check the health status of the AgentOS API. Returns a simple status indicator.",
347
+ response_model=HealthResponse,
348
+ responses={
349
+ 200: {
350
+ "description": "API is healthy and operational",
351
+ "content": {"application/json": {"example": {"status": "ok"}}},
352
+ }
353
+ },
354
+ )
355
+ async def health_check() -> HealthResponse:
356
+ return HealthResponse(status="ok")
317
357
 
318
358
  @router.get(
319
359
  "/config",
@@ -321,6 +361,79 @@ def get_base_router(
321
361
  response_model_exclude_none=True,
322
362
  tags=["Core"],
323
363
  operation_id="get_config",
364
+ summary="Get OS Configuration",
365
+ description=(
366
+ "Retrieve the complete configuration of the AgentOS instance, including:\n\n"
367
+ "- Available models and databases\n"
368
+ "- Registered agents, teams, and workflows\n"
369
+ "- Chat, session, memory, knowledge, and evaluation configurations\n"
370
+ "- Available interfaces and their routes"
371
+ ),
372
+ responses={
373
+ 200: {
374
+ "description": "OS configuration retrieved successfully",
375
+ "content": {
376
+ "application/json": {
377
+ "example": {
378
+ "os_id": "demo",
379
+ "description": "Example AgentOS configuration",
380
+ "available_models": [],
381
+ "databases": ["9c884dc4-9066-448c-9074-ef49ec7eb73c"],
382
+ "session": {
383
+ "dbs": [
384
+ {
385
+ "db_id": "9c884dc4-9066-448c-9074-ef49ec7eb73c",
386
+ "domain_config": {"display_name": "Sessions"},
387
+ }
388
+ ]
389
+ },
390
+ "metrics": {
391
+ "dbs": [
392
+ {
393
+ "db_id": "9c884dc4-9066-448c-9074-ef49ec7eb73c",
394
+ "domain_config": {"display_name": "Metrics"},
395
+ }
396
+ ]
397
+ },
398
+ "memory": {
399
+ "dbs": [
400
+ {
401
+ "db_id": "9c884dc4-9066-448c-9074-ef49ec7eb73c",
402
+ "domain_config": {"display_name": "Memory"},
403
+ }
404
+ ]
405
+ },
406
+ "knowledge": {
407
+ "dbs": [
408
+ {
409
+ "db_id": "9c884dc4-9066-448c-9074-ef49ec7eb73c",
410
+ "domain_config": {"display_name": "Knowledge"},
411
+ }
412
+ ]
413
+ },
414
+ "evals": {
415
+ "dbs": [
416
+ {
417
+ "db_id": "9c884dc4-9066-448c-9074-ef49ec7eb73c",
418
+ "domain_config": {"display_name": "Evals"},
419
+ }
420
+ ]
421
+ },
422
+ "agents": [
423
+ {
424
+ "id": "main-agent",
425
+ "name": "Main Agent",
426
+ "db_id": "9c884dc4-9066-448c-9074-ef49ec7eb73c",
427
+ }
428
+ ],
429
+ "teams": [],
430
+ "workflows": [],
431
+ "interfaces": [],
432
+ }
433
+ }
434
+ },
435
+ }
436
+ },
324
437
  )
325
438
  async def config() -> ConfigResponse:
326
439
  return ConfigResponse(
@@ -349,8 +462,26 @@ def get_base_router(
349
462
  response_model_exclude_none=True,
350
463
  tags=["Core"],
351
464
  operation_id="get_models",
465
+ summary="Get Available Models",
466
+ description=(
467
+ "Retrieve a list of all unique models currently used by agents and teams in this OS instance. "
468
+ "This includes the model ID and provider information for each model."
469
+ ),
470
+ responses={
471
+ 200: {
472
+ "description": "List of models retrieved successfully",
473
+ "content": {
474
+ "application/json": {
475
+ "example": [
476
+ {"id": "gpt-4", "provider": "openai"},
477
+ {"id": "claude-3-sonnet", "provider": "anthropic"},
478
+ ]
479
+ }
480
+ },
481
+ }
482
+ },
352
483
  )
353
- async def get_models():
484
+ async def get_models() -> List[Model]:
354
485
  """Return the list of all models used by agents and teams in the contextual OS"""
355
486
  all_components: List[Union[Agent, Team]] = []
356
487
  if os.agents:
@@ -371,7 +502,39 @@ def get_base_router(
371
502
  # -- Agent routes ---
372
503
 
373
504
  @router.post(
374
- "/agents/{agent_id}/runs", tags=["Agents"], operation_id="create_agent_run", response_model_exclude_none=True
505
+ "/agents/{agent_id}/runs",
506
+ tags=["Agents"],
507
+ operation_id="create_agent_run",
508
+ response_model_exclude_none=True,
509
+ summary="Create Agent Run",
510
+ description=(
511
+ "Execute an agent with a message and optional media files. Supports both streaming and non-streaming responses.\n\n"
512
+ "**Features:**\n"
513
+ "- Text message input with optional session management\n"
514
+ "- Multi-media support: images (PNG, JPEG, WebP), audio (WAV, MP3), video (MP4, WebM, etc.)\n"
515
+ "- Document processing: PDF, CSV, DOCX, TXT, JSON\n"
516
+ "- Real-time streaming responses with Server-Sent Events (SSE)\n"
517
+ "- User and session context preservation\n\n"
518
+ "**Streaming Response:**\n"
519
+ "When `stream=true`, returns SSE events with `event` and `data` fields."
520
+ ),
521
+ responses={
522
+ 200: {
523
+ "description": "Agent run executed successfully",
524
+ "content": {
525
+ "text/event-stream": {
526
+ "examples": {
527
+ "event_strea": {
528
+ "summary": "Example event stream response",
529
+ "value": 'event: RunStarted\ndata: {"content": "Hello!", "run_id": "123..."}\n\n',
530
+ }
531
+ }
532
+ },
533
+ },
534
+ },
535
+ 400: {"description": "Invalid request or unsupported file type", "model": BadRequestResponse},
536
+ 404: {"description": "Agent not found", "model": NotFoundResponse},
537
+ },
375
538
  )
376
539
  async def create_agent_run(
377
540
  agent_id: str,
@@ -481,6 +644,16 @@ def get_base_router(
481
644
  tags=["Agents"],
482
645
  operation_id="cancel_agent_run",
483
646
  response_model_exclude_none=True,
647
+ summary="Cancel Agent Run",
648
+ description=(
649
+ "Cancel a currently executing agent run. This will attempt to stop the agent's execution gracefully.\n\n"
650
+ "**Note:** Cancellation may not be immediate for all operations."
651
+ ),
652
+ responses={
653
+ 200: {},
654
+ 404: {"description": "Agent not found", "model": NotFoundResponse},
655
+ 500: {"description": "Failed to cancel run", "model": InternalServerErrorResponse},
656
+ },
484
657
  )
485
658
  async def cancel_agent_run(
486
659
  agent_id: str,
@@ -500,6 +673,27 @@ def get_base_router(
500
673
  tags=["Agents"],
501
674
  operation_id="continue_agent_run",
502
675
  response_model_exclude_none=True,
676
+ summary="Continue Agent Run",
677
+ description=(
678
+ "Continue a paused or incomplete agent run with updated tool results.\n\n"
679
+ "**Use Cases:**\n"
680
+ "- Resume execution after tool approval/rejection\n"
681
+ "- Provide manual tool execution results\n\n"
682
+ "**Tools Parameter:**\n"
683
+ "JSON string containing array of tool execution objects with results."
684
+ ),
685
+ responses={
686
+ 200: {
687
+ "description": "Agent run continued successfully",
688
+ "content": {
689
+ "text/event-stream": {
690
+ "example": 'event: RunContent\ndata: {"created_at": 1757348314, "run_id": "123..."}\n\n'
691
+ },
692
+ },
693
+ },
694
+ 400: {"description": "Invalid JSON in tools field or invalid tool structure", "model": BadRequestResponse},
695
+ 404: {"description": "Agent not found", "model": NotFoundResponse},
696
+ },
503
697
  )
504
698
  async def continue_agent_run(
505
699
  agent_id: str,
@@ -564,8 +758,39 @@ def get_base_router(
564
758
  response_model_exclude_none=True,
565
759
  tags=["Agents"],
566
760
  operation_id="get_agents",
761
+ summary="List All Agents",
762
+ description=(
763
+ "Retrieve a comprehensive list of all agents configured in this OS instance.\n\n"
764
+ "**Returns:**\n"
765
+ "- Agent metadata (ID, name, description)\n"
766
+ "- Model configuration and capabilities\n"
767
+ "- Available tools and their configurations\n"
768
+ "- Session, knowledge, memory, and reasoning settings\n"
769
+ "- Only meaningful (non-default) configurations are included"
770
+ ),
771
+ responses={
772
+ 200: {
773
+ "description": "List of agents retrieved successfully",
774
+ "content": {
775
+ "application/json": {
776
+ "example": [
777
+ {
778
+ "id": "main-agent",
779
+ "name": "Main Agent",
780
+ "db_id": "c6bf0644-feb8-4930-a305-380dae5ad6aa",
781
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
782
+ "tools": None,
783
+ "sessions": {"session_table": "agno_sessions"},
784
+ "knowledge": {"knowledge_table": "main_knowledge"},
785
+ "system_message": {"markdown": True, "add_datetime_to_context": True},
786
+ }
787
+ ]
788
+ }
789
+ },
790
+ }
791
+ },
567
792
  )
568
- async def get_agents():
793
+ async def get_agents() -> List[AgentResponse]:
569
794
  """Return the list of all Agents present in the contextual OS"""
570
795
  if os.agents is None:
571
796
  return []
@@ -582,8 +807,39 @@ def get_base_router(
582
807
  response_model_exclude_none=True,
583
808
  tags=["Agents"],
584
809
  operation_id="get_agent",
810
+ summary="Get Agent Details",
811
+ description=(
812
+ "Retrieve detailed configuration and capabilities of a specific agent.\n\n"
813
+ "**Returns comprehensive agent information including:**\n"
814
+ "- Model configuration and provider details\n"
815
+ "- Complete tool inventory and configurations\n"
816
+ "- Session management settings\n"
817
+ "- Knowledge base and memory configurations\n"
818
+ "- Reasoning capabilities and settings\n"
819
+ "- System prompts and response formatting options"
820
+ ),
821
+ responses={
822
+ 200: {
823
+ "description": "Agent details retrieved successfully",
824
+ "content": {
825
+ "application/json": {
826
+ "example": {
827
+ "id": "main-agent",
828
+ "name": "Main Agent",
829
+ "db_id": "9e064c70-6821-4840-a333-ce6230908a70",
830
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
831
+ "tools": None,
832
+ "sessions": {"session_table": "agno_sessions"},
833
+ "knowledge": {"knowledge_table": "main_knowledge"},
834
+ "system_message": {"markdown": True, "add_datetime_to_context": True},
835
+ }
836
+ }
837
+ },
838
+ },
839
+ 404: {"description": "Agent not found", "model": NotFoundResponse},
840
+ },
585
841
  )
586
- async def get_agent(agent_id: str):
842
+ async def get_agent(agent_id: str) -> AgentResponse:
587
843
  agent = get_agent_by_id(agent_id, os.agents)
588
844
  if agent is None:
589
845
  raise HTTPException(status_code=404, detail="Agent not found")
@@ -593,7 +849,34 @@ def get_base_router(
593
849
  # -- Team routes ---
594
850
 
595
851
  @router.post(
596
- "/teams/{team_id}/runs", tags=["Teams"], operation_id="create_team_run", response_model_exclude_none=True
852
+ "/teams/{team_id}/runs",
853
+ tags=["Teams"],
854
+ operation_id="create_team_run",
855
+ response_model_exclude_none=True,
856
+ summary="Create Team Run",
857
+ description=(
858
+ "Execute a team collaboration with multiple agents working together on a task.\n\n"
859
+ "**Features:**\n"
860
+ "- Text message input with optional session management\n"
861
+ "- Multi-media support: images (PNG, JPEG, WebP), audio (WAV, MP3), video (MP4, WebM, etc.)\n"
862
+ "- Document processing: PDF, CSV, DOCX, TXT, JSON\n"
863
+ "- Real-time streaming responses with Server-Sent Events (SSE)\n"
864
+ "- User and session context preservation\n\n"
865
+ "**Streaming Response:**\n"
866
+ "When `stream=true`, returns SSE events with `event` and `data` fields."
867
+ ),
868
+ responses={
869
+ 200: {
870
+ "description": "Team run executed successfully",
871
+ "content": {
872
+ "text/event-stream": {
873
+ "example": 'event: RunStarted\ndata: {"content": "Hello!", "run_id": "123..."}\n\n'
874
+ },
875
+ },
876
+ },
877
+ 400: {"description": "Invalid request or unsupported file type", "model": BadRequestResponse},
878
+ 404: {"description": "Team not found", "model": NotFoundResponse},
879
+ },
597
880
  )
598
881
  async def create_team_run(
599
882
  team_id: str,
@@ -700,6 +983,16 @@ def get_base_router(
700
983
  tags=["Teams"],
701
984
  operation_id="cancel_team_run",
702
985
  response_model_exclude_none=True,
986
+ summary="Cancel Team Run",
987
+ description=(
988
+ "Cancel a currently executing team run. This will attempt to stop the team's execution gracefully.\n\n"
989
+ "**Note:** Cancellation may not be immediate for all operations."
990
+ ),
991
+ responses={
992
+ 200: {},
993
+ 404: {"description": "Team not found", "model": NotFoundResponse},
994
+ 500: {"description": "Failed to cancel team run", "model": InternalServerErrorResponse},
995
+ },
703
996
  )
704
997
  async def cancel_team_run(
705
998
  team_id: str,
@@ -720,8 +1013,82 @@ def get_base_router(
720
1013
  response_model_exclude_none=True,
721
1014
  tags=["Teams"],
722
1015
  operation_id="get_teams",
1016
+ summary="List All Teams",
1017
+ description=(
1018
+ "Retrieve a comprehensive list of all teams configured in this OS instance.\n\n"
1019
+ "**Returns team information including:**\n"
1020
+ "- Team metadata (ID, name, description, execution mode)\n"
1021
+ "- Model configuration for team coordination\n"
1022
+ "- Team member roster with roles and capabilities\n"
1023
+ "- Knowledge sharing and memory configurations"
1024
+ ),
1025
+ responses={
1026
+ 200: {
1027
+ "description": "List of teams retrieved successfully",
1028
+ "content": {
1029
+ "application/json": {
1030
+ "example": [
1031
+ {
1032
+ "team_id": "basic-team",
1033
+ "name": "Basic Team",
1034
+ "mode": "coordinate",
1035
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
1036
+ "tools": [
1037
+ {
1038
+ "name": "transfer_task_to_member",
1039
+ "description": "Use this function to transfer a task to the selected team member.\nYou must provide a clear and concise description of the task the member should achieve AND the expected output.",
1040
+ "parameters": {
1041
+ "type": "object",
1042
+ "properties": {
1043
+ "member_id": {
1044
+ "type": "string",
1045
+ "description": "(str) The ID of the member to transfer the task to. Use only the ID of the member, not the ID of the team followed by the ID of the member.",
1046
+ },
1047
+ "task_description": {
1048
+ "type": "string",
1049
+ "description": "(str) A clear and concise description of the task the member should achieve.",
1050
+ },
1051
+ "expected_output": {
1052
+ "type": "string",
1053
+ "description": "(str) The expected output from the member (optional).",
1054
+ },
1055
+ },
1056
+ "additionalProperties": False,
1057
+ "required": ["member_id", "task_description"],
1058
+ },
1059
+ }
1060
+ ],
1061
+ "members": [
1062
+ {
1063
+ "agent_id": "basic-agent",
1064
+ "name": "Basic Agent",
1065
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI gpt-4o"},
1066
+ "memory": {
1067
+ "app_name": "Memory",
1068
+ "app_url": None,
1069
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
1070
+ },
1071
+ "session_table": "agno_sessions",
1072
+ "memory_table": "agno_memories",
1073
+ }
1074
+ ],
1075
+ "enable_agentic_context": False,
1076
+ "memory": {
1077
+ "app_name": "agno_memories",
1078
+ "app_url": "/memory/1",
1079
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
1080
+ },
1081
+ "async_mode": False,
1082
+ "session_table": "agno_sessions",
1083
+ "memory_table": "agno_memories",
1084
+ }
1085
+ ]
1086
+ }
1087
+ },
1088
+ }
1089
+ },
723
1090
  )
724
- async def get_teams():
1091
+ async def get_teams() -> List[TeamResponse]:
725
1092
  """Return the list of all Teams present in the contextual OS"""
726
1093
  if os.teams is None:
727
1094
  return []
@@ -738,8 +1105,85 @@ def get_base_router(
738
1105
  response_model_exclude_none=True,
739
1106
  tags=["Teams"],
740
1107
  operation_id="get_team",
1108
+ summary="Get Team Details",
1109
+ description=("Retrieve detailed configuration and member information for a specific team."),
1110
+ responses={
1111
+ 200: {
1112
+ "description": "Team details retrieved successfully",
1113
+ "content": {
1114
+ "application/json": {
1115
+ "example": {
1116
+ "team_id": "basic-team",
1117
+ "name": "Basic Team",
1118
+ "description": None,
1119
+ "mode": "coordinate",
1120
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
1121
+ "tools": [
1122
+ {
1123
+ "name": "transfer_task_to_member",
1124
+ "description": "Use this function to transfer a task to the selected team member.\nYou must provide a clear and concise description of the task the member should achieve AND the expected output.",
1125
+ "parameters": {
1126
+ "type": "object",
1127
+ "properties": {
1128
+ "member_id": {
1129
+ "type": "string",
1130
+ "description": "(str) The ID of the member to transfer the task to. Use only the ID of the member, not the ID of the team followed by the ID of the member.",
1131
+ },
1132
+ "task_description": {
1133
+ "type": "string",
1134
+ "description": "(str) A clear and concise description of the task the member should achieve.",
1135
+ },
1136
+ "expected_output": {
1137
+ "type": "string",
1138
+ "description": "(str) The expected output from the member (optional).",
1139
+ },
1140
+ },
1141
+ "additionalProperties": False,
1142
+ "required": ["member_id", "task_description"],
1143
+ },
1144
+ }
1145
+ ],
1146
+ "instructions": None,
1147
+ "members": [
1148
+ {
1149
+ "agent_id": "basic-agent",
1150
+ "name": "Basic Agent",
1151
+ "description": None,
1152
+ "instructions": None,
1153
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI gpt-4o"},
1154
+ "tools": None,
1155
+ "memory": {
1156
+ "app_name": "Memory",
1157
+ "app_url": None,
1158
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
1159
+ },
1160
+ "knowledge": None,
1161
+ "session_table": "agno_sessions",
1162
+ "memory_table": "agno_memories",
1163
+ "knowledge_table": None,
1164
+ }
1165
+ ],
1166
+ "expected_output": None,
1167
+ "dependencies": None,
1168
+ "enable_agentic_context": False,
1169
+ "memory": {
1170
+ "app_name": "Memory",
1171
+ "app_url": None,
1172
+ "model": {"name": "OpenAIChat", "model": "gpt-4o", "provider": "OpenAI"},
1173
+ },
1174
+ "knowledge": None,
1175
+ "async_mode": False,
1176
+ "session_table": "agno_sessions",
1177
+ "memory_table": "agno_memories",
1178
+ "knowledge_table": None,
1179
+ }
1180
+ }
1181
+ },
1182
+ },
1183
+ 404: {"description": "Team not found", "model": NotFoundResponse},
1184
+ },
741
1185
  )
742
- async def get_team(team_id: str):
1186
+ async def get_team(team_id: str) -> TeamResponse:
743
1187
  team = get_team_by_id(team_id, os.teams)
744
1188
  if team is None:
745
1189
  raise HTTPException(status_code=404, detail="Team not found")
@@ -748,7 +1192,10 @@ def get_base_router(
748
1192
 
749
1193
  # -- Workflow routes ---
750
1194
 
751
- @router.websocket("/workflows/ws")
1195
+ @router.websocket(
1196
+ "/workflows/ws",
1197
+ name="workflow_websocket",
1198
+ )
752
1199
  async def workflow_websocket_endpoint(websocket: WebSocket):
753
1200
  """WebSocket endpoint for receiving real-time workflow events"""
754
1201
  await websocket_manager.connect(websocket)
@@ -776,12 +1223,38 @@ def get_base_router(
776
1223
 
777
1224
  @router.get(
778
1225
  "/workflows",
779
- response_model=List[WorkflowResponse],
1226
+ response_model=List[WorkflowSummaryResponse],
780
1227
  response_model_exclude_none=True,
781
1228
  tags=["Workflows"],
782
1229
  operation_id="get_workflows",
1230
+ summary="List All Workflows",
1231
+ description=(
1232
+ "Retrieve a comprehensive list of all workflows configured in this OS instance.\n\n"
1233
+ "**Return Information:**\n"
1234
+ "- Workflow metadata (ID, name, description)\n"
1235
+ "- Input schema requirements\n"
1236
+ "- Step sequence and execution flow\n"
1237
+ "- Associated agents and teams"
1238
+ ),
1239
+ responses={
1240
+ 200: {
1241
+ "description": "List of workflows retrieved successfully",
1242
+ "content": {
1243
+ "application/json": {
1244
+ "example": [
1245
+ {
1246
+ "id": "content-creation-workflow",
1247
+ "name": "Content Creation Workflow",
1248
+ "description": "Automated content creation from blog posts to social media",
1249
+ "db_id": "123",
1250
+ }
1251
+ ]
1252
+ }
1253
+ },
1254
+ }
1255
+ },
783
1256
  )
784
- async def get_workflows():
1257
+ async def get_workflows() -> List[WorkflowSummaryResponse]:
785
1258
  if os.workflows is None:
786
1259
  return []
787
1260
 
@@ -793,8 +1266,26 @@ def get_base_router(
793
1266
  response_model_exclude_none=True,
794
1267
  tags=["Workflows"],
795
1268
  operation_id="get_workflow",
1269
+ summary="Get Workflow Details",
1270
+ description=("Retrieve detailed configuration and step information for a specific workflow."),
1271
+ responses={
1272
+ 200: {
1273
+ "description": "Workflow details retrieved successfully",
1274
+ "content": {
1275
+ "application/json": {
1276
+ "example": {
1277
+ "id": "content-creation-workflow",
1278
+ "name": "Content Creation Workflow",
1279
+ "description": "Automated content creation from blog posts to social media",
1280
+ "db_id": "123",
1281
+ }
1282
+ }
1283
+ },
1284
+ },
1285
+ 404: {"description": "Workflow not found", "model": NotFoundResponse},
1286
+ },
796
1287
  )
797
- async def get_workflow(workflow_id: str):
1288
+ async def get_workflow(workflow_id: str) -> WorkflowResponse:
798
1289
  workflow = get_workflow_by_id(workflow_id, os.workflows)
799
1290
  if workflow is None:
800
1291
  raise HTTPException(status_code=404, detail="Workflow not found")
@@ -806,6 +1297,34 @@ def get_base_router(
806
1297
  tags=["Workflows"],
807
1298
  operation_id="create_workflow_run",
808
1299
  response_model_exclude_none=True,
1300
+ summary="Execute Workflow",
1301
+ description=(
1302
+ "Execute a workflow with the provided input data. Workflows can run in streaming or batch mode.\n\n"
1303
+ "**Execution Modes:**\n"
1304
+ "- **Streaming (`stream=true`)**: Real-time step-by-step execution updates via SSE\n"
1305
+ "- **Non-Streaming (`stream=false`)**: Complete workflow execution with final result\n\n"
1306
+ "**Workflow Execution Process:**\n"
1307
+ "1. Input validation against workflow schema\n"
1308
+ "2. Sequential or parallel step execution based on workflow design\n"
1309
+ "3. Data flow between steps with transformation\n"
1310
+ "4. Error handling and automatic retries where configured\n"
1311
+ "5. Final result compilation and response\n\n"
1312
+ "**Session Management:**\n"
1313
+ "Workflows support session continuity for stateful execution across multiple runs."
1314
+ ),
1315
+ responses={
1316
+ 200: {
1317
+ "description": "Workflow executed successfully",
1318
+ "content": {
1319
+ "text/event-stream": {
1320
+ "example": 'event: RunStarted\ndata: {"content": "Hello!", "run_id": "123..."}\n\n'
1321
+ },
1322
+ },
1323
+ },
1324
+ 400: {"description": "Invalid input data or workflow configuration", "model": BadRequestResponse},
1325
+ 404: {"description": "Workflow not found", "model": NotFoundResponse},
1326
+ 500: {"description": "Workflow execution error", "model": InternalServerErrorResponse},
1327
+ },
809
1328
  )
810
1329
  async def create_workflow_run(
811
1330
  workflow_id: str,
@@ -853,7 +1372,19 @@ def get_base_router(
853
1372
  raise HTTPException(status_code=500, detail=f"Error running workflow: {str(e)}")
854
1373
 
855
1374
  @router.post(
856
- "/workflows/{workflow_id}/runs/{run_id}/cancel", tags=["Workflows"], operation_id="cancel_workflow_run"
1375
+ "/workflows/{workflow_id}/runs/{run_id}/cancel",
1376
+ tags=["Workflows"],
1377
+ operation_id="cancel_workflow_run",
1378
+ summary="Cancel Workflow Run",
1379
+ description=(
1380
+ "Cancel a currently executing workflow run, stopping all active steps and cleanup.\n"
1381
+ "**Note:** Complex workflows with multiple parallel steps may take time to fully cancel."
1382
+ ),
1383
+ responses={
1384
+ 200: {},
1385
+ 404: {"description": "Workflow or run not found", "model": NotFoundResponse},
1386
+ 500: {"description": "Failed to cancel workflow run", "model": InternalServerErrorResponse},
1387
+ },
857
1388
  )
858
1389
  async def cancel_workflow_run(workflow_id: str, run_id: str):
859
1390
  workflow = get_workflow_by_id(workflow_id, os.workflows)