Python: [BREAKING] Support code-defined agent skills (#4387)

* support code skills

* address pr review comments

* address package and syntax checks

* address pr review comments

* address pr review comment

* address failed check

* rename agentskill and agetnskillprovider

* move agent skills related assets to _skills.py

* address pr review comments

* address review comments
This commit is contained in:
SergeyMenshykh
2026-03-04 18:36:02 +00:00
committed by GitHub
Unverified
parent 5fb0cc106a
commit 4dad26fcae
7 changed files with 2324 additions and 653 deletions
@@ -59,7 +59,7 @@ from ._sessions import (
register_state_type,
)
from ._settings import SecretString, load_settings
from ._skills import FileAgentSkillsProvider
from ._skills import Skill, SkillResource, SkillsProvider
from ._telemetry import (
AGENT_FRAMEWORK_USER_AGENT,
APP_INFO,
@@ -205,6 +205,9 @@ __all__ = [
"AgentResponseUpdate",
"AgentRunInputs",
"AgentSession",
"Skill",
"SkillResource",
"SkillsProvider",
"Annotation",
"BaseAgent",
"BaseChatClient",
@@ -234,7 +237,6 @@ __all__ = [
"Executor",
"FanInEdgeGroup",
"FanOutEdgeGroup",
"FileAgentSkillsProvider",
"FileCheckpointStorage",
"FinalT",
"FinishReason",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,6 @@
# Agent Skills Sample
This sample demonstrates how to use **Agent Skills** with a `FileAgentSkillsProvider` in the Microsoft Agent Framework.
This sample demonstrates how to use **Agent Skills** with a `SkillsProvider` in the Microsoft Agent Framework.
## What are Agent Skills?
@@ -20,8 +20,8 @@ Policy-based expense filing with spending limits, receipt requirements, and appr
## Project Structure
```
basic_skills/
├── basic_file_skills.py
basic_skill/
├── basic_skill.py
├── README.md
└── skills/
└── expense-report/
@@ -52,7 +52,7 @@ This sample uses `AzureCliCredential` for authentication. Run `az login` in your
```bash
cd python
uv run samples/02-agents/skills/basic_skills/basic_file_skills.py
uv run samples/02-agents/skills/basic_skill/basic_skill.py
```
### Examples
@@ -4,18 +4,15 @@ import asyncio
import os
from pathlib import Path
from agent_framework import Agent, FileAgentSkillsProvider
from agent_framework import Agent, SkillsProvider
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
"""
Agent Skills Sample
This sample demonstrates how to use file-based Agent Skills with a FileAgentSkillsProvider.
This sample demonstrates how to use file-based Agent Skills with a SkillsProvider.
Agent Skills are modular packages of instructions and resources that extend an agent's
capabilities. They follow the progressive disclosure pattern:
@@ -27,6 +24,9 @@ This sample includes the expense-report skill:
- Policy-based expense filing with references and assets
"""
# Load environment variables from .env file
load_dotenv()
async def main() -> None:
"""Run the Agent Skills demo."""
@@ -44,7 +44,7 @@ async def main() -> None:
# --- 2. Create the skills provider ---
# Discovers skills from the 'skills' directory and makes them available to the agent
skills_dir = Path(__file__).parent / "skills"
skills_provider = FileAgentSkillsProvider(skill_paths=str(skills_dir))
skills_provider = SkillsProvider(skill_paths=str(skills_dir))
# --- 3. Create the agent with skills ---
async with Agent(
@@ -0,0 +1,56 @@
# Code-Defined Agent Skills Sample
This sample demonstrates how to create **Agent Skills** in Python code, without needing `SKILL.md` files on disk.
## What are Code-Defined Skills?
While file-based skills use `SKILL.md` files discovered on disk, code-defined skills let you define skills entirely in Python using `Skill` and `SkillResource` classes. Two patterns are shown:
1. **Basic Code Skill** — Create a `Skill` directly with static resources (inline content)
2. **Dynamic Resources** — Attach callable resources via the `@skill.resource` decorator that generate content at invocation time
Both patterns can be combined with file-based skills in a single `SkillsProvider`.
## Project Structure
```
code_skill/
├── code_skill.py
└── README.md
```
## 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`):
- `AZURE_AI_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint
- `AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME`: 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/code_skill/code_skill.py
```
### Examples
The sample runs two examples:
1. **Code style question** — Uses Pattern 1 (static resources): the agent loads the `code-style` skill and reads the `style-guide` resource to answer naming convention questions
2. **Project info question** — Uses Pattern 2 (dynamic resources): the agent reads dynamically generated `environment` and `team-roster` resources
## Learn More
- [Agent Skills Specification](https://agentskills.io/)
- [File-based Skills Sample](../basic_skill/)
- [Microsoft Agent Framework Documentation](../../../../../docs/)
@@ -0,0 +1,151 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
import sys
from textwrap import dedent
from agent_framework import Agent, Skill, SkillResource, SkillsProvider
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
"""
Code-Defined Agent Skills — Define skills in Python code
This sample demonstrates how to create Agent Skills in code,
without needing SKILL.md files on disk. Two patterns are shown:
Pattern 1: Basic Code Skill
Create a Skill instance directly with static resources (inline content).
Pattern 2: Dynamic Resources
Create a Skill and attach callable resources via the @skill.resource
decorator. Resources can be sync or async functions that generate content at
invocation time.
Both patterns can be combined with file-based skills in a single SkillsProvider.
"""
# Load environment variables from .env file
load_dotenv()
# Pattern 1: Basic Code Skill — direct construction with static resources
code_style_skill = Skill(
name="code-style",
description="Coding style guidelines and conventions for the team",
content=dedent("""\
Use this skill when answering questions about coding style, conventions,
or best practices for the team.
"""),
resources=[
SkillResource(
name="style-guide",
content=dedent("""\
# Team Coding Style Guide
## General Rules
- Use 4-space indentation (no tabs)
- Maximum line length: 120 characters
- Use type annotations on all public functions
- Use Google-style docstrings
## Naming Conventions
- Classes: PascalCase (e.g., UserAccount)
- Functions/methods: snake_case (e.g., get_user_name)
- Constants: UPPER_SNAKE_CASE (e.g., MAX_RETRIES)
- Private members: prefix with underscore (e.g., _internal_state)
"""),
),
],
)
# Pattern 2: Dynamic Resources — @skill.resource decorator
project_info_skill = Skill(
name="project-info",
description="Project status and configuration information",
content=dedent("""\
Use this skill for questions about the current project status,
environment configuration, or team structure.
"""),
)
@project_info_skill.resource
def environment() -> str:
"""Get current environment configuration."""
env = os.environ.get("APP_ENV", "development")
region = os.environ.get("APP_REGION", "us-east-1")
return f"""\
# Environment Configuration
- Environment: {env}
- Region: {region}
- Python: {sys.version}
"""
@project_info_skill.resource(name="team-roster", description="Current team members and roles")
def get_team_roster() -> str:
"""Return the team roster."""
return """\
# Team Roster
| Name | Role |
|--------------|-------------------|
| Alice Chen | Tech Lead |
| Bob Smith | Backend Engineer |
| Carol Davis | Frontend Engineer |
"""
async def main() -> None:
"""Run the code-defined skills demo."""
endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]
deployment = os.environ.get("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME", "gpt-4o-mini")
client = AzureOpenAIResponsesClient(
project_endpoint=endpoint,
deployment_name=deployment,
credential=AzureCliCredential(),
)
# Create the skills provider with both code-defined skills
skills_provider = SkillsProvider(
skills=[code_style_skill, project_info_skill],
)
async with Agent(
client=client,
instructions="You are a helpful assistant for our development team.",
context_providers=[skills_provider],
) as agent:
# Example 1: Code style question (Pattern 1 — static resources)
print("Example 1: Code style question")
print("-------------------------------")
response = await agent.run("What naming convention should I use for class attributes?")
print(f"Agent: {response}\n")
# Example 2: Project info question (Pattern 2 — dynamic resources)
print("Example 2: Project info question")
print("---------------------------------")
response = await agent.run("What environment are we running in and who is on the team?")
print(f"Agent: {response}\n")
"""
Expected output:
Example 1: Code style question
-------------------------------
Agent: Based on our team's coding style guide, class attributes should follow
snake_case naming. Private attributes use an underscore prefix (_internal_state).
Constants use UPPER_SNAKE_CASE (MAX_RETRIES).
Example 2: Project info question
---------------------------------
Agent: We're running in the development environment in us-east-1.
The team consists of Alice Chen (Tech Lead), Bob Smith (Backend Engineer),
and Carol Davis (Frontend Engineer).
"""
if __name__ == "__main__":
asyncio.run(main())