Fix greptile review

This commit is contained in:
Sameer Kankute 2026-04-27 17:46:45 +05:30
parent 7882f8072f
commit c6a51d031f
No known key found for this signature in database
4 changed files with 98 additions and 2 deletions

View file

@ -667,6 +667,8 @@ class GeminiRealtimeConfig(BaseRealtimeConfig):
def transform_tool_call_events(
self,
tool_call_message: dict,
response_id: Optional[str] = None,
output_item_id: Optional[str] = None,
) -> List[Dict[str, Any]]:
"""
Transform Gemini toolCall message to OpenAI function call events.
@ -674,6 +676,8 @@ class GeminiRealtimeConfig(BaseRealtimeConfig):
Converts Gemini's functionCalls format to OpenAI's response.function_call_arguments.done events.
"""
function_calls = tool_call_message.get("functionCalls", [])
resolved_response_id = response_id or f"resp_{uuid.uuid4()}"
resolved_output_item_id = output_item_id or f"item_{uuid.uuid4()}"
verbose_logger.debug(
f"Gemini Realtime: Transforming {len(function_calls)} tool call(s) to OpenAI format"
@ -683,11 +687,14 @@ class GeminiRealtimeConfig(BaseRealtimeConfig):
{
"type": "response.function_call_arguments.done",
"event_id": f"event_{uuid.uuid4()}",
"response_id": resolved_response_id,
"item_id": resolved_output_item_id,
"output_index": idx,
"call_id": fc.get("id", ""),
"name": fc.get("name", ""),
"arguments": json.dumps(fc.get("args", {})),
}
for fc in function_calls
for idx, fc in enumerate(function_calls)
]
@staticmethod
@ -1067,7 +1074,11 @@ class GeminiRealtimeConfig(BaseRealtimeConfig):
returned_message.append(transformed_message)
elif openai_event == ResponsesAPIStreamEvents.FUNCTION_CALL_ARGUMENTS_DONE:
# Handle toolCall from Gemini
tool_call_events = self.transform_tool_call_events(value)
tool_call_events = self.transform_tool_call_events(
value,
response_id=current_response_id,
output_item_id=current_output_item_id,
)
returned_message.extend(tool_call_events)
elif openai_event == OpenAIRealtimeEventTypes.RESPONSE_DONE:
transformed_response_done_event = self.transform_response_done_event(

View file

@ -254,6 +254,50 @@ async def test_transcription_captured_in_backend_to_client():
assert logging_obj.model_call_details["messages"] == streaming.input_messages
@pytest.mark.asyncio
async def test_client_ack_caches_setup_to_prevent_duplicate_session_update_setup():
websocket = MagicMock()
backend_ws = MagicMock()
logging_obj = MagicMock()
logging_obj.pre_call = MagicMock()
# Two session.update messages arrive before setupComplete round-trip.
websocket.receive_text = AsyncMock(
side_effect=[
json.dumps({"type": "session.update", "session": {"tools": []}}),
json.dumps({"type": "session.update", "session": {"tools": []}}),
Exception("client done"),
]
)
provider_config = MagicMock()
def _transform(message: str, model: str, session_configuration_request=None):
if session_configuration_request is None:
return [json.dumps({"setup": {"model": "models/gemini-2.5-flash"}})]
return []
provider_config.transform_realtime_request = MagicMock(side_effect=_transform)
backend_ws.send = AsyncMock()
streaming = RealTimeStreaming(
websocket=websocket,
backend_ws=backend_ws,
logging_obj=logging_obj,
provider_config=provider_config,
model="gemini-2.5-flash",
)
await streaming.client_ack_messages()
# Setup should be forwarded exactly once even with repeated session.update.
assert backend_ws.send.await_count == 1
assert streaming.session_configuration_request is not None
sent_payload = json.loads(backend_ws.send.await_args_list[0].args[0])
assert "setup" in sent_payload
def test_collect_session_tools_from_session_update():
"""
Test that tools from session.update events are collected.

View file

@ -297,6 +297,9 @@ def test_gemini_realtime_tool_call_transformation():
assert function_call_event is not None, "Expected function_call_arguments.done event"
assert function_call_event["call_id"] == "call_123"
assert function_call_event["name"] == "get_weather"
assert function_call_event["response_id"] == "resp_123"
assert function_call_event["item_id"] == "item_123"
assert function_call_event["output_index"] == 0
# Verify arguments are properly serialized as JSON string
args = json.loads(function_call_event["arguments"])
@ -454,3 +457,18 @@ def test_gemini_realtime_user_text_transformation():
assert len(turn["parts"]) == 1
assert turn["parts"][0]["text"] == "What's the weather in London?"
assert client_content["turnComplete"] is True
def test_return_new_content_delta_events_without_session_config_does_not_error():
config = GeminiRealtimeConfig()
events = config.return_new_content_delta_events(
response_id="resp_1",
output_item_id="item_1",
conversation_id="conv_1",
delta_type="text",
session_configuration_request=None,
)
assert len(events) >= 1
assert events[0]["type"] == "response.created"

View file

@ -97,6 +97,29 @@ def test_vertex_requires_session_configuration_feature_flag(monkeypatch):
assert cfg.requires_session_configuration() is False
def test_vertex_session_update_defaults_to_audio_modality():
cfg = VertexAIRealtimeConfig(
access_token="tok", project="my-proj", location="us-central1"
)
session_update = {
"type": "session.update",
"session": {
"instructions": "You are a helpful assistant.",
# No modalities provided on purpose
},
}
messages = cfg.transform_realtime_request(
json.dumps(session_update),
"gemini-live-2.5-flash-native-audio",
session_configuration_request=None,
)
assert len(messages) == 1
setup_payload = json.loads(messages[0])["setup"]
assert setup_payload["generationConfig"]["responseModalities"] == ["AUDIO"]
# ---------------------------------------------------------------------------
# Round-trip test: text-in / text-out via RealTimeStreaming
# ---------------------------------------------------------------------------