Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add _process_content_object function in _rehydration_utils file to ex…
…tract output from event.content object before assigning it to child.output, in _reconstruct_node_states and add unittest for _process_content_object and modify exisiting test test_scan_message_as_output
  • Loading branch information
samarth1224 committed May 11, 2026
commit 8e7a18d317c16b86c996321437fa4035fc772f86
20 changes: 19 additions & 1 deletion src/google/adk/workflow/utils/_rehydration_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,24 @@ def _validate_resume_response(response_data: Any, schema: Any) -> Any:
raise ValueError(f'Validation failed against schema: {e}') from e


def _process_content_object(event: Event) -> Any:
"""Extracts output from event.content."""
if not event.content or not event.content.parts:
return None

text = ''.join(
p.text for p in event.content.parts if p.text and not p.thought
)
if not text:
return None

text = text.strip()
try:
return json.loads(text)
except (json.JSONDecodeError, ValueError):
return text


def _reconstruct_node_states(
events: list[Event],
base_path: str,
Expand Down Expand Up @@ -266,7 +284,7 @@ def get_owner_key(event_path_builder: _NodePathBuilder) -> str | None:
child.output = event.output
child.branch = event.branch
elif use_message_as_output:
child.output = event.content
child.output = _process_content_object(event)
if event.actions and event.actions.route is not None:
child.route = event.actions.route

Expand Down
45 changes: 44 additions & 1 deletion tests/unittests/workflow/utils/test_rehydration_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from google.adk.events.event import NodeInfo
from google.adk.events.request_input import RequestInput
from google.adk.workflow.utils._rehydration_utils import _ChildScanState
from google.adk.workflow.utils._rehydration_utils import _process_content_object
from google.adk.workflow.utils._rehydration_utils import _reconstruct_node_states
from google.adk.workflow.utils._rehydration_utils import _unwrap_response
from google.adk.workflow.utils._rehydration_utils import _validate_resume_response
Expand Down Expand Up @@ -157,6 +158,48 @@ class User(BaseModel):
)


# --- _process_content_object ---


class TestProcessContentObject:

def test_extracts_plain_text(self):
content = types.Content(parts=[types.Part(text="hello world")])
event = Event(content=content, invocation_id="id")
assert _process_content_object(event) == "hello world"

def test_parses_json_text(self):
content = types.Content(parts=[types.Part(text='{"foo": "bar"}')])
event = Event(content=content, invocation_id="id")
assert _process_content_object(event) == {"foo": "bar"}

def test_joins_multiple_parts(self):
content = types.Content(
parts=[types.Part(text="hello "), types.Part(text="world")]
)
event = Event(content=content, invocation_id="id")
assert _process_content_object(event) == "hello world"

def test_filters_thought_parts(self):
content = types.Content(
parts=[
types.Part(text="thinking...", thought=True),
types.Part(text='{"answer": 42}'),
]
)
event = Event(content=content, invocation_id="id")
assert _process_content_object(event) == {"answer": 42}

def test_returns_none_for_no_content(self):
event = Event(invocation_id="id")
assert _process_content_object(event) is None

def test_returns_none_for_empty_text(self):
content = types.Content(parts=[types.Part(text=" ")])
event = Event(content=content, invocation_id="id")
assert _process_content_object(event) is None


# --- _reconstruct_node_states ---


Expand Down Expand Up @@ -188,7 +231,7 @@ def test_scan_message_as_output(self):
results = _reconstruct_node_states([event], "/wf@1", invocation_id="test_id", group_by_direct_child=True)

assert "node_a@1" in results
assert results["node_a@1"].output == content
assert results["node_a@1"].output == "hello"

def test_scan_descendant_interrupts(self):
event = Event(
Expand Down