agno 1.7.7__py3-none-any.whl → 1.7.8__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/team/team.py CHANGED
@@ -230,6 +230,10 @@ class Team:
230
230
  parser_model: Optional[Model] = None
231
231
  # Provide a prompt for the parser model
232
232
  parser_model_prompt: Optional[str] = None
233
+ # Provide an output model to parse the response from the team
234
+ output_model: Optional[Model] = None
235
+ # Provide a prompt for the output model
236
+ output_model_prompt: Optional[str] = None
233
237
  # If `response_model` is set, sets the response mode of the model, i.e. if the model should explicitly respond with a JSON object instead of a Pydantic model
234
238
  use_json_mode: bool = False
235
239
  # If True, parse the response
@@ -346,6 +350,8 @@ class Team:
346
350
  response_model: Optional[Type[BaseModel]] = None,
347
351
  parser_model: Optional[Model] = None,
348
352
  parser_model_prompt: Optional[str] = None,
353
+ output_model: Optional[Model] = None,
354
+ output_model_prompt: Optional[str] = None,
349
355
  use_json_mode: bool = False,
350
356
  parse_response: bool = True,
351
357
  memory: Optional[Union[TeamMemory, Memory]] = None,
@@ -432,6 +438,8 @@ class Team:
432
438
  self.response_model = response_model
433
439
  self.parser_model = parser_model
434
440
  self.parser_model_prompt = parser_model_prompt
441
+ self.output_model = output_model
442
+ self.output_model_prompt = output_model_prompt
435
443
  self.use_json_mode = use_json_mode
436
444
  self.parse_response = parse_response
437
445
 
@@ -1016,6 +1024,9 @@ class Team:
1016
1024
  tool_call_limit=self.tool_call_limit,
1017
1025
  )
1018
1026
 
1027
+ # If an output model is provided, generate output using the output model
1028
+ self._parse_response_with_output_model(model_response, run_messages)
1029
+
1019
1030
  # If a parser model is provided, structure the response separately
1020
1031
  self._parse_response_with_parser_model(model_response, run_messages)
1021
1032
 
@@ -1085,12 +1096,31 @@ class Team:
1085
1096
  yield self._handle_event(create_team_run_response_started_event(run_response), run_response)
1086
1097
 
1087
1098
  # 2. Get a response from the model
1088
- yield from self._handle_model_response_stream(
1089
- run_response=run_response,
1090
- run_messages=run_messages,
1091
- response_format=response_format,
1092
- stream_intermediate_steps=stream_intermediate_steps,
1093
- )
1099
+ if self.output_model is None:
1100
+ yield from self._handle_model_response_stream(
1101
+ run_response=run_response,
1102
+ run_messages=run_messages,
1103
+ response_format=response_format,
1104
+ stream_intermediate_steps=stream_intermediate_steps,
1105
+ )
1106
+ else:
1107
+ for event in self._handle_model_response_stream(
1108
+ run_response=run_response,
1109
+ run_messages=run_messages,
1110
+ response_format=response_format,
1111
+ stream_intermediate_steps=stream_intermediate_steps,
1112
+ ):
1113
+ from agno.run.team import RunResponseContentEvent
1114
+
1115
+ if isinstance(event, RunResponseContentEvent):
1116
+ if stream_intermediate_steps:
1117
+ yield event
1118
+ else:
1119
+ yield event
1120
+
1121
+ yield from self._generate_response_with_output_model_stream(
1122
+ run_response=run_response, run_messages=run_messages
1123
+ )
1094
1124
 
1095
1125
  # If a parser model is provided, structure the response separately
1096
1126
  yield from self._parse_response_with_parser_model_stream(
@@ -1409,6 +1439,9 @@ class Team:
1409
1439
  tool_call_limit=self.tool_call_limit,
1410
1440
  ) # type: ignore
1411
1441
 
1442
+ # If an output model is provided, generate output using the output model
1443
+ await self._agenerate_response_with_output_model(model_response=model_response, run_messages=run_messages)
1444
+
1412
1445
  # If a parser model is provided, structure the response separately
1413
1446
  await self._aparse_response_with_parser_model(model_response=model_response, run_messages=run_messages)
1414
1447
 
@@ -1477,13 +1510,29 @@ class Team:
1477
1510
  )
1478
1511
 
1479
1512
  # 2. Get a response from the model
