Skip to content

Commit 70b533f

Browse files
committed
test(workflow): Verify workflow pause and resume with tool confirmation
Change-Id: I4ddaa58a9344ad22155643e1a0809600e0076386
1 parent ca83818 commit 70b533f

1 file changed

Lines changed: 94 additions & 0 deletions

File tree

tests/unittests/workflow/test_workflow_llm_agent_interruptions.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
209303
async def test_workflow_pause_and_resume_parent_interruption(
210304
request: pytest.FixtureRequest,

0 commit comments

Comments
 (0)