agno 1.7.3__py3-none-any.whl → 1.7.5__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 +113 -31
- agno/api/schemas/agent.py +1 -0
- agno/api/schemas/team.py +1 -0
- agno/app/fastapi/app.py +1 -1
- agno/app/fastapi/async_router.py +67 -16
- agno/app/fastapi/sync_router.py +80 -14
- agno/app/playground/app.py +2 -1
- agno/app/playground/async_router.py +97 -28
- agno/app/playground/operator.py +25 -19
- agno/app/playground/schemas.py +1 -0
- agno/app/playground/sync_router.py +93 -26
- agno/knowledge/agent.py +39 -2
- agno/knowledge/combined.py +1 -1
- agno/run/base.py +2 -0
- agno/run/response.py +4 -4
- agno/run/team.py +6 -6
- agno/run/v2/__init__.py +0 -0
- agno/run/v2/workflow.py +563 -0
- agno/storage/base.py +4 -4
- agno/storage/dynamodb.py +74 -10
- agno/storage/firestore.py +6 -1
- agno/storage/gcs_json.py +8 -2
- agno/storage/json.py +20 -5
- agno/storage/mongodb.py +14 -5
- agno/storage/mysql.py +56 -17
- agno/storage/postgres.py +55 -13
- agno/storage/redis.py +25 -5
- agno/storage/session/__init__.py +3 -1
- agno/storage/session/agent.py +3 -0
- agno/storage/session/team.py +3 -0
- agno/storage/session/v2/__init__.py +5 -0
- agno/storage/session/v2/workflow.py +89 -0
- agno/storage/singlestore.py +74 -12
- agno/storage/sqlite.py +64 -18
- agno/storage/yaml.py +26 -6
- agno/team/team.py +105 -21
- agno/tools/decorator.py +45 -2
- agno/tools/function.py +16 -12
- agno/utils/log.py +12 -0
- agno/utils/message.py +5 -1
- agno/utils/openai.py +20 -5
- agno/utils/pprint.py +34 -8
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +493 -0
- agno/workflow/v2/__init__.py +21 -0
- agno/workflow/v2/condition.py +554 -0
- agno/workflow/v2/loop.py +602 -0
- agno/workflow/v2/parallel.py +659 -0
- agno/workflow/v2/router.py +521 -0
- agno/workflow/v2/step.py +861 -0
- agno/workflow/v2/steps.py +465 -0
- agno/workflow/v2/types.py +347 -0
- agno/workflow/v2/workflow.py +3132 -0
- {agno-1.7.3.dist-info → agno-1.7.5.dist-info}/METADATA +4 -1
- {agno-1.7.3.dist-info → agno-1.7.5.dist-info}/RECORD +59 -44
- {agno-1.7.3.dist-info → agno-1.7.5.dist-info}/WHEEL +0 -0
- {agno-1.7.3.dist-info → agno-1.7.5.dist-info}/entry_points.txt +0 -0
- {agno-1.7.3.dist-info → agno-1.7.5.dist-info}/licenses/LICENSE +0 -0
- {agno-1.7.3.dist-info → agno-1.7.5.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -119,6 +119,8 @@ class Agent:
|
|
|
119
119
|
session_state: Optional[Dict[str, Any]] = None
|
|
120
120
|
search_previous_sessions_history: Optional[bool] = False
|
|
121
121
|
num_history_sessions: Optional[int] = None
|
|
122
|
+
# If True, cache the session in memory
|
|
123
|
+
cache_session: bool = True
|
|
122
124
|
|
|
123
125
|
# --- Agent Context ---
|
|
124
126
|
# Context available for tools and prompt functions
|
|
@@ -318,9 +320,13 @@ class Agent:
|
|
|
318
320
|
|
|
319
321
|
# Optional workflow ID. Indicates this agent is part of a workflow.
|
|
320
322
|
workflow_id: Optional[str] = None
|
|
323
|
+
# Set when this agent is part of a workflow.
|
|
324
|
+
workflow_session_id: Optional[str] = None
|
|
321
325
|
|
|
322
326
|
# Optional team session state. Set by the team leader agent.
|
|
323
327
|
team_session_state: Optional[Dict[str, Any]] = None
|
|
328
|
+
# Optional workflow session state. Set by the workflow.
|
|
329
|
+
workflow_session_state: Optional[Dict[str, Any]] = None
|
|
324
330
|
|
|
325
331
|
# --- Debug & Monitoring ---
|
|
326
332
|
# Enable debug logs
|
|
@@ -347,6 +353,7 @@ class Agent:
|
|
|
347
353
|
session_state: Optional[Dict[str, Any]] = None,
|
|
348
354
|
search_previous_sessions_history: Optional[bool] = False,
|
|
349
355
|
num_history_sessions: Optional[int] = None,
|
|
356
|
+
cache_session: bool = True,
|
|
350
357
|
context: Optional[Dict[str, Any]] = None,
|
|
351
358
|
add_context: bool = False,
|
|
352
359
|
resolve_context: bool = True,
|
|
@@ -437,6 +444,8 @@ class Agent:
|
|
|
437
444
|
self.search_previous_sessions_history = search_previous_sessions_history
|
|
438
445
|
self.num_history_sessions = num_history_sessions
|
|
439
446
|
|
|
447
|
+
self.cache_session = cache_session
|
|
448
|
+
|
|
440
449
|
self.context = context
|
|
441
450
|
self.add_context = add_context
|
|
442
451
|
self.resolve_context = resolve_context
|
|
@@ -543,7 +552,7 @@ class Agent:
|
|
|
543
552
|
self.session_metrics: Optional[SessionMetrics] = None
|
|
544
553
|
|
|
545
554
|
self.run_id: Optional[str] = None
|
|
546
|
-
self.run_input: Optional[Union[str, List, Dict, Message]] = None
|
|
555
|
+
self.run_input: Optional[Union[str, List, Dict, Message, BaseModel]] = None
|
|
547
556
|
self.run_messages: Optional[RunMessages] = None
|
|
548
557
|
self.run_response: Optional[RunResponse] = None
|
|
549
558
|
|
|
@@ -695,10 +704,14 @@ class Agent:
|
|
|
695
704
|
self.session_state["current_user_id"] = user_id
|
|
696
705
|
if self.team_session_state is not None:
|
|
697
706
|
self.team_session_state["current_user_id"] = user_id
|
|
707
|
+
if self.workflow_session_state is not None:
|
|
708
|
+
self.workflow_session_state["current_user_id"] = user_id
|
|
698
709
|
if session_id is not None:
|
|
699
710
|
self.session_state["current_session_id"] = session_id
|
|
700
711
|
if self.team_session_state is not None:
|
|
701
712
|
self.team_session_state["current_session_id"] = session_id
|
|
713
|
+
if self.workflow_session_state is not None:
|
|
714
|
+
self.workflow_session_state["current_user_id"] = user_id
|
|
702
715
|
|
|
703
716
|
def _reset_session_state(self) -> None:
|
|
704
717
|
"""Reset the session state for the agent."""
|
|
@@ -746,9 +759,6 @@ class Agent:
|
|
|
746
759
|
|
|
747
760
|
self._initialize_session_state(user_id=user_id, session_id=session_id)
|
|
748
761
|
|
|
749
|
-
# Read existing session from storage
|
|
750
|
-
self.read_from_storage(session_id=session_id)
|
|
751
|
-
|
|
752
762
|
return session_id, user_id
|
|
753
763
|
|
|
754
764
|
def _run(
|
|
@@ -929,7 +939,7 @@ class Agent:
|
|
|
929
939
|
@overload
|
|
930
940
|
def run(
|
|
931
941
|
self,
|
|
932
|
-
message: Optional[Union[str, List, Dict, Message]] = None,
|
|
942
|
+
message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
|
|
933
943
|
*,
|
|
934
944
|
stream: Literal[False] = False,
|
|
935
945
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -950,7 +960,7 @@ class Agent:
|
|
|
950
960
|
@overload
|
|
951
961
|
def run(
|
|
952
962
|
self,
|
|
953
|
-
message: Optional[Union[str, List, Dict, Message]] = None,
|
|
963
|
+
message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
|
|
954
964
|
*,
|
|
955
965
|
stream: Literal[True] = True,
|
|
956
966
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -970,7 +980,7 @@ class Agent:
|
|
|
970
980
|
|
|
971
981
|
def run(
|
|
972
982
|
self,
|
|
973
|
-
message: Optional[Union[str, List, Dict, Message]] = None,
|
|
983
|
+
message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
|
|
974
984
|
*,
|
|
975
985
|
stream: Optional[bool] = None,
|
|
976
986
|
stream_intermediate_steps: Optional[bool] = None,
|
|
@@ -988,16 +998,18 @@ class Agent:
|
|
|
988
998
|
**kwargs: Any,
|
|
989
999
|
) -> Union[RunResponse, Iterator[RunResponseEvent]]:
|
|
990
1000
|
"""Run the Agent and return the response."""
|
|
991
|
-
|
|
992
1001
|
session_id, user_id = self._initialize_session(
|
|
993
1002
|
session_id=session_id, user_id=user_id, session_state=session_state
|
|
994
1003
|
)
|
|
995
1004
|
|
|
996
|
-
log_debug(f"Session ID: {session_id}", center=True)
|
|
997
|
-
|
|
998
1005
|
# Initialize the Agent
|
|
999
1006
|
self.initialize_agent()
|
|
1000
1007
|
|
|
1008
|
+
# Read existing session from storage
|
|
1009
|
+
self.read_from_storage(session_id=session_id)
|
|
1010
|
+
|
|
1011
|
+
log_debug(f"Session ID: {session_id}", center=True)
|
|
1012
|
+
|
|
1001
1013
|
# Initialize Knowledge Filters
|
|
1002
1014
|
effective_filters = knowledge_filters
|
|
1003
1015
|
|
|
@@ -1346,7 +1358,7 @@ class Agent:
|
|
|
1346
1358
|
|
|
1347
1359
|
async def arun(
|
|
1348
1360
|
self,
|
|
1349
|
-
message: Optional[Union[str, List, Dict, Message]] = None,
|
|
1361
|
+
message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
|
|
1350
1362
|
*,
|
|
1351
1363
|
stream: Optional[bool] = None,
|
|
1352
1364
|
user_id: Optional[str] = None,
|
|
@@ -1374,6 +1386,9 @@ class Agent:
|
|
|
1374
1386
|
# Initialize the Agent
|
|
1375
1387
|
self.initialize_agent()
|
|
1376
1388
|
|
|
1389
|
+
# Read existing session from storage
|
|
1390
|
+
self.read_from_storage(session_id=session_id)
|
|
1391
|
+
|
|
1377
1392
|
effective_filters = knowledge_filters
|
|
1378
1393
|
# When filters are passed manually
|
|
1379
1394
|
if self.knowledge_filters or knowledge_filters:
|
|
@@ -1598,6 +1613,9 @@ class Agent:
|
|
|
1598
1613
|
retries: The number of retries to continue the run for.
|
|
1599
1614
|
knowledge_filters: The knowledge filters to use for the run.
|
|
1600
1615
|
"""
|
|
1616
|
+
# Initialize the Agent
|
|
1617
|
+
self.initialize_agent()
|
|
1618
|
+
|
|
1601
1619
|
if session_id is not None:
|
|
1602
1620
|
self.reset_run_state()
|
|
1603
1621
|
# Reset session state if a session_id is provided. Session name and session state will be loaded from storage.
|
|
@@ -1606,9 +1624,6 @@ class Agent:
|
|
|
1606
1624
|
if self.session_id is not None and session_id != self.session_id:
|
|
1607
1625
|
self.session_state = None
|
|
1608
1626
|
|
|
1609
|
-
# Initialize the Agent
|
|
1610
|
-
self.initialize_agent()
|
|
1611
|
-
|
|
1612
1627
|
# Initialize Session
|
|
1613
1628
|
# Use the default user_id and session_id when necessary
|
|
1614
1629
|
user_id = user_id if user_id is not None else self.user_id
|
|
@@ -1988,6 +2003,9 @@ class Agent:
|
|
|
1988
2003
|
retries: The number of retries to continue the run for.
|
|
1989
2004
|
knowledge_filters: The knowledge filters to use for the run.
|
|
1990
2005
|
"""
|
|
2006
|
+
# Initialize the Agent
|
|
2007
|
+
self.initialize_agent()
|
|
2008
|
+
|
|
1991
2009
|
if session_id is not None:
|
|
1992
2010
|
self.reset_run_state()
|
|
1993
2011
|
# Reset session state if a session_id is provided. Session name and session state will be loaded from storage.
|
|
@@ -1996,9 +2014,6 @@ class Agent:
|
|
|
1996
2014
|
if self.session_id is not None and session_id != self.session_id:
|
|
1997
2015
|
self.session_state = None
|
|
1998
2016
|
|
|
1999
|
-
# Initialize the Agent
|
|
2000
|
-
self.initialize_agent()
|
|
2001
|
-
|
|
2002
2017
|
# Initialize Session
|
|
2003
2018
|
# Use the default user_id and session_id when necessary
|
|
2004
2019
|
user_id = user_id if user_id is not None else self.user_id
|
|
@@ -3869,6 +3884,8 @@ class Agent:
|
|
|
3869
3884
|
session_data["session_state"] = self.session_state
|
|
3870
3885
|
if self.team_session_state is not None and len(self.team_session_state) > 0:
|
|
3871
3886
|
session_data["team_session_state"] = self.team_session_state
|
|
3887
|
+
if self.workflow_session_state is not None and len(self.workflow_session_state) > 0:
|
|
3888
|
+
session_data["workflow_session_state"] = self.workflow_session_state
|
|
3872
3889
|
if self.session_metrics is not None:
|
|
3873
3890
|
session_data["session_metrics"] = asdict(self.session_metrics) if self.session_metrics is not None else None
|
|
3874
3891
|
if self.team_data is not None:
|
|
@@ -3905,12 +3922,15 @@ class Agent:
|
|
|
3905
3922
|
memory_dict = None
|
|
3906
3923
|
|
|
3907
3924
|
self.team_session_id = cast(str, self.team_session_id)
|
|
3925
|
+
self.workflow_session_id = cast(str, self.workflow_session_id)
|
|
3926
|
+
|
|
3908
3927
|
self.agent_id = cast(str, self.agent_id)
|
|
3909
3928
|
return AgentSession(
|
|
3910
3929
|
session_id=session_id,
|
|
3911
3930
|
agent_id=self.agent_id,
|
|
3912
3931
|
user_id=user_id,
|
|
3913
3932
|
team_session_id=self.team_session_id,
|
|
3933
|
+
workflow_session_id=self.workflow_session_id,
|
|
3914
3934
|
memory=memory_dict,
|
|
3915
3935
|
agent_data=self.get_agent_data(),
|
|
3916
3936
|
session_data=self.get_session_data(),
|
|
@@ -3921,6 +3941,9 @@ class Agent:
|
|
|
3921
3941
|
def load_agent_session(self, session: AgentSession):
|
|
3922
3942
|
"""Load the existing Agent from an AgentSession (from the database)"""
|
|
3923
3943
|
|
|
3944
|
+
if not hasattr(session, "memory"):
|
|
3945
|
+
return
|
|
3946
|
+
|
|
3924
3947
|
from agno.utils.merge_dict import merge_dictionaries
|
|
3925
3948
|
|
|
3926
3949
|
# Get the agent_id, user_id and session_id from the database
|
|
@@ -3977,6 +4000,22 @@ class Agent:
|
|
|
3977
4000
|
# Update the current team_session_state
|
|
3978
4001
|
self.team_session_state = team_session_state_from_db
|
|
3979
4002
|
|
|
4003
|
+
if "workflow_session_state" in session.session_data:
|
|
4004
|
+
workflow_session_state_from_db = session.session_data.get("workflow_session_state")
|
|
4005
|
+
if (
|
|
4006
|
+
workflow_session_state_from_db is not None
|
|
4007
|
+
and isinstance(workflow_session_state_from_db, dict)
|
|
4008
|
+
and len(workflow_session_state_from_db) > 0
|
|
4009
|
+
):
|
|
4010
|
+
# If the workflow_session_state is already set, merge the workflow_session_state from the database with the current workflow_session_state
|
|
4011
|
+
if self.workflow_session_state is not None and len(self.workflow_session_state) > 0:
|
|
4012
|
+
# This updates workflow_session_state_from_db
|
|
4013
|
+
# If there are conflicting keys, values from workflow_session_state_from_db will take precedence
|
|
4014
|
+
merge_dictionaries(self.workflow_session_state, workflow_session_state_from_db)
|
|
4015
|
+
else:
|
|
4016
|
+
# Update the current workflow_session_state
|
|
4017
|
+
self.workflow_session_state = workflow_session_state_from_db
|
|
4018
|
+
|
|
3980
4019
|
# Get the session_metrics from the database
|
|
3981
4020
|
if "session_metrics" in session.session_data:
|
|
3982
4021
|
session_metrics_from_db = session.session_data.get("session_metrics")
|
|
@@ -4024,6 +4063,7 @@ class Agent:
|
|
|
4024
4063
|
# Convert dict to Memory
|
|
4025
4064
|
elif isinstance(self.memory, dict):
|
|
4026
4065
|
memory_dict = self.memory
|
|
4066
|
+
|
|
4027
4067
|
memory_dict.pop("runs")
|
|
4028
4068
|
self.memory = Memory(**memory_dict)
|
|
4029
4069
|
else:
|
|
@@ -4079,6 +4119,7 @@ class Agent:
|
|
|
4079
4119
|
self.memory.runs[session.session_id] = []
|
|
4080
4120
|
for run in session.memory["runs"]:
|
|
4081
4121
|
run_session_id = run["session_id"]
|
|
4122
|
+
|
|
4082
4123
|
if "team_id" in run:
|
|
4083
4124
|
self.memory.runs[run_session_id].append(TeamRunResponse.from_dict(run))
|
|
4084
4125
|
else:
|
|
@@ -4147,10 +4188,10 @@ class Agent:
|
|
|
4147
4188
|
if not self.storage:
|
|
4148
4189
|
return
|
|
4149
4190
|
|
|
4150
|
-
agent_session_from_db = self.storage.read(session_id=session_id)
|
|
4191
|
+
agent_session_from_db = self.storage.read(session_id=session_id) # type: ignore
|
|
4151
4192
|
if (
|
|
4152
4193
|
agent_session_from_db is not None
|
|
4153
|
-
and agent_session_from_db.memory is not None
|
|
4194
|
+
and agent_session_from_db.memory is not None # type: ignore
|
|
4154
4195
|
and "runs" in agent_session_from_db.memory # type: ignore
|
|
4155
4196
|
):
|
|
4156
4197
|
if isinstance(self.memory, AgentMemory):
|
|
@@ -4192,6 +4233,11 @@ class Agent:
|
|
|
4192
4233
|
AgentSession,
|
|
4193
4234
|
self.storage.upsert(session=self.get_agent_session(session_id=session_id, user_id=user_id)),
|
|
4194
4235
|
)
|
|
4236
|
+
|
|
4237
|
+
if not self.cache_session:
|
|
4238
|
+
if self.memory is not None and self.memory.runs is not None and session_id in self.memory.runs:
|
|
4239
|
+
self.memory.runs.pop(session_id) # type: ignore
|
|
4240
|
+
|
|
4195
4241
|
return self.agent_session
|
|
4196
4242
|
|
|
4197
4243
|
def add_introduction(self, introduction: str) -> None:
|
|
@@ -4278,6 +4324,7 @@ class Agent:
|
|
|
4278
4324
|
format_variables = ChainMap(
|
|
4279
4325
|
self.session_state or {},
|
|
4280
4326
|
self.team_session_state or {},
|
|
4327
|
+
self.workflow_session_state or {},
|
|
4281
4328
|
self.context or {},
|
|
4282
4329
|
self.extra_data or {},
|
|
4283
4330
|
{"user_id": self.user_id} if self.user_id is not None else {},
|
|
@@ -4614,7 +4661,7 @@ class Agent:
|
|
|
4614
4661
|
def get_user_message(
|
|
4615
4662
|
self,
|
|
4616
4663
|
*,
|
|
4617
|
-
message: Optional[Union[str, List]],
|
|
4664
|
+
message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
|
|
4618
4665
|
audio: Optional[Sequence[Audio]] = None,
|
|
4619
4666
|
images: Optional[Sequence[Image]] = None,
|
|
4620
4667
|
videos: Optional[Sequence[Video]] = None,
|
|
@@ -4687,7 +4734,7 @@ class Agent:
|
|
|
4687
4734
|
)
|
|
4688
4735
|
|
|
4689
4736
|
# 2. If create_default_user_message is False or message is a list, return the message as is.
|
|
4690
|
-
if not self.create_default_user_message
|
|
4737
|
+
if not self.create_default_user_message:
|
|
4691
4738
|
return Message(
|
|
4692
4739
|
role=self.user_message_role,
|
|
4693
4740
|
content=message,
|
|
@@ -4698,6 +4745,24 @@ class Agent:
|
|
|
4698
4745
|
**kwargs,
|
|
4699
4746
|
)
|
|
4700
4747
|
|
|
4748
|
+
# Handle list messages by converting to string
|
|
4749
|
+
if isinstance(message, list):
|
|
4750
|
+
# Convert list to string (join with newlines if all elements are strings)
|
|
4751
|
+
if all(isinstance(item, str) for item in message):
|
|
4752
|
+
message_content = "\n".join(message)
|
|
4753
|
+
else:
|
|
4754
|
+
message_content = str(message)
|
|
4755
|
+
|
|
4756
|
+
return Message(
|
|
4757
|
+
role=self.user_message_role,
|
|
4758
|
+
content=message_content,
|
|
4759
|
+
images=images,
|
|
4760
|
+
audio=audio,
|
|
4761
|
+
videos=videos,
|
|
4762
|
+
files=files,
|
|
4763
|
+
**kwargs,
|
|
4764
|
+
)
|
|
4765
|
+
|
|
4701
4766
|
# 3. Build the default user message for the Agent
|
|
4702
4767
|
if message is None:
|
|
4703
4768
|
# If we have any media, return a message with empty content
|
|
@@ -4719,6 +4784,10 @@ class Agent:
|
|
|
4719
4784
|
# Format the message with the session state variables
|
|
4720
4785
|
if self.add_state_in_messages:
|
|
4721
4786
|
user_msg_content = self.format_message_with_state_variables(message)
|
|
4787
|
+
|
|
4788
|
+
# Convert to string for concatenation operations
|
|
4789
|
+
user_msg_content_str = get_text_from_message(user_msg_content) if user_msg_content is not None else ""
|
|
4790
|
+
|
|
4722
4791
|
# 4.1 Add references to user message
|
|
4723
4792
|
if (
|
|
4724
4793
|
self.add_references
|
|
@@ -4726,15 +4795,18 @@ class Agent:
|
|
|
4726
4795
|
and references.references is not None
|
|
4727
4796
|
and len(references.references) > 0
|
|
4728
4797
|
):
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4798
|
+
user_msg_content_str += "\n\nUse the following references from the knowledge base if it helps:\n"
|
|
4799
|
+
user_msg_content_str += "<references>\n"
|
|
4800
|
+
user_msg_content_str += self.convert_documents_to_string(references.references) + "\n"
|
|
4801
|
+
user_msg_content_str += "</references>"
|
|
4733
4802
|
# 4.2 Add context to user message
|
|
4734
4803
|
if self.add_context and self.context is not None:
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4804
|
+
user_msg_content_str += "\n\n<context>\n"
|
|
4805
|
+
user_msg_content_str += self.convert_context_to_string(self.context) + "\n"
|
|
4806
|
+
user_msg_content_str += "</context>"
|
|
4807
|
+
|
|
4808
|
+
# Use the string version for the final content
|
|
4809
|
+
user_msg_content = user_msg_content_str
|
|
4738
4810
|
|
|
4739
4811
|
# Return the user message
|
|
4740
4812
|
return Message(
|
|
@@ -4750,7 +4822,7 @@ class Agent:
|
|
|
4750
4822
|
def get_run_messages(
|
|
4751
4823
|
self,
|
|
4752
4824
|
*,
|
|
4753
|
-
message: Optional[Union[str, List, Dict, Message]] = None,
|
|
4825
|
+
message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
|
|
4754
4826
|
session_id: str,
|
|
4755
4827
|
user_id: Optional[str] = None,
|
|
4756
4828
|
audio: Optional[Sequence[Audio]] = None,
|
|
@@ -4877,6 +4949,14 @@ class Agent:
|
|
|
4877
4949
|
user_message = Message.model_validate(message)
|
|
4878
4950
|
except Exception as e:
|
|
4879
4951
|
log_warning(f"Failed to validate message: {e}")
|
|
4952
|
+
# 4.4 If message is provided as a BaseModel, convert it to a Message
|
|
4953
|
+
elif isinstance(message, BaseModel):
|
|
4954
|
+
try:
|
|
4955
|
+
# Create a user message with the BaseModel content
|
|
4956
|
+
content = message.model_dump_json(indent=2, exclude_none=True)
|
|
4957
|
+
user_message = Message(role=self.user_message_role, content=content)
|
|
4958
|
+
except Exception as e:
|
|
4959
|
+
log_warning(f"Failed to convert BaseModel to message: {e}")
|
|
4880
4960
|
# Add user message to run_messages
|
|
4881
4961
|
if user_message is not None:
|
|
4882
4962
|
run_messages.user_message = user_message
|
|
@@ -6731,6 +6811,7 @@ class Agent:
|
|
|
6731
6811
|
session_id=agent_session.session_id,
|
|
6732
6812
|
agent_data=agent_session.to_dict() if self.monitoring else agent_session.telemetry_data(),
|
|
6733
6813
|
team_session_id=agent_session.team_session_id,
|
|
6814
|
+
workflow_session_id=agent_session.workflow_session_id,
|
|
6734
6815
|
),
|
|
6735
6816
|
monitor=self.monitoring,
|
|
6736
6817
|
)
|
|
@@ -6758,6 +6839,7 @@ class Agent:
|
|
|
6758
6839
|
session_id=agent_session.session_id,
|
|
6759
6840
|
agent_data=agent_session.to_dict() if self.monitoring else agent_session.telemetry_data(),
|
|
6760
6841
|
team_session_id=agent_session.team_session_id,
|
|
6842
|
+
workflow_session_id=agent_session.workflow_session_id,
|
|
6761
6843
|
),
|
|
6762
6844
|
monitor=self.monitoring,
|
|
6763
6845
|
)
|
|
@@ -6770,7 +6852,7 @@ class Agent:
|
|
|
6770
6852
|
|
|
6771
6853
|
def print_response(
|
|
6772
6854
|
self,
|
|
6773
|
-
message: Optional[Union[List, Dict, str, Message]] = None,
|
|
6855
|
+
message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
|
|
6774
6856
|
*,
|
|
6775
6857
|
session_id: Optional[str] = None,
|
|
6776
6858
|
session_state: Optional[Dict[str, Any]] = None,
|
|
@@ -7219,7 +7301,7 @@ class Agent:
|
|
|
7219
7301
|
|
|
7220
7302
|
async def aprint_response(
|
|
7221
7303
|
self,
|
|
7222
|
-
message: Optional[Union[List, Dict, str, Message]] = None,
|
|
7304
|
+
message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
|
|
7223
7305
|
*,
|
|
7224
7306
|
messages: Optional[List[Union[Dict, Message]]] = None,
|
|
7225
7307
|
session_id: Optional[str] = None,
|
agno/api/schemas/agent.py
CHANGED
|
@@ -15,6 +15,7 @@ class AgentRunCreate(BaseModel):
|
|
|
15
15
|
|
|
16
16
|
session_id: str
|
|
17
17
|
team_session_id: Optional[str] = None
|
|
18
|
+
workflow_session_id: Optional[str] = None
|
|
18
19
|
run_id: Optional[str] = None
|
|
19
20
|
run_data: Optional[Dict[str, Any]] = None
|
|
20
21
|
agent_data: Optional[Dict[str, Any]] = None
|
agno/api/schemas/team.py
CHANGED
|
@@ -15,6 +15,7 @@ class TeamRunCreate(BaseModel):
|
|
|
15
15
|
|
|
16
16
|
session_id: str
|
|
17
17
|
team_session_id: Optional[str] = None
|
|
18
|
+
workflow_session_id: Optional[str] = None
|
|
18
19
|
run_id: Optional[str] = None
|
|
19
20
|
run_data: Optional[Dict[str, Any]] = None
|
|
20
21
|
team_data: Optional[Dict[str, Any]] = None
|
agno/app/fastapi/app.py
CHANGED
|
@@ -77,7 +77,7 @@ class FastAPIApp(BaseAPIApp):
|
|
|
77
77
|
|
|
78
78
|
if self.workflows:
|
|
79
79
|
for workflow in self.workflows:
|
|
80
|
-
if not workflow.app_id:
|
|
80
|
+
if hasattr(workflow, "app_id") and not workflow.app_id:
|
|
81
81
|
workflow.app_id = self.app_id
|
|
82
82
|
if not workflow.workflow_id:
|
|
83
83
|
workflow.workflow_id = generate_id(workflow.name)
|
agno/app/fastapi/async_router.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from dataclasses import asdict
|
|
3
3
|
from io import BytesIO
|
|
4
|
-
from typing import AsyncGenerator, List, Optional, cast
|
|
4
|
+
from typing import Any, AsyncGenerator, Dict, List, Optional, Union, cast
|
|
5
5
|
from uuid import uuid4
|
|
6
6
|
|
|
7
7
|
from fastapi import APIRouter, File, Form, HTTPException, Query, UploadFile
|
|
@@ -14,8 +14,10 @@ from agno.media import File as FileMedia
|
|
|
14
14
|
from agno.run.response import RunResponseErrorEvent
|
|
15
15
|
from agno.run.team import RunResponseErrorEvent as TeamRunResponseErrorEvent
|
|
16
16
|
from agno.run.team import TeamRunResponseEvent
|
|
17
|
+
from agno.run.v2.workflow import WorkflowErrorEvent
|
|
17
18
|
from agno.team.team import Team
|
|
18
19
|
from agno.utils.log import logger
|
|
20
|
+
from agno.workflow.v2.workflow import Workflow as WorkflowV2
|
|
19
21
|
from agno.workflow.workflow import Workflow
|
|
20
22
|
|
|
21
23
|
|
|
@@ -83,6 +85,42 @@ async def team_chat_response_streamer(
|
|
|
83
85
|
return
|
|
84
86
|
|
|
85
87
|
|
|
88
|
+
async def workflow_response_streamer(
|
|
89
|
+
workflow: WorkflowV2,
|
|
90
|
+
body: Union[Dict[str, Any], str],
|
|
91
|
+
session_id: Optional[str] = None,
|
|
92
|
+
user_id: Optional[str] = None,
|
|
93
|
+
) -> AsyncGenerator:
|
|
94
|
+
try:
|
|
95
|
+
if isinstance(body, dict):
|
|
96
|
+
run_response = await workflow.arun( # type: ignore
|
|
97
|
+
**body,
|
|
98
|
+
user_id=user_id,
|
|
99
|
+
session_id=session_id,
|
|
100
|
+
stream=True,
|
|
101
|
+
stream_intermediate_steps=True,
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
run_response = await workflow.arun( # type: ignore
|
|
105
|
+
body,
|
|
106
|
+
user_id=user_id,
|
|
107
|
+
session_id=session_id,
|
|
108
|
+
stream=True,
|
|
109
|
+
stream_intermediate_steps=True,
|
|
110
|
+
)
|
|
111
|
+
async for run_response_chunk in run_response:
|
|
112
|
+
yield run_response_chunk.to_json()
|
|
113
|
+
except Exception as e:
|
|
114
|
+
import traceback
|
|
115
|
+
|
|
116
|
+
traceback.print_exc(limit=3)
|
|
117
|
+
error_response = WorkflowErrorEvent(
|
|
118
|
+
error=str(e),
|
|
119
|
+
)
|
|
120
|
+
yield error_response.to_json()
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
|
|
86
124
|
def get_async_router(
|
|
87
125
|
agents: Optional[List[Agent]] = None, teams: Optional[List[Team]] = None, workflows: Optional[List[Workflow]] = None
|
|
88
126
|
) -> APIRouter:
|
|
@@ -351,17 +389,24 @@ def get_async_router(
|
|
|
351
389
|
media_type="text/event-stream",
|
|
352
390
|
)
|
|
353
391
|
elif workflow:
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
392
|
+
if isinstance(workflow, Workflow):
|
|
393
|
+
workflow_instance = workflow.deep_copy(update={"workflow_id": workflow_id})
|
|
394
|
+
workflow_instance.user_id = user_id
|
|
395
|
+
workflow_instance.session_name = None
|
|
396
|
+
|
|
397
|
+
if isinstance(workflow_input, dict):
|
|
398
|
+
return StreamingResponse(
|
|
399
|
+
(json.dumps(asdict(result)) for result in await workflow_instance.arun(**workflow_input)),
|
|
400
|
+
media_type="text/event-stream",
|
|
401
|
+
)
|
|
402
|
+
else:
|
|
403
|
+
return StreamingResponse(
|
|
404
|
+
(json.dumps(asdict(result)) for result in await workflow_instance.arun(workflow_input)), # type: ignore
|
|
405
|
+
media_type="text/event-stream",
|
|
406
|
+
)
|
|
362
407
|
else:
|
|
363
408
|
return StreamingResponse(
|
|
364
|
-
(
|
|
409
|
+
workflow_response_streamer(workflow, workflow_input, session_id=session_id, user_id=user_id), # type: ignore
|
|
365
410
|
media_type="text/event-stream",
|
|
366
411
|
)
|
|
367
412
|
else:
|
|
@@ -392,12 +437,18 @@ def get_async_router(
|
|
|
392
437
|
)
|
|
393
438
|
return team_run_response.to_dict()
|
|
394
439
|
elif workflow:
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
440
|
+
if isinstance(workflow, Workflow):
|
|
441
|
+
workflow_instance = workflow.deep_copy(update={"workflow_id": workflow_id})
|
|
442
|
+
workflow_instance.user_id = user_id
|
|
443
|
+
workflow_instance.session_name = None
|
|
444
|
+
if isinstance(workflow_input, dict):
|
|
445
|
+
return (await workflow_instance.arun(**workflow_input)).to_dict()
|
|
446
|
+
else:
|
|
447
|
+
return (await workflow_instance.arun(workflow_input)).to_dict() # type: ignore
|
|
400
448
|
else:
|
|
401
|
-
|
|
449
|
+
if isinstance(workflow_input, dict):
|
|
450
|
+
return (await workflow.arun(**workflow_input, session_id=session_id, user_id=user_id)).to_dict()
|
|
451
|
+
else:
|
|
452
|
+
return (await workflow.arun(workflow_input, session_id=session_id, user_id=user_id)).to_dict() # type: ignore
|
|
402
453
|
|
|
403
454
|
return router
|