1480
- async for event in self._ahandle_model_response_stream(
1481
- run_response=run_response,
1482
- run_messages=run_messages,
1483
- response_format=response_format,
1484
- stream_intermediate_steps=stream_intermediate_steps,
1485
- ):
1486
- yield event
1513
+ if self.output_model is None:
1514
+ async for event in self._ahandle_model_response_stream(
1515
+ run_response=run_response,
1516
+ run_messages=run_messages,
1517
+ response_format=response_format,
1518
+ stream_intermediate_steps=stream_intermediate_steps,
1519
+ ):
1520
+ yield event
1521
+ else:
1522
+ from agno.run.team import RunResponseContentEvent
1523
+
1524
+ async for event in self._agenerate_response_with_output_model_stream(
1525
+ run_response=run_response,
1526
+ run_messages=run_messages,
1527
+ stream_intermediate_steps=stream_intermediate_steps,
1528
+ ):
1529
+ if isinstance(event, RunResponseContentEvent):
1530
+ if stream_intermediate_steps:
1531
+ yield event
1532
+ else:
1533
+ yield event
1534
+
1535
+ yield event
1487
1536
 
1488
1537
  # If a parser model is provided, structure the response separately
1489
1538
  async for event in self._aparse_response_with_parser_model_stream(
@@ -2387,6 +2436,108 @@ class Team:
2387
2436
  else:
2388
2437
  log_warning("A response model is required to parse the response with a parser model")
2389
2438
 
2439
+ def _parse_response_with_output_model(self, model_response: ModelResponse, run_messages: RunMessages) -> None:
2440
+ """Parse the model response using the output model."""
2441
+ if self.output_model is None:
2442
+ return
2443
+
2444
+ messages_for_output_model = self.get_messages_for_output_model(run_messages.messages)
2445
+ output_model_response: ModelResponse = self.output_model.response(messages=messages_for_output_model)
2446
+ model_response.content = output_model_response.content
2447
+
2448
+ def _generate_response_with_output_model_stream(
2449
+ self, run_response: TeamRunResponse, run_messages: RunMessages, stream_intermediate_steps: bool = True
2450
+ ):
2451
+ """Parse the model response using the output model stream."""
2452
+
2453
+ from agno.utils.events import (
2454
+ create_team_output_model_response_completed_event,
2455
+ create_team_output_model_response_started_event,
2456
+ )
2457
+
2458
+ if self.output_model is None:
2459
+ return
2460
+
2461
+ if stream_intermediate_steps:
2462
+ yield self._handle_event(create_team_output_model_response_started_event(run_response), run_response)
2463
+
2464
+ messages_for_output_model = self.get_messages_for_output_model(run_messages.messages)
2465
+ model_response = ModelResponse(content="")
2466
+
2467
+ for model_response_event in self.output_model.response_stream(messages=messages_for_output_model):
2468
+ yield from self._handle_model_response_chunk(
2469
+ run_response=run_response,
2470
+ full_model_response=model_response,
2471
+ model_response_event=model_response_event,
2472
+ )
2473
+
2474
+ # Update the TeamRunResponse content
2475
+ run_response.content = model_response.content
2476
+ run_response.created_at = model_response.created_at
2477
+
2478
+ if stream_intermediate_steps:
2479
+ yield self._handle_event(create_team_output_model_response_completed_event(run_response), run_response)
2480
+
2481
+ # Build a list of messages that should be added to the RunResponse
2482
+ messages_for_run_response = [m for m in run_messages.messages if m.add_to_agent_memory]
2483
+ # Update the RunResponse messages
2484
+ run_response.messages = messages_for_run_response
2485
+ # Update the RunResponse metrics
2486
+ run_response.metrics = self._aggregate_metrics_from_messages(messages_for_run_response)
2487
+
2488
+ async def _agenerate_response_with_output_model(
2489
+ self, model_response: ModelResponse, run_messages: RunMessages
2490
+ ) -> None:
2491
+ """Parse the model response using the output model stream."""
2492
+ if self.output_model is None:
2493
+ return
2494
+
2495
+ messages_for_output_model = self.get_messages_for_output_model(run_messages.messages)
2496
+ output_model_response: ModelResponse = await self.output_model.aresponse(messages=messages_for_output_model)
2497
+ model_response.content = output_model_response.content
2498
+
2499
+ async def _agenerate_response_with_output_model_stream(
2500
+ self, run_response: TeamRunResponse, run_messages: RunMessages, stream_intermediate_steps: bool = True
2501
+ ):
2502
+ """Parse the model response using the output model stream."""
2503
+ from agno.utils.events import (
2504
+ create_team_output_model_response_completed_event,
2505
+ create_team_output_model_response_started_event,
2506
+ )
2507
+
2508
+ if self.output_model is None:
2509
+ return
2510
+
2511
+ if stream_intermediate_steps:
2512
+ yield self._handle_event(create_team_output_model_response_started_event(run_response), run_response)
2513
+
2514
+ messages_for_output_model = self.get_messages_for_output_model(run_messages.messages)
2515
+ model_response = ModelResponse(content="")
2516
+
2517
+ model_response_stream = self.output_model.aresponse_stream(messages=messages_for_output_model)
2518
+
2519
+ async for model_response_event in model_response_stream:
2520
+ for event in self._handle_model_response_chunk(
2521
+ run_response=run_response,
2522
+ full_model_response=model_response,
2523
+ model_response_event=model_response_event,
2524
+ ):
2525
+ yield event
2526
+
2527
+ # Update the TeamRunResponse content
2528
+ run_response.content = model_response.content
2529
+ run_response.created_at = model_response.created_at
2530
+
2531
+ if stream_intermediate_steps:
2532
+ yield self._handle_event(create_team_output_model_response_completed_event(run_response), run_response)
2533
+
2534
+ # Build a list of messages that should be added to the RunResponse
2535
+ messages_for_run_response = [m for m in run_messages.messages if m.add_to_agent_memory]
2536
+ # Update the RunResponse messages
2537
+ run_response.messages = messages_for_run_response
2538
+ # Update the RunResponse metrics
2539
+ run_response.metrics = self._aggregate_metrics_from_messages(messages_for_run_response)
2540
+
2390
2541
  def _handle_event(self, event: Union[RunResponseEvent, TeamRunResponseEvent], run_response: TeamRunResponse):
2391
2542
  # We only store events that are not run_response_content events
2392
2543
  events_to_skip = [event.value for event in self.events_to_skip] if self.events_to_skip else []
@@ -2788,10 +2939,9 @@ class Team:
2788
2939
  if not tags_to_include_in_markdown:
2789
2940
  tags_to_include_in_markdown = {"think", "thinking"}
2790
2941
 
2791
- stream_intermediate_steps = True # With streaming print response, we need to stream intermediate steps
2792
-
2793
2942
  _response_content: str = ""
2794
2943
  _response_thinking: str = ""
2944
+ _response_reasoning_content: str = ""
2795
2945
  reasoning_steps: List[ReasoningStep] = []
2796
2946
 
2797
2947
  # Track tool calls by member and team
@@ -2856,7 +3006,7 @@ class Team:
2856
3006
  if self.response_model is not None:
2857
3007
  team_markdown = False
2858
3008
 
2859
- if isinstance(resp, tuple(get_args(TeamRunResponseEvent))):
3009
+ if isinstance(resp, tuple(get_args(TeamRunResponseEvent))) and resp.team_id == self.team_id:
2860
3010
  if resp.event == TeamRunEvent.run_response_content:
2861
3011
  if isinstance(resp.content, str):
2862
3012
  _response_content += resp.content
@@ -2867,6 +3017,8 @@ class Team:
2867
3017
  log_warning(f"Failed to convert response to JSON: {e}")
2868
3018
  if resp.thinking is not None:
2869
3019
  _response_thinking += resp.thinking
3020
+ if hasattr(resp, "reasoning_content") and resp.reasoning_content is not None:
3021
+ _response_reasoning_content += resp.reasoning_content
2870
3022
  if (
2871
3023
  hasattr(resp, "extra_data")
2872
3024
  and resp.extra_data is not None
@@ -2887,7 +3039,12 @@ class Team:
2887
3039
  team_tool_calls.append(tool)
2888
3040
 
2889
3041
  # Collect member tool calls, avoiding duplicates
2890
- if self.show_tool_calls and hasattr(resp, "member_responses") and resp.member_responses:
3042
+ if (
3043
+ self.show_tool_calls
3044
+ and hasattr(resp, "member_responses")
3045
+ and resp.member_responses
3046
+ and self.show_members_responses
3047
+ ):
2891
3048
  for member_response in resp.member_responses:
2892
3049
  member_id = None
2893
3050
  if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
@@ -2918,6 +3075,7 @@ class Team:
2918
3075
  # Create new panels for each chunk
2919
3076
  panels = []
2920
3077
 
3078
+ # Print user message
2921
3079
  if message and show_message:
2922
3080
  render = True
2923
3081
  # Convert message to a panel
@@ -2950,60 +3108,61 @@ class Team:
2950
3108
  panels.append(status)
2951
3109
 
2952
3110
  # Process member responses and their tool calls
2953
- for member_response in resp.member_responses if hasattr(resp, "member_responses") else []:
2954
- member_id = None
2955
- member_name = "Team Member"
2956
- if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
2957
- member_id = member_response.agent_id
2958
- member_name = self._get_member_name(member_id)
2959
- elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
2960
- member_id = member_response.team_id
2961
- member_name = self._get_member_name(member_id)
3111
+ if self.show_members_responses and hasattr(resp, "member_responses") and resp.member_responses:
3112
+ for member_response in resp.member_responses:
3113
+ member_id = None
3114
+ member_name = "Team Member"
3115
+ if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3116
+ member_id = member_response.agent_id
3117
+ member_name = self._get_member_name(member_id)
3118
+ elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3119
+ member_id = member_response.team_id
3120
+ member_name = self._get_member_name(member_id)
2962
3121
 
2963
- # If we have tool calls for this member, display them
2964
- if self.show_tool_calls and member_id in member_tool_calls and member_tool_calls[member_id]:
2965
- formatted_calls = format_tool_calls(member_tool_calls[member_id])
2966
- if formatted_calls:
2967
- console_width = console.width if console else 80
2968
- panel_width = console_width + 30
3122
+ # If we have tool calls for this member, display them
3123
+ if self.show_tool_calls and member_id in member_tool_calls and member_tool_calls[member_id]:
3124
+ formatted_calls = format_tool_calls(member_tool_calls[member_id])
3125
+ if formatted_calls:
3126
+ console_width = console.width if console else 80
3127
+ panel_width = console_width + 30
2969
3128
 
2970
- lines = []
2971
- for call in formatted_calls:
2972
- wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
2973
- lines.append(wrapped_call)
2974
-
2975
- tool_calls_text = "\n\n".join(lines)
3129
+ lines = []
3130
+ for call in formatted_calls:
3131
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
3132
+ lines.append(wrapped_call)
2976
3133
 
2977
- member_tool_calls_panel = create_panel(
2978
- content=tool_calls_text,
2979
- title=f"{member_name} Tool Calls",
2980
- border_style="yellow",
2981
- )
2982
- panels.append(member_tool_calls_panel)
3134
+ tool_calls_text = "\n\n".join(lines)
2983
3135
 
2984
- # Process member response content
2985
- if self.show_members_responses and member_id is not None:
2986
- show_markdown = False
2987
- if markdown:
2988
- show_markdown = True
3136
+ member_tool_calls_panel = create_panel(
3137
+ content=tool_calls_text,
3138
+ title=f"{member_name} Tool Calls",
3139
+ border_style="yellow",
3140
+ )
3141
+ panels.append(member_tool_calls_panel)
2989
3142
 
2990
- member_response_content = self._parse_response_content(
2991
- member_response,
2992
- tags_to_include_in_markdown,
2993
- show_markdown=show_markdown,
2994
- )
3143
+ # Process member response content
3144
+ if member_id is not None:
3145
+ show_markdown = False
3146
+ if markdown:
3147
+ show_markdown = True
3148
+
3149
+ member_response_content = self._parse_response_content(
3150
+ member_response,
3151
+ tags_to_include_in_markdown,
3152
+ show_markdown=show_markdown,
3153
+ )
2995
3154
 
2996
- member_response_panel = create_panel(
2997
- content=member_response_content,
2998
- title=f"{member_name} Response",
2999
- border_style="magenta",
3000
- )
3155
+ member_response_panel = create_panel(
3156
+ content=member_response_content,
3157
+ title=f"{member_name} Response",
3158
+ border_style="magenta",
3159
+ )
3001
3160
 
3002
- panels.append(member_response_panel)
3161
+ panels.append(member_response_panel)
3003
3162
 
3004
- # Store for reference
3005
- if member_id is not None:
3006
- member_response_panels[member_id] = member_response_panel
3163
+ # Store for reference
3164
+ if member_id is not None:
3165
+ member_response_panels[member_id] = member_response_panel
3007
3166
 
3008
3167
  # Add team tool calls panel if available (before the team response)
3009
3168
  if self.show_tool_calls and team_tool_calls:
@@ -3128,90 +3287,91 @@ class Team:
3128
3287
  final_panels.append(thinking_panel)
3129
3288
 
3130
3289
  # Add member tool calls and responses in correct order
3131
- for i, member_response in enumerate(self.run_response.member_responses if self.run_response else []):
3132
- member_id = None
3133
- if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3134
- member_id = member_response.agent_id
3135
- elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3136
- member_id = member_response.team_id
3137
-
3138
- if member_id:
3139
- # First add tool calls if any
3140
- if self.show_tool_calls and member_id in member_tool_calls and member_tool_calls[member_id]:
3141
- formatted_calls = format_tool_calls(member_tool_calls[member_id])
3142
- if formatted_calls:
3143
- console_width = console.width if console else 80
3144
- panel_width = console_width + 30
3145
-
3146
- lines = []
3147
- for call in formatted_calls:
3148
- wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
3149
- lines.append(wrapped_call)
3290
+ if self.show_members_responses:
3291
+ for i, member_response in enumerate(self.run_response.member_responses if self.run_response else []):
3292
+ member_id = None
3293
+ if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3294
+ member_id = member_response.agent_id
3295
+ elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3296
+ member_id = member_response.team_id
3150
3297
 
3151
- tool_calls_text = "\n\n".join(lines)
3298
+ if member_id:
3299
+ # First add tool calls if any
3300
+ if self.show_tool_calls and member_id in member_tool_calls and member_tool_calls[member_id]:
3301
+ formatted_calls = format_tool_calls(member_tool_calls[member_id])
3302
+ if formatted_calls:
3303
+ console_width = console.width if console else 80
3304
+ panel_width = console_width + 30
3152
3305
 
3153
- member_name = self._get_member_name(member_id)
3154
- member_tool_calls_panel = create_panel(
3155
- content=tool_calls_text,
3156
- title=f"{member_name} Tool Calls",
3157
- border_style="yellow",
3158
- )
3159
- final_panels.append(member_tool_calls_panel)
3306
+ lines = []
3307
+ for call in formatted_calls:
3308
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
3309
+ lines.append(wrapped_call)
3160
3310
 
3161
- # Add reasoning steps if any
3162
- reasoning_steps = []
3163
- if (
3164
- member_response.extra_data is not None
3165
- and member_response.extra_data.reasoning_steps is not None
3166
- ):
3167
- reasoning_steps = member_response.extra_data.reasoning_steps
3168
- if reasoning_steps and show_reasoning:
3169
- for j, step in enumerate(reasoning_steps, 1):
3170
- member_reasoning_panel = self._build_reasoning_step_panel(
3171
- j, step, show_full_reasoning, color="magenta"
3172
- )
3173
- final_panels.append(member_reasoning_panel)
3311
+ tool_calls_text = "\n\n".join(lines)
3174
3312
 
3175
- # Then add response
3176
- show_markdown = False
3177
- if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3178
- show_markdown = member_markdown.get(member_response.agent_id, False)
3179
- elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3180
- show_markdown = member_markdown.get(member_response.team_id, False)
3313
+ member_name = self._get_member_name(member_id)
3314
+ member_tool_calls_panel = create_panel(
3315
+ content=tool_calls_text,
3316
+ title=f"{member_name} Tool Calls",
3317
+ border_style="yellow",
3318
+ )
3319
+ final_panels.append(member_tool_calls_panel)
3181
3320
 
3182
- member_response_content = self._parse_response_content(
3183
- member_response,
3184
- tags_to_include_in_markdown,
3185
- show_markdown=show_markdown,
3186
- )
3321
+ # Add reasoning steps if any
3322
+ reasoning_steps = []
3323
+ if (
3324
+ member_response.extra_data is not None
3325
+ and member_response.extra_data.reasoning_steps is not None
3326
+ ):
3327
+ reasoning_steps = member_response.extra_data.reasoning_steps
3328
+ if reasoning_steps and show_reasoning:
3329
+ for j, step in enumerate(reasoning_steps, 1):
3330
+ member_reasoning_panel = self._build_reasoning_step_panel(
3331
+ j, step, show_full_reasoning, color="magenta"
3332
+ )
3333
+ final_panels.append(member_reasoning_panel)
3187
3334
 
3188
- member_name = "Team Member"
3189
- if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3190
- member_name = self._get_member_name(member_response.agent_id)
3191
- elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3192
- member_name = self._get_member_name(member_response.team_id)
3335
+ # Then add response
3336
+ show_markdown = False
3337
+ if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3338
+ show_markdown = member_markdown.get(member_response.agent_id, False)
3339
+ elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3340
+ show_markdown = member_markdown.get(member_response.team_id, False)
3193
3341
 
3194
- member_response_panel = create_panel(
3195
- content=member_response_content,
3196
- title=f"{member_name} Response",
3197
- border_style="magenta",
3198
- )
3199
- final_panels.append(member_response_panel)
3200
-
3201
- # Add citations if any
3202
- if member_response.citations is not None and member_response.citations.urls is not None:
3203
- md_content = "\n".join(
3204
- f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
3205
- for i, citation in enumerate(member_response.citations.urls)
3206
- if citation.url # Only include citations with valid URLs
3342
+ member_response_content = self._parse_response_content(
3343
+ member_response,
3344
+ tags_to_include_in_markdown,
3345
+ show_markdown=show_markdown,
3207
3346
  )
3208
- if md_content: # Only create panel if there are citations
3209
- citations_panel = create_panel(
3210
- content=Markdown(md_content),
3211
- title="Citations",
3212
- border_style="magenta",
3347
+
3348
+ member_name = "Team Member"
3349
+ if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3350
+ member_name = self._get_member_name(member_response.agent_id)
3351
+ elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3352
+ member_name = self._get_member_name(member_response.team_id)
3353
+
3354
+ member_response_panel = create_panel(
3355
+ content=member_response_content,
3356
+ title=f"{member_name} Response",
3357
+ border_style="magenta",
3358
+ )
3359
+ final_panels.append(member_response_panel)
3360
+
3361
+ # Add citations if any
3362
+ if member_response.citations is not None and member_response.citations.urls is not None:
3363
+ md_content = "\n".join(
3364
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
3365
+ for i, citation in enumerate(member_response.citations.urls)
3366
+ if citation.url # Only include citations with valid URLs
3213
3367
  )
3214
- final_panels.append(citations_panel)
3368
+ if md_content: # Only create panel if there are citations
3369
+ citations_panel = create_panel(
3370
+ content=Markdown(md_content),
3371
+ title="Citations",
3372
+ border_style="magenta",
3373
+ )
3374
+ final_panels.append(citations_panel)
3215
3375
 
3216
3376
  # Add team tool calls before team response
3217
3377
  if self.show_tool_calls and team_tool_calls:
@@ -3654,12 +3814,11 @@ class Team:
3654
3814
  if not tags_to_include_in_markdown:
3655
3815
  tags_to_include_in_markdown = {"think", "thinking"}
3656
3816
 
3657
- stream_intermediate_steps = True # With streaming print response, we need to stream intermediate steps
3658
-
3659
3817
  self.run_response = cast(TeamRunResponse, self.run_response)
3660
3818
 
3661
3819
  _response_content: str = ""
3662
3820
  _response_thinking: str = ""
3821
+ _response_reasoning_content: str = ""
3663
3822
  reasoning_steps: List[ReasoningStep] = []
3664
3823
 
3665
3824
  # Track tool calls by member and team
@@ -3722,7 +3881,7 @@ class Team:
3722
3881
  if self.response_model is not None:
3723
3882
  team_markdown = False
3724
3883
 
3725
- if isinstance(resp, tuple(get_args(TeamRunResponseEvent))):
3884
+ if isinstance(resp, tuple(get_args(TeamRunResponseEvent))) and resp.team_id == self.team_id:
3726
3885
  if resp.event == TeamRunEvent.run_response_content:
3727
3886
  if isinstance(resp.content, str):
3728
3887
  _response_content += resp.content
@@ -3733,6 +3892,8 @@ class Team:
3733
3892
  log_warning(f"Failed to convert response to JSON: {e}")
3734
3893
  if resp.thinking is not None:
3735
3894
  _response_thinking += resp.thinking
3895
+ if hasattr(resp, "reasoning_content") and resp.reasoning_content is not None:
3896
+ _response_reasoning_content += resp.reasoning_content
3736
3897
  if (
3737
3898
  hasattr(resp, "extra_data")
3738
3899
  and resp.extra_data is not None
@@ -3753,7 +3914,12 @@ class Team:
3753
3914
  team_tool_calls.append(tool)
3754
3915
 
3755
3916
  # Collect member tool calls, avoiding duplicates
3756
- if self.show_tool_calls and hasattr(resp, "member_responses") and resp.member_responses:
3917
+ if (
3918
+ self.show_tool_calls
3919
+ and hasattr(resp, "member_responses")
3920
+ and resp.member_responses
3921
+ and self.show_members_responses
3922
+ ):
3757
3923
  for member_response in resp.member_responses:
3758
3924
  member_id = None
3759
3925
  if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
@@ -3817,6 +3983,18 @@ class Team:
3817
3983
  if render:
3818
3984
  live_console.update(Group(*panels))
3819
3985
 
3986
+ if len(_response_reasoning_content) > 0:
3987
+ render = True
3988
+ # Create panel for reasoning content
3989
+ reasoning_panel = create_panel(
3990
+ content=Text(_response_reasoning_content),
3991
+ title=f"Reasoning ({response_timer.elapsed:.1f}s)",
3992
+ border_style="green",
3993
+ )
3994
+ panels.append(reasoning_panel)
3995
+ if render:
3996
+ live_console.update(Group(*panels))
3997
+
3820
3998
  # Add tool calls panel if available
3821
3999
  if self.show_tool_calls and resp is not None and self.run_response.formatted_tool_calls:
3822
4000
  render = True
@@ -3929,95 +4107,98 @@ class Team:
3929
4107
  final_panels.append(thinking_panel)
3930
4108
 
3931
4109
  # Add member tool calls and responses in correct order
3932
- for i, member_response in enumerate(self.run_response.member_responses if self.run_response else []):
3933
- member_id = None
3934
- if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3935
- member_id = member_response.agent_id
3936
- elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3937
- member_id = member_response.team_id
3938
-
3939
- if member_id:
3940
- # First add tool calls if any
3941
- if self.show_tool_calls and member_id in member_tool_calls and member_tool_calls[member_id]:
3942
- formatted_calls = format_tool_calls(member_tool_calls[member_id])
3943
- if formatted_calls:
3944
- console_width = console.width if console else 80
3945
- panel_width = console_width + 30
3946
-
3947
- lines = []
3948
- # Create a set to track already added calls by their string representation
3949
- added_calls = set()
3950
- for call in formatted_calls:
3951
- if call not in added_calls:
3952
- added_calls.add(call)
3953
- # Wrap the call text to fit within the panel
3954
- wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
3955
- lines.append(wrapped_call)
4110
+ if self.show_members_responses:
4111
+ for i, member_response in enumerate(self.run_response.member_responses if self.run_response else []):
4112
+ member_id = None
4113
+ if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
4114
+ member_id = member_response.agent_id
4115
+ elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
4116
+ member_id = member_response.team_id
3956
4117
 
3957
- tool_calls_text = "\n\n".join(lines)
4118
+ if member_id:
4119
+ # First add tool calls if any
4120
+ if self.show_tool_calls and member_id in member_tool_calls and member_tool_calls[member_id]:
4121
+ formatted_calls = format_tool_calls(member_tool_calls[member_id])
4122
+ if formatted_calls:
4123
+ console_width = console.width if console else 80
4124
+ panel_width = console_width + 30
4125
+
4126
+ lines = []
4127
+ # Create a set to track already added calls by their string representation
4128
+ added_calls = set()
4129
+ for call in formatted_calls:
4130
+ if call not in added_calls:
4131
+ added_calls.add(call)
4132
+ # Wrap the call text to fit within the panel
4133
+ wrapped_call = textwrap.fill(
4134
+ f"• {call}", width=panel_width, subsequent_indent=" "
4135
+ )
4136
+ lines.append(wrapped_call)
3958
4137
 
3959
- member_name = self._get_member_name(member_id)
3960
- member_tool_calls_panel = create_panel(
3961
- content=tool_calls_text,
3962
- title=f"{member_name} Tool Calls",
3963
- border_style="yellow",
3964
- )
3965
- final_panels.append(member_tool_calls_panel)
4138
+ tool_calls_text = "\n\n".join(lines)
3966
4139
 
3967
- # Add reasoning steps if any
3968
- reasoning_steps = []
3969
- if (
3970
- member_response.extra_data is not None
3971
- and member_response.extra_data.reasoning_steps is not None
3972
- ):
3973
- reasoning_steps = member_response.extra_data.reasoning_steps
3974
- if reasoning_steps and show_reasoning:
3975
- for j, step in enumerate(reasoning_steps, 1):
3976
- member_reasoning_panel = self._build_reasoning_step_panel(
3977
- j, step, show_full_reasoning, color="magenta"
3978
- )
3979
- final_panels.append(member_reasoning_panel)
4140
+ member_name = self._get_member_name(member_id)
4141
+ member_tool_calls_panel = create_panel(
4142
+ content=tool_calls_text,
4143
+ title=f"{member_name} Tool Calls",
4144
+ border_style="yellow",
4145
+ )
4146
+ final_panels.append(member_tool_calls_panel)
3980
4147
 
3981
- # Then add response
3982
- show_markdown = False
3983
- if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3984
- show_markdown = member_markdown.get(member_response.agent_id, False)
3985
- elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3986
- show_markdown = member_markdown.get(member_response.team_id, False)
4148
+ # Add reasoning steps if any
4149
+ reasoning_steps = []
4150
+ if (
4151
+ member_response.extra_data is not None
4152
+ and member_response.extra_data.reasoning_steps is not None
4153
+ ):
4154
+ reasoning_steps = member_response.extra_data.reasoning_steps
4155
+ if reasoning_steps and show_reasoning:
4156
+ for j, step in enumerate(reasoning_steps, 1):
4157
+ member_reasoning_panel = self._build_reasoning_step_panel(
4158
+ j, step, show_full_reasoning, color="magenta"
4159
+ )
4160
+ final_panels.append(member_reasoning_panel)
3987
4161
 
3988
- member_response_content = self._parse_response_content(
3989
- member_response,
3990
- tags_to_include_in_markdown,
3991
- show_markdown=show_markdown,
3992
- )
4162
+ # Then add response
4163
+ show_markdown = False
4164
+ if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
4165
+ show_markdown = member_markdown.get(member_response.agent_id, False)
4166
+ elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
4167
+ show_markdown = member_markdown.get(member_response.team_id, False)
3993
4168
 
3994
- member_name = "Team Member"
3995
- if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
3996
- member_name = self._get_member_name(member_response.agent_id)
3997
- elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
3998
- member_name = self._get_member_name(member_response.team_id)
4169
+ member_response_content = self._parse_response_content(
4170
+ member_response,
4171
+ tags_to_include_in_markdown,
4172
+ show_markdown=show_markdown,
4173
+ )
3999
4174
 
4000
- member_response_panel = create_panel(
4001
- content=member_response_content,
4002
- title=f"{member_name} Response",
4003
- border_style="magenta",
4004
- )
4005
- final_panels.append(member_response_panel)
4006
-
4007
- # Add citations if any
4008
- if member_response.citations is not None and member_response.citations.urls is not None:
4009
- md_content = "\n".join(
4010
- f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
4011
- for i, citation in enumerate(member_response.citations.urls)
4012
- if citation.url # Only include citations with valid URLs
4175
+ member_name = "Team Member"
4176
+ if isinstance(member_response, RunResponse) and member_response.agent_id is not None:
4177
+ member_name = self._get_member_name(member_response.agent_id)
4178
+ elif isinstance(member_response, TeamRunResponse) and member_response.team_id is not None:
4179
+ member_name = self._get_member_name(member_response.team_id)
4180
+
4181
+ member_response_panel = create_panel(
4182
+ content=member_response_content,
4183
+ title=f"{member_name} Response",
4184
+ border_style="magenta",
4013
4185
  )
4014
- if md_content: # Only create panel if there are citations
4015
- citations_panel = create_panel(
4016
- content=Markdown(md_content),
4017
- title="Citations",
4018
- border_style="magenta",
4186
+ final_panels.append(member_response_panel)
4187
+
4188
+ # Add citations if any
4189
+ if member_response.citations is not None and member_response.citations.urls is not None:
4190
+ md_content = "\n".join(
4191
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
4192
+ for i, citation in enumerate(member_response.citations.urls)
4193
+ if citation.url # Only include citations with valid URLs
4019
4194
  )
4020
- final_panels.append(citations_panel)
4195
+ if md_content: # Only create panel if there are citations
4196
+ citations_panel = create_panel(
4197
+ content=Markdown(md_content),
4198
+ title="Citations",
4199
+ border_style="magenta",
4200
+ )
4201
+ final_panels.append(citations_panel)
4021
4202
 
4022
4203
  # Add team tool calls before team response
4023
4204
  if self.show_tool_calls and team_tool_calls:
@@ -5508,6 +5689,13 @@ class Team:
5508
5689
  return Message.model_validate(message)
5509
5690
  except Exception as e:
5510
5691
  log_warning(f"Failed to validate message: {e}")
5692
+ elif isinstance(message, BaseModel):
5693
+ try:
5694
+ # Create a user message with the BaseModel content
5695
+ content = message.model_dump_json(indent=2, exclude_none=True)
5696
+ return Message(role="user", content=content)
5697
+ except Exception as e:
5698
+ log_warning(f"Failed to convert BaseModel to message: {e}")
5511
5699
 
5512
5700
  def get_messages_for_parser_model(
5513
5701
  self, model_response: ModelResponse, response_format: Optional[Union[Dict, Type[BaseModel]]]
@@ -5549,6 +5737,24 @@ class Team:
5549
5737
  Message(role="user", content=run_response.content),
5550
5738
  ]
5551
5739
 
5740
+ def get_messages_for_output_model(self, messages: List[Message]) -> List[Message]:
5741
+ """Get the messages for the output model."""
5742
+
5743
+ if self.output_model_prompt is not None:
5744
+ system_message_exists = False
5745
+ for message in messages:
5746
+ if message.role == "system":
5747
+ system_message_exists = True
5748
+ message.content = self.output_model_prompt
5749
+ break
5750
+ if not system_message_exists:
5751
+ messages.insert(0, Message(role="system", content=self.output_model_prompt))
5752
+
5753
+ # Remove the last assistant message from the messages list
5754
+ messages.pop(-1)
5755
+
5756
+ return messages
5757
+
5552
5758
  def _format_message_with_state_variables(self, message: Any, user_id: Optional[str] = None) -> Any:
5553
5759
  """Format a message with the session state variables."""
5554
5760
  import re
@@ -6920,9 +7126,10 @@ class Team:
6920
7126
  # If the session_state is already set, merge the session_state from the database with the current session_state
6921
7127
  if self.session_state is not None and len(self.session_state) > 0:
6922
7128
  # This updates session_state_from_db
6923
- merge_dictionaries(session_state_from_db, self.session_state)
6924
- # Update the current session_state
6925
- self.session_state = session_state_from_db
7129
+ merge_dictionaries(self.session_state, session_state_from_db)
7130
+ else:
7131
+ # Update the current session_state
7132
+ self.session_state = session_state_from_db
6926
7133
 
6927
7134
  if "team_session_state" in session.session_data:
6928
7135
  team_session_state_from_db = session.session_data.get("team_session_state")