chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,62 @@
# Skills Auto-Approval — Configure Auto-Approval Rules for Skill Tools
This sample demonstrates how to configure **auto-approval rules** for skill
tools using `ToolApprovalMiddleware`. Every tool exposed by `SkillsProvider`
(`load_skill`, `read_skill_resource`, and `run_skill_script`) requires host
approval by default. Auto-approval rules let you selectively bypass the approval
prompt for safe operations.
## How It Works
1. A code-defined unit-converter skill (with a resource and a script) is registered via `SkillsProvider`.
2. The agent installs `ToolApprovalMiddleware` with `SkillsProvider.read_only_tools_auto_approval_rule`.
3. The read-only tools (`load_skill`, `read_skill_resource`) are approved automatically.
4. `run_skill_script` still requires explicit approval and is handled with the standard `result.user_input_requests` loop.
## Auto-Approval Rules
`SkillsProvider` exposes two static rules to pass to `ToolApprovalMiddleware(auto_approval_rules=[...])`:
- **`SkillsProvider.read_only_tools_auto_approval_rule`** — approves only the read-only tools (`load_skill`, `read_skill_resource`), while still prompting for `run_skill_script`.
- **`SkillsProvider.all_tools_auto_approval_rule`** — approves every skill tool, including `run_skill_script` (no manual approval loop needed).
Both rules reject any call carrying a `server_label`, so they stay scoped to this provider's local tools and never auto-approve a same-named hosted tool.
> **Note:** To use auto-approval rules, the agent must have `ToolApprovalMiddleware` in its middleware stack.
## Key Components
- **`ToolApprovalMiddleware(auto_approval_rules=[...])`** — Drives the approval handshake and applies the rules
- **`SkillsProvider.read_only_tools_auto_approval_rule`** — Auto-approves read-only skill tools
- **`SkillsProvider.all_tools_auto_approval_rule`** — Auto-approves all skill tools
- **`SkillsProvider.LOAD_SKILL_TOOL_NAME` / `READ_SKILL_RESOURCE_TOOL_NAME` / `RUN_SKILL_SCRIPT_TOOL_NAME`** — Tool-name constants for building custom rules
## Running the Sample
### Prerequisites
- An [Azure AI Foundry](https://ai.azure.com/) project with a deployed model (e.g. `gpt-4o-mini`)
### Environment Variables
Set the required environment variables in a `.env` file (see `python/.env.example`):
- `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint
- `FOUNDRY_MODEL`: The name of your model deployment (defaults to `gpt-4o-mini`)
### Authentication
This sample uses `AzureCliCredential` for authentication. Run `az login` in your terminal before running the sample.
### Run
```bash
cd python
uv run samples/02-agents/skills/skills_auto_approval/skills_auto_approval.py
```
## Learn More
- [Skill Tool Approval Sample](../script_approval/) — manual human-in-the-loop approval
- [Code-Defined Skills Sample](../code_defined_skill/)
- [File-Based Skills Sample](../file_based_skill/)
- [Agent Skills Specification](https://agentskills.io/)
@@ -0,0 +1,191 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import json
import os
from textwrap import dedent
from typing import Any
from agent_framework import (
Agent,
Content,
InlineSkill,
InlineSkillResource,
Message,
SkillFrontmatter,
SkillsProvider,
ToolApprovalMiddleware,
)
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
"""
Skills Auto-Approval — Configure auto-approval rules for skill tools
Every tool exposed by :class:`SkillsProvider` (``load_skill``,
``read_skill_resource``, and ``run_skill_script``) requires host approval by
default. Rather than prompting for every call, this sample uses
:class:`ToolApprovalMiddleware` with a static auto-approval rule so that the
read-only tools are approved automatically while script execution still
requires explicit user approval.
How it works:
1. A code-defined unit-converter skill (with a resource and a script) is
registered via SkillsProvider.
2. The agent installs ``ToolApprovalMiddleware`` with
``SkillsProvider.read_only_tools_auto_approval_rule``. This auto-approves
``load_skill`` and ``read_skill_resource`` while still prompting for
``run_skill_script``.
3. The application handles the remaining ``run_skill_script`` approval requests
via the standard ``result.user_input_requests`` loop.
Available auto-approval rules:
- ``SkillsProvider.read_only_tools_auto_approval_rule`` — approves only the
read-only tools (``load_skill``, ``read_skill_resource``).
- ``SkillsProvider.all_tools_auto_approval_rule`` — approves every skill tool,
including ``run_skill_script`` (no manual approval loop needed).
To use auto-approval rules, the agent must have ``ToolApprovalMiddleware`` in
its middleware stack.
Prerequisites:
- FOUNDRY_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint.
- FOUNDRY_MODEL (defaults to "gpt-4o-mini").
"""
# Load environment variables from .env file
load_dotenv()
# A code-defined unit-converter skill with a resource (read-only) and a script.
unit_converter_skill = InlineSkill(
frontmatter=SkillFrontmatter(
name="unit-converter", description="Convert between common units using a conversion factor"
),
instructions=dedent("""\
Use this skill when the user asks to convert between units.
1. Review the conversion-tables resource to find the factor for the
requested conversion.
2. Use the convert script, passing the value and factor from the table.
"""),
resources=[
InlineSkillResource(
name="conversion-tables",
content=dedent("""\
# Conversion Tables
Formula: **result = value × factor**
| From | To | Factor |
|-------------|-------------|----------|
| miles | kilometers | 1.60934 |
| kilometers | miles | 0.621371 |
| pounds | kilograms | 0.453592 |
| kilograms | pounds | 2.20462 |
"""),
),
],
)
@unit_converter_skill.script(name="convert", description="Convert a value: result = value × factor")
def convert_units(value: float, factor: float, **kwargs: Any) -> str:
"""Convert a value using a multiplication factor: result = value × factor.
Args:
value: The numeric value to convert.
factor: Conversion factor from the conversion table.
**kwargs: Runtime keyword arguments from ``agent.run()``.
Returns:
JSON string with the inputs and converted result.
"""
result = round(value * factor, 2)
return json.dumps({"value": value, "factor": factor, "result": result})
async def main() -> None:
"""Run the skills auto-approval demo."""
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
deployment = os.environ.get("FOUNDRY_MODEL", "gpt-4o-mini")
client = FoundryChatClient(
project_endpoint=endpoint,
model=deployment,
credential=AzureCliCredential(),
)
skills_provider = SkillsProvider(unit_converter_skill)
# Install ToolApprovalMiddleware with the read-only auto-approval rule.
# load_skill and read_skill_resource are approved automatically; the agent
# only pauses for run_skill_script.
#
# To approve every skill tool without prompting, swap the rule for
# SkillsProvider.all_tools_auto_approval_rule (the manual approval loop
# below then becomes a no-op).
approval_middleware = ToolApprovalMiddleware(
auto_approval_rules=[SkillsProvider.read_only_tools_auto_approval_rule]
)
async with Agent(
client=client,
instructions="You are a helpful assistant that can convert units.",
context_providers=[skills_provider],
middleware=[approval_middleware],
) as agent:
session = agent.create_session()
print("Converting units with skill tools and read-only auto-approval")
print("-" * 60)
query = "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?"
print(f"User: {query}")
result = await agent.run(query, session=session)
# Read-only tools (load_skill, read_skill_resource) were auto-approved.
# Only run_skill_script reaches this loop and needs explicit approval.
# Collect a response for every request and send them in one run so the
# loop always makes progress.
while result.user_input_requests:
approval_responses: list[Content] = []
for request in result.user_input_requests:
if request.function_call is None:
# Not a function-approval request; reject it so the run can proceed.
approval_responses.append(request.to_function_approval_response(approved=False))
continue
print("\nApproval needed:")
print(f" Function: {request.function_call.name}")
print(f" Arguments: {request.function_call.arguments}")
# In a real application, prompt the user here.
approved = True
print(f" Decision: {'Approved' if approved else 'Rejected'}")
approval_responses.append(request.to_function_approval_response(approved=approved))
result = await agent.run(Message(role="user", contents=approval_responses), session=session)
print(f"\nAgent: {result}")
if __name__ == "__main__":
asyncio.run(main())
"""
Sample output:
Converting units with skill tools and read-only auto-approval
------------------------------------------------------------
User: How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?
Approval needed:
Function: run_skill_script
Arguments: {"skill_name": "unit-converter", "script_name": "convert", ...}
Decision: Approved
Agent: Here are your conversions:
1. 26.2 miles -> 42.16 km (a marathon distance)
2. 75 kg -> 165.35 lbs
"""