Principle:Microsoft Agent framework Tool Approval Configuration
| Knowledge Sources | |
|---|---|
| Domains | Agent_Architecture, Safety |
| Last Updated | 2026-02-11 17:00 GMT |
Overview
A configuration pattern for controlling whether LLM-initiated tool calls require explicit human approval before execution, enabling human-in-the-loop safety workflows within the Microsoft Agent Framework.
Description
Tool Approval Configuration addresses the critical safety requirement of keeping a human in the loop when an AI agent invokes tools that have real-world side effects. By default, the agent framework auto-executes tool calls as the LLM requests them. The approval_mode parameter on the @tool decorator changes this behavior: when set to "always_require", the agent pauses its execution loop and emits a function_approval_request event instead of immediately invoking the tool. The human operator (or an external approval system) must then approve or reject the call before the agent proceeds.
This pattern separates the policy decision (should this tool require approval?) from the mechanism (how approval is collected), allowing developers to declare approval requirements at tool-definition time while deferring the approval UX to the agent runtime or host application.
Usage
Use this principle when registering tools that perform destructive, irreversible, or sensitive operations such as deleting records, sending emails, executing financial transactions, or modifying infrastructure. Apply approval_mode="always_require" to any tool where unsupervised execution poses a risk. Leave approval_mode unset or set to "never_require" for read-only or idempotent tools where automatic execution is acceptable.
Theoretical Basis
The Tool Approval Configuration pattern implements the Gate Pattern from safety engineering, where a checkpoint is inserted into an automated pipeline to require explicit authorization before a high-consequence action proceeds. In the context of agentic AI systems, this maps to the human-in-the-loop paradigm:
- The LLM generates a tool call request based on the user's query and available tool schemas.
- The agent runtime inspects the tool's
approval_modesetting. - If
approval_mode="always_require", the runtime emits afunction_approval_requestcontaining the tool name, arguments, and context. - Execution is suspended until an external signal (approval or rejection) is received.
- On approval, the tool executes normally and its result is fed back to the LLM. On rejection, the agent receives a rejection signal and can inform the user or take an alternative path.
# Conceptual flow (pseudocode)
tool_call = llm_response.tool_calls[0]
tool_def = registry.get(tool_call.name)
if tool_def.approval_mode == "always_require":
emit(function_approval_request(tool_call))
decision = await wait_for_approval()
if decision == "rejected":
return rejection_response()
# Proceed with tool execution
result = await tool_def.invoke(tool_call.arguments)
This design follows the Principle of Least Authority by not granting the LLM unconditional execution rights over sensitive tools, and the Strategy Pattern by allowing the approval policy to be configured per-tool at decoration time.
I/O Contract
Configuration Inputs
| Parameter | Type | Required | Description |
|---|---|---|---|
| approval_mode | None | No | Controls whether tool invocation requires human approval. When "always_require", the agent pauses and emits a function_approval_request. When "never_require" or None, the tool auto-executes.
|
Runtime Outputs
| Output | Type | Description |
|---|---|---|
| function_approval_request | Event | Emitted when a tool with approval_mode="always_require" is called by the LLM. Contains the tool name, arguments, and invocation context for human review.
|
Usage Examples
Requiring Approval for a Destructive Tool
from agent_framework import Agent, tool
@tool(approval_mode="always_require")
def delete_record(record_id: str) -> str:
"""Delete a database record permanently."""
return f"Deleted {record_id}"
agent = Agent(
client=client,
name="DataManager",
tools=[delete_record],
)
Mixing Approved and Auto-Executed Tools
from agent_framework import Agent, tool
@tool(approval_mode="always_require")
def send_email(to: str, subject: str, body: str) -> str:
"""Send an email to a recipient."""
return f"Sent email to {to}"
@tool(approval_mode="never_require")
def lookup_contact(name: str) -> str:
"""Look up a contact's email address. Read-only, safe to auto-execute."""
return f"{name.lower()}@example.com"
agent = Agent(
client=client,
name="EmailAssistant",
tools=[send_email, lookup_contact],
)
In this configuration, the agent will auto-execute lookup_contact but pause and request human approval before executing send_email.
Related Pages
Implemented By
- Implementation:Microsoft_Agent_framework_Tool_Decorator_With_Approval
- Heuristic:Microsoft_Agent_framework_Tool_Approval_Mode_Production
Sources
| Type | Name | URL |
|---|---|---|
| Repo | Microsoft Agent Framework | https://github.com/microsoft/agent-framework |