11#!/usr/bin/env python
22"""Comprehensive tests for EventTranslator, focusing on untested paths."""
33
4+ import json
5+ from dataclasses import asdict , dataclass
6+ from types import SimpleNamespace
7+
48import pytest
59import uuid
610from unittest .mock import MagicMock , patch , AsyncMock
711
812from ag_ui .core import (
913 EventType , TextMessageStartEvent , TextMessageContentEvent , TextMessageEndEvent ,
10- ToolCallStartEvent , ToolCallArgsEvent , ToolCallEndEvent , StateDeltaEvent , CustomEvent
14+ ToolCallStartEvent , ToolCallArgsEvent , ToolCallEndEvent , ToolCallResultEvent ,
15+ StateDeltaEvent , CustomEvent
1116)
1217from google .adk .events import Event as ADKEvent
1318from ag_ui_adk .event_translator import EventTranslator
@@ -109,15 +114,68 @@ async def test_translate_function_calls_detection(self, translator, mock_adk_eve
109114 async def test_translate_function_responses_handling (self , translator , mock_adk_event ):
110115 """Test function responses handling."""
111116 # Mock event with function responses
112- mock_function_response = MagicMock ()
113- mock_adk_event .get_function_responses = MagicMock (return_value = [mock_function_response ])
117+ function_response = SimpleNamespace (id = "tool-1" , response = {"ok" : True })
118+ mock_adk_event .get_function_calls = MagicMock (return_value = [])
119+ mock_adk_event .get_function_responses = MagicMock (return_value = [function_response ])
114120
115121 events = []
116122 async for event in translator .translate (mock_adk_event , "thread_1" , "run_1" ):
117123 events .append (event )
118124
119- # Function responses should be handled but not emit events
120- assert len (events ) == 0
125+ assert len (events ) == 1
126+ event = events [0 ]
127+ assert isinstance (event , ToolCallResultEvent )
128+ assert json .loads (event .content ) == {"ok" : True }
129+
130+ @pytest .mark .asyncio
131+ async def test_translate_function_response_with_call_tool_result_payload (self , translator ):
132+ """Ensure complex CallToolResult payloads are serialized correctly."""
133+
134+ @dataclass
135+ class TextContent :
136+ type : str = "text"
137+ text : str = ""
138+ annotations : list | None = None
139+ meta : dict | None = None
140+
141+ @dataclass
142+ class CallToolResult :
143+ meta : dict | None
144+ structuredContent : dict | None
145+ isError : bool
146+ content : list [TextContent ]
147+
148+ repeated_text_entries = [
149+ "Primary Task: Provide a detailed walkthrough for the requested topic." ,
150+ "Primary Task: Provide a detailed walkthrough for the requested topic." ,
151+ "Constraints: Ensure clarity and maintain a concise explanation." ,
152+ "Constraints: Ensure clarity and maintain a concise explanation." ,
153+ ]
154+
155+ payload = CallToolResult (
156+ meta = None ,
157+ structuredContent = None ,
158+ isError = False ,
159+ content = [TextContent (text = text ) for text in repeated_text_entries ],
160+ )
161+
162+ function_response = SimpleNamespace (
163+ id = "tool-structured-1" ,
164+ response = {"result" : payload },
165+ )
166+
167+ events = []
168+ async for event in translator ._translate_function_response ([function_response ]):
169+ events .append (event )
170+
171+ assert len (events ) == 1
172+ event = events [0 ]
173+ assert isinstance (event , ToolCallResultEvent )
174+
175+ content = json .loads (event .content )
176+ assert content ["result" ]["isError" ] is False
177+ assert content ["result" ]["structuredContent" ] is None
178+ assert [item ["text" ] for item in content ["result" ]["content" ]] == repeated_text_entries
121179
122180 @pytest .mark .asyncio
123181 async def test_translate_state_delta_event (self , translator , mock_adk_event ):
@@ -781,4 +839,4 @@ async def test_partial_streaming_continuation(self, translator, mock_adk_event_w
781839
782840 # Should reset streaming state
783841 assert translator ._is_streaming is False
784- assert translator ._streaming_message_id is None
842+ assert translator ._streaming_message_id is None
0 commit comments