diff --git a/python/packages/core/agent_framework/_workflows/_runner_context.py b/python/packages/core/agent_framework/_workflows/_runner_context.py index edbbfea50c9..205d3bd9538 100644 --- a/python/packages/core/agent_framework/_workflows/_runner_context.py +++ b/python/packages/core/agent_framework/_workflows/_runner_context.py @@ -585,9 +585,17 @@ async def send_request_info_response(self, request_id: str, response: Any) -> No # Validate response type if specified if event.response_type and not is_instance_of(response, event.response_type): + # response_type may be a union/generic (e.g. int | str), which has no usable + # __name__ on Python 3.10/3.11 (AttributeError) and only yields "Union" on 3.12+. + # Use the readable repr for anything that isn't a plain class. + expected = ( + event.response_type.__name__ + if isinstance(event.response_type, type) + else str(event.response_type) + ) raise TypeError( f"Response type mismatch for request_id {request_id}: " - f"expected {event.response_type.__name__}, got {type(response).__name__}" + f"expected {expected}, got {type(response).__name__}" ) source_executor_id = event.source_executor_id diff --git a/python/packages/core/tests/workflow/test_request_info_event_rehydrate.py b/python/packages/core/tests/workflow/test_request_info_event_rehydrate.py index 1be0a75f58e..88cb3dd7049 100644 --- a/python/packages/core/tests/workflow/test_request_info_event_rehydrate.py +++ b/python/packages/core/tests/workflow/test_request_info_event_rehydrate.py @@ -532,3 +532,24 @@ async def test_apply_checkpoint_preserves_streaming_flag() -> None: await target.apply_checkpoint(checkpoint) assert target.is_streaming() is True + + +async def test_send_request_info_response_union_type_mismatch_message() -> None: + """A union response_type must produce a readable TypeError, not crash on __name__. + + ``types.UnionType`` (e.g. ``int | str``) has no ``__name__`` on Python 3.10/3.11 + (AttributeError) and only yields the unhelpful ``"Union"`` on 3.12+. The mismatch + message should name the union itself. + """ + event = WorkflowEvent.request_info( + request_id="union-req", + source_executor_id="gateway", + request_data=MockRequest(), + response_type=int | str, + ) + + runner_context = InProcRunnerContext(InMemoryCheckpointStorage()) + await runner_context.add_request_info_event(event) + + with pytest.raises(TypeError, match=r"expected int \| str, got float"): + await runner_context.send_request_info_response("union-req", 3.14)