Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Microsoft Agent framework Tool Decorator With Approval

From Leeroopedia
Knowledge Sources
Domains Agent_Architecture, Safety
Last Updated 2026-02-11 17:00 GMT

Overview

The @tool decorator with approval_mode support, used to register Python functions as agent-callable tools while declaring whether each tool invocation requires human approval before execution.

Description

The @tool decorator transforms a standard Python function into an agent-compatible tool definition. When the approval_mode parameter is specified, it attaches approval metadata to the tool so the agent runtime can enforce human-in-the-loop gating at invocation time. The decorator preserves the full @tool signature (name, description, schema overrides) while adding the approval dimension. At runtime, when the LLM issues a call to a tool decorated with approval_mode="always_require", the agent emits a function_approval_request event and suspends execution until the approval decision is received.

Usage

Import the tool decorator from the top-level agent_framework package. Apply it to any function that should be exposed to the LLM as a callable tool. Set approval_mode="always_require" on tools that perform destructive, irreversible, or sensitive operations. Leave approval_mode unset or set to "never_require" for safe, read-only tools.

Code Reference

Source Location

  • Repository: agent-framework
  • File: python/packages/core/agent_framework/_tools.py
  • Lines: L903-1049

Signature

def tool(
    func: Callable[..., Any] | None = None,
    *,
    name: str | None = None,
    description: str | None = None,
    schema: dict[str, Any] | None = None,
    strict: bool | None = None,
    approval_mode: Literal["always_require", "never_require"] | None = None,
) -> Callable[..., Any]:

Import

from agent_framework import tool

I/O Contract

Inputs (Decorator Parameters)

Name Type Required Description
func None No The function to decorate. When None, the decorator is being called with keyword arguments and returns a partial decorator.
name None No Override the tool name exposed to the LLM. Defaults to the function name.
description None No Override the tool description. Defaults to the function's docstring.
schema None No Override the auto-generated JSON schema for the tool's parameters.
strict None No Enable strict schema validation for tool call arguments.
approval_mode None No Controls whether invocation of this tool requires human approval. "always_require" causes the agent to emit a function_approval_request and pause. "never_require" or None allows automatic execution.

Outputs

Name Type Description
decorated_function Callable[..., Any] The original function with attached tool metadata (name, description, schema, approval_mode) accessible by the agent runtime.

Usage Examples

Basic Tool With Approval Required

from typing import Annotated
from agent_framework import tool

@tool(approval_mode="always_require")
def delete_record(record_id: Annotated[str, "Record to delete"]) -> str:
    """Delete a database record."""
    return f"Deleted {record_id}"

When the LLM calls delete_record, the agent runtime will emit a function_approval_request containing the tool name and arguments, and will not execute the function until approval is granted.

Tool Without Approval (Auto-Execute)

from typing import Annotated
from agent_framework import tool

@tool(approval_mode="never_require")
def get_weather(city: Annotated[str, "City name"]) -> str:
    """Get current weather for a city."""
    return f"Weather in {city}: 72F, sunny"

This tool executes immediately when called by the LLM, with no approval gate.

Combining Approved and Auto-Executed Tools in an Agent

from typing import Annotated
from agent_framework import Agent, tool

@tool(approval_mode="always_require")
def delete_record(record_id: Annotated[str, "Record to delete"]) -> str:
    """Delete a database record."""
    return f"Deleted {record_id}"

@tool
def list_records() -> str:
    """List all available records. Safe read-only operation."""
    return "record-1, record-2, record-3"

agent = Agent(
    client=client,
    name="RecordManager",
    instructions="You manage database records. Always list records before deleting.",
    tools=[delete_record, list_records],
)

In this agent, list_records auto-executes while delete_record requires human approval.

Using Custom Name and Approval Together

from typing import Annotated
from agent_framework import tool

@tool(name="remove_user", approval_mode="always_require")
def delete_user_account(
    user_id: Annotated[str, "The user ID to remove"],
    reason: Annotated[str, "Reason for account removal"],
) -> str:
    """Permanently remove a user account and all associated data."""
    return f"User {user_id} removed. Reason: {reason}"

The tool is exposed to the LLM as remove_user (not delete_user_account), and requires human approval before execution.

Related Pages

Implements Principle

Sources

Type Name URL
Repo Microsoft Agent Framework https://github.com/microsoft/agent-framework

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment