agno 1.7.2__py3-none-any.whl → 1.7.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.
Files changed (63) hide show
  1. agno/agent/agent.py +264 -155
  2. agno/api/schemas/agent.py +1 -0
  3. agno/api/schemas/team.py +1 -0
  4. agno/app/base.py +0 -22
  5. agno/app/discord/client.py +134 -56
  6. agno/app/fastapi/app.py +0 -11
  7. agno/app/playground/app.py +3 -24
  8. agno/app/playground/async_router.py +97 -28
  9. agno/app/playground/operator.py +25 -19
  10. agno/app/playground/schemas.py +1 -0
  11. agno/app/playground/sync_router.py +93 -26
  12. agno/document/reader/gcs/__init__.py +0 -0
  13. agno/document/reader/gcs/pdf_reader.py +44 -0
  14. agno/embedder/langdb.py +9 -5
  15. agno/knowledge/document.py +199 -8
  16. agno/knowledge/gcs/__init__.py +0 -0
  17. agno/knowledge/gcs/base.py +39 -0
  18. agno/knowledge/gcs/pdf.py +21 -0
  19. agno/models/langdb/langdb.py +8 -5
  20. agno/run/base.py +2 -0
  21. agno/run/response.py +4 -4
  22. agno/run/team.py +6 -6
  23. agno/run/v2/__init__.py +0 -0
  24. agno/run/v2/workflow.py +563 -0
  25. agno/storage/base.py +4 -4
  26. agno/storage/dynamodb.py +74 -10
  27. agno/storage/firestore.py +6 -1
  28. agno/storage/gcs_json.py +8 -2
  29. agno/storage/json.py +20 -5
  30. agno/storage/mongodb.py +14 -5
  31. agno/storage/mysql.py +56 -17
  32. agno/storage/postgres.py +55 -13
  33. agno/storage/redis.py +25 -5
  34. agno/storage/session/__init__.py +3 -1
  35. agno/storage/session/agent.py +3 -0
  36. agno/storage/session/team.py +3 -0
  37. agno/storage/session/v2/__init__.py +5 -0
  38. agno/storage/session/v2/workflow.py +89 -0
  39. agno/storage/singlestore.py +74 -12
  40. agno/storage/sqlite.py +64 -18
  41. agno/storage/yaml.py +26 -6
  42. agno/team/team.py +198 -243
  43. agno/tools/scrapegraph.py +8 -10
  44. agno/utils/log.py +12 -0
  45. agno/utils/message.py +5 -1
  46. agno/utils/openai.py +20 -5
  47. agno/utils/pprint.py +32 -8
  48. agno/workflow/v2/__init__.py +21 -0
  49. agno/workflow/v2/condition.py +554 -0
  50. agno/workflow/v2/loop.py +602 -0
  51. agno/workflow/v2/parallel.py +659 -0
  52. agno/workflow/v2/router.py +521 -0
  53. agno/workflow/v2/step.py +861 -0
  54. agno/workflow/v2/steps.py +465 -0
  55. agno/workflow/v2/types.py +347 -0
  56. agno/workflow/v2/workflow.py +3134 -0
  57. agno/workflow/workflow.py +15 -147
  58. {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/METADATA +1 -1
  59. {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/RECORD +63 -45
  60. {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/WHEEL +0 -0
  61. {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/entry_points.txt +0 -0
  62. {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/licenses/LICENSE +0 -0
  63. {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/top_level.txt +0 -0
agno/team/team.py CHANGED
@@ -112,6 +112,9 @@ class Team:
112
112
  parent_team_id: Optional[str] = None
113
113
  # The workflow this team belongs to
114
114
  workflow_id: Optional[str] = None
115
+ # Set when this team is part of a workflow.
116
+ workflow_session_id: Optional[str] = None
117
+
115
118
  role: Optional[str] = None
116
119
 
117
120
  # --- User settings ---
@@ -130,6 +133,8 @@ class Team:
130
133
 
131
134
  # Team session state (shared between team leaders and team members)
132
135
  team_session_state: Optional[Dict[str, Any]] = None
136
+ workflow_session_state: Optional[Dict[str, Any]] = None
137
+
133
138
  # If True, add the session state variables in the user and system messages
134
139
  add_state_in_messages: bool = False
135
140
 
@@ -304,6 +309,7 @@ class Team:
304
309
  session_name: Optional[str] = None,
305
310
  session_state: Optional[Dict[str, Any]] = None,
306
311
  team_session_state: Optional[Dict[str, Any]] = None,
312
+ workflow_session_state: Optional[Dict[str, Any]] = None,
307
313
  add_state_in_messages: bool = False,
308
314
  description: Optional[str] = None,
309
315
  instructions: Optional[Union[str, List[str], Callable]] = None,
@@ -381,6 +387,7 @@ class Team:
381
387
  self.session_name = session_name
382
388
  self.session_state = session_state
383
389
  self.team_session_state = team_session_state
390
+ self.workflow_session_state = workflow_session_state
384
391
  self.add_state_in_messages = add_state_in_messages
385
392
 
386
393
  self.description = description
@@ -472,7 +479,7 @@ class Team:
472
479
  self.full_team_session_metrics: Optional[SessionMetrics] = None
473
480
 
474
481
  self.run_id: Optional[str] = None
475
- self.run_input: Optional[Union[str, List, Dict]] = None
482
+ self.run_input: Optional[Union[str, List, Dict, BaseModel]] = None
476
483
  self.run_messages: Optional[RunMessages] = None
477
484
  self.run_response: Optional[TeamRunResponse] = None
478
485
 
@@ -549,6 +556,12 @@ class Team:
549
556
  else:
550
557
  merge_dictionaries(member.team_session_state, self.team_session_state)
551
558
 
559
+ if self.workflow_session_state is not None:
560
+ if member.workflow_session_state is None:
561
+ member.workflow_session_state = self.workflow_session_state
562
+ else:
563
+ merge_dictionaries(member.workflow_session_state, self.workflow_session_state)
564
+
552
565
  if isinstance(member, Agent):
553
566
  member.team_id = self.team_id
554
567
  member.set_agent_id()
@@ -585,11 +598,12 @@ class Team:
585
598
  if self.num_of_interactions_from_history is not None:
586
599
  self.num_history_runs = self.num_of_interactions_from_history
587
600
 
588
- def _reset_session_state(self) -> None:
601
+ def _reset_session(self) -> None:
589
602
  self.session_name = None
590
603
  self.session_state = None
591
604
  self.team_session_state = None
592
605
  self.session_metrics = None
606
+ self.session_state = None
593
607
  self.images = None
594
608
  self.videos = None
595
609
  self.audio = None
@@ -652,14 +666,83 @@ class Team:
652
666
  self.tools = tools
653
667
  self._rebuild_tools = True
654
668
 
669
+ def _initialize_session_state(self, user_id: Optional[str] = None, session_id: Optional[str] = None) -> None:
670
+ self.session_state = self.session_state or {}
671
+
672
+ if user_id is not None:
673
+ self.session_state["current_user_id"] = user_id
674
+ if self.team_session_state is not None:
675
+ self.team_session_state["current_user_id"] = user_id
676
+ if self.workflow_session_state is not None:
677
+ self.workflow_session_state["current_user_id"] = user_id
678
+
679
+ if session_id is not None:
680
+ self.session_state["current_session_id"] = session_id
681
+ if self.team_session_state is not None:
682
+ self.team_session_state["current_session_id"] = session_id
683
+ if self.workflow_session_state is not None:
684
+ self.workflow_session_state["current_user_id"] = user_id
685
+
686
+ def _reset_session_state(self) -> None:
687
+ """Reset the session state for the agent."""
688
+ if self.team_session_state is not None:
689
+ self.team_session_state.pop("current_session_id", None)
690
+ self.team_session_state.pop("current_user_id", None)
691
+ if self.session_state is not None:
692
+ self.session_state.pop("current_session_id", None)
693
+ self.session_state.pop("current_user_id", None)
694
+
695
+ def _initialize_session(
696
+ self,
697
+ session_id: Optional[str] = None,
698
+ user_id: Optional[str] = None,
699
+ session_state: Optional[Dict[str, Any]] = None,
700
+ ) -> Tuple[str, Optional[str]]:
701
+ """Initialize the session for the agent."""
702
+
703
+ self._reset_run_state()
704
+
705
+ # Determine the session_id
706
+ if session_id is not None and session_id != "":
707
+ # Reset session state if a session_id is provided. Session name and session state will be loaded from storage.
708
+ # Only reset session state if the session_id is different from the current session_id
709
+ if self.session_id is not None and session_id != self.session_id:
710
+ self._reset_session()
711
+
712
+ self.session_id = session_id
713
+ else:
714
+ if not (self.session_id is None or self.session_id == ""):
715
+ session_id = self.session_id
716
+ else:
717
+ # Generate a new session_id and store it in the agent
718
+ self.session_id = session_id = str(uuid4())
719
+
720
+ # Use the default user_id when necessary
721
+ if user_id is not None and user_id != "":
722
+ user_id = user_id
723
+ else:
724
+ user_id = self.user_id
725
+
726
+ # Determine the session_state
727
+ if session_state is not None:
728
+ self.session_state = session_state
729
+
730
+ self._initialize_session_state(user_id=user_id, session_id=session_id)
731
+
732
+ # Read existing session from storage
733
+ self.read_from_storage(session_id=session_id)
734
+
735
+ return session_id, user_id
736
+
655
737
  @overload
656
738
  def run(
657
739
  self,
658
- message: Union[str, List, Dict, Message],
740
+ message: Union[str, List, Dict, Message, BaseModel],
659
741
  *,
660
742
  stream: Literal[False] = False,
661
743
  stream_intermediate_steps: Optional[bool] = None,
662
744
  session_id: Optional[str] = None,
745
+ session_state: Optional[Dict[str, Any]] = None,
663
746
  user_id: Optional[str] = None,
664
747
  retries: Optional[int] = None,
665
748
  audio: Optional[Sequence[Audio]] = None,
@@ -673,11 +756,12 @@ class Team:
673
756
  @overload
674
757
  def run(
675
758
  self,
676
- message: Union[str, List, Dict, Message],
759
+ message: Union[str, List, Dict, Message, BaseModel],
677
760
  *,
678
761
  stream: Literal[True] = True,
679
762
  stream_intermediate_steps: Optional[bool] = None,
680
763
  session_id: Optional[str] = None,
764
+ session_state: Optional[Dict[str, Any]] = None,
681
765
  user_id: Optional[str] = None,
682
766
  retries: Optional[int] = None,
683
767
  audio: Optional[Sequence[Audio]] = None,
@@ -690,11 +774,12 @@ class Team:
690
774
 
691
775
  def run(
692
776
  self,
693
- message: Union[str, List, Dict, Message],
777
+ message: Union[str, List, Dict, Message, BaseModel],
694
778
  *,
695
779
  stream: Optional[bool] = None,
696
780
  stream_intermediate_steps: Optional[bool] = None,
697
781
  session_id: Optional[str] = None,
782
+ session_state: Optional[Dict[str, Any]] = None,
698
783
  user_id: Optional[str] = None,
699
784
  retries: Optional[int] = None,
700
785
  audio: Optional[Sequence[Audio]] = None,
@@ -706,31 +791,9 @@ class Team:
706
791
  ) -> Union[TeamRunResponse, Iterator[Union[RunResponseEvent, TeamRunResponseEvent]]]:
707
792
  """Run the Team and return the response."""
708
793
 
709
- self._reset_run_state()
710
-
711
- if session_id is not None:
712
- # Reset session state if a session_id is provided. Session name and session state will be loaded from storage.
713
- self._reset_session_state()
714
-
715
- # Use the default user_id and session_id when necessary
716
- if user_id is None:
717
- user_id = self.user_id
718
-
719
- if session_id is None or session_id == "":
720
- # Default to the team's session_id if no session_id is provided
721
- if not (self.session_id is None or self.session_id == ""):
722
- session_id = self.session_id
723
- else:
724
- # Generate a new session_id and store it in the agent
725
- session_id = str(uuid4())
726
- self.session_id = session_id
727
- else:
728
- self.session_id = session_id
729
-
730
- session_id = cast(str, session_id)
731
-
732
- self._initialize_session_state(user_id=user_id, session_id=session_id)
733
-
794
+ session_id, user_id = self._initialize_session(
795
+ session_id=session_id, user_id=user_id, session_state=session_state
796
+ )
734
797
  log_debug(f"Session ID: {session_id}", center=True)
735
798
 
736
799
  # Initialize Team
@@ -772,9 +835,6 @@ class Team:
772
835
  self.stream = self.stream or stream
773
836
  self.stream_intermediate_steps = self.stream_intermediate_steps or (stream_intermediate_steps and self.stream)
774
837
 
775
- # Read existing session from storage
776
- self.read_from_storage(session_id=session_id)
777
-
778
838
  # Read existing session from storage
779
839
  if self.context is not None:
780
840
  self._resolve_run_context()
@@ -909,6 +969,8 @@ class Team:
909
969
  from_run_response=run_response,
910
970
  session_id=session_id,
911
971
  )
972
+ finally:
973
+ self._reset_session_state()
912
974
 
913
975
  # If we get here, all retries failed
914
976
  if last_exception is not None:
@@ -1076,11 +1138,12 @@ class Team:
1076
1138
  @overload
1077
1139
  async def arun(
1078
1140
  self,
1079
- message: Union[str, List, Dict, Message],
1141
+ message: Union[str, List, Dict, Message, BaseModel],
1080
1142
  *,
1081
1143
  stream: Literal[False] = False,
1082
1144
  stream_intermediate_steps: Optional[bool] = None,
1083
1145
  session_id: Optional[str] = None,
1146
+ session_state: Optional[Dict[str, Any]] = None,
1084
1147
  user_id: Optional[str] = None,
1085
1148
  retries: Optional[int] = None,
1086
1149
  audio: Optional[Sequence[Audio]] = None,
@@ -1094,11 +1157,12 @@ class Team:
1094
1157
  @overload
1095
1158
  async def arun(
1096
1159
  self,
1097
- message: Union[str, List, Dict, Message],
1160
+ message: Union[str, List, Dict, Message, BaseModel],
1098
1161
  *,
1099
1162
  stream: Literal[True] = True,
1100
1163
  stream_intermediate_steps: Optional[bool] = None,
1101
1164
  session_id: Optional[str] = None,
1165
+ session_state: Optional[Dict[str, Any]] = None,
1102
1166
  user_id: Optional[str] = None,
1103
1167
  retries: Optional[int] = None,
1104
1168
  audio: Optional[Sequence[Audio]] = None,
@@ -1111,11 +1175,12 @@ class Team:
1111
1175
 
1112
1176
  async def arun(
1113
1177
  self,
1114
- message: Union[str, List, Dict, Message],
1178
+ message: Union[str, List, Dict, Message, BaseModel],
1115
1179
  *,
1116
1180
  stream: Optional[bool] = None,
1117
1181
  stream_intermediate_steps: Optional[bool] = None,
1118
1182
  session_id: Optional[str] = None,
1183
+ session_state: Optional[Dict[str, Any]] = None,
1119
1184
  user_id: Optional[str] = None,
1120
1185
  retries: Optional[int] = None,
1121
1186
  audio: Optional[Sequence[Audio]] = None,
@@ -1127,31 +1192,9 @@ class Team:
1127
1192
  ) -> Union[TeamRunResponse, AsyncIterator[Union[RunResponseEvent, TeamRunResponseEvent]]]:
1128
1193
  """Run the Team asynchronously and return the response."""
1129
1194
 
1130
- self._reset_run_state()
1131
-
1132
- if session_id is not None:
1133
- # Reset session state if a session_id is provided. Session name and session state will be loaded from storage.
1134
- self._reset_session_state()
1135
-
1136
- # Use the default user_id and session_id when necessary
1137
- if user_id is None:
1138
- user_id = self.user_id
1139
-
1140
- if session_id is None or session_id == "":
1141
- # Default to the team's session_id if no session_id is provided
1142
- if not (self.session_id is None or self.session_id == ""):
1143
- session_id = self.session_id
1144
- else:
1145
- # Generate a new session_id and store it in the team
1146
- session_id = str(uuid4())
1147
- self.session_id = session_id
1148
- else:
1149
- self.session_id = session_id
1150
-
1151
- session_id = cast(str, session_id)
1152
-
1153
- self._initialize_session_state(user_id=user_id, session_id=session_id)
1154
-
1195
+ session_id, user_id = self._initialize_session(
1196
+ session_id=session_id, user_id=user_id, session_state=session_state
1197
+ )
1155
1198
  log_debug(f"Session ID: {session_id}", center=True)
1156
1199
 
1157
1200
  self.initialize_team(session_id=session_id)
@@ -1186,9 +1229,6 @@ class Team:
1186
1229
  self.stream = self.stream or stream
1187
1230
  self.stream_intermediate_steps = self.stream_intermediate_steps or (stream_intermediate_steps and self.stream)
1188
1231
 
1189
- # Read existing session from storage
1190
- self.read_from_storage(session_id=session_id)
1191
-
1192
1232
  # Read existing session from storage
1193
1233
  if self.context is not None:
1194
1234
  self._resolve_run_context()
@@ -1315,6 +1355,8 @@ class Team:
1315
1355
  from_run_response=run_response,
1316
1356
  session_id=session_id,
1317
1357
  )
1358
+ finally:
1359
+ self._reset_session_state()
1318
1360
 
1319
1361
  # If we get here, all retries failed
1320
1362
  if last_exception is not None:
@@ -2078,19 +2120,6 @@ class Team:
2078
2120
  else:
2079
2121
  log_warning("Something went wrong. Member run response content is not a string")
2080
2122
 
2081
- def _initialize_session_state(self, user_id: Optional[str] = None, session_id: Optional[str] = None) -> None:
2082
- self.session_state = self.session_state or {}
2083
-
2084
- if user_id is not None:
2085
- self.session_state["current_user_id"] = user_id
2086
- if self.team_session_state is not None:
2087
- self.team_session_state["current_user_id"] = user_id
2088
-
2089
- if session_id is not None:
2090
- self.session_state["current_session_id"] = session_id
2091
- if self.team_session_state is not None:
2092
- self.team_session_state["current_session_id"] = session_id
2093
-
2094
2123
  def _make_memories_and_summaries(
2095
2124
  self, run_messages: RunMessages, session_id: str, user_id: Optional[str] = None
2096
2125
  ) -> Iterator[TeamRunResponseEvent]:
@@ -2378,11 +2407,12 @@ class Team:
2378
2407
 
2379
2408
  def print_response(
2380
2409
  self,
2381
- message: Optional[Union[List, Dict, str, Message]] = None,
2410
+ message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
2382
2411
  *,
2383
2412
  stream: bool = False,
2384
2413
  stream_intermediate_steps: bool = False,
2385
2414
  session_id: Optional[str] = None,
2415
+ session_state: Optional[Dict[str, Any]] = None,
2386
2416
  user_id: Optional[str] = None,
2387
2417
  show_message: bool = True,
2388
2418
  show_reasoning: bool = True,
@@ -2414,6 +2444,7 @@ class Team:
2414
2444
  show_full_reasoning=show_full_reasoning,
2415
2445
  tags_to_include_in_markdown=tags_to_include_in_markdown,
2416
2446
  session_id=session_id,
2447
+ session_state=session_state,
2417
2448
  user_id=user_id,
2418
2449
  audio=audio,
2419
2450
  images=images,
@@ -2433,6 +2464,7 @@ class Team:
2433
2464
  show_full_reasoning=show_full_reasoning,
2434
2465
  tags_to_include_in_markdown=tags_to_include_in_markdown,
2435
2466
  session_id=session_id,
2467
+ session_state=session_state,
2436
2468
  user_id=user_id,
2437
2469
  audio=audio,
2438
2470
  images=images,
@@ -2445,13 +2477,14 @@ class Team:
2445
2477
 
2446
2478
  def _print_response(
2447
2479
  self,
2448
- message: Optional[Union[List, Dict, str, Message]] = None,
2480
+ message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
2449
2481
  console: Optional[Any] = None,
2450
2482
  show_message: bool = True,
2451
2483
  show_reasoning: bool = True,
2452
2484
  show_full_reasoning: bool = False,
2453
2485
  tags_to_include_in_markdown: Optional[Set[str]] = None,
2454
2486
  session_id: Optional[str] = None,
2487
+ session_state: Optional[Dict[str, Any]] = None,
2455
2488
  user_id: Optional[str] = None,
2456
2489
  audio: Optional[Sequence[Audio]] = None,
2457
2490
  images: Optional[Sequence[Image]] = None,
@@ -2504,6 +2537,7 @@ class Team:
2504
2537
  files=files,
2505
2538
  stream=False,
2506
2539
  session_id=session_id,
2540
+ session_state=session_state,
2507
2541
  user_id=user_id,
2508
2542
  knowledge_filters=knowledge_filters,
2509
2543
  **kwargs,
@@ -2727,13 +2761,14 @@ class Team:
2727
2761
 
2728
2762
  def _print_response_stream(
2729
2763
  self,
2730
- message: Optional[Union[List, Dict, str, Message]] = None,
2764
+ message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
2731
2765
  console: Optional[Any] = None,
2732
2766
  show_message: bool = True,
2733
2767
  show_reasoning: bool = True,
2734
2768
  show_full_reasoning: bool = False,
2735
2769
  tags_to_include_in_markdown: Optional[Set[str]] = None,
2736
2770
  session_id: Optional[str] = None,
2771
+ session_state: Optional[Dict[str, Any]] = None,
2737
2772
  user_id: Optional[str] = None,
2738
2773
  audio: Optional[Sequence[Audio]] = None,
2739
2774
  images: Optional[Sequence[Image]] = None,
@@ -2804,6 +2839,7 @@ class Team:
2804
2839
  stream=True,
2805
2840
  stream_intermediate_steps=stream_intermediate_steps,
2806
2841
  session_id=session_id,
2842
+ session_state=session_state,
2807
2843
  user_id=user_id,
2808
2844
  knowledge_filters=knowledge_filters,
2809
2845
  **kwargs,
@@ -3242,11 +3278,12 @@ class Team:
3242
3278
 
3243
3279
  async def aprint_response(
3244
3280
  self,
3245
- message: Optional[Union[List, Dict, str, Message]] = None,
3281
+ message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
3246
3282
  *,
3247
3283
  stream: bool = False,
3248
3284
  stream_intermediate_steps: bool = False,
3249
3285
  session_id: Optional[str] = None,
3286
+ session_state: Optional[Dict[str, Any]] = None,
3250
3287
  user_id: Optional[str] = None,
3251
3288
  show_message: bool = True,
3252
3289
  show_reasoning: bool = True,
@@ -3278,6 +3315,7 @@ class Team:
3278
3315
  show_full_reasoning=show_full_reasoning,
3279
3316
  tags_to_include_in_markdown=tags_to_include_in_markdown,
3280
3317
  session_id=session_id,
3318
+ session_state=session_state,
3281
3319
  user_id=user_id,
3282
3320
  audio=audio,
3283
3321
  images=images,
@@ -3297,6 +3335,7 @@ class Team:
3297
3335
  show_full_reasoning=show_full_reasoning,
3298
3336
  tags_to_include_in_markdown=tags_to_include_in_markdown,
3299
3337
  session_id=session_id,
3338
+ session_state=session_state,
3300
3339
  user_id=user_id,
3301
3340
  audio=audio,
3302
3341
  images=images,
@@ -3309,13 +3348,14 @@ class Team:
3309
3348
 
3310
3349
  async def _aprint_response(
3311
3350
  self,
3312
- message: Optional[Union[List, Dict, str, Message]] = None,
3351
+ message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
3313
3352
  console: Optional[Any] = None,
3314
3353
  show_message: bool = True,
3315
3354
  show_reasoning: bool = True,
3316
3355
  show_full_reasoning: bool = False,
3317
3356
  tags_to_include_in_markdown: Optional[Set[str]] = None,
3318
3357
  session_id: Optional[str] = None,
3358
+ session_state: Optional[Dict[str, Any]] = None,
3319
3359
  user_id: Optional[str] = None,
3320
3360
  audio: Optional[Sequence[Audio]] = None,
3321
3361
  images: Optional[Sequence[Image]] = None,
@@ -3368,6 +3408,7 @@ class Team:
3368
3408
  files=files,
3369
3409
  stream=False,
3370
3410
  session_id=session_id,
3411
+ session_state=session_state,
3371
3412
  user_id=user_id,
3372
3413
  knowledge_filters=knowledge_filters,
3373
3414
  **kwargs,
@@ -3589,13 +3630,14 @@ class Team:
3589
3630
 
3590
3631
  async def _aprint_response_stream(
3591
3632
  self,
3592
- message: Optional[Union[List, Dict, str, Message]] = None,
3633
+ message: Optional[Union[List, Dict, str, Message, BaseModel]] = None,
3593
3634
  console: Optional[Any] = None,
3594
3635
  show_message: bool = True,
3595
3636
  show_reasoning: bool = True,
3596
3637
  show_full_reasoning: bool = False,
3597
3638
  tags_to_include_in_markdown: Optional[Set[str]] = None,
3598
3639
  session_id: Optional[str] = None,
3640
+ session_state: Optional[Dict[str, Any]] = None,
3599
3641
  user_id: Optional[str] = None,
3600
3642
  audio: Optional[Sequence[Audio]] = None,
3601
3643
  images: Optional[Sequence[Image]] = None,
@@ -3668,6 +3710,7 @@ class Team:
3668
3710
  stream=True,
3669
3711
  stream_intermediate_steps=stream_intermediate_steps,
3670
3712
  session_id=session_id,
3713
+ session_state=session_state,
3671
3714
  user_id=user_id,
3672
3715
  **kwargs,
3673
3716
  )
@@ -4779,7 +4822,7 @@ class Team:
4779
4822
  user_id: Optional[str] = None,
4780
4823
  async_mode: bool = False,
4781
4824
  knowledge_filters: Optional[Dict[str, Any]] = None,
4782
- message: Optional[Union[str, List, Dict, Message]] = None,
4825
+ message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
4783
4826
  images: Optional[Sequence[Image]] = None,
4784
4827
  videos: Optional[Sequence[Video]] = None,
4785
4828
  audio: Optional[Sequence[Audio]] = None,
@@ -5028,7 +5071,15 @@ class Team:
5028
5071
  if self.instructions is not None:
5029
5072
  _instructions = self.instructions
5030
5073
  if callable(self.instructions):
5031
- _instructions = self.instructions(agent=self)
5074
+ import inspect
5075
+
5076
+ signature = inspect.signature(self.instructions)
5077
+ if "team" in signature.parameters:
5078
+ _instructions = self.instructions(team=self)
5079
+ elif "agent" in signature.parameters:
5080
+ _instructions = self.instructions(agent=self)
5081
+ else:
5082
+ _instructions = self.instructions()
5032
5083
 
5033
5084
  if isinstance(_instructions, str):
5034
5085
  instructions.append(_instructions)
@@ -5267,7 +5318,7 @@ class Team:
5267
5318
  *,
5268
5319
  session_id: str,
5269
5320
  user_id: Optional[str] = None,
5270
- message: Optional[Union[str, List, Dict, Message]] = None,
5321
+ message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
5271
5322
  audio: Optional[Sequence[Audio]] = None,
5272
5323
  images: Optional[Sequence[Image]] = None,
5273
5324
  videos: Optional[Sequence[Video]] = None,
@@ -5349,7 +5400,7 @@ class Team:
5349
5400
 
5350
5401
  def _get_user_message(
5351
5402
  self,
5352
- message: Optional[Union[str, List, Dict, Message]] = None,
5403
+ message: Optional[Union[str, List, Dict, Message, BaseModel]] = None,
5353
5404
  user_id: Optional[str] = None,
5354
5405
  audio: Optional[Sequence[Audio]] = None,
5355
5406
  images: Optional[Sequence[Image]] = None,
@@ -5367,6 +5418,8 @@ class Team:
5367
5418
  message_str = message
5368
5419
  elif callable(message):
5369
5420
  message_str = message(agent=self)
5421
+ elif isinstance(message, BaseModel):
5422
+ message_str = message.model_dump_json(indent=2, exclude_none=True)
5370
5423
  else:
5371
5424
  raise Exception("message must be a string or a callable when add_references is True")
5372
5425
 
@@ -5512,6 +5565,7 @@ class Team:
5512
5565
  format_variables = ChainMap(
5513
5566
  self.session_state or {},
5514
5567
  self.team_session_state or {},
5568
+ self.workflow_session_state or {},
5515
5569
  self.context or {},
5516
5570
  self.extra_data or {},
5517
5571
  {"user_id": user_id} if user_id is not None else {},
@@ -5784,6 +5838,23 @@ class Team:
5784
5838
  else:
5785
5839
  merge_dictionaries(self.team_session_state, member_agent.team_session_state)
5786
5840
 
5841
+ def _update_workflow_session_state(self, member_agent: Union[Agent, "Team"]) -> None:
5842
+ """Update workflow session state from either an Agent or nested Team member"""
5843
+ # Get member state safely
5844
+ member_state = getattr(member_agent, "workflow_session_state", None)
5845
+
5846
+ # Only proceed if member has valid state
5847
+ if member_state is not None and isinstance(member_state, dict):
5848
+ # Initialize team state if needed
5849
+ if self.workflow_session_state is None:
5850
+ self.workflow_session_state = {}
5851
+
5852
+ # Only merge if both are dictionaries and member state is not empty
5853
+ if isinstance(self.workflow_session_state, dict) and member_state:
5854
+ from agno.utils.merge_dict import merge_dictionaries
5855
+
5856
+ merge_dictionaries(self.workflow_session_state, member_state)
5857
+
5787
5858
  def get_run_member_agents_function(
5788
5859
  self,
5789
5860
  session_id: str,
@@ -5828,7 +5899,7 @@ class Team:
5828
5899
  )
5829
5900
 
5830
5901
  # 3. Create the member agent task
5831
- member_agent_task = self._formate_member_agent_task(
5902
+ member_agent_task = self._format_member_agent_task(
5832
5903
  task_description, expected_output, team_context_str, team_member_interactions_str
5833
5904
  )
5834
5905
 
@@ -5912,6 +5983,8 @@ class Team:
5912
5983
  # Update team session state
5913
5984
  self._update_team_session_state(member_agent)
5914
5985
 
5986
+ self._update_workflow_session_state(member_agent)
5987
+
5915
5988
  # Update the team media
5916
5989
  self._update_team_media(member_agent.run_response) # type: ignore
5917
5990
 
@@ -5941,7 +6014,7 @@ class Team:
5941
6014
  )
5942
6015
 
5943
6016
  # 3. Create the member agent task
5944
- member_agent_task = self._formate_member_agent_task(
6017
+ member_agent_task = self._format_member_agent_task(
5945
6018
  task_description, expected_output, team_context_str, team_member_interactions_str
5946
6019
  )
5947
6020
 
@@ -5964,6 +6037,7 @@ class Team:
5964
6037
  audio=audio,
5965
6038
  files=files,
5966
6039
  stream=False,
6040
+ refresh_session_before_write=True,
5967
6041
  )
5968
6042
  check_if_run_cancelled(response)
5969
6043
 
@@ -5990,6 +6064,8 @@ class Team:
5990
6064
  # Update team session state
5991
6065
  self._update_team_session_state(current_agent)
5992
6066
 
6067
+ self._update_workflow_session_state(current_agent)
6068
+
5993
6069
  # Update the team media
5994
6070
  self._update_team_media(agent.run_response)
5995
6071
 
@@ -6120,7 +6196,7 @@ class Team:
6120
6196
  )
6121
6197
 
6122
6198
  # 3. Create the member agent task
6123
- member_agent_task = self._formate_member_agent_task(
6199
+ member_agent_task = self._format_member_agent_task(
6124
6200
  task_description, expected_output, team_context_str, team_member_interactions_str
6125
6201
  )
6126
6202
 
@@ -6226,6 +6302,8 @@ class Team:
6226
6302
  # Update team session state
6227
6303
  self._update_team_session_state(member_agent)
6228
6304
 
6305
+ self._update_workflow_session_state(member_agent)
6306
+
6229
6307
  # Update the team media
6230
6308
  self._update_team_media(member_agent.run_response) # type: ignore
6231
6309
 
@@ -6258,7 +6336,7 @@ class Team:
6258
6336
  )
6259
6337
 
6260
6338
  # 3. Create the member agent task
6261
- member_agent_task = self._formate_member_agent_task(
6339
+ member_agent_task = self._format_member_agent_task(
6262
6340
  task_description, expected_output, team_context_str, team_member_interactions_str
6263
6341
  )
6264
6342
 
@@ -6284,6 +6362,7 @@ class Team:
6284
6362
  knowledge_filters=knowledge_filters
6285
6363
  if not member_agent.knowledge_filters and member_agent.knowledge
6286
6364
  else None,
6365
+ refresh_session_before_write=True,
6287
6366
  )
6288
6367
  async for member_agent_run_response_event in member_agent_run_response_stream:
6289
6368
  check_if_run_cancelled(member_agent_run_response_event)
@@ -6302,6 +6381,7 @@ class Team:
6302
6381
  knowledge_filters=knowledge_filters
6303
6382
  if not member_agent.knowledge_filters and member_agent.knowledge
6304
6383
  else None,
6384
+ refresh_session_before_write=True,
6305
6385
  )
6306
6386
  check_if_run_cancelled(member_agent_run_response)
6307
6387
 
@@ -6354,6 +6434,8 @@ class Team:
6354
6434
  # Update team session state
6355
6435
  self._update_team_session_state(member_agent)
6356
6436
 
6437
+ self._update_workflow_session_state(member_agent)
6438
+
6357
6439
  # Update the team media
6358
6440
  self._update_team_media(member_agent.run_response) # type: ignore
6359
6441
 
@@ -6366,7 +6448,7 @@ class Team:
6366
6448
 
6367
6449
  return transfer_func
6368
6450
 
6369
- def _formate_member_agent_task(
6451
+ def _format_member_agent_task(
6370
6452
  self,
6371
6453
  task_description: str,
6372
6454
  expected_output: Optional[str] = None,
@@ -6592,6 +6674,8 @@ class Team:
6592
6674
  # Update team session state
6593
6675
  self._update_team_session_state(member_agent)
6594
6676
 
6677
+ self._update_workflow_session_state(member_agent)
6678
+
6595
6679
  # Update the team media
6596
6680
  self._update_team_media(member_agent.run_response) # type: ignore
6597
6681
 
@@ -6650,6 +6734,7 @@ class Team:
6650
6734
  knowledge_filters=knowledge_filters
6651
6735
  if not member_agent.knowledge_filters and member_agent.knowledge
6652
6736
  else None,
6737
+ refresh_session_before_write=True,
6653
6738
  )
6654
6739
  async for member_agent_run_response_event in member_agent_run_response_stream:
6655
6740
  check_if_run_cancelled(member_agent_run_response_event)
@@ -6668,6 +6753,7 @@ class Team:
6668
6753
  knowledge_filters=knowledge_filters
6669
6754
  if (member_agent.knowledge_filters and member_agent.knowledge)
6670
6755
  else None,
6756
+ refresh_session_before_write=True,
6671
6757
  )
6672
6758
 
6673
6759
  try:
@@ -6719,6 +6805,8 @@ class Team:
6719
6805
  # Update team session state
6720
6806
  self._update_team_session_state(member_agent)
6721
6807
 
6808
+ self._update_workflow_session_state(member_agent)
6809
+
6722
6810
  # Update the team media
6723
6811
  self._update_team_media(member_agent.run_response) # type: ignore
6724
6812
 
@@ -6748,9 +6836,6 @@ class Team:
6748
6836
  self.team_session = cast(TeamSession, self.storage.read(session_id=session_id))
6749
6837
  if self.team_session is not None:
6750
6838
  self.load_team_session(session=self.team_session)
6751
- else:
6752
- # New session, just reset the state
6753
- self.session_name = None
6754
6839
  return self.team_session
6755
6840
 
6756
6841
  def write_to_storage(self, session_id: str, user_id: Optional[str] = None) -> Optional[TeamSession]:
@@ -6809,7 +6894,6 @@ class Team:
6809
6894
  # Get the session_name from database and update the current session_name if not set
6810
6895
  if self.session_name is None and "session_name" in session.session_data:
6811
6896
  self.session_name = session.session_data.get("session_name")
6812
-
6813
6897
  # Get the session_state from the database and update the current session_state
6814
6898
  if "session_state" in session.session_data:
6815
6899
  session_state_from_db = session.session_data.get("session_state")
@@ -6839,6 +6923,20 @@ class Team:
6839
6923
  # Update the current team_session_state
6840
6924
  self.team_session_state = team_session_state_from_db
6841
6925
 
6926
+ if "workflow_session_state" in session.session_data:
6927
+ workflow_session_state_from_db = session.session_data.get("workflow_session_state")
6928
+ if (
6929
+ workflow_session_state_from_db is not None
6930
+ and isinstance(workflow_session_state_from_db, dict)
6931
+ and len(workflow_session_state_from_db) > 0
6932
+ ):
6933
+ # If the workflow_session_state is already set, merge the workflow_session_state from the database with the current workflow_session_state
6934
+ if self.workflow_session_state is not None and len(self.workflow_session_state) > 0:
6935
+ # This updates workflow_session_state_from_db
6936
+ merge_dictionaries(workflow_session_state_from_db, self.workflow_session_state)
6937
+ # Update the current workflow_session_state
6938
+ self.workflow_session_state = workflow_session_state_from_db
6939
+
6842
6940
  # Get the session_metrics from the database
6843
6941
  if "session_metrics" in session.session_data:
6844
6942
  session_metrics_from_db = session.session_data.get("session_metrics")
@@ -7612,6 +7710,8 @@ class Team:
7612
7710
  session_data["session_state"] = self.session_state
7613
7711
  if self.team_session_state is not None and len(self.team_session_state) > 0:
7614
7712
  session_data["team_session_state"] = self.team_session_state
7713
+ if self.workflow_session_state is not None and len(self.workflow_session_state) > 0:
7714
+ session_data["workflow_session_state"] = self.workflow_session_state
7615
7715
  if self.session_metrics is not None:
7616
7716
  session_data["session_metrics"] = asdict(self.session_metrics) if self.session_metrics is not None else None
7617
7717
  if self.images is not None:
@@ -7644,6 +7744,7 @@ class Team:
7644
7744
  team_id=self.team_id,
7645
7745
  user_id=user_id,
7646
7746
  team_session_id=self.team_session_id,
7747
+ workflow_session_id=self.workflow_session_id,
7647
7748
  memory=memory_dict,
7648
7749
  team_data=self._get_team_data(),
7649
7750
  session_data=self._get_session_data(),
@@ -7668,6 +7769,7 @@ class Team:
7668
7769
  run_id=self.run_id, # type: ignore
7669
7770
  run_data=run_data,
7670
7771
  team_session_id=team_session.team_session_id,
7772
+ workflow_session_id=self.workflow_session_id,
7671
7773
  session_id=team_session.session_id,
7672
7774
  team_data=team_session.to_dict() if self.monitoring else team_session.telemetry_data(),
7673
7775
  ),
@@ -7744,150 +7846,3 @@ class Team:
7744
7846
 
7745
7847
  log_info(f"Filters used by Agent: {search_filters}")
7746
7848
  return search_filters
7747
-
7748
- def register_team(self) -> None:
7749
- self._set_monitoring()
7750
- if not self.monitoring:
7751
- return
7752
-
7753
- from agno.api.team import TeamCreate, create_team
7754
-
7755
- try:
7756
- create_team(
7757
- team=TeamCreate(
7758
- team_id=self.team_id,
7759
- name=self.name,
7760
- config=self.to_platform_dict(),
7761
- parent_team_id=self.parent_team_id,
7762
- app_id=self.app_id,
7763
- workflow_id=self.workflow_id,
7764
- ),
7765
- )
7766
-
7767
- except Exception as e:
7768
- log_debug(f"Could not create team on platform: {e}")
7769
-
7770
- async def _aregister_team(self) -> None:
7771
- self._set_monitoring()
7772
- if not self.monitoring:
7773
- return
7774
-
7775
- from agno.api.team import TeamCreate, acreate_team
7776
-
7777
- try:
7778
- await acreate_team(
7779
- team=TeamCreate(
7780
- team_id=self.team_id,
7781
- name=self.name,
7782
- config=self.to_platform_dict(),
7783
- parent_team_id=self.parent_team_id,
7784
- app_id=self.app_id,
7785
- workflow_id=self.workflow_id,
7786
- ),
7787
- )
7788
- except Exception as e:
7789
- log_debug(f"Could not create team on platform: {e}")
7790
-
7791
- def to_platform_dict(self) -> Dict[str, Any]:
7792
- model = None
7793
- if self.model is not None:
7794
- model = {
7795
- "name": self.model.__class__.__name__,
7796
- "model": self.model.id,
7797
- "provider": self.model.provider,
7798
- }
7799
- tools: List[Dict[str, Any]] = []
7800
- if self.tools is not None:
7801
- if not hasattr(self, "_tools_for_model") or self._tools_for_model is None:
7802
- team_model = self.model
7803
- if team_model is not None:
7804
- self.session_id = cast(str, self.session_id)
7805
- self.determine_tools_for_model(model=team_model, session_id=self.session_id)
7806
-
7807
- if self._tools_for_model is not None:
7808
- for tool in self._tools_for_model:
7809
- if isinstance(tool, dict) and tool.get("type") == "function":
7810
- tools.append(tool["function"])
7811
- payload = {
7812
- "members": [
7813
- {
7814
- **(
7815
- member.get_agent_config_dict()
7816
- if isinstance(member, Agent)
7817
- else member.to_platform_dict()
7818
- if isinstance(member, Team)
7819
- else {}
7820
- ),
7821
- "agent_id": member.agent_id if hasattr(member, "agent_id") else None,
7822
- "team_id": member.team_id if hasattr(member, "team_id") else None,
7823
- "members": (
7824
- [
7825
- {
7826
- **(
7827
- sub_member.get_agent_config_dict()
7828
- if isinstance(sub_member, Agent)
7829
- else sub_member.to_platform_dict()
7830
- if isinstance(sub_member, Team)
7831
- else {}
7832
- ),
7833
- "agent_id": sub_member.agent_id if hasattr(sub_member, "agent_id") else None,
7834
- "team_id": sub_member.team_id if hasattr(sub_member, "team_id") else None,
7835
- }
7836
- for sub_member in member.members
7837
- if sub_member is not None
7838
- ]
7839
- if isinstance(member, Team) and hasattr(member, "members")
7840
- else []
7841
- ),
7842
- }
7843
- for member in self.members
7844
- if member is not None
7845
- ],
7846
- "mode": self.mode,
7847
- "model": model,
7848
- "tools": tools,
7849
- "name": self.name,
7850
- "instructions": self.instructions,
7851
- "description": self.description,
7852
- "storage": {
7853
- "name": self.storage.__class__.__name__,
7854
- }
7855
- if self.storage is not None
7856
- else None,
7857
- # "tools": [tool.to_dict() for tool in self.tools] if self.tools is not None else None,
7858
- "memory": (
7859
- {
7860
- "name": self.memory.__class__.__name__,
7861
- "model": (
7862
- {
7863
- "name": self.memory.model.__class__.__name__,
7864
- "model": self.memory.model.id,
7865
- "provider": self.memory.model.provider,
7866
- }
7867
- if hasattr(self.memory, "model") and self.memory.model is not None
7868
- else (
7869
- {
7870
- "name": self.model.__class__.__name__,
7871
- "model": self.model.id,
7872
- "provider": self.model.provider,
7873
- }
7874
- if self.model is not None
7875
- else None
7876
- )
7877
- ),
7878
- "db": (
7879
- {
7880
- "name": self.memory.db.__class__.__name__,
7881
- "table_name": self.memory.db.table_name if hasattr(self.memory.db, "table_name") else None,
7882
- "db_url": self.memory.db.db_url if hasattr(self.memory.db, "db_url") else None,
7883
- }
7884
- if hasattr(self.memory, "db") and self.memory.db is not None
7885
- else None
7886
- ),
7887
- }
7888
- if self.memory is not None and hasattr(self.memory, "db") and self.memory.db is not None
7889
- else None
7890
- ),
7891
- }
7892
- payload = {k: v for k, v in payload.items() if v is not None}
7893
- return payload