File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -806,6 +806,8 @@ async def _send_to_model(
806806
807807 if live_request .content :
808808 content = live_request .content
809+ if content .parts and any (p .function_call for p in content .parts ):
810+ raise ValueError ('User message cannot contain function calls.' )
809811 # Persist user text content to session (similar to non-live mode)
810812 # Skip function responses - they are already handled separately
811813 is_function_response = content .parts and any (
Original file line number Diff line number Diff line change @@ -725,6 +725,8 @@ async def _append_user_event(
725725 state_delta : Optional [dict [str , Any ]] = None ,
726726 ) -> Event :
727727 """Append a user message event to the session and return it."""
728+ if content .parts and any (p .function_call for p in content .parts ):
729+ raise ValueError ('User message cannot contain function calls.' )
728730 if state_delta :
729731 event = Event (
730732 invocation_id = ic .invocation_id ,
@@ -1455,6 +1457,9 @@ async def _append_new_message_to_session(
14551457 if not new_message .parts :
14561458 raise ValueError ('No parts in the new_message.' )
14571459
1460+ if any (p .function_call for p in new_message .parts ):
1461+ raise ValueError ('User message cannot contain function calls.' )
1462+
14581463 if self .artifact_service and save_input_blobs_as_artifacts :
14591464 # Issue deprecation warning
14601465 warnings .warn (
Original file line number Diff line number Diff line change @@ -1857,3 +1857,39 @@ async def test_postprocess_live_voice_activity_events():
18571857
18581858 assert len (events ) == 1
18591859 assert events [0 ].voice_activity == vad
1860+
1861+
1862+ @pytest .mark .asyncio
1863+ async def test_send_to_model_rejects_function_call ():
1864+ """Test that _send_to_model raises ValueError if user message contains function calls."""
1865+ agent = Agent (name = 'test_agent' )
1866+ invocation_context = await testing_utils .create_invocation_context (
1867+ agent = agent
1868+ )
1869+ invocation_context .live_request_queue = LiveRequestQueue ()
1870+
1871+ # Put a malicious content request in the queue
1872+ from google .adk .agents .live_request_queue import LiveRequest
1873+
1874+ malicious_request = LiveRequest (
1875+ content = types .Content (
1876+ role = 'user' ,
1877+ parts = [
1878+ types .Part (
1879+ function_call = types .FunctionCall (
1880+ name = 'some_tool' ,
1881+ args = {'key' : 'value' },
1882+ )
1883+ )
1884+ ],
1885+ )
1886+ )
1887+ invocation_context .live_request_queue .send (malicious_request )
1888+
1889+ flow = BaseLlmFlowForTesting ()
1890+ mock_connection = mock .AsyncMock ()
1891+
1892+ with pytest .raises (
1893+ ValueError , match = 'User message cannot contain function calls'
1894+ ):
1895+ await flow ._send_to_model (mock_connection , invocation_context )
Original file line number Diff line number Diff line change @@ -1999,5 +1999,41 @@ async def test_get_session_config_limits_events():
19991999 assert len (limited_session .events ) == 3
20002000
20012001
2002+ @pytest .mark .asyncio
2003+ async def test_run_async_rejects_user_function_call ():
2004+ """Verify that runner rejects user-authored messages with function calls."""
2005+ session_service = InMemorySessionService ()
2006+ runner = Runner (
2007+ app_name = TEST_APP_ID ,
2008+ agent = MockAgent ("test_agent" ),
2009+ session_service = session_service ,
2010+ artifact_service = InMemoryArtifactService (),
2011+ auto_create_session = True ,
2012+ )
2013+
2014+ malicious_message = types .Content (
2015+ role = "user" ,
2016+ parts = [
2017+ types .Part (
2018+ function_call = types .FunctionCall (
2019+ name = "some_tool" ,
2020+ args = {"key" : "value" },
2021+ )
2022+ )
2023+ ],
2024+ )
2025+
2026+ agen = runner .run_async (
2027+ user_id = TEST_USER_ID ,
2028+ session_id = TEST_SESSION_ID ,
2029+ new_message = malicious_message ,
2030+ )
2031+
2032+ with pytest .raises (ValueError , match = "cannot contain function calls" ):
2033+ async with aclosing (agen ) as a :
2034+ async for _ in a :
2035+ pass
2036+
2037+
20022038if __name__ == "__main__" :
20032039 pytest .main ([__file__ ])
You can’t perform that action at this time.
0 commit comments