@@ -81,6 +81,12 @@ async def run_async(
8181 # Preserve all contents that were added by instruction processor
8282 # (since llm_request.contents will be completely reassigned below)
8383 instruction_related_contents = llm_request .contents
84+ run_config = invocation_context .run_config
85+ include_thoughts_from_other_agents = (
86+ run_config .include_thoughts_from_other_agents
87+ if run_config is not None
88+ else False
89+ )
8490
8591 is_single_turn = getattr (agent , 'mode' , None ) == 'single_turn'
8692 if agent .include_contents == 'default' :
@@ -93,6 +99,7 @@ async def run_async(
9399 isolation_scope = invocation_context .isolation_scope ,
94100 is_single_turn = is_single_turn ,
95101 user_content = invocation_context .user_content ,
102+ include_thoughts_from_other_agents = include_thoughts_from_other_agents ,
96103 )
97104 else :
98105 # Include current turn context only (no conversation history)
@@ -104,6 +111,7 @@ async def run_async(
104111 isolation_scope = invocation_context .isolation_scope ,
105112 is_single_turn = is_single_turn ,
106113 user_content = invocation_context .user_content ,
114+ include_thoughts_from_other_agents = False ,
107115 )
108116
109117 if (
@@ -274,7 +282,9 @@ def _rearrange_events_for_latest_function_response(
274282 return result_events
275283
276284
277- def _is_part_invisible (p : types .Part ) -> bool :
285+ def _is_part_invisible (
286+ p : types .Part , * , include_thoughts : bool = False
287+ ) -> bool :
278288 """Returns whether a part is invisible for LLM context.
279289
280290 A part is invisible if:
@@ -294,7 +304,7 @@ def _is_part_invisible(p: types.Part) -> bool:
294304 if p .function_call or p .function_response :
295305 return False
296306
297- return p .thought or not (
307+ return ( p .thought and not include_thoughts ) or not (
298308 p .text
299309 or p .inline_data
300310 or p .file_data
@@ -303,7 +313,9 @@ def _is_part_invisible(p: types.Part) -> bool:
303313 )
304314
305315
306- def _contains_empty_content (event : Event ) -> bool :
316+ def _contains_empty_content (
317+ event : Event , * , include_thoughts : bool = False
318+ ) -> bool :
307319 """Check if an event should be skipped due to missing or empty content.
308320
309321 This can happen to the events that only changed session state.
@@ -325,7 +337,10 @@ def _contains_empty_content(event: Event) -> bool:
325337 not event .content
326338 or not event .content .role
327339 or not event .content .parts
328- or all (_is_part_invisible (p ) for p in event .content .parts )
340+ or all (
341+ _is_part_invisible (p , include_thoughts = include_thoughts )
342+ for p in event .content .parts
343+ )
329344 ) and (not event .output_transcription and not event .input_transcription )
330345
331346
@@ -393,6 +408,8 @@ def _should_include_event_in_context(
393408 current_branch : Optional [str ],
394409 event : Event ,
395410 isolation_scope : Optional [str ] = None ,
411+ * ,
412+ include_thoughts : bool = False ,
396413) -> bool :
397414 """Determines if an event should be included in the LLM context.
398415
@@ -418,7 +435,7 @@ def _should_include_event_in_context(
418435 if ev_iso != isolation_scope :
419436 return False
420437 return not (
421- _contains_empty_content (event )
438+ _contains_empty_content (event , include_thoughts = include_thoughts )
422439 or not _is_event_belongs_to_branch (current_branch , event )
423440 or _is_adk_framework_event (event )
424441 or _is_auth_event (event )
@@ -577,6 +594,7 @@ def _get_contents(
577594 isolation_scope : Optional [str ] = None ,
578595 is_single_turn : bool = False ,
579596 user_content : Optional [types .Content ] = None ,
597+ include_thoughts_from_other_agents : bool = False ,
580598) -> list [types .Content ]:
581599 """Get the contents for the LLM request.
582600
@@ -592,6 +610,8 @@ def _get_contents(
592610 user_content: Fallback first user turn for task agents whose
593611 originating delegation FC is not in session (workflow-node
594612 task case).
613+ include_thoughts_from_other_agents: Whether to include thought parts from
614+ other agents when presenting their messages as user context.
595615
596616 Returns:
597617 A list of processed contents.
@@ -624,7 +644,13 @@ def _get_contents(
624644 e
625645 for e in rewind_filtered_events
626646 if _should_include_event_in_context (
627- current_branch , e , isolation_scope = isolation_scope
647+ current_branch ,
648+ e ,
649+ isolation_scope = isolation_scope ,
650+ include_thoughts = (
651+ include_thoughts_from_other_agents
652+ and _is_other_agent_reply (agent_name , e )
653+ ),
628654 )
629655 ]
630656
@@ -699,7 +725,9 @@ def _get_contents(
699725 break
700726
701727 if is_other_reply :
702- if converted_event := _present_other_agent_message (event ):
728+ if converted_event := _present_other_agent_message (
729+ event , include_thoughts = include_thoughts_from_other_agents
730+ ):
703731 filtered_events .append (converted_event )
704732 else :
705733 filtered_events .append (event )
@@ -752,6 +780,7 @@ def _get_current_turn_contents(
752780 is_single_turn : bool = False ,
753781 isolation_scope : Optional [str ] = None ,
754782 user_content : Optional [types .Content ] = None ,
783+ include_thoughts_from_other_agents : bool = False ,
755784) -> list [types .Content ]:
756785 """Get contents for the current turn only (no conversation history).
757786
@@ -768,6 +797,8 @@ def _get_current_turn_contents(
768797 events: A list of all session events.
769798 agent_name: The name of the agent.
770799 preserve_function_call_ids: Whether to preserve function call ids.
800+ include_thoughts_from_other_agents: Whether to include thought parts from
801+ other agents when presenting their messages as user context.
771802
772803 Returns:
773804 A list of contents for the current turn only, preserving context needed
@@ -778,7 +809,13 @@ def _get_current_turn_contents(
778809 event = events [i ]
779810 if (
780811 _should_include_event_in_context (
781- current_branch , event , isolation_scope = isolation_scope
812+ current_branch ,
813+ event ,
814+ isolation_scope = isolation_scope ,
815+ include_thoughts = (
816+ include_thoughts_from_other_agents
817+ and _is_other_agent_reply (agent_name , event )
818+ ),
782819 )
783820 and (event .author == 'user' or _is_other_agent_reply (agent_name , event ))
784821 and not _is_direct_transfer (event )
@@ -791,6 +828,7 @@ def _get_current_turn_contents(
791828 isolation_scope = isolation_scope ,
792829 is_single_turn = is_single_turn ,
793830 user_content = user_content ,
831+ include_thoughts_from_other_agents = include_thoughts_from_other_agents ,
794832 )
795833
796834 return []
@@ -851,14 +889,18 @@ def _is_other_agent_reply(current_agent_name: str, event: Event) -> bool:
851889 )
852890
853891
854- def _present_other_agent_message (event : Event ) -> Optional [Event ]:
892+ def _present_other_agent_message (
893+ event : Event , * , include_thoughts : bool = False
894+ ) -> Optional [Event ]:
855895 """Presents another agent's message as user context for the current agent.
856896
857897 Reformats the event with role='user' and adds '[agent_name] said:' prefix
858898 to provide context without confusion about authorship.
859899
860900 Args:
861901 event: The event from another agent to present as context.
902+ include_thoughts: Whether to include thought parts as explicit text
903+ context.
862904
863905 Returns:
864906 Event reformatted as user-role context with agent attribution, or None
@@ -872,7 +914,10 @@ def _present_other_agent_message(event: Event) -> Optional[Event]:
872914 content .parts = [types .Part (text = 'For context:' )]
873915 for part in event .content .parts :
874916 if part .thought :
875- # Exclude thoughts from the context.
917+ if include_thoughts and part .text is not None and part .text .strip ():
918+ content .parts .append (
919+ types .Part (text = f'[{ event .author } ] thought: { part .text } ' )
920+ )
876921 continue
877922 elif part .text is not None and part .text .strip ():
878923 content .parts .append (
0 commit comments