@@ -205,6 +205,100 @@ async def test_workflow_pause_and_resume_task_mode(
205205 assert any ('LLM response after tool in task mode' in t for t in content_texts )
206206
207207
208+ @pytest .mark .asyncio
209+ async def test_workflow_pause_and_resume_tool_confirmation (
210+ request : pytest .FixtureRequest ,
211+ ):
212+ """Tests that a workflow can pause and resume with a tool requiring confirmation.
213+
214+ Setup: Workflow with a single LlmAgent node having a tool requiring confirmation.
215+ Act:
216+ - Run 1: Start workflow, tool requests confirmation.
217+ - Run 2: Send confirmation response.
218+ Assert:
219+ - Run 1: Workflow pauses and yields confirmation request.
220+ - Run 2: Workflow resumes and completes with LLM response.
221+ """
222+ from google .adk .tools .function_tool import FunctionTool
223+ from google .adk .flows .llm_flows .functions import REQUEST_CONFIRMATION_FUNCTION_CALL_NAME
224+
225+ # Given a tool that requires confirmation and a mock model
226+ def _simple_tool_func ():
227+ return {"result" : "tool executed" }
228+
229+ mock_model = testing_utils .MockModel .create (
230+ responses = [
231+ types .Part .from_function_call (
232+ name = '_simple_tool_func' ,
233+ args = {},
234+ ),
235+ types .Part .from_text (text = 'LLM response after confirmation' ),
236+ ]
237+ )
238+
239+ node_a = LlmAgent (
240+ name = 'my_agent' ,
241+ model = mock_model ,
242+ tools = [FunctionTool (func = _simple_tool_func , require_confirmation = True )],
243+ )
244+
245+ wf = Workflow (
246+ name = 'test_workflow_confirmation' ,
247+ edges = [(START , node_a )],
248+ )
249+
250+ app = App (
251+ name = request .function .__name__ ,
252+ root_agent = wf ,
253+ )
254+ runner = testing_utils .InMemoryRunner (app = app )
255+
256+ # When the workflow is started
257+ user_event = testing_utils .get_user_content ('start workflow' )
258+ events1 = await runner .run_async (user_event )
259+
260+ # Then it should request confirmation
261+ fc_event = None
262+ for e in events1 :
263+ if e .content and e .content .parts :
264+ for p in e .content .parts :
265+ if p .function_call and p .function_call .name == REQUEST_CONFIRMATION_FUNCTION_CALL_NAME :
266+ fc_event = e
267+ break
268+
269+ assert fc_event is not None , "Did not find confirmation request event"
270+
271+ ask_for_confirmation_function_call_id = fc_event .content .parts [0 ].function_call .id
272+ invocation_id = events1 [0 ].invocation_id
273+
274+ # When the user confirms the tool call
275+ user_confirmation = testing_utils .UserContent (
276+ types .Part (
277+ function_response = types .FunctionResponse (
278+ id = ask_for_confirmation_function_call_id ,
279+ name = REQUEST_CONFIRMATION_FUNCTION_CALL_NAME ,
280+ response = {"confirmed" : True },
281+ )
282+ )
283+ )
284+
285+ events2 = await runner .run_async (
286+ new_message = user_confirmation ,
287+ invocation_id = invocation_id ,
288+ )
289+
290+ # Then the workflow completes with the LLM response
291+ content_texts = [
292+ p .text
293+ for e in events2
294+ if e .content and e .content .parts
295+ for p in e .content .parts
296+ if p .text
297+ ]
298+
299+ assert any ('LLM response after confirmation' in t for t in content_texts )
300+
301+
208302@pytest .mark .asyncio
209303async def test_workflow_pause_and_resume_parent_interruption (
210304 request : pytest .FixtureRequest ,
0 commit comments