Action confirmations ↗
noOriginal Documentation
Supported in ADKPython v1.14.0Go v0.3.0Experimental
Some agent workflows require confirmation for decision making, verification, security, or general oversight. In these cases, you want to get a response from a human or supervising system before proceeding with a workflow. The Tool Confirmation feature in the Agent Development Kit (ADK) allows an ADK Tool to pause its execution and interact with a user or other system for confirmation or to gather structured data before proceeding. You can use Tool Confirmation with an ADK Tool in the following ways:
- Boolean Confirmation: You can configure a tool with a confirmation flag or provider. This option pauses the tool for a yes or no confirmation response.
- Advanced Confirmation: For scenarios requiring structured data responses, you can configure a tool with a text prompt to explain the confirmation and an expected response.
Experimental
The Tool Confirmation feature is experimental and has some known limitations. We welcome your feedback!
You can configure how a request is communicated to a user, and the system can also use remote responses sent via the ADK server’s REST API. When using the confirmation feature with the ADK web user interface, the agent workflow displays a dialog box to the user to request input, as shown in Figure 1:
Figure 1. Example confirmation response request dialog box using an advanced, tool response implementation.
The following sections describe how to use this feature for the confirmation scenarios. For a complete code sample, see the human_tool_confirmation example. There are additional ways to incorporate human input into your agent workflow, for more details, see the Human-in-the-loop agent pattern.
Boolean confirmation#
When your tool only requires a simple yes or no from the user, you can append a confirmation step using the FunctionTool class as a wrapper. For example, if you have a tool called reimburse, you can enable a confirmation step by wrapping it with the FunctionTool class and setting the require_confirmation parameter to True, as shown in the following example:
root_agent = Agent(
# ...
tools = [
# Set require_confirmation to True to require user confirmation
# for the tool call.
FunctionTool(reimburse, require_confirmation=True),
],
# ...
)
# This implementation method requires minimal code, but is limited to simple
# approvals from the user or confirming system. For a complete example of this
# approach, see the following code sample for a more detailed example:
# https://github.com/google/adk-python/blob/main/contributing/samples/human_tool_confirmation/agent.pyreimburseTool, _ := functiontool.New(functiontool.Config{
Name: "reimburse",
Description: "Reimburse an amount",
// Set RequireConfirmation to true to require user confirmation
// for the tool call.
RequireConfirmation: true,
}, func(ctx tool.Context, args ReimburseArgs) (ReimburseResult, error) {
// actual implementation
return ReimburseResult{Status: "ok"}, nil
})
rootAgent, _ := llmagent.New(llmagent.Config{
// ...
Tools: []tool.Tool{reimburseTool},
})LlmAgent rootAgent = LlmAgent.builder()
// ...
.tools(
// Set requireConfirmation to true to require user confirmation
// for the tool call.
FunctionTool.create(myClassInstance, "reimburse", true)
)
// ...
.build();Require confirmation function#
You can modify the behavior of the confirmation requirement by using a function that returns a boolean response based on the tool’s input.
async def confirmation_threshold(
amount: int, tool_context: ToolContext
) -> bool:
"""Returns true if the amount is greater than 1000."""
return amount > 1000
root_agent = Agent(
# ...
tools = [
# Pass the threshold function to dynamically require confirmation
FunctionTool(reimburse, require_confirmation=confirmation_threshold),
],
# ...
)reimburseTool, _ := functiontool.New(functiontool.Config{
Name: "reimburse",
Description: "Reimburse an amount",
// RequireConfirmationProvider allows for dynamic determination
// of whether user confirmation is needed.
RequireConfirmationProvider: func(args ReimburseArgs) bool {
return args.Amount > 1000
},
}, func(ctx tool.Context, args ReimburseArgs) (ReimburseResult, error) {
// actual implementation
return ReimburseResult{Status: "ok"}, nil
})// In ADK Java, dynamic threshold confirmation logic is evaluated directly
// inside the tool logic using the ToolContext rather than via a lambda parameter.
public Map<String, Object> reimburse(
@Schema(name="amount") int amount, ToolContext toolContext) {
// 1. Dynamic threshold check
if (amount > 1000) {
Optional<ToolConfirmation> toolConfirmation = toolContext.toolConfirmation();
if (toolConfirmation.isEmpty()) {
toolContext.requestConfirmation("Amount > 1000 requires approval.");
return Map.of("status", "Pending manager approval.");
} else if (!toolConfirmation.get().confirmed()) {
return Map.of("status", "Reimbursement rejected.");
}
}
// 2. Proceed with actual tool logic
return Map.of("status", "ok", "reimbursedAmount", amount);
}
LlmAgent rootAgent = LlmAgent.builder()
// ...
.tools(
// No requireConfirmation flag is set because the custom threshold
// logic is already handled inside the method!
FunctionTool.create(this, "reimburse")
)
// ...
.build();Advanced confirmation#
When a tool confirmation requires more details for the user or a more complex response, use a tool_confirmation implementation. This approach extends the ToolContext object to add a text description of the request for the user and allows for more complex response data. When implementing tool confirmation this way, you can pause a tool’s execution, request specific information, and then resume the tool with the provided data.
This confirmation flow has a request stage where the system assembles and sends an input request human response, and a response stage where the system receives and processes the returned data.
Confirmation definition#
When creating a Tool with advanced confirmation, use the Tool Context Request Confirmation method with hint and payload parameters:
hint: Descriptive message that explains what is needed from the user.payload: The structure of the data you expect in return. This must be serializable into a JSON-formatted string.
For a complete example of this approach, see the human_tool_confirmation code sample. Keep in mind that the agent workflow tool execution pauses while a confirmation is obtained. After confirmation is received, you can access the confirmation response in the tool_confirmation.payload object and then proceed with the execution of the workflow.
The following code shows an example implementation for a tool that processes time off requests for an employee:
def request_time_off(days: int, tool_context: ToolContext):
"""Request day off for the employee."""
# ...
tool_confirmation = tool_context.tool_confirmation
if not tool_confirmation:
tool_context.request_confirmation(
hint=(
'Please approve or reject the tool call request_time_off() by'
' responding with a FunctionResponse with an expected'
' ToolConfirmation payload.'
),
payload={
'approved_days': 0,
},
)
# Return intermediate status indicating that the tool is waiting for
# a confirmation response:
return {'status': 'Manager approval is required.'}
approved_days = tool_confirmation.payload['approved_days']
approved_days = min(approved_days, days)
if approved_days == 0:
return {'status': 'The time off request is rejected.', 'approved_days': 0}
return {
'status': 'ok',
'approved_days': approved_days,
}func requestTimeOff(ctx tool.Context, args RequestTimeOffArgs) (map[string]any, error) {
confirmation := ctx.ToolConfirmation()
if confirmation == nil {
ctx.RequestConfirmation(
"Please approve or reject the tool call requestTimeOff() by "+
"responding with a FunctionResponse with an expected "+
"ToolConfirmation payload.",
map[string]any{"approved_days": 0},
)
return map[string]any{"status": "Manager approval is required."}, nil
}
payload := confirmation.Payload.(map[string]any)
// Values in map[string]any from JSON are float64 by default in Go
approvedDays := int(payload["approved_days"].(float64))
approvedDays = min(approvedDays, args.Days)
if approvedDays == 0 {
return map[string]any{"status": "The time off request is rejected.", "approved_days": 0}, nil
}
return map[string]any{
"status": "ok",
"approved_days": approvedDays,
}, nil
}public Map<String, Object> requestTimeOff(
@Schema(name="days") int days,
ToolContext toolContext) {
// Request day off for the employee.
// ...
Optional<ToolConfirmation> toolConfirmation = toolContext.toolConfirmation();
if (toolConfirmation.isEmpty()) {
toolContext.requestConfirmation(
"Please approve or reject the tool call requestTimeOff() by " +
"responding with a FunctionResponse with an expected " +
"ToolConfirmation payload.",
Map.of("approved_days", 0)
);
// Return intermediate status indicating that the tool is waiting for
// a confirmation response:
return Map.of("status", "Manager approval is required.");
}
Map<String, Object> payload = (Map<String, Object>) toolConfirmation.get().payload();
int approvedDays = (int) payload.get("approved_days");
approvedDays = Math.min(approvedDays, days);
if (approvedDays == 0) {
return Map.of("status", "The time off request is rejected.", "approved_days", 0);
}
return Map.of(
"status", "ok",
"approved_days", approvedDays
);
}Remote confirmation with REST API#
If there is no active user interface for a human confirmation of an agent workflow, you can handle the confirmation through a command-line interface or by routing it through another channel like email or a chat application. To confirm the tool call, the user or calling application needs to send a FunctionResponse event with the tool confirmation data.
You can send the request to the ADK API server’s /run or /run_sse endpoint, or directly to the ADK runner. The following example uses a curl command to send the confirmation to the /run_sse endpoint:
curl -X POST http://localhost:8000/run_sse \
-H "Content-Type: application/json" \
-d '{
"app_name": "human_tool_confirmation",
"user_id": "user",
"session_id": "7828f575-2402-489f-8079-74ea95b6a300",
"new_message": {
"parts": [
{
"function_response": {
"id": "adk-13b84a8c-c95c-4d66-b006-d72b30447e35",
"name": "adk_request_confirmation",
"response": {
"confirmed": true,
"payload": {
"approved_days": 5
}
}
}
}
],
"role": "user"
}
}'A REST-based response for a confirmation must meet the following requirements:
The
idin thefunction_responseshould match thefunction_call_idfrom theadk_request_confirmationFunctionCallevent.The
nameshould beadk_request_confirmation.The
responseobject contains theconfirmedstatus and any additionalpayloaddata.Note: Confirmation with Resume feature
If your ADK agent workflow is configured with the Resume feature, you also must include the Invocation ID (
invocation_id) parameter with the confirmation response. The Invocation ID you provide must be the same invocation that generated the confirmation request, otherwise the system starts a new invocation with the confirmation response. If your agent uses the Resume feature, consider including the Invocation ID as a parameter with your confirmation request, so it can be included with the response. For more details on using the Resume feature, see Resume stopped agents.
Known limitations#
The tool confirmation feature has the following limitations:
- DatabaseSessionService is not supported by this feature.
- VertexAiSessionService is not supported by this feature.
Next steps#
For more information on building ADK tools for agent workflows, see Function tools.