agno 2.3.4__py3-none-any.whl → 2.3.6__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 +184 -45
- agno/culture/manager.py +2 -2
- agno/db/base.py +330 -8
- agno/db/dynamo/dynamo.py +722 -2
- agno/db/dynamo/schemas.py +127 -0
- agno/db/firestore/firestore.py +573 -1
- agno/db/firestore/schemas.py +40 -0
- agno/db/gcs_json/gcs_json_db.py +446 -1
- agno/db/in_memory/in_memory_db.py +143 -1
- agno/db/json/json_db.py +438 -1
- agno/db/mongo/async_mongo.py +522 -0
- agno/db/mongo/mongo.py +523 -1
- agno/db/mongo/schemas.py +29 -0
- agno/db/mysql/mysql.py +536 -3
- agno/db/mysql/schemas.py +38 -0
- agno/db/postgres/async_postgres.py +553 -15
- agno/db/postgres/postgres.py +544 -5
- agno/db/postgres/schemas.py +38 -0
- agno/db/redis/redis.py +468 -1
- agno/db/redis/schemas.py +32 -0
- agno/db/singlestore/schemas.py +38 -0
- agno/db/singlestore/singlestore.py +523 -1
- agno/db/sqlite/async_sqlite.py +549 -10
- agno/db/sqlite/schemas.py +38 -0
- agno/db/sqlite/sqlite.py +540 -9
- agno/db/sqlite/utils.py +6 -8
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +548 -1
- agno/eval/accuracy.py +18 -8
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/exceptions.py +11 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +1 -1
- agno/knowledge/chunking/semantic.py +2 -2
- agno/models/aimlapi/aimlapi.py +2 -3
- agno/models/anthropic/claude.py +18 -13
- agno/models/aws/bedrock.py +3 -4
- agno/models/aws/claude.py +5 -1
- agno/models/azure/ai_foundry.py +2 -2
- agno/models/azure/openai_chat.py +8 -0
- agno/models/cerebras/cerebras.py +62 -11
- agno/models/cerebras/cerebras_openai.py +2 -3
- agno/models/cohere/chat.py +1 -5
- agno/models/cometapi/cometapi.py +2 -3
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +2 -3
- agno/models/deepseek/deepseek.py +2 -3
- agno/models/fireworks/fireworks.py +2 -3
- agno/models/google/gemini.py +9 -7
- agno/models/groq/groq.py +2 -3
- agno/models/huggingface/huggingface.py +1 -5
- agno/models/ibm/watsonx.py +1 -5
- agno/models/internlm/internlm.py +2 -3
- agno/models/langdb/langdb.py +6 -4
- agno/models/litellm/chat.py +2 -2
- agno/models/litellm/litellm_openai.py +2 -3
- agno/models/meta/llama.py +1 -5
- agno/models/meta/llama_openai.py +4 -5
- agno/models/mistral/mistral.py +1 -5
- agno/models/nebius/nebius.py +2 -3
- agno/models/nvidia/nvidia.py +4 -5
- agno/models/openai/chat.py +14 -3
- agno/models/openai/responses.py +14 -3
- agno/models/openrouter/openrouter.py +4 -5
- agno/models/perplexity/perplexity.py +2 -3
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +4 -5
- agno/models/response.py +2 -1
- agno/models/sambanova/sambanova.py +4 -5
- agno/models/siliconflow/siliconflow.py +3 -4
- agno/models/together/together.py +4 -5
- agno/models/vercel/v0.py +4 -5
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +4 -5
- agno/os/app.py +104 -0
- agno/os/config.py +13 -0
- agno/os/interfaces/whatsapp/router.py +0 -1
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/mcp.py +1 -0
- agno/os/router.py +31 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/schema.py +12 -2
- agno/os/utils.py +57 -0
- agno/run/agent.py +1 -0
- agno/run/base.py +17 -0
- agno/run/team.py +4 -0
- agno/table.py +10 -0
- agno/team/team.py +221 -69
- agno/tools/function.py +10 -8
- agno/tools/google_drive.py +4 -3
- agno/tools/nano_banana.py +1 -1
- agno/tools/spotify.py +922 -0
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +6 -6
- agno/utils/hooks.py +56 -1
- agno/utils/mcp.py +1 -1
- agno/vectordb/qdrant/qdrant.py +22 -22
- agno/workflow/condition.py +8 -0
- agno/workflow/loop.py +8 -0
- agno/workflow/parallel.py +8 -0
- agno/workflow/router.py +8 -0
- agno/workflow/step.py +20 -0
- agno/workflow/steps.py +8 -0
- agno/workflow/workflow.py +88 -19
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/METADATA +38 -33
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/RECORD +116 -105
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/WHEEL +0 -0
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/top_level.txt +0 -0
agno/workflow/workflow.py
CHANGED
|
@@ -186,6 +186,9 @@ class Workflow:
|
|
|
186
186
|
# Deprecated. Use stream_events instead.
|
|
187
187
|
stream_intermediate_steps: bool = False
|
|
188
188
|
|
|
189
|
+
# If True, run hooks as FastAPI background tasks (non-blocking). Set by AgentOS.
|
|
190
|
+
_run_hooks_in_background: bool = False
|
|
191
|
+
|
|
189
192
|
def __init__(
|
|
190
193
|
self,
|
|
191
194
|
id: Optional[str] = None,
|
|
@@ -198,6 +201,7 @@ class Workflow:
|
|
|
198
201
|
session_state: Optional[Dict[str, Any]] = None,
|
|
199
202
|
overwrite_db_session_state: bool = False,
|
|
200
203
|
user_id: Optional[str] = None,
|
|
204
|
+
debug_level: Literal[1, 2] = 1,
|
|
201
205
|
debug_mode: Optional[bool] = False,
|
|
202
206
|
stream: Optional[bool] = None,
|
|
203
207
|
stream_events: bool = False,
|
|
@@ -223,6 +227,7 @@ class Workflow:
|
|
|
223
227
|
self.overwrite_db_session_state = overwrite_db_session_state
|
|
224
228
|
self.user_id = user_id
|
|
225
229
|
self.debug_mode = debug_mode
|
|
230
|
+
self.debug_level = debug_level
|
|
226
231
|
self.store_events = store_events
|
|
227
232
|
self.events_to_skip = events_to_skip or []
|
|
228
233
|
self.stream = stream
|
|
@@ -1105,9 +1110,12 @@ class Workflow:
|
|
|
1105
1110
|
"""Set debug mode and configure logging"""
|
|
1106
1111
|
if self.debug_mode or getenv("AGNO_DEBUG", "false").lower() == "true":
|
|
1107
1112
|
use_workflow_logger()
|
|
1113
|
+
debug_level: Literal[1, 2] = (
|
|
1114
|
+
cast(Literal[1, 2], int(env)) if (env := getenv("AGNO_DEBUG_LEVEL")) in ("1", "2") else self.debug_level
|
|
1115
|
+
)
|
|
1108
1116
|
|
|
1109
1117
|
self.debug_mode = True
|
|
1110
|
-
set_log_level_to_debug(source_type="workflow")
|
|
1118
|
+
set_log_level_to_debug(source_type="workflow", level=debug_level)
|
|
1111
1119
|
|
|
1112
1120
|
# Propagate to steps - only if steps is iterable (not callable)
|
|
1113
1121
|
if self.steps and not callable(self.steps):
|
|
@@ -1282,14 +1290,13 @@ class Workflow:
|
|
|
1282
1290
|
execution_input: WorkflowExecutionInput,
|
|
1283
1291
|
workflow_run_response: WorkflowRunOutput,
|
|
1284
1292
|
run_context: RunContext,
|
|
1293
|
+
background_tasks: Optional[Any] = None,
|
|
1285
1294
|
**kwargs: Any,
|
|
1286
1295
|
) -> WorkflowRunOutput:
|
|
1287
1296
|
"""Execute a specific pipeline by name synchronously"""
|
|
1288
1297
|
from inspect import isasyncgenfunction, iscoroutinefunction, isgeneratorfunction
|
|
1289
1298
|
|
|
1290
1299
|
workflow_run_response.status = RunStatus.running
|
|
1291
|
-
if workflow_run_response.run_id:
|
|
1292
|
-
register_run(workflow_run_response.run_id) # type: ignore
|
|
1293
1300
|
|
|
1294
1301
|
if callable(self.steps):
|
|
1295
1302
|
if iscoroutinefunction(self.steps) or isasyncgenfunction(self.steps):
|
|
@@ -1355,6 +1362,7 @@ class Workflow:
|
|
|
1355
1362
|
if self.add_workflow_history_to_steps
|
|
1356
1363
|
else None,
|
|
1357
1364
|
num_history_runs=self.num_history_runs,
|
|
1365
|
+
background_tasks=background_tasks,
|
|
1358
1366
|
)
|
|
1359
1367
|
|
|
1360
1368
|
# Check for cancellation after step execution
|
|
@@ -1455,6 +1463,7 @@ class Workflow:
|
|
|
1455
1463
|
workflow_run_response: WorkflowRunOutput,
|
|
1456
1464
|
run_context: RunContext,
|
|
1457
1465
|
stream_events: bool = False,
|
|
1466
|
+
background_tasks: Optional[Any] = None,
|
|
1458
1467
|
**kwargs: Any,
|
|
1459
1468
|
) -> Iterator[WorkflowRunOutputEvent]:
|
|
1460
1469
|
"""Execute a specific pipeline by name with event streaming"""
|
|
@@ -1462,10 +1471,6 @@ class Workflow:
|
|
|
1462
1471
|
|
|
1463
1472
|
workflow_run_response.status = RunStatus.running
|
|
1464
1473
|
|
|
1465
|
-
# Register run for cancellation tracking
|
|
1466
|
-
if workflow_run_response.run_id:
|
|
1467
|
-
register_run(workflow_run_response.run_id)
|
|
1468
|
-
|
|
1469
1474
|
workflow_started_event = WorkflowStartedEvent(
|
|
1470
1475
|
run_id=workflow_run_response.run_id or "",
|
|
1471
1476
|
workflow_name=workflow_run_response.workflow_name,
|
|
@@ -1552,6 +1557,7 @@ class Workflow:
|
|
|
1552
1557
|
if self.add_workflow_history_to_steps
|
|
1553
1558
|
else None,
|
|
1554
1559
|
num_history_runs=self.num_history_runs,
|
|
1560
|
+
background_tasks=background_tasks,
|
|
1555
1561
|
):
|
|
1556
1562
|
raise_if_cancelled(workflow_run_response.run_id) # type: ignore
|
|
1557
1563
|
|
|
@@ -1831,7 +1837,7 @@ class Workflow:
|
|
|
1831
1837
|
self._update_metadata(session=workflow_session)
|
|
1832
1838
|
|
|
1833
1839
|
# Update session state from DB
|
|
1834
|
-
_session_state = session_state
|
|
1840
|
+
_session_state = session_state if session_state is not None else {}
|
|
1835
1841
|
_session_state = self._load_session_state(session=workflow_session, session_state=_session_state)
|
|
1836
1842
|
|
|
1837
1843
|
return workflow_session, _session_state
|
|
@@ -1843,6 +1849,7 @@ class Workflow:
|
|
|
1843
1849
|
execution_input: WorkflowExecutionInput,
|
|
1844
1850
|
workflow_run_response: WorkflowRunOutput,
|
|
1845
1851
|
run_context: RunContext,
|
|
1852
|
+
background_tasks: Optional[Any] = None,
|
|
1846
1853
|
**kwargs: Any,
|
|
1847
1854
|
) -> WorkflowRunOutput:
|
|
1848
1855
|
"""Execute a specific pipeline by name asynchronously"""
|
|
@@ -1855,10 +1862,6 @@ class Workflow:
|
|
|
1855
1862
|
|
|
1856
1863
|
workflow_run_response.status = RunStatus.running
|
|
1857
1864
|
|
|
1858
|
-
# Register run for cancellation tracking
|
|
1859
|
-
if workflow_run_response.run_id:
|
|
1860
|
-
register_run(workflow_run_response.run_id) # type: ignore
|
|
1861
|
-
|
|
1862
1865
|
if callable(self.steps):
|
|
1863
1866
|
# Execute the workflow with the custom executor
|
|
1864
1867
|
content = ""
|
|
@@ -1931,6 +1934,7 @@ class Workflow:
|
|
|
1931
1934
|
if self.add_workflow_history_to_steps
|
|
1932
1935
|
else None,
|
|
1933
1936
|
num_history_runs=self.num_history_runs,
|
|
1937
|
+
background_tasks=background_tasks,
|
|
1934
1938
|
)
|
|
1935
1939
|
|
|
1936
1940
|
# Check for cancellation after step execution
|
|
@@ -2031,6 +2035,7 @@ class Workflow:
|
|
|
2031
2035
|
run_context: RunContext,
|
|
2032
2036
|
stream_events: bool = False,
|
|
2033
2037
|
websocket_handler: Optional[WebSocketHandler] = None,
|
|
2038
|
+
background_tasks: Optional[Any] = None,
|
|
2034
2039
|
**kwargs: Any,
|
|
2035
2040
|
) -> AsyncIterator[WorkflowRunOutputEvent]:
|
|
2036
2041
|
"""Execute a specific pipeline by name with event streaming"""
|
|
@@ -2043,10 +2048,6 @@ class Workflow:
|
|
|
2043
2048
|
|
|
2044
2049
|
workflow_run_response.status = RunStatus.running
|
|
2045
2050
|
|
|
2046
|
-
# Register run for cancellation tracking
|
|
2047
|
-
if workflow_run_response.run_id:
|
|
2048
|
-
register_run(workflow_run_response.run_id)
|
|
2049
|
-
|
|
2050
2051
|
workflow_started_event = WorkflowStartedEvent(
|
|
2051
2052
|
run_id=workflow_run_response.run_id or "",
|
|
2052
2053
|
workflow_name=workflow_run_response.workflow_name,
|
|
@@ -2141,6 +2142,7 @@ class Workflow:
|
|
|
2141
2142
|
if self.add_workflow_history_to_steps
|
|
2142
2143
|
else None,
|
|
2143
2144
|
num_history_runs=self.num_history_runs,
|
|
2145
|
+
background_tasks=background_tasks,
|
|
2144
2146
|
):
|
|
2145
2147
|
if workflow_run_response.run_id:
|
|
2146
2148
|
raise_if_cancelled(workflow_run_response.run_id)
|
|
@@ -3457,6 +3459,7 @@ class Workflow:
|
|
|
3457
3459
|
stream_events: Optional[bool] = None,
|
|
3458
3460
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3459
3461
|
background: Optional[bool] = False,
|
|
3462
|
+
background_tasks: Optional[Any] = None,
|
|
3460
3463
|
) -> WorkflowRunOutput: ...
|
|
3461
3464
|
|
|
3462
3465
|
@overload
|
|
@@ -3475,6 +3478,7 @@ class Workflow:
|
|
|
3475
3478
|
stream_events: Optional[bool] = None,
|
|
3476
3479
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3477
3480
|
background: Optional[bool] = False,
|
|
3481
|
+
background_tasks: Optional[Any] = None,
|
|
3478
3482
|
) -> Iterator[WorkflowRunOutputEvent]: ...
|
|
3479
3483
|
|
|
3480
3484
|
def run(
|
|
@@ -3492,20 +3496,23 @@ class Workflow:
|
|
|
3492
3496
|
stream_events: Optional[bool] = None,
|
|
3493
3497
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3494
3498
|
background: Optional[bool] = False,
|
|
3499
|
+
background_tasks: Optional[Any] = None,
|
|
3495
3500
|
**kwargs: Any,
|
|
3496
3501
|
) -> Union[WorkflowRunOutput, Iterator[WorkflowRunOutputEvent]]:
|
|
3497
3502
|
"""Execute the workflow synchronously with optional streaming"""
|
|
3498
3503
|
if self._has_async_db():
|
|
3499
3504
|
raise Exception("`run()` is not supported with an async DB. Please use `arun()`.")
|
|
3500
3505
|
|
|
3506
|
+
# Create a run_id for this specific run and register immediately for cancellation tracking
|
|
3507
|
+
run_id = str(uuid4())
|
|
3508
|
+
register_run(run_id)
|
|
3509
|
+
|
|
3501
3510
|
input = self._validate_input(input)
|
|
3502
3511
|
if background:
|
|
3503
3512
|
raise RuntimeError("Background execution is not supported for sync run()")
|
|
3504
3513
|
|
|
3505
3514
|
self._set_debug()
|
|
3506
3515
|
|
|
3507
|
-
run_id = str(uuid4())
|
|
3508
|
-
|
|
3509
3516
|
self.initialize_workflow()
|
|
3510
3517
|
session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
|
|
3511
3518
|
|
|
@@ -3515,7 +3522,10 @@ class Workflow:
|
|
|
3515
3522
|
|
|
3516
3523
|
# Initialize session state
|
|
3517
3524
|
session_state = self._initialize_session_state(
|
|
3518
|
-
session_state=session_state
|
|
3525
|
+
session_state=session_state if session_state is not None else {},
|
|
3526
|
+
user_id=user_id,
|
|
3527
|
+
session_id=session_id,
|
|
3528
|
+
run_id=run_id,
|
|
3519
3529
|
)
|
|
3520
3530
|
# Update session state from DB
|
|
3521
3531
|
session_state = self._load_session_state(session=workflow_session, session_state=session_state)
|
|
@@ -3592,6 +3602,7 @@ class Workflow:
|
|
|
3592
3602
|
workflow_run_response=workflow_run_response,
|
|
3593
3603
|
stream_events=stream_events,
|
|
3594
3604
|
run_context=run_context,
|
|
3605
|
+
background_tasks=background_tasks,
|
|
3595
3606
|
**kwargs,
|
|
3596
3607
|
)
|
|
3597
3608
|
else:
|
|
@@ -3600,6 +3611,7 @@ class Workflow:
|
|
|
3600
3611
|
execution_input=inputs, # type: ignore[arg-type]
|
|
3601
3612
|
workflow_run_response=workflow_run_response,
|
|
3602
3613
|
run_context=run_context,
|
|
3614
|
+
background_tasks=background_tasks,
|
|
3603
3615
|
**kwargs,
|
|
3604
3616
|
)
|
|
3605
3617
|
|
|
@@ -3620,6 +3632,7 @@ class Workflow:
|
|
|
3620
3632
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3621
3633
|
background: Optional[bool] = False,
|
|
3622
3634
|
websocket: Optional[WebSocket] = None,
|
|
3635
|
+
background_tasks: Optional[Any] = None,
|
|
3623
3636
|
) -> WorkflowRunOutput: ...
|
|
3624
3637
|
|
|
3625
3638
|
@overload
|
|
@@ -3639,6 +3652,7 @@ class Workflow:
|
|
|
3639
3652
|
stream_intermediate_steps: Optional[bool] = None,
|
|
3640
3653
|
background: Optional[bool] = False,
|
|
3641
3654
|
websocket: Optional[WebSocket] = None,
|
|
3655
|
+
background_tasks: Optional[Any] = None,
|
|
3642
3656
|
) -> AsyncIterator[WorkflowRunOutputEvent]: ...
|
|
3643
3657
|
|
|
3644
3658
|
def arun( # type: ignore
|
|
@@ -3657,6 +3671,7 @@ class Workflow:
|
|
|
3657
3671
|
stream_intermediate_steps: Optional[bool] = False,
|
|
3658
3672
|
background: Optional[bool] = False,
|
|
3659
3673
|
websocket: Optional[WebSocket] = None,
|
|
3674
|
+
background_tasks: Optional[Any] = None,
|
|
3660
3675
|
**kwargs: Any,
|
|
3661
3676
|
) -> Union[WorkflowRunOutput, AsyncIterator[WorkflowRunOutputEvent]]:
|
|
3662
3677
|
"""Execute the workflow synchronously with optional streaming"""
|
|
@@ -3715,7 +3730,9 @@ class Workflow:
|
|
|
3715
3730
|
|
|
3716
3731
|
self._set_debug()
|
|
3717
3732
|
|
|
3733
|
+
# Create a run_id for this specific run and register immediately for cancellation tracking
|
|
3718
3734
|
run_id = str(uuid4())
|
|
3735
|
+
register_run(run_id)
|
|
3719
3736
|
|
|
3720
3737
|
self.initialize_workflow()
|
|
3721
3738
|
session_id, user_id = self._initialize_session(session_id=session_id, user_id=user_id)
|
|
@@ -3793,6 +3810,7 @@ class Workflow:
|
|
|
3793
3810
|
files=files,
|
|
3794
3811
|
session_state=session_state,
|
|
3795
3812
|
run_context=run_context,
|
|
3813
|
+
background_tasks=background_tasks,
|
|
3796
3814
|
**kwargs,
|
|
3797
3815
|
)
|
|
3798
3816
|
else:
|
|
@@ -3805,6 +3823,7 @@ class Workflow:
|
|
|
3805
3823
|
files=files,
|
|
3806
3824
|
session_state=session_state,
|
|
3807
3825
|
run_context=run_context,
|
|
3826
|
+
background_tasks=background_tasks,
|
|
3808
3827
|
**kwargs,
|
|
3809
3828
|
)
|
|
3810
3829
|
|
|
@@ -4153,6 +4172,56 @@ class Workflow:
|
|
|
4153
4172
|
if hasattr(member, "workflow_id"):
|
|
4154
4173
|
member.workflow_id = self.id
|
|
4155
4174
|
|
|
4175
|
+
def propagate_run_hooks_in_background(self, run_in_background: bool = True) -> None:
|
|
4176
|
+
"""
|
|
4177
|
+
Propagate _run_hooks_in_background setting to this workflow and all agents/teams in steps.
|
|
4178
|
+
|
|
4179
|
+
This method sets _run_hooks_in_background on the workflow and all agents/teams
|
|
4180
|
+
within its steps, including nested teams and their members.
|
|
4181
|
+
|
|
4182
|
+
Args:
|
|
4183
|
+
run_in_background: Whether hooks should run in background. Defaults to True.
|
|
4184
|
+
"""
|
|
4185
|
+
self._run_hooks_in_background = run_in_background
|
|
4186
|
+
|
|
4187
|
+
if not self.steps or callable(self.steps):
|
|
4188
|
+
return
|
|
4189
|
+
|
|
4190
|
+
steps_list = self.steps.steps if isinstance(self.steps, Steps) else self.steps
|
|
4191
|
+
|
|
4192
|
+
for step in steps_list:
|
|
4193
|
+
self._propagate_hooks_to_step(step, run_in_background)
|
|
4194
|
+
|
|
4195
|
+
def _propagate_hooks_to_step(self, step: Any, run_in_background: bool) -> None:
|
|
4196
|
+
"""Recursively propagate _run_hooks_in_background to a step and its nested content."""
|
|
4197
|
+
# Handle Step objects with active executor
|
|
4198
|
+
if hasattr(step, "active_executor") and step.active_executor:
|
|
4199
|
+
executor = step.active_executor
|
|
4200
|
+
# If it's a team, use its propagation method
|
|
4201
|
+
if hasattr(executor, "propagate_run_hooks_in_background"):
|
|
4202
|
+
executor.propagate_run_hooks_in_background(run_in_background)
|
|
4203
|
+
elif hasattr(executor, "_run_hooks_in_background"):
|
|
4204
|
+
executor._run_hooks_in_background = run_in_background
|
|
4205
|
+
|
|
4206
|
+
# Handle agent/team directly on step
|
|
4207
|
+
if hasattr(step, "agent") and step.agent:
|
|
4208
|
+
if hasattr(step.agent, "_run_hooks_in_background"):
|
|
4209
|
+
step.agent._run_hooks_in_background = run_in_background
|
|
4210
|
+
if hasattr(step, "team") and step.team:
|
|
4211
|
+
# Use team's method to propagate to all nested members
|
|
4212
|
+
if hasattr(step.team, "propagate_run_hooks_in_background"):
|
|
4213
|
+
step.team.propagate_run_hooks_in_background(run_in_background)
|
|
4214
|
+
elif hasattr(step.team, "_run_hooks_in_background"):
|
|
4215
|
+
step.team._run_hooks_in_background = run_in_background
|
|
4216
|
+
|
|
4217
|
+
# Handle nested primitives - check 'steps' and 'choices' attributes
|
|
4218
|
+
for attr_name in ["steps", "choices"]:
|
|
4219
|
+
if hasattr(step, attr_name):
|
|
4220
|
+
attr_value = getattr(step, attr_name)
|
|
4221
|
+
if attr_value and isinstance(attr_value, list):
|
|
4222
|
+
for nested_step in attr_value:
|
|
4223
|
+
self._propagate_hooks_to_step(nested_step, run_in_background)
|
|
4224
|
+
|
|
4156
4225
|
###########################################################################
|
|
4157
4226
|
# Telemetry functions
|
|
4158
4227
|
###########################################################################
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agno
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.6
|
|
4
4
|
Summary: Agno: a lightweight library for building Multi-Agent Systems
|
|
5
5
|
Author-email: Ashpreet Bedi <ashpreet@agno.com>
|
|
6
6
|
Project-URL: homepage, https://agno.com
|
|
@@ -153,7 +153,7 @@ Requires-Dist: mcp>=1.9.2; extra == "mcp"
|
|
|
153
153
|
Provides-Extra: mem0
|
|
154
154
|
Requires-Dist: mem0ai; extra == "mem0"
|
|
155
155
|
Provides-Extra: memori
|
|
156
|
-
Requires-Dist: memorisdk; extra == "memori"
|
|
156
|
+
Requires-Dist: memorisdk==2.3.3; extra == "memori"
|
|
157
157
|
Provides-Extra: newspaper
|
|
158
158
|
Requires-Dist: newspaper4k; extra == "newspaper"
|
|
159
159
|
Requires-Dist: lxml_html_clean; extra == "newspaper"
|
|
@@ -381,6 +381,7 @@ Requires-Dist: agno[agui]; extra == "tests"
|
|
|
381
381
|
Requires-Dist: agno[integration-tests]; extra == "tests"
|
|
382
382
|
Requires-Dist: twine; extra == "tests"
|
|
383
383
|
Requires-Dist: build; extra == "tests"
|
|
384
|
+
Requires-Dist: grpcio==1.74.0; extra == "tests"
|
|
384
385
|
Provides-Extra: integration-tests
|
|
385
386
|
Requires-Dist: exa_py; extra == "integration-tests"
|
|
386
387
|
Requires-Dist: ddgs; extra == "integration-tests"
|
|
@@ -411,15 +412,15 @@ Dynamic: license-file
|
|
|
411
412
|
|
|
412
413
|
## What is Agno?
|
|
413
414
|
|
|
414
|
-
Agno is
|
|
415
|
+
Agno is an incredibly fast multi-agent framework, runtime and control plane.
|
|
415
416
|
|
|
416
|
-
It provides
|
|
417
|
+
It provides the complete stack for building, running and managing multi-agent systems:
|
|
417
418
|
|
|
418
|
-
- **
|
|
419
|
-
- **
|
|
420
|
-
- **
|
|
419
|
+
- **Framework**: Build agents, multi-agent teams and workflows with memory, knowledge, state, guardrails, HITL, context compression, MCP, A2A and 100+ toolkits.
|
|
420
|
+
- **AgentOS Runtime**: Run your multi-agent system in production with a secure, stateless runtime and ready to use integration endpoints.
|
|
421
|
+
- **AgentOS Control Plane**: Test, monitor and manage AgentOS deployments across environments with full operational visibility.
|
|
421
422
|
|
|
422
|
-
|
|
423
|
+
Checkout the full list of features [here](#features).
|
|
423
424
|
|
|
424
425
|
## Getting started
|
|
425
426
|
|
|
@@ -436,7 +437,7 @@ After that, checkout the [examples gallery](https://docs.agno.com/examples/use-c
|
|
|
436
437
|
|
|
437
438
|
## Example
|
|
438
439
|
|
|
439
|
-
Here
|
|
440
|
+
Here's an example of an Agent that connects to an MCP server, manages conversation state in a database, is served using a FastAPI application that you can chat with using the [AgentOS UI](https://os.agno.com).
|
|
440
441
|
|
|
441
442
|
```python agno_agent.py
|
|
442
443
|
from agno.agent import Agent
|
|
@@ -471,21 +472,21 @@ if __name__ == "__main__":
|
|
|
471
472
|
|
|
472
473
|
## AgentOS - Production Runtime for Multi-Agent Systems
|
|
473
474
|
|
|
474
|
-
Building Agents is easy, running them
|
|
475
|
+
Building Agents is easy, running them as a secure, scalable service is hard. AgentOS solves this by providing a high performance runtime for serving multi-agent systems in production. Key features include:
|
|
475
476
|
|
|
476
|
-
1. **Pre-built FastAPI app**: AgentOS
|
|
477
|
+
1. **Pre-built FastAPI app**: AgentOS includes a ready-to-use FastAPI app for running your agents, teams and workflows. This gives you a significant head start when building an AI product.
|
|
477
478
|
|
|
478
|
-
2. **Integrated Control Plane**: The [AgentOS UI](https://os.agno.com) connects directly to your runtime,
|
|
479
|
+
2. **Integrated Control Plane**: The [AgentOS UI](https://os.agno.com) connects directly to your runtime, so you can test, monitor and manage your system in real time with full operational visibility.
|
|
479
480
|
|
|
480
|
-
3. **Private by Design**: AgentOS runs entirely in your cloud, ensuring complete data privacy. No data
|
|
481
|
+
3. **Private by Design**: AgentOS runs entirely in your cloud, ensuring complete data privacy. No data leaves your environment, making it ideal for security conscious enterprises..
|
|
481
482
|
|
|
482
|
-
|
|
483
|
+
When you run the example script shared above, you get a FastAPI app that you can connect to the [AgentOS UI](https://os.agno.com). Here's what it looks like in action:
|
|
483
484
|
|
|
484
485
|
https://github.com/user-attachments/assets/feb23db8-15cc-4e88-be7c-01a21a03ebf6
|
|
485
486
|
|
|
486
487
|
## The Complete Agentic Solution
|
|
487
488
|
|
|
488
|
-
|
|
489
|
+
Agno provides the complete solution for companies building agentic systems:
|
|
489
490
|
|
|
490
491
|
- The fastest framework for building agents, multi-agent teams and agentic workflows.
|
|
491
492
|
- A ready-to-use FastAPI app that gets you building AI products on day one.
|
|
@@ -493,28 +494,32 @@ For companies building agents, Agno provides the complete agentic solution:
|
|
|
493
494
|
|
|
494
495
|
Agno brings a novel architecture that no other framework provides, your AgentOS runs securely in your cloud, and the control plane connects directly to it from your browser. You don't need to send data to any external services or pay retention costs, you get complete privacy and control.
|
|
495
496
|
|
|
496
|
-
##
|
|
497
|
+
## Features
|
|
497
498
|
|
|
498
|
-
Agno is an incredibly feature-rich framework
|
|
499
|
+
Agno is an incredibly feature-rich framework purpose-built for Agent Engineering. Here are some key features:
|
|
499
500
|
|
|
500
501
|
| **Category** | **Feature** | **Description** |
|
|
501
502
|
| -------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
502
|
-
| **
|
|
503
|
-
| | **Type Safe** |
|
|
504
|
-
| | **Dynamic Context
|
|
505
|
-
| **
|
|
506
|
-
|
|
|
507
|
-
| | **
|
|
508
|
-
| | **
|
|
509
|
-
| **
|
|
503
|
+
| **Foundational Principles** | **Model Agnostic** | Supports all model providers so you can choose the best model for your use case |
|
|
504
|
+
| | **Type Safe** | Enforces structured I/O through input_schema and output_schema for predictable and composable agent behavior. |
|
|
505
|
+
| | **Dynamic Context** | Inject variables, state, and retrieved data at runtime into context. Compress, summarize and filter context to keep your Agents focused and efficient. |
|
|
506
|
+
| | **Designed for Scale** | Designed around async execution and long-running tasks for high throughput agent workloads. |
|
|
507
|
+
| **Memory, Knowledge, and Persistence** | **Persistent Storage** | Give your Agents, Teams, and Workflows a database to persist session history, state, and messages. |
|
|
508
|
+
| | **User Memory** | Built in memory layer that helps agents recall user specific context across sessions. |
|
|
509
|
+
| | **Agentic RAG** | Connect to 20+ vector stores (called **Knowledge**) with hybrid search, reranking, and chunking out of the box. |
|
|
510
|
+
| | **Culture** | Shared long term collective memory that compounds across agents and time. |
|
|
511
|
+
| | **Ephemeral Context** | In memory scratchpad for short lived reasoning without polluting long term state. |
|
|
512
|
+
| **Execution & Control** | **Human-in-the-Loop** | Native support for confirmations, approvals, manual overrides, and external actions. |
|
|
510
513
|
| | **Guardrails** | Built-in safeguards for validation, security, and prompt protection. |
|
|
511
|
-
| | **Agent Lifecycle Hooks** | Pre
|
|
512
|
-
| | **MCP Integration** | First-class support for the Model Context Protocol (MCP) to connect Agents with external systems.
|
|
513
|
-
| | **
|
|
514
|
-
|
|
|
515
|
-
|
|
|
516
|
-
| | **
|
|
517
|
-
| | **
|
|
514
|
+
| | **Agent Lifecycle Hooks** | Pre and post hooks to validate, enrich, or transform inputs and outputs. |
|
|
515
|
+
| | **MCP Integration** | First-class support for the Model Context Protocol (MCP) to connect Agents with external systems. |
|
|
516
|
+
| | **A2A Integration** | First-class support for the Agent to Agent communication protocol (A2A). |
|
|
517
|
+
| | **Toolkits** | 100+ built in toolkits with thousands of tools covering data, code, web, and enterprise APIs. |
|
|
518
|
+
| **Runtime & Evaluation** | **Runtime** | Prebuilt FastAPI runtime with SSE compatible endpoints. Production ready from day one. |
|
|
519
|
+
| | **Control Plane (UI)** | Integrated interface to test, observe, and debug your agents, teams, and workflows in real time. |
|
|
520
|
+
| | **Natively Multimodal** | Agents can process and generate text, images, audio, video, and files. |
|
|
521
|
+
| | **Evals** | Measure Accuracy, Performance, Latency, and Reliability across agents and workflows. |
|
|
522
|
+
| | **Durable Execution** | Built in support for long running, resumable workflows. |
|
|
518
523
|
| **Security & Privacy** | **Private by Design** | Runs entirely in your cloud. The UI connects directly to your AgentOS from your browser, no data is ever sent externally. |
|
|
519
524
|
| | **Data Governance** | Your data lives securely in your Agent database, no external data sharing or vendor lock-in. |
|
|
520
525
|
| | **Access Control** | Role-based access (RBAC) and per-agent permissions to protect sensitive contexts and tools. |
|
|
@@ -544,7 +549,7 @@ At Agno, we optimize performance across 3 dimensions:
|
|
|
544
549
|
|
|
545
550
|
1. **Agent performance:** We optimize static operations (instantiation, memory footprint) and runtime operations (tool calls, memory updates, history management).
|
|
546
551
|
2. **System performance:** The AgentOS API is async by default and has a minimal memory footprint. The system is stateless and horizontally scalable, with a focus on preventing memory leaks. It handles parallel and batch embedding generation during knowledge ingestion, metrics collection in background tasks, and other system-level optimizations.
|
|
547
|
-
3. **Agent reliability and accuracy:** Monitored through evals, which we
|
|
552
|
+
3. **Agent reliability and accuracy:** Monitored through evals, which we'll explore later.
|
|
548
553
|
|
|
549
554
|
### Agent Performance
|
|
550
555
|
|