Skip to content

Commit cf3f758

Browse files
minzznguyenJames Nguyen
andauthored
fix(dea): accumulate all agent text parts and increase timeout (#456)
Co-authored-by: James Nguyen <jamesamn@google.com>
1 parent 4f55589 commit cf3f758

2 files changed

Lines changed: 66 additions & 19 deletions

File tree

‎evalbench/generators/models/gcp_data_engineering_agent.py‎

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ def _get_and_refresh_token(self) -> str:
120120
return token_val
121121

122122

123+
def _is_iterable(obj: Any) -> bool:
124+
"""Safely checks if an object is iterable, excluding strings and bytes."""
125+
if isinstance(obj, (str, bytes)):
126+
return False
127+
try:
128+
iter(obj)
129+
return True
130+
except TypeError:
131+
return False
132+
133+
123134
def _extract_message_text(msg: Any) -> str:
124135
"""Extracts agent message text from a single Message object."""
125136
if getattr(msg, "role", None) != pb.ROLE_AGENT:
@@ -141,51 +152,49 @@ def _extract_message_text(msg: Any) -> str:
141152

142153

143154
def _find_agent_text_recursive(obj: Any) -> str:
144-
"""Recursively searches obj to find the first valid agent text."""
145-
text = _extract_message_text(obj)
146-
if text:
147-
return text
155+
"""Recursively searches obj to find and accumulate agent texts."""
156+
texts = []
157+
158+
self_text = _extract_message_text(obj)
159+
if self_text:
160+
texts.append(self_text)
148161

149162
# 1. Handle dict-like mappings by traversing their values
150163
if isinstance(obj, collections.abc.Mapping):
151164
for val in obj.values():
152165
text = _find_agent_text_recursive(val)
153166
if text:
154-
return text
167+
texts.append(text)
168+
return "\n\n".join(texts)
155169

156170
# 2. Handle iterables (exclude string/bytes)
157-
is_iterable = False
158-
if not isinstance(obj, (str, bytes)):
159-
try:
160-
iter(obj)
161-
is_iterable = True
162-
except TypeError as e:
163-
logger.info("Object is not iterable: %s", e)
164-
165-
if is_iterable:
171+
if _is_iterable(obj):
166172
for item in obj:
167173
text = _find_agent_text_recursive(item)
168174
if text:
169-
return text
175+
texts.append(text)
176+
return "\n\n".join(texts)
170177

171178
# 3. Handle standard Protobuf Messages via ListFields
172179
elif hasattr(obj, "ListFields"):
173180
try:
174181
for field_desc, field_value in obj.ListFields():
175182
text = _find_agent_text_recursive(field_value)
176183
if text:
177-
return text
184+
texts.append(text)
178185
except Exception:
179186
pass
187+
return "\n\n".join(texts)
180188

181189
# 4. Fallback for other standard objects
182190
elif hasattr(obj, "__dict__"):
183191
for val in obj.__dict__.values():
184192
text = _find_agent_text_recursive(val)
185193
if text:
186-
return text
194+
texts.append(text)
195+
return "\n\n".join(texts)
187196

188-
return ""
197+
return "\n\n".join(texts)
189198

190199

191200
class DataEngineeringAgentGenerator(QueryGenerator):
@@ -336,7 +345,7 @@ async def _run_client(
336345
message_req.metadata[CONVERSATION_TOKEN_URI] = token
337346

338347
context = ClientCallContext(
339-
timeout=180.0,
348+
timeout=300.0,
340349
service_parameters={
341350
"A2A-Extensions": ALL_EXTENSIONS
342351
}

‎evalbench/test/gcp_data_engineering_agent_test.py‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,41 @@ def test_extract_reply_text_heuristic_recursive_fallback():
467467

468468
container = [{"some_key": "some_value"}, [nested_msg]]
469469
assert _find_agent_text_recursive(container) == "Nested message text"
470+
471+
472+
def test_find_agent_text_recursive_accumulation():
473+
# 1. Test multiple agent messages are accumulated
474+
# and joined by double newlines
475+
nested_msg1 = pb.Message(role=pb.ROLE_AGENT)
476+
nested_msg1.parts.append(pb.Part(text="Part 1 text"))
477+
nested_msg2 = pb.Message(role=pb.ROLE_AGENT)
478+
nested_msg2.parts.append(pb.Part(text="Part 2 text"))
479+
480+
container = [
481+
nested_msg1,
482+
{"some_other_key": nested_msg2},
483+
]
484+
expected = "Part 1 text\n\nPart 2 text"
485+
assert _find_agent_text_recursive(container) == expected
486+
487+
# 2. Test resilience against non-iterable primitives
488+
# (should skip them and not crash)
489+
class NonIterableObject:
490+
pass
491+
492+
nested_msg3 = pb.Message(role=pb.ROLE_AGENT)
493+
nested_msg3.parts.append(pb.Part(text="Valid text"))
494+
495+
mixed_container = {
496+
"number": 42,
497+
"flag": True,
498+
"none_value": None,
499+
"custom_obj": NonIterableObject(),
500+
"nested": nested_msg3,
501+
}
502+
assert _find_agent_text_recursive(mixed_container) == "Valid text"
503+
504+
# 3. Test empty/edge cases return empty string
505+
assert _find_agent_text_recursive(None) == ""
506+
assert _find_agent_text_recursive([]) == ""
507+
assert _find_agent_text_recursive({}) == ""

0 commit comments

Comments
 (0)