agno 2.0.2__py3-none-any.whl → 2.0.4__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 +164 -87
- agno/db/dynamo/dynamo.py +8 -0
- agno/db/firestore/firestore.py +8 -1
- agno/db/gcs_json/gcs_json_db.py +9 -0
- agno/db/json/json_db.py +8 -0
- agno/db/mongo/mongo.py +10 -1
- agno/db/mysql/mysql.py +10 -0
- agno/db/postgres/postgres.py +16 -8
- agno/db/redis/redis.py +6 -0
- agno/db/singlestore/schemas.py +1 -1
- agno/db/singlestore/singlestore.py +8 -1
- agno/db/sqlite/sqlite.py +9 -1
- agno/db/utils.py +14 -0
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/knowledge.py +91 -65
- agno/knowledge/reader/base.py +3 -0
- agno/knowledge/reader/csv_reader.py +1 -1
- agno/knowledge/reader/json_reader.py +1 -1
- agno/knowledge/reader/markdown_reader.py +5 -5
- agno/knowledge/reader/s3_reader.py +0 -12
- agno/knowledge/reader/text_reader.py +5 -5
- agno/models/base.py +2 -2
- agno/models/cerebras/cerebras.py +5 -3
- agno/models/cerebras/cerebras_openai.py +5 -3
- agno/models/google/gemini.py +33 -11
- agno/models/litellm/chat.py +1 -1
- agno/models/openai/chat.py +3 -0
- agno/models/openai/responses.py +81 -40
- agno/models/response.py +5 -0
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/os/app.py +4 -1
- agno/os/auth.py +24 -14
- agno/os/interfaces/slack/router.py +1 -1
- agno/os/interfaces/whatsapp/router.py +2 -0
- agno/os/router.py +187 -76
- agno/os/routers/evals/utils.py +9 -9
- agno/os/routers/health.py +26 -0
- agno/os/routers/knowledge/knowledge.py +11 -11
- agno/os/routers/session/session.py +24 -8
- agno/os/schema.py +8 -2
- agno/run/agent.py +5 -2
- agno/run/base.py +6 -3
- agno/run/team.py +11 -3
- agno/run/workflow.py +69 -12
- agno/session/team.py +1 -0
- agno/team/team.py +196 -93
- agno/tools/mcp.py +1 -0
- agno/tools/mem0.py +11 -17
- agno/tools/memory.py +419 -0
- agno/tools/workflow.py +279 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/print_response/agent.py +6 -2
- agno/utils/streamlit.py +14 -8
- agno/vectordb/chroma/chromadb.py +8 -2
- agno/workflow/step.py +111 -13
- agno/workflow/workflow.py +16 -13
- {agno-2.0.2.dist-info → agno-2.0.4.dist-info}/METADATA +1 -1
- {agno-2.0.2.dist-info → agno-2.0.4.dist-info}/RECORD +63 -58
- {agno-2.0.2.dist-info → agno-2.0.4.dist-info}/WHEEL +0 -0
- {agno-2.0.2.dist-info → agno-2.0.4.dist-info}/licenses/LICENSE +0 -0
- {agno-2.0.2.dist-info → agno-2.0.4.dist-info}/top_level.txt +0 -0
|
@@ -222,7 +222,9 @@ def attach_routes(router: APIRouter, dbs: dict[str, BaseDb]) -> APIRouter:
|
|
|
222
222
|
db = get_db(dbs, db_id)
|
|
223
223
|
session = db.get_session(session_id=session_id, session_type=session_type)
|
|
224
224
|
if not session:
|
|
225
|
-
raise HTTPException(
|
|
225
|
+
raise HTTPException(
|
|
226
|
+
status_code=404, detail=f"{session_type.value.title()} Session with id '{session_id}' not found"
|
|
227
|
+
)
|
|
226
228
|
|
|
227
229
|
if session_type == SessionType.AGENT:
|
|
228
230
|
return AgentSessionDetailSchema.from_session(session) # type: ignore
|
|
@@ -233,7 +235,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, BaseDb]) -> APIRouter:
|
|
|
233
235
|
|
|
234
236
|
@router.get(
|
|
235
237
|
"/sessions/{session_id}/runs",
|
|
236
|
-
response_model=Union[
|
|
238
|
+
response_model=List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]],
|
|
237
239
|
status_code=200,
|
|
238
240
|
operation_id="get_session_runs",
|
|
239
241
|
summary="Get Session Runs",
|
|
@@ -251,7 +253,8 @@ def attach_routes(router: APIRouter, dbs: dict[str, BaseDb]) -> APIRouter:
|
|
|
251
253
|
"summary": "Example completed run",
|
|
252
254
|
"value": {
|
|
253
255
|
"run_id": "fcdf50f0-7c32-4593-b2ef-68a558774340",
|
|
254
|
-
"
|
|
256
|
+
"parent_run_id": "80056af0-c7a5-4d69-b6a2-c3eba9f040e0",
|
|
257
|
+
"agent_id": "basic-agent",
|
|
255
258
|
"user_id": "",
|
|
256
259
|
"run_input": "Which tools do you have access to?",
|
|
257
260
|
"content": "I don't have access to external tools or the internet. However, I can assist you with a wide range of topics by providing information, answering questions, and offering suggestions based on the knowledge I've been trained on. If there's anything specific you need help with, feel free to ask!",
|
|
@@ -351,7 +354,7 @@ def attach_routes(router: APIRouter, dbs: dict[str, BaseDb]) -> APIRouter:
|
|
|
351
354
|
default=SessionType.AGENT, description="Session type (agent, team, or workflow)", alias="type"
|
|
352
355
|
),
|
|
353
356
|
db_id: Optional[str] = Query(default=None, description="Database ID to query runs from"),
|
|
354
|
-
) -> Union[
|
|
357
|
+
) -> List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]]:
|
|
355
358
|
db = get_db(dbs, db_id)
|
|
356
359
|
session = db.get_session(session_id=session_id, session_type=session_type, deserialize=False)
|
|
357
360
|
if not session:
|
|
@@ -365,13 +368,26 @@ def attach_routes(router: APIRouter, dbs: dict[str, BaseDb]) -> APIRouter:
|
|
|
365
368
|
return [RunSchema.from_dict(run) for run in runs]
|
|
366
369
|
|
|
367
370
|
elif session_type == SessionType.TEAM:
|
|
368
|
-
|
|
371
|
+
run_responses: List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]] = []
|
|
372
|
+
for run in runs:
|
|
373
|
+
if run.get("agent_id") is not None:
|
|
374
|
+
run_responses.append(RunSchema.from_dict(run))
|
|
375
|
+
elif run.get("team_id") is not None:
|
|
376
|
+
run_responses.append(TeamRunSchema.from_dict(run))
|
|
377
|
+
return run_responses
|
|
369
378
|
|
|
370
379
|
elif session_type == SessionType.WORKFLOW:
|
|
371
|
-
|
|
372
|
-
|
|
380
|
+
run_responses: List[Union[RunSchema, TeamRunSchema, WorkflowRunSchema]] = [] # type: ignore
|
|
381
|
+
for run in runs:
|
|
382
|
+
if run.get("workflow_id") is not None:
|
|
383
|
+
run_responses.append(WorkflowRunSchema.from_dict(run))
|
|
384
|
+
elif run.get("team_id") is not None:
|
|
385
|
+
run_responses.append(TeamRunSchema.from_dict(run))
|
|
386
|
+
else:
|
|
387
|
+
run_responses.append(RunSchema.from_dict(run))
|
|
388
|
+
return run_responses
|
|
373
389
|
else:
|
|
374
|
-
|
|
390
|
+
raise HTTPException(status_code=400, detail=f"Invalid session type: {session_type}")
|
|
375
391
|
|
|
376
392
|
@router.delete(
|
|
377
393
|
"/sessions/{session_id}",
|
agno/os/schema.py
CHANGED
|
@@ -826,7 +826,8 @@ class WorkflowSessionDetailSchema(BaseModel):
|
|
|
826
826
|
|
|
827
827
|
class RunSchema(BaseModel):
|
|
828
828
|
run_id: str
|
|
829
|
-
|
|
829
|
+
parent_run_id: Optional[str]
|
|
830
|
+
agent_id: Optional[str]
|
|
830
831
|
user_id: Optional[str]
|
|
831
832
|
run_input: Optional[str]
|
|
832
833
|
content: Optional[Union[str, dict]]
|
|
@@ -844,7 +845,8 @@ class RunSchema(BaseModel):
|
|
|
844
845
|
run_response_format = "text" if run_dict.get("content_type", "str") == "str" else "json"
|
|
845
846
|
return cls(
|
|
846
847
|
run_id=run_dict.get("run_id", ""),
|
|
847
|
-
|
|
848
|
+
parent_run_id=run_dict.get("parent_run_id", ""),
|
|
849
|
+
agent_id=run_dict.get("agent_id", ""),
|
|
848
850
|
user_id=run_dict.get("user_id", ""),
|
|
849
851
|
run_input=run_input,
|
|
850
852
|
content=run_dict.get("content", ""),
|
|
@@ -863,6 +865,7 @@ class RunSchema(BaseModel):
|
|
|
863
865
|
class TeamRunSchema(BaseModel):
|
|
864
866
|
run_id: str
|
|
865
867
|
parent_run_id: Optional[str]
|
|
868
|
+
team_id: Optional[str]
|
|
866
869
|
content: Optional[Union[str, dict]]
|
|
867
870
|
reasoning_content: Optional[str]
|
|
868
871
|
run_input: Optional[str]
|
|
@@ -880,6 +883,7 @@ class TeamRunSchema(BaseModel):
|
|
|
880
883
|
return cls(
|
|
881
884
|
run_id=run_dict.get("run_id", ""),
|
|
882
885
|
parent_run_id=run_dict.get("parent_run_id", ""),
|
|
886
|
+
team_id=run_dict.get("team_id", ""),
|
|
883
887
|
run_input=run_input,
|
|
884
888
|
content=run_dict.get("content", ""),
|
|
885
889
|
run_response_format=run_response_format,
|
|
@@ -897,6 +901,7 @@ class TeamRunSchema(BaseModel):
|
|
|
897
901
|
class WorkflowRunSchema(BaseModel):
|
|
898
902
|
run_id: str
|
|
899
903
|
run_input: Optional[str]
|
|
904
|
+
workflow_id: Optional[str]
|
|
900
905
|
user_id: Optional[str]
|
|
901
906
|
content: Optional[Union[str, dict]]
|
|
902
907
|
content_type: Optional[str]
|
|
@@ -912,6 +917,7 @@ class WorkflowRunSchema(BaseModel):
|
|
|
912
917
|
return cls(
|
|
913
918
|
run_id=run_response.get("run_id", ""),
|
|
914
919
|
run_input=run_input,
|
|
920
|
+
workflow_id=run_response.get("workflow_id", ""),
|
|
915
921
|
user_id=run_response.get("user_id", ""),
|
|
916
922
|
content=run_response.get("content", ""),
|
|
917
923
|
content_type=run_response.get("content_type", ""),
|
agno/run/agent.py
CHANGED
|
@@ -536,7 +536,7 @@ class RunOutput:
|
|
|
536
536
|
|
|
537
537
|
return _dict
|
|
538
538
|
|
|
539
|
-
def to_json(self) -> str:
|
|
539
|
+
def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
|
|
540
540
|
import json
|
|
541
541
|
|
|
542
542
|
try:
|
|
@@ -545,7 +545,10 @@ class RunOutput:
|
|
|
545
545
|
logger.error("Failed to convert response to json", exc_info=True)
|
|
546
546
|
raise
|
|
547
547
|
|
|
548
|
-
|
|
548
|
+
if indent is None:
|
|
549
|
+
return json.dumps(_dict, separators=separators)
|
|
550
|
+
else:
|
|
551
|
+
return json.dumps(_dict, indent=indent, separators=separators)
|
|
549
552
|
|
|
550
553
|
@classmethod
|
|
551
554
|
def from_dict(cls, data: Dict[str, Any]) -> "RunOutput":
|
agno/run/base.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from dataclasses import asdict, dataclass
|
|
2
2
|
from enum import Enum
|
|
3
|
-
from typing import Any, Dict
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
@@ -115,7 +115,7 @@ class BaseRunOutputEvent:
|
|
|
115
115
|
|
|
116
116
|
return _dict
|
|
117
117
|
|
|
118
|
-
def to_json(self) -> str:
|
|
118
|
+
def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
|
|
119
119
|
import json
|
|
120
120
|
|
|
121
121
|
try:
|
|
@@ -124,7 +124,10 @@ class BaseRunOutputEvent:
|
|
|
124
124
|
log_error("Failed to convert response event to json", exc_info=True)
|
|
125
125
|
raise
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
if indent is None:
|
|
128
|
+
return json.dumps(_dict, separators=separators)
|
|
129
|
+
else:
|
|
130
|
+
return json.dumps(_dict, indent=indent, separators=separators)
|
|
128
131
|
|
|
129
132
|
@classmethod
|
|
130
133
|
def from_dict(cls, data: Dict[str, Any]):
|
agno/run/team.py
CHANGED
|
@@ -12,6 +12,7 @@ from agno.models.response import ToolExecution
|
|
|
12
12
|
from agno.reasoning.step import ReasoningStep
|
|
13
13
|
from agno.run.agent import RunEvent, RunOutput, RunOutputEvent, run_output_event_from_dict
|
|
14
14
|
from agno.run.base import BaseRunOutputEvent, MessageReferences, RunStatus
|
|
15
|
+
from agno.utils.log import log_error
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class TeamRunEvent(str, Enum):
|
|
@@ -488,12 +489,19 @@ class TeamRunOutput:
|
|
|
488
489
|
|
|
489
490
|
return _dict
|
|
490
491
|
|
|
491
|
-
def to_json(self) -> str:
|
|
492
|
+
def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
|
|
492
493
|
import json
|
|
493
494
|
|
|
494
|
-
|
|
495
|
+
try:
|
|
496
|
+
_dict = self.to_dict()
|
|
497
|
+
except Exception:
|
|
498
|
+
log_error("Failed to convert response to json", exc_info=True)
|
|
499
|
+
raise
|
|
495
500
|
|
|
496
|
-
|
|
501
|
+
if indent is None:
|
|
502
|
+
return json.dumps(_dict, separators=separators)
|
|
503
|
+
else:
|
|
504
|
+
return json.dumps(_dict, indent=indent, separators=separators)
|
|
497
505
|
|
|
498
506
|
@classmethod
|
|
499
507
|
def from_dict(cls, data: Dict[str, Any]) -> "TeamRunOutput":
|
agno/run/workflow.py
CHANGED
|
@@ -7,7 +7,7 @@ from pydantic import BaseModel
|
|
|
7
7
|
|
|
8
8
|
from agno.media import Audio, Image, Video
|
|
9
9
|
from agno.run.agent import RunOutput
|
|
10
|
-
from agno.run.base import RunStatus
|
|
10
|
+
from agno.run.base import BaseRunOutputEvent, RunStatus
|
|
11
11
|
from agno.run.team import TeamRunOutput
|
|
12
12
|
from agno.utils.log import log_error
|
|
13
13
|
|
|
@@ -53,7 +53,7 @@ class WorkflowRunEvent(str, Enum):
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
@dataclass
|
|
56
|
-
class BaseWorkflowRunOutputEvent:
|
|
56
|
+
class BaseWorkflowRunOutputEvent(BaseRunOutputEvent):
|
|
57
57
|
"""Base class for all workflow run response events"""
|
|
58
58
|
|
|
59
59
|
created_at: int = field(default_factory=lambda: int(time()))
|
|
@@ -75,23 +75,27 @@ class BaseWorkflowRunOutputEvent:
|
|
|
75
75
|
|
|
76
76
|
# Handle StepOutput fields that contain Message objects
|
|
77
77
|
if hasattr(self, "step_results") and self.step_results is not None:
|
|
78
|
-
_dict["step_results"] = [step.to_dict() for step in self.step_results]
|
|
78
|
+
_dict["step_results"] = [step.to_dict() if hasattr(step, "to_dict") else step for step in self.step_results]
|
|
79
79
|
|
|
80
80
|
if hasattr(self, "step_response") and self.step_response is not None:
|
|
81
|
-
_dict["step_response"] =
|
|
81
|
+
_dict["step_response"] = (
|
|
82
|
+
self.step_response.to_dict() if hasattr(self.step_response, "to_dict") else self.step_response
|
|
83
|
+
)
|
|
82
84
|
|
|
83
85
|
if hasattr(self, "iteration_results") and self.iteration_results is not None:
|
|
84
|
-
_dict["iteration_results"] = [
|
|
86
|
+
_dict["iteration_results"] = [
|
|
87
|
+
step.to_dict() if hasattr(step, "to_dict") else step for step in self.iteration_results
|
|
88
|
+
]
|
|
85
89
|
|
|
86
90
|
if hasattr(self, "all_results") and self.all_results is not None:
|
|
87
|
-
_dict["all_results"] = [
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
_dict["all_results"] = [
|
|
92
|
+
[step.to_dict() if hasattr(step, "to_dict") else step for step in iteration]
|
|
93
|
+
for iteration in self.all_results
|
|
94
|
+
]
|
|
91
95
|
|
|
92
96
|
return _dict
|
|
93
97
|
|
|
94
|
-
def to_json(self) -> str:
|
|
98
|
+
def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
|
|
95
99
|
import json
|
|
96
100
|
|
|
97
101
|
try:
|
|
@@ -100,7 +104,10 @@ class BaseWorkflowRunOutputEvent:
|
|
|
100
104
|
log_error("Failed to convert response to json", exc_info=True)
|
|
101
105
|
raise
|
|
102
106
|
|
|
103
|
-
|
|
107
|
+
if indent is None:
|
|
108
|
+
return json.dumps(_dict, separators=separators)
|
|
109
|
+
else:
|
|
110
|
+
return json.dumps(_dict, indent=indent, separators=separators)
|
|
104
111
|
|
|
105
112
|
@property
|
|
106
113
|
def is_cancelled(self):
|
|
@@ -417,6 +424,39 @@ WorkflowRunOutputEvent = Union[
|
|
|
417
424
|
CustomEvent,
|
|
418
425
|
]
|
|
419
426
|
|
|
427
|
+
# Map event string to dataclass for workflow events
|
|
428
|
+
WORKFLOW_RUN_EVENT_TYPE_REGISTRY = {
|
|
429
|
+
WorkflowRunEvent.workflow_started.value: WorkflowStartedEvent,
|
|
430
|
+
WorkflowRunEvent.workflow_completed.value: WorkflowCompletedEvent,
|
|
431
|
+
WorkflowRunEvent.workflow_cancelled.value: WorkflowCancelledEvent,
|
|
432
|
+
WorkflowRunEvent.workflow_error.value: WorkflowErrorEvent,
|
|
433
|
+
WorkflowRunEvent.step_started.value: StepStartedEvent,
|
|
434
|
+
WorkflowRunEvent.step_completed.value: StepCompletedEvent,
|
|
435
|
+
WorkflowRunEvent.step_error.value: StepErrorEvent,
|
|
436
|
+
WorkflowRunEvent.loop_execution_started.value: LoopExecutionStartedEvent,
|
|
437
|
+
WorkflowRunEvent.loop_iteration_started.value: LoopIterationStartedEvent,
|
|
438
|
+
WorkflowRunEvent.loop_iteration_completed.value: LoopIterationCompletedEvent,
|
|
439
|
+
WorkflowRunEvent.loop_execution_completed.value: LoopExecutionCompletedEvent,
|
|
440
|
+
WorkflowRunEvent.parallel_execution_started.value: ParallelExecutionStartedEvent,
|
|
441
|
+
WorkflowRunEvent.parallel_execution_completed.value: ParallelExecutionCompletedEvent,
|
|
442
|
+
WorkflowRunEvent.condition_execution_started.value: ConditionExecutionStartedEvent,
|
|
443
|
+
WorkflowRunEvent.condition_execution_completed.value: ConditionExecutionCompletedEvent,
|
|
444
|
+
WorkflowRunEvent.router_execution_started.value: RouterExecutionStartedEvent,
|
|
445
|
+
WorkflowRunEvent.router_execution_completed.value: RouterExecutionCompletedEvent,
|
|
446
|
+
WorkflowRunEvent.steps_execution_started.value: StepsExecutionStartedEvent,
|
|
447
|
+
WorkflowRunEvent.steps_execution_completed.value: StepsExecutionCompletedEvent,
|
|
448
|
+
WorkflowRunEvent.step_output.value: StepOutputEvent,
|
|
449
|
+
WorkflowRunEvent.custom_event.value: CustomEvent,
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def workflow_run_output_event_from_dict(data: dict) -> BaseWorkflowRunOutputEvent:
|
|
454
|
+
event_type = data.get("event", "")
|
|
455
|
+
cls = WORKFLOW_RUN_EVENT_TYPE_REGISTRY.get(event_type)
|
|
456
|
+
if not cls:
|
|
457
|
+
raise ValueError(f"Unknown workflow event type: {event_type}")
|
|
458
|
+
return cls.from_dict(data) # type: ignore
|
|
459
|
+
|
|
420
460
|
|
|
421
461
|
@dataclass
|
|
422
462
|
class WorkflowRunOutput:
|
|
@@ -565,7 +605,24 @@ class WorkflowRunOutput:
|
|
|
565
605
|
response_audio = data.pop("response_audio", None)
|
|
566
606
|
response_audio = Audio.model_validate(response_audio) if response_audio else None
|
|
567
607
|
|
|
568
|
-
|
|
608
|
+
events_data = data.pop("events", [])
|
|
609
|
+
final_events = []
|
|
610
|
+
for event in events_data or []:
|
|
611
|
+
if "agent_id" in event:
|
|
612
|
+
# Agent event from agent step
|
|
613
|
+
from agno.run.agent import run_output_event_from_dict
|
|
614
|
+
|
|
615
|
+
event = run_output_event_from_dict(event)
|
|
616
|
+
elif "team_id" in event:
|
|
617
|
+
# Team event from team step
|
|
618
|
+
from agno.run.team import team_run_output_event_from_dict
|
|
619
|
+
|
|
620
|
+
event = team_run_output_event_from_dict(event)
|
|
621
|
+
else:
|
|
622
|
+
# Pure workflow event
|
|
623
|
+
event = workflow_run_output_event_from_dict(event)
|
|
624
|
+
final_events.append(event)
|
|
625
|
+
events = final_events
|
|
569
626
|
|
|
570
627
|
return cls(
|
|
571
628
|
step_results=parsed_step_results,
|