@@ -587,3 +587,108 @@ async def test_request_confirmation_processor_dynamic_success():
587587 assert (
588588 args [4 ][MOCK_FUNCTION_CALL_ID ] == user_confirmation
589589 ) # tool_confirmation_dict
590+
591+
592+ @pytest .mark .parametrize (
593+ "tools, original_args, confirmation_args, expected_exception_match" ,
594+ [
595+ (
596+ [],
597+ {"param1" : "test" },
598+ {"param1" : "test" },
599+ "is not registered" ,
600+ ),
601+ (
602+ [FunctionTool (mock_tool , require_confirmation = False )],
603+ {"param1" : "test" },
604+ {"param1" : "test" },
605+ "does not require confirmation" ,
606+ ),
607+ (
608+ [FunctionTool (mock_tool , require_confirmation = True )],
609+ {"param1" : "test" },
610+ {"param1" : "tampered" },
611+ "arguments mismatch" ,
612+ ),
613+ ],
614+ )
615+ @pytest .mark .asyncio
616+ async def test_request_confirmation_processor_rejections (
617+ tools , original_args , confirmation_args , expected_exception_match
618+ ):
619+ """Test various validation rejections in request confirmation processor."""
620+ agent = LlmAgent (name = "test_agent" , tools = tools )
621+ invocation_context = await testing_utils .create_invocation_context (
622+ agent = agent
623+ )
624+ llm_request = LlmRequest ()
625+
626+ original_function_call = types .FunctionCall (
627+ name = MOCK_TOOL_NAME , args = original_args , id = MOCK_FUNCTION_CALL_ID
628+ )
629+
630+ # 1. Event with the original tool call
631+ invocation_context .session .events .append (
632+ Event (
633+ author = agent .name ,
634+ content = types .Content (
635+ parts = [types .Part (function_call = original_function_call )]
636+ ),
637+ )
638+ )
639+
640+ # 2. Confirmation request event from the agent to the client.
641+ confirmation_function_call = types .FunctionCall (
642+ name = MOCK_TOOL_NAME , args = confirmation_args , id = MOCK_FUNCTION_CALL_ID
643+ )
644+ tool_confirmation = ToolConfirmation (confirmed = False , hint = "test hint" )
645+ tool_confirmation_args = {
646+ "originalFunctionCall" : confirmation_function_call .model_dump (
647+ exclude_none = True , by_alias = True
648+ ),
649+ "toolConfirmation" : tool_confirmation .model_dump (
650+ by_alias = True , exclude_none = True
651+ ),
652+ }
653+
654+ invocation_context .session .events .append (
655+ Event (
656+ author = agent .name ,
657+ content = types .Content (
658+ parts = [
659+ types .Part (
660+ function_call = types .FunctionCall (
661+ name = functions .REQUEST_CONFIRMATION_FUNCTION_CALL_NAME ,
662+ args = tool_confirmation_args ,
663+ id = MOCK_CONFIRMATION_FUNCTION_CALL_ID ,
664+ )
665+ )
666+ ]
667+ ),
668+ )
669+ )
670+
671+ # 3. Event with the user's confirmation response.
672+ user_confirmation = ToolConfirmation (confirmed = True )
673+ invocation_context .session .events .append (
674+ Event (
675+ author = "user" ,
676+ content = types .Content (
677+ parts = [
678+ types .Part (
679+ function_response = types .FunctionResponse (
680+ name = functions .REQUEST_CONFIRMATION_FUNCTION_CALL_NAME ,
681+ id = MOCK_CONFIRMATION_FUNCTION_CALL_ID ,
682+ response = {
683+ "response" : user_confirmation .model_dump_json ()
684+ },
685+ )
686+ )
687+ ]
688+ ),
689+ )
690+ )
691+
692+ with pytest .raises (ValueError , match = expected_exception_match ):
693+ async for _ in request_processor .run_async (invocation_context , llm_request ):
694+ pass
0 commit comments