@@ -67,6 +67,9 @@ async def run_async(
6767 # Preserve all contents that were added by instruction processor
6868 # (since llm_request.contents will be completely reassigned below)
6969 instruction_related_contents = llm_request .contents
70+ include_thoughts_from_other_agents = (
71+ invocation_context .run_config .include_thoughts_from_other_agents
72+ )
7073
7174 if agent .include_contents == 'default' :
7275 # Include full conversation history
@@ -75,6 +78,7 @@ async def run_async(
7578 invocation_context .session .events ,
7679 agent .name ,
7780 preserve_function_call_ids = preserve_function_call_ids ,
81+ include_thoughts_from_other_agents = include_thoughts_from_other_agents ,
7882 )
7983 else :
8084 # Include current turn context only (no conversation history)
@@ -83,6 +87,7 @@ async def run_async(
8387 invocation_context .session .events ,
8488 agent .name ,
8589 preserve_function_call_ids = preserve_function_call_ids ,
90+ include_thoughts_from_other_agents = False ,
8691 )
8792
8893 # Add instruction-related contents to proper position in conversation
@@ -241,7 +246,9 @@ def _rearrange_events_for_latest_function_response(
241246 return result_events
242247
243248
244- def _is_part_invisible (p : types .Part ) -> bool :
249+ def _is_part_invisible (
250+ p : types .Part , * , include_thoughts : bool = False
251+ ) -> bool :
245252 """Returns whether a part is invisible for LLM context.
246253
247254 A part is invisible if:
@@ -261,7 +268,7 @@ def _is_part_invisible(p: types.Part) -> bool:
261268 if p .function_call or p .function_response :
262269 return False
263270
264- return p .thought or not (
271+ return ( p .thought and not include_thoughts ) or not (
265272 p .text
266273 or p .inline_data
267274 or p .file_data
@@ -270,7 +277,9 @@ def _is_part_invisible(p: types.Part) -> bool:
270277 )
271278
272279
273- def _contains_empty_content (event : Event ) -> bool :
280+ def _contains_empty_content (
281+ event : Event , * , include_thoughts : bool = False
282+ ) -> bool :
274283 """Check if an event should be skipped due to missing or empty content.
275284
276285 This can happen to the events that only changed session state.
@@ -292,12 +301,18 @@ def _contains_empty_content(event: Event) -> bool:
292301 not event .content
293302 or not event .content .role
294303 or not event .content .parts
295- or all (_is_part_invisible (p ) for p in event .content .parts )
304+ or all (
305+ _is_part_invisible (p , include_thoughts = include_thoughts )
306+ for p in event .content .parts
307+ )
296308 ) and (not event .output_transcription and not event .input_transcription )
297309
298310
299311def _should_include_event_in_context (
300- current_branch : Optional [str ], event : Event
312+ current_branch : Optional [str ],
313+ event : Event ,
314+ * ,
315+ include_thoughts : bool = False ,
301316) -> bool :
302317 """Determines if an event should be included in the LLM context.
303318
@@ -313,7 +328,7 @@ def _should_include_event_in_context(
313328 True if the event should be included in the context, False otherwise.
314329 """
315330 return not (
316- _contains_empty_content (event )
331+ _contains_empty_content (event , include_thoughts = include_thoughts )
317332 or not _is_event_belongs_to_branch (current_branch , event )
318333 or _is_adk_framework_event (event )
319334 or _is_auth_event (event )
@@ -424,6 +439,7 @@ def _get_contents(
424439 agent_name : str = '' ,
425440 * ,
426441 preserve_function_call_ids : bool = False ,
442+ include_thoughts_from_other_agents : bool = False ,
427443) -> list [types .Content ]:
428444 """Get the contents for the LLM request.
429445
@@ -434,6 +450,8 @@ def _get_contents(
434450 events: Events to process.
435451 agent_name: The name of the agent.
436452 preserve_function_call_ids: Whether to preserve function call ids.
453+ include_thoughts_from_other_agents: Whether to include thought parts from
454+ other agents when presenting their messages as user context.
437455
438456 Returns:
439457 A list of processed contents.
@@ -465,7 +483,14 @@ def _get_contents(
465483 raw_filtered_events = [
466484 e
467485 for e in rewind_filtered_events
468- if _should_include_event_in_context (current_branch , e )
486+ if _should_include_event_in_context (
487+ current_branch ,
488+ e ,
489+ include_thoughts = (
490+ include_thoughts_from_other_agents
491+ and _is_other_agent_reply (agent_name , e )
492+ ),
493+ )
469494 ]
470495
471496 has_compaction_events = any (
@@ -515,7 +540,10 @@ def _get_contents(
515540 accumulated_output_transcription = ''
516541
517542 if _is_other_agent_reply (agent_name , event ):
518- if converted_event := _present_other_agent_message (event ):
543+ if converted_event := _present_other_agent_message (
544+ event ,
545+ include_thoughts = include_thoughts_from_other_agents ,
546+ ):
519547 filtered_events .append (converted_event )
520548 else :
521549 filtered_events .append (event )
@@ -545,6 +573,7 @@ def _get_current_turn_contents(
545573 agent_name : str = '' ,
546574 * ,
547575 preserve_function_call_ids : bool = False ,
576+ include_thoughts_from_other_agents : bool = False ,
548577) -> list [types .Content ]:
549578 """Get contents for the current turn only (no conversation history).
550579
@@ -561,6 +590,8 @@ def _get_current_turn_contents(
561590 events: A list of all session events.
562591 agent_name: The name of the agent.
563592 preserve_function_call_ids: Whether to preserve function call ids.
593+ include_thoughts_from_other_agents: Whether to include thought parts from
594+ other agents when presenting their messages as user context.
564595
565596 Returns:
566597 A list of contents for the current turn only, preserving context needed
@@ -569,14 +600,20 @@ def _get_current_turn_contents(
569600 # Find the latest event that starts the current turn and process from there
570601 for i in range (len (events ) - 1 , - 1 , - 1 ):
571602 event = events [i ]
572- if _should_include_event_in_context (current_branch , event ) and (
573- event .author == 'user' or _is_other_agent_reply (agent_name , event )
574- ):
603+ if _should_include_event_in_context (
604+ current_branch ,
605+ event ,
606+ include_thoughts = (
607+ include_thoughts_from_other_agents
608+ and _is_other_agent_reply (agent_name , event )
609+ ),
610+ ) and (event .author == 'user' or _is_other_agent_reply (agent_name , event )):
575611 return _get_contents (
576612 current_branch ,
577613 events [i :],
578614 agent_name ,
579615 preserve_function_call_ids = preserve_function_call_ids ,
616+ include_thoughts_from_other_agents = include_thoughts_from_other_agents ,
580617 )
581618
582619 return []
@@ -613,14 +650,18 @@ def _is_other_agent_reply(current_agent_name: str, event: Event) -> bool:
613650 )
614651
615652
616- def _present_other_agent_message (event : Event ) -> Optional [Event ]:
653+ def _present_other_agent_message (
654+ event : Event , * , include_thoughts : bool = False
655+ ) -> Optional [Event ]:
617656 """Presents another agent's message as user context for the current agent.
618657
619658 Reformats the event with role='user' and adds '[agent_name] said:' prefix
620659 to provide context without confusion about authorship.
621660
622661 Args:
623662 event: The event from another agent to present as context.
663+ include_thoughts: Whether to include thought parts as explicit text
664+ context.
624665
625666 Returns:
626667 Event reformatted as user-role context with agent attribution, or None
@@ -634,7 +675,10 @@ def _present_other_agent_message(event: Event) -> Optional[Event]:
634675 content .parts = [types .Part (text = 'For context:' )]
635676 for part in event .content .parts :
636677 if part .thought :
637- # Exclude thoughts from the context.
678+ if include_thoughts and part .text is not None and part .text .strip ():
679+ content .parts .append (
680+ types .Part (text = f'[{ event .author } ] thought: { part .text } ' )
681+ )
638682 continue
639683 elif part .text is not None and part .text .strip ():
640684 content .parts .append (
0 commit comments