How to Add User Confirmation to Tool Call Requests#
WayFlow Agents can be equipped with Tools to enhance their capabilities. However, end users may want to confirm or deny tool call requests emitted from the agent.
This guide shows you how to achieve this with the ClientTool.
Basic implementation#
In this example, you will build a simple Agent equipped with three tools:
A tool to add numbers
A tool to subtract numbers
A tool to multiply numbers
This guide requires the use of an LLM. WayFlow supports several LLM API providers. Select an LLM from the options below:
from wayflowcore.models import OCIGenAIModel
if __name__ == "__main__":
llm = OCIGenAIModel(
model_id="provider.model-id",
service_endpoint="https://url-to-service-endpoint.com",
compartment_id="compartment-id",
auth_type="API_KEY",
)
from wayflowcore.models import VllmModel
llm = VllmModel(
model_id="model-id",
host_port="VLLM_HOST_PORT",
)
from wayflowcore.models import OllamaModel
llm = OllamaModel(
model_id="model-id",
)
To learn more about the different LLM providers, read the guide on How to Use LLMs from Different Providers.
Creating the tools#
Sometimes you will want to ask for user confirmation before executing certain tools. To do this you use a ClientTool.
from wayflowcore.tools import ClientTool
add_numbers_tool = ClientTool(
name="add_numbers",
description="Add two numbers",
parameters={
"number1": {"description": "the first number", "type": "number"},
"number2": {"description": "the second number", "type": "number"},
},
output={"type": "number"},
)
subtract_numbers_tool = ClientTool(
name="subtract_numbers",
description="Subtract two numbers",
parameters={
"number1": {"description": "the first number", "type": "number"},
"number2": {"description": "the second number", "type": "number"},
},
output={"type": "number"},
)
multiply_numbers_tool = ClientTool(
name="multiply_numbers",
description="Multiply two numbers",
parameters={
"number1": {"description": "the first number", "type": "number"},
"number2": {"description": "the second number", "type": "number"},
},
output={"type": "number"},
)
Creating the client-side execution logic#
To enable users to accept or deny tool call requests, you add simple validation logic before executing the tools requested by the agent.
from typing import Any, List
from wayflowcore.tools import ToolRequest
def _add_numbers(number1: float, number2: float) -> float:
return number1 + number2
def _subtract_numbers(number1: float, number2: float) -> float:
return number1 - number2
def _multiply_numbers(number1: float, number2: float) -> float:
return number1 * number2
def _ask_for_user_confirmation(tool_request: ToolRequest) -> bool:
import json
message = (
"---\nThe Agent requests the following Tool Call:\n"
f"Name: `{tool_request.name}`\n"
f"Args: {json.dumps(tool_request.args, indent=2)}\n---\n"
f"Do you accept this tool call request? (Y/N)\n"
">>> "
)
while True:
user_response = input(message).strip()
if user_response == "Y":
return True
elif user_response == "N":
return False
print(f"Unrecognized option: `{user_response}`.")
def execute_client_tool_from_tool_request(
tool_request: ToolRequest, tools_requiring_confirmation: List[str]
) -> Any:
if tool_request.name in tools_requiring_confirmation:
is_confirmed = _ask_for_user_confirmation(tool_request)
if not is_confirmed:
return (
f"The user denied the tool request for the tool {tool_request.name} at this time."
)
if tool_request.name == "add_numbers":
return _add_numbers(**tool_request.args)
elif tool_request.name == "subtract_numbers":
return _subtract_numbers(**tool_request.args)
elif tool_request.name == "multiply_numbers":
return _multiply_numbers(**tool_request.args)
else:
raise ValueError(f"Tool name {tool_request.name} is not recognized")
Here, you simply loop until the user answers whether to accept the tool request (with Y
) or reject it (with N
).
Creating the agent#
Finally, you create a simple Agent
to test the execution code written in the previous section.
from wayflowcore.agent import Agent
assistant = Agent(
llm=llm,
tools=[add_numbers_tool, subtract_numbers_tool, multiply_numbers_tool],
custom_instruction="Use the tools at your disposal to answer the user requests.",
)
Running the agent in an execution loop#
Now, you create a simple execution loop to test the agent.
In this loop, you specify that only the subtract_numbers
and multiply_numbers
tools require user confirmation,
while the add_numbers
tool can be executed autonomously by the agent.
from wayflowcore.executors.executionstatus import (
FinishedStatus, UserMessageRequestStatus, ToolRequestStatus
)
from wayflowcore.messagelist import Message, MessageType
from wayflowcore.models import VllmModel
from wayflowcore.tools import ToolResult
TOOLS_REQUIRING_CONFIRMATION = ["subtract_numbers", "multiply_numbers"]
conversation_inputs = {}
conversation = assistant.start_conversation(inputs=conversation_inputs)
while True:
status = conversation.execute()
assistant_reply = conversation.get_last_message()
if assistant_reply:
print(f"Assistant>>> {assistant_reply.content}\n")
if isinstance(status, FinishedStatus):
print(f"Finished assistant execution. Output values:\n{status.output_values}",)
break
elif isinstance(status, UserMessageRequestStatus):
user_input = input("User>>> ")
print("\n")
conversation.append_user_message(user_input)
elif isinstance(status, ToolRequestStatus):
tool_request = status.tool_requests[0]
tool_result = execute_client_tool_from_tool_request(tool_request, TOOLS_REQUIRING_CONFIRMATION)
print(f"{tool_result!r}")
conversation.append_message(
Message(
tool_result=ToolResult(content=tool_result, tool_request_id=tool_request.tool_request_id),
message_type=MessageType.TOOL_RESULT,
)
)
else:
raise ValueError(f"Unsupported execution status: '{status}'")
Recap#
In this guide, you learned how to support client-side confirmation for tool call requests.
Below is the complete code from this guide.
from wayflowcore.tools import ClientTool
add_numbers_tool = ClientTool(
name="add_numbers",
description="Add two numbers",
parameters={
"number1": {"description": "the first number", "type": "number"},
"number2": {"description": "the second number", "type": "number"},
},
output={"type": "number"},
)
subtract_numbers_tool = ClientTool(
name="subtract_numbers",
description="Subtract two numbers",
parameters={
"number1": {"description": "the first number", "type": "number"},
"number2": {"description": "the second number", "type": "number"},
},
output={"type": "number"},
)
multiply_numbers_tool = ClientTool(
name="multiply_numbers",
description="Multiply two numbers",
parameters={
"number1": {"description": "the first number", "type": "number"},
"number2": {"description": "the second number", "type": "number"},
},
output={"type": "number"},
)
from typing import Any, List
from wayflowcore.tools import ToolRequest
def _add_numbers(number1: float, number2: float) -> float:
return number1 + number2
def _subtract_numbers(number1: float, number2: float) -> float:
return number1 - number2
def _multiply_numbers(number1: float, number2: float) -> float:
return number1 * number2
def _ask_for_user_confirmation(tool_request: ToolRequest) -> bool:
import json
message = (
"---\nThe Agent requests the following Tool Call:\n"
f"Name: `{tool_request.name}`\n"
f"Args: {json.dumps(tool_request.args, indent=2)}\n---\n"
f"Do you accept this tool call request? (Y/N)\n"
">>> "
)
while True:
user_response = input(message).strip()
if user_response == "Y":
return True
elif user_response == "N":
return False
print(f"Unrecognized option: `{user_response}`.")
def execute_client_tool_from_tool_request(
tool_request: ToolRequest, tools_requiring_confirmation: List[str]
) -> Any:
if tool_request.name in tools_requiring_confirmation:
is_confirmed = _ask_for_user_confirmation(tool_request)
if not is_confirmed:
return (
f"The user denied the tool request for the tool {tool_request.name} at this time."
)
if tool_request.name == "add_numbers":
return _add_numbers(**tool_request.args)
elif tool_request.name == "subtract_numbers":
return _subtract_numbers(**tool_request.args)
elif tool_request.name == "multiply_numbers":
return _multiply_numbers(**tool_request.args)
else:
raise ValueError(f"Tool name {tool_request.name} is not recognized")
from wayflowcore.agent import Agent
assistant = Agent(
llm=llm,
tools=[add_numbers_tool, subtract_numbers_tool, multiply_numbers_tool],
custom_instruction="Use the tools at your disposal to answer the user requests.",
)
from wayflowcore.executors.executionstatus import (
FinishedStatus, UserMessageRequestStatus, ToolRequestStatus
)
from wayflowcore.messagelist import Message, MessageType
from wayflowcore.models import VllmModel
from wayflowcore.tools import ToolResult
TOOLS_REQUIRING_CONFIRMATION = ["subtract_numbers", "multiply_numbers"]
conversation_inputs = {}
conversation = assistant.start_conversation(inputs=conversation_inputs)
while True:
status = conversation.execute()
assistant_reply = conversation.get_last_message()
if assistant_reply:
print(f"Assistant>>> {assistant_reply.content}\n")
if isinstance(status, FinishedStatus):
print(f"Finished assistant execution. Output values:\n{status.output_values}",)
break
elif isinstance(status, UserMessageRequestStatus):
user_input = input("User>>> ")
print("\n")
conversation.append_user_message(user_input)
elif isinstance(status, ToolRequestStatus):
tool_request = status.tool_requests[0]
tool_result = execute_client_tool_from_tool_request(tool_request, TOOLS_REQUIRING_CONFIRMATION)
print(f"{tool_result!r}")
conversation.append_message(
Message(
tool_result=ToolResult(content=tool_result, tool_request_id=tool_request.tool_request_id),
message_type=MessageType.TOOL_RESULT,
)
)
else:
raise ValueError(f"Unsupported execution status: '{status}'")
Next steps#
Having learned how to add user confirmation for tool calls, you may now proceed to: