agno 2.0.0a1__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.
- agno/agent/agent.py +416 -41
- agno/api/agent.py +2 -2
- agno/api/evals.py +2 -2
- agno/api/os.py +1 -1
- agno/api/settings.py +2 -2
- agno/api/team.py +2 -2
- agno/db/dynamo/dynamo.py +0 -6
- agno/db/firestore/firestore.py +0 -6
- agno/db/in_memory/in_memory_db.py +0 -6
- agno/db/json/json_db.py +0 -6
- agno/db/mongo/mongo.py +8 -9
- agno/db/mysql/utils.py +0 -1
- agno/db/postgres/postgres.py +0 -10
- agno/db/postgres/utils.py +0 -1
- agno/db/redis/redis.py +0 -4
- agno/db/singlestore/singlestore.py +0 -10
- agno/db/singlestore/utils.py +0 -1
- agno/db/sqlite/sqlite.py +0 -4
- agno/db/sqlite/utils.py +0 -1
- agno/eval/accuracy.py +12 -5
- agno/integrations/discord/client.py +5 -1
- agno/knowledge/chunking/strategy.py +14 -14
- agno/knowledge/embedder/aws_bedrock.py +2 -2
- agno/knowledge/knowledge.py +156 -120
- agno/knowledge/reader/arxiv_reader.py +5 -5
- agno/knowledge/reader/csv_reader.py +6 -77
- agno/knowledge/reader/docx_reader.py +5 -5
- agno/knowledge/reader/firecrawl_reader.py +5 -5
- agno/knowledge/reader/json_reader.py +5 -5
- agno/knowledge/reader/markdown_reader.py +31 -9
- agno/knowledge/reader/pdf_reader.py +10 -123
- agno/knowledge/reader/reader_factory.py +65 -72
- agno/knowledge/reader/s3_reader.py +44 -114
- agno/knowledge/reader/text_reader.py +5 -5
- agno/knowledge/reader/url_reader.py +75 -31
- agno/knowledge/reader/web_search_reader.py +6 -29
- agno/knowledge/reader/website_reader.py +5 -5
- agno/knowledge/reader/wikipedia_reader.py +5 -5
- agno/knowledge/reader/youtube_reader.py +6 -6
- agno/knowledge/utils.py +10 -10
- agno/models/anthropic/claude.py +2 -49
- agno/models/aws/bedrock.py +3 -7
- agno/models/base.py +37 -6
- agno/models/message.py +7 -6
- agno/os/app.py +168 -64
- agno/os/interfaces/agui/agui.py +1 -1
- agno/os/interfaces/agui/utils.py +16 -9
- agno/os/interfaces/slack/slack.py +2 -3
- agno/os/interfaces/whatsapp/whatsapp.py +2 -3
- agno/os/mcp.py +235 -0
- agno/os/router.py +576 -19
- agno/os/routers/evals/evals.py +201 -12
- agno/os/routers/knowledge/knowledge.py +455 -18
- agno/os/routers/memory/memory.py +260 -29
- agno/os/routers/metrics/metrics.py +127 -7
- agno/os/routers/session/session.py +398 -25
- agno/os/schema.py +55 -2
- agno/os/settings.py +0 -1
- agno/run/agent.py +96 -2
- agno/run/cancel.py +0 -2
- agno/run/team.py +93 -2
- agno/run/workflow.py +25 -12
- agno/team/team.py +863 -1053
- agno/tools/function.py +65 -7
- agno/tools/linear.py +1 -1
- agno/tools/mcp.py +1 -2
- agno/utils/gemini.py +31 -1
- agno/utils/log.py +52 -2
- agno/utils/mcp.py +55 -3
- agno/utils/models/claude.py +41 -0
- agno/utils/print_response/team.py +177 -73
- agno/utils/streamlit.py +481 -0
- agno/workflow/workflow.py +17 -1
- {agno-2.0.0a1.dist-info → agno-2.0.0rc2.dist-info}/METADATA +1 -1
- {agno-2.0.0a1.dist-info → agno-2.0.0rc2.dist-info}/RECORD +78 -77
- agno/knowledge/reader/gcs_reader.py +0 -67
- {agno-2.0.0a1.dist-info → agno-2.0.0rc2.dist-info}/WHEEL +0 -0
- {agno-2.0.0a1.dist-info → agno-2.0.0rc2.dist-info}/licenses/LICENSE +0 -0
- {agno-2.0.0a1.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,19 +313,127 @@ def get_base_router(
|
|
|
307
313
|
os: "AgentOS",
|
|
308
314
|
settings: AgnoAPISettings = AgnoAPISettings(),
|
|
309
315
|
) -> APIRouter:
|
|
310
|
-
|
|
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(
|
|
315
|
-
|
|
316
|
-
|
|
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",
|
|
320
360
|
response_model=ConfigResponse,
|
|
321
361
|
response_model_exclude_none=True,
|
|
322
362
|
tags=["Core"],
|
|
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
|
+
},
|
|
323
437
|
)
|
|
324
438
|
async def config() -> ConfigResponse:
|
|
325
439
|
return ConfigResponse(
|
|
@@ -347,8 +461,27 @@ def get_base_router(
|
|
|
347
461
|
response_model=List[Model],
|
|
348
462
|
response_model_exclude_none=True,
|
|
349
463
|
tags=["Core"],
|
|
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
|
+
},
|
|
350
483
|
)
|
|
351
|
-
async def get_models():
|
|
484
|
+
async def get_models() -> List[Model]:
|
|
352
485
|
"""Return the list of all models used by agents and teams in the contextual OS"""
|
|
353
486
|
all_components: List[Union[Agent, Team]] = []
|
|
354
487
|
if os.agents:
|
|
@@ -368,7 +501,41 @@ def get_base_router(
|
|
|
368
501
|
|
|
369
502
|
# -- Agent routes ---
|
|
370
503
|
|
|
371
|
-
@router.post(
|
|
504
|
+
@router.post(
|
|
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
|
+
},
|
|
538
|
+
)
|
|
372
539
|
async def create_agent_run(
|
|
373
540
|
agent_id: str,
|
|
374
541
|
message: str = Form(...),
|
|
@@ -475,6 +642,18 @@ def get_base_router(
|
|
|
475
642
|
@router.post(
|
|
476
643
|
"/agents/{agent_id}/runs/{run_id}/cancel",
|
|
477
644
|
tags=["Agents"],
|
|
645
|
+
operation_id="cancel_agent_run",
|
|
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
|
+
},
|
|
478
657
|
)
|
|
479
658
|
async def cancel_agent_run(
|
|
480
659
|
agent_id: str,
|
|
@@ -492,6 +671,29 @@ def get_base_router(
|
|
|
492
671
|
@router.post(
|
|
493
672
|
"/agents/{agent_id}/runs/{run_id}/continue",
|
|
494
673
|
tags=["Agents"],
|
|
674
|
+
operation_id="continue_agent_run",
|
|
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
|
+
},
|
|
495
697
|
)
|
|
496
698
|
async def continue_agent_run(
|
|
497
699
|
agent_id: str,
|
|
@@ -555,8 +757,40 @@ def get_base_router(
|
|
|
555
757
|
response_model=List[AgentResponse],
|
|
556
758
|
response_model_exclude_none=True,
|
|
557
759
|
tags=["Agents"],
|
|
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
|
+
},
|
|
558
792
|
)
|
|
559
|
-
async def get_agents():
|
|
793
|
+
async def get_agents() -> List[AgentResponse]:
|
|
560
794
|
"""Return the list of all Agents present in the contextual OS"""
|
|
561
795
|
if os.agents is None:
|
|
562
796
|
return []
|
|
@@ -572,8 +806,40 @@ def get_base_router(
|
|
|
572
806
|
response_model=AgentResponse,
|
|
573
807
|
response_model_exclude_none=True,
|
|
574
808
|
tags=["Agents"],
|
|
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
|
+
},
|
|
575
841
|
)
|
|
576
|
-
async def get_agent(agent_id: str):
|
|
842
|
+
async def get_agent(agent_id: str) -> AgentResponse:
|
|
577
843
|
agent = get_agent_by_id(agent_id, os.agents)
|
|
578
844
|
if agent is None:
|
|
579
845
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
@@ -582,7 +848,36 @@ def get_base_router(
|
|
|
582
848
|
|
|
583
849
|
# -- Team routes ---
|
|
584
850
|
|
|
585
|
-
@router.post(
|
|
851
|
+
@router.post(
|
|
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
|
+
},
|
|
880
|
+
)
|
|
586
881
|
async def create_team_run(
|
|
587
882
|
team_id: str,
|
|
588
883
|
message: str = Form(...),
|
|
@@ -686,6 +981,18 @@ def get_base_router(
|
|
|
686
981
|
@router.post(
|
|
687
982
|
"/teams/{team_id}/runs/{run_id}/cancel",
|
|
688
983
|
tags=["Teams"],
|
|
984
|
+
operation_id="cancel_team_run",
|
|
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
|
+
},
|
|
689
996
|
)
|
|
690
997
|
async def cancel_team_run(
|
|
691
998
|
team_id: str,
|
|
@@ -705,8 +1012,83 @@ def get_base_router(
|
|
|
705
1012
|
response_model=List[TeamResponse],
|
|
706
1013
|
response_model_exclude_none=True,
|
|
707
1014
|
tags=["Teams"],
|
|
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
|
+
},
|
|
708
1090
|
)
|
|
709
|
-
async def get_teams():
|
|
1091
|
+
async def get_teams() -> List[TeamResponse]:
|
|
710
1092
|
"""Return the list of all Teams present in the contextual OS"""
|
|
711
1093
|
if os.teams is None:
|
|
712
1094
|
return []
|
|
@@ -722,8 +1104,86 @@ def get_base_router(
|
|
|
722
1104
|
response_model=TeamResponse,
|
|
723
1105
|
response_model_exclude_none=True,
|
|
724
1106
|
tags=["Teams"],
|
|
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
|
+
},
|
|
725
1185
|
)
|
|
726
|
-
async def get_team(team_id: str):
|
|
1186
|
+
async def get_team(team_id: str) -> TeamResponse:
|
|
727
1187
|
team = get_team_by_id(team_id, os.teams)
|
|
728
1188
|
if team is None:
|
|
729
1189
|
raise HTTPException(status_code=404, detail="Team not found")
|
|
@@ -732,7 +1192,10 @@ def get_base_router(
|
|
|
732
1192
|
|
|
733
1193
|
# -- Workflow routes ---
|
|
734
1194
|
|
|
735
|
-
@router.websocket(
|
|
1195
|
+
@router.websocket(
|
|
1196
|
+
"/workflows/ws",
|
|
1197
|
+
name="workflow_websocket",
|
|
1198
|
+
)
|
|
736
1199
|
async def workflow_websocket_endpoint(websocket: WebSocket):
|
|
737
1200
|
"""WebSocket endpoint for receiving real-time workflow events"""
|
|
738
1201
|
await websocket_manager.connect(websocket)
|
|
@@ -749,9 +1212,10 @@ def get_base_router(
|
|
|
749
1212
|
elif action == "start-workflow":
|
|
750
1213
|
# Handle workflow execution directly via WebSocket
|
|
751
1214
|
await handle_workflow_via_websocket(websocket, message, os)
|
|
752
|
-
|
|
753
1215
|
except Exception as e:
|
|
754
|
-
|
|
1216
|
+
if "1012" not in str(e):
|
|
1217
|
+
logger.error(f"WebSocket error: {e}")
|
|
1218
|
+
finally:
|
|
755
1219
|
# Clean up any run_ids associated with this websocket
|
|
756
1220
|
runs_to_remove = [run_id for run_id, ws in websocket_manager.active_connections.items() if ws == websocket]
|
|
757
1221
|
for run_id in runs_to_remove:
|
|
@@ -759,11 +1223,38 @@ def get_base_router(
|
|
|
759
1223
|
|
|
760
1224
|
@router.get(
|
|
761
1225
|
"/workflows",
|
|
762
|
-
response_model=List[
|
|
1226
|
+
response_model=List[WorkflowSummaryResponse],
|
|
763
1227
|
response_model_exclude_none=True,
|
|
764
1228
|
tags=["Workflows"],
|
|
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
|
+
},
|
|
765
1256
|
)
|
|
766
|
-
async def get_workflows():
|
|
1257
|
+
async def get_workflows() -> List[WorkflowSummaryResponse]:
|
|
767
1258
|
if os.workflows is None:
|
|
768
1259
|
return []
|
|
769
1260
|
|
|
@@ -774,15 +1265,67 @@ def get_base_router(
|
|
|
774
1265
|
response_model=WorkflowResponse,
|
|
775
1266
|
response_model_exclude_none=True,
|
|
776
1267
|
tags=["Workflows"],
|
|
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
|
+
},
|
|
777
1287
|
)
|
|
778
|
-
async def get_workflow(workflow_id: str):
|
|
1288
|
+
async def get_workflow(workflow_id: str) -> WorkflowResponse:
|
|
779
1289
|
workflow = get_workflow_by_id(workflow_id, os.workflows)
|
|
780
1290
|
if workflow is None:
|
|
781
1291
|
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
782
1292
|
|
|
783
1293
|
return WorkflowResponse.from_workflow(workflow)
|
|
784
1294
|
|
|
785
|
-
@router.post(
|
|
1295
|
+
@router.post(
|
|
1296
|
+
"/workflows/{workflow_id}/runs",
|
|
1297
|
+
tags=["Workflows"],
|
|
1298
|
+
operation_id="create_workflow_run",
|
|
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
|
+
},
|
|
1328
|
+
)
|
|
786
1329
|
async def create_workflow_run(
|
|
787
1330
|
workflow_id: str,
|
|
788
1331
|
message: str = Form(...),
|
|
@@ -828,7 +1371,21 @@ def get_base_router(
|
|
|
828
1371
|
# Handle unexpected runtime errors
|
|
829
1372
|
raise HTTPException(status_code=500, detail=f"Error running workflow: {str(e)}")
|
|
830
1373
|
|
|
831
|
-
@router.post(
|
|
1374
|
+
@router.post(
|
|
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
|
+
},
|
|
1388
|
+
)
|
|
832
1389
|
async def cancel_workflow_run(workflow_id: str, run_id: str):
|
|
833
1390
|
workflow = get_workflow_by_id(workflow_id, os.workflows)
|
|
834
1391
|
|