@@ -66,6 +66,9 @@ async def run_async(
6666 # Preserve all contents that were added by instruction processor
6767 # (since llm_request.contents will be completely reassigned below)
6868 instruction_related_contents = llm_request .contents
69+ include_thoughts_from_other_agents = (
70+ invocation_context .run_config .include_thoughts_from_other_agents
71+ )
6972
7073 is_single_turn = getattr (agent , 'mode' , None ) == 'single_turn'
7174 if agent .include_contents == 'default' :
@@ -78,6 +81,7 @@ async def run_async(
7881 isolation_scope = invocation_context .isolation_scope ,
7982 is_single_turn = is_single_turn ,
8083 user_content = invocation_context .user_content ,
84+ include_thoughts_from_other_agents = include_thoughts_from_other_agents ,
8185 )
8286 else :
8387 # Include current turn context only (no conversation history)
@@ -89,6 +93,7 @@ async def run_async(
8993 isolation_scope = invocation_context .isolation_scope ,
9094 is_single_turn = is_single_turn ,
9195 user_content = invocation_context .user_content ,
96+ include_thoughts_from_other_agents = False ,
9297 )
9398
9499 # Add instruction-related contents to proper position in conversation
@@ -247,7 +252,9 @@ def _rearrange_events_for_latest_function_response(
247252 return result_events
248253
249254
250- def _is_part_invisible (p : types .Part ) -> bool :
255+ def _is_part_invisible (
256+ p : types .Part , * , include_thoughts : bool = False
257+ ) -> bool :
251258 """Returns whether a part is invisible for LLM context.
252259
253260 A part is invisible if:
@@ -267,7 +274,7 @@ def _is_part_invisible(p: types.Part) -> bool:
267274 if p .function_call or p .function_response :
268275 return False
269276
270- return p .thought or not (
277+ return ( p .thought and not include_thoughts ) or not (
271278 p .text
272279 or p .inline_data
273280 or p .file_data
@@ -276,7 +283,9 @@ def _is_part_invisible(p: types.Part) -> bool:
276283 )
277284
278285
279- def _contains_empty_content (event : Event ) -> bool :
286+ def _contains_empty_content (
287+ event : Event , * , include_thoughts : bool = False
288+ ) -> bool :
280289 """Check if an event should be skipped due to missing or empty content.
281290
282291 This can happen to the events that only changed session state.
@@ -298,7 +307,10 @@ def _contains_empty_content(event: Event) -> bool:
298307 not event .content
299308 or not event .content .role
300309 or not event .content .parts
301- or all (_is_part_invisible (p ) for p in event .content .parts )
310+ or all (
311+ _is_part_invisible (p , include_thoughts = include_thoughts )
312+ for p in event .content .parts
313+ )
302314 ) and (not event .output_transcription and not event .input_transcription )
303315
304316
@@ -366,6 +378,8 @@ def _should_include_event_in_context(
366378 current_branch : Optional [str ],
367379 event : Event ,
368380 isolation_scope : Optional [str ] = None ,
381+ * ,
382+ include_thoughts : bool = False ,
369383) -> bool :
370384 """Determines if an event should be included in the LLM context.
371385
@@ -391,7 +405,7 @@ def _should_include_event_in_context(
391405 if ev_iso != isolation_scope :
392406 return False
393407 return not (
394- _contains_empty_content (event )
408+ _contains_empty_content (event , include_thoughts = include_thoughts )
395409 or not _is_event_belongs_to_branch (current_branch , event )
396410 or _is_adk_framework_event (event )
397411 or _is_auth_event (event )
@@ -504,6 +518,7 @@ def _get_contents(
504518 isolation_scope : Optional [str ] = None ,
505519 is_single_turn : bool = False ,
506520 user_content : Optional [types .Content ] = None ,
521+ include_thoughts_from_other_agents : bool = False ,
507522) -> list [types .Content ]:
508523 """Get the contents for the LLM request.
509524
@@ -519,6 +534,8 @@ def _get_contents(
519534 user_content: Fallback first user turn for task agents whose
520535 originating delegation FC is not in session (workflow-node
521536 task case).
537+ include_thoughts_from_other_agents: Whether to include thought parts from
538+ other agents when presenting their messages as user context.
522539
523540 Returns:
524541 A list of processed contents.
@@ -551,7 +568,11 @@ def _get_contents(
551568 e
552569 for e in rewind_filtered_events
553570 if _should_include_event_in_context (
554- current_branch , e , isolation_scope = isolation_scope
571+ current_branch , e , isolation_scope = isolation_scope ,
572+ include_thoughts = (
573+ include_thoughts_from_other_agents
574+ and _is_other_agent_reply (agent_name , e )
575+ )
555576 )
556577 ]
557578
@@ -626,7 +647,7 @@ def _get_contents(
626647 break
627648
628649 if is_other_reply :
629- if converted_event := _present_other_agent_message (event ):
650+ if converted_event := _present_other_agent_message (event , include_thoughts = include_thoughts_from_other_agents ):
630651 filtered_events .append (converted_event )
631652 else :
632653 filtered_events .append (event )
@@ -677,6 +698,7 @@ def _get_current_turn_contents(
677698 is_single_turn : bool = False ,
678699 isolation_scope : Optional [str ] = None ,
679700 user_content : Optional [types .Content ] = None ,
701+ include_thoughts_from_other_agents : bool = False ,
680702) -> list [types .Content ]:
681703 """Get contents for the current turn only (no conversation history).
682704
@@ -693,6 +715,8 @@ def _get_current_turn_contents(
693715 events: A list of all session events.
694716 agent_name: The name of the agent.
695717 preserve_function_call_ids: Whether to preserve function call ids.
718+ include_thoughts_from_other_agents: Whether to include thought parts from
719+ other agents when presenting their messages as user context.
696720
697721 Returns:
698722 A list of contents for the current turn only, preserving context needed
@@ -702,7 +726,11 @@ def _get_current_turn_contents(
702726 for i in range (len (events ) - 1 , - 1 , - 1 ):
703727 event = events [i ]
704728 if _should_include_event_in_context (
705- current_branch , event , isolation_scope = isolation_scope
729+ current_branch , event , isolation_scope = isolation_scope ,
730+ include_thoughts = (
731+ include_thoughts_from_other_agents
732+ and _is_other_agent_reply (agent_name , event )
733+ ),
706734 ) and (event .author == 'user' or _is_other_agent_reply (agent_name , event )):
707735 return _get_contents (
708736 current_branch ,
@@ -712,6 +740,7 @@ def _get_current_turn_contents(
712740 isolation_scope = isolation_scope ,
713741 is_single_turn = is_single_turn ,
714742 user_content = user_content ,
743+ include_thoughts_from_other_agents = include_thoughts_from_other_agents ,
715744 )
716745
717746 return []
@@ -748,14 +777,18 @@ def _is_other_agent_reply(current_agent_name: str, event: Event) -> bool:
748777 )
749778
750779
751- def _present_other_agent_message (event : Event ) -> Optional [Event ]:
780+ def _present_other_agent_message (
781+ event : Event , * , include_thoughts : bool = False
782+ ) -> Optional [Event ]:
752783 """Presents another agent's message as user context for the current agent.
753784
754785 Reformats the event with role='user' and adds '[agent_name] said:' prefix
755786 to provide context without confusion about authorship.
756787
757788 Args:
758789 event: The event from another agent to present as context.
790+ include_thoughts: Whether to include thought parts as explicit text
791+ context.
759792
760793 Returns:
761794 Event reformatted as user-role context with agent attribution, or None
@@ -769,7 +802,10 @@ def _present_other_agent_message(event: Event) -> Optional[Event]:
769802 content .parts = [types .Part (text = 'For context:' )]
770803 for part in event .content .parts :
771804 if part .thought :
772- # Exclude thoughts from the context.
805+ if include_thoughts and part .text is not None and part .text .strip ():
806+ content .parts .append (
807+ types .Part (text = f'[{ event .author } ] thought: { part .text } ' )
808+ )
773809 continue
774810 elif part .text is not None and part .text .strip ():
775811 content .parts .append (
0 commit comments