Files
SergeyMenshykh 08541ee5a9 .NET: [Breaking] Refactor AgentSkill API to async resource and script lookup (#6030)
* .NET: Refactor AgentSkill API to async resource and script lookup

Replace property-based AgentSkill.Content, Resources, and Scripts with
async-by-name lookup methods plus boolean availability flags:

- Content (string getter) -> GetContentAsync(CancellationToken)
- Resources (full list) -> HasResources + GetResourceAsync(name, ct)
- Scripts (full list) -> HasScripts + GetScriptAsync(name, ct)

This makes the API friendlier for sources like MCP where enumerating all
resources up front is expensive or impossible, and allows skill implementations
to fetch content lazily.

Subclass changes:
- AgentFileSkill and AgentInlineSkill implement the new async API while
  preserving content caching.
- AgentClassSkill<TSelf> keeps virtual Resources/Scripts properties for
  reflection-based discovery and seals the new HasResources/HasScripts/
  GetResourceAsync/GetScriptAsync overrides. Its previously non-thread-safe
  lazy initialization is replaced with Lazy<T> (default thread-safety) wired
  up in a new protected constructor, so concurrent first-access from multiple
  threads is safe.
- AgentSkillsProvider calls the new async API and exposes 
ead_skill_resource
  / load_skill / 
un_skill_script tools that await the per-name lookups.

Includes baseline CompatibilitySuppressions.xml entries for the removed
property getters.

Tests:
- Direct coverage for HasResources, HasScripts, GetResourceAsync, and
  GetScriptAsync on all three skill implementations (positive, missing-name,
  and no-resources/no-scripts cases).
- Thread-safety regression test for AgentClassSkill<TSelf> that exercises
  concurrent first-access to Resources, Scripts, and GetContentAsync from
  many tasks and asserts all observers see the same cached instance.
- Provider-level coverage for the 
ead_skill_resource tool (invocation +
  error paths) and for the previously untested error paths of load_skill
  and 
un_skill_script (empty names, skill/resource/script not found).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review comments

- Move GetScriptAsync inside try/catch in RunSkillScriptAsync for error-handling parity
- Remove dead _reflectedResources branch from AgentSkillTestExtensions
- Fix XML docs to reference virtual Resources/Scripts properties (not sealed methods)
- Add Async suffix to async test methods per naming convention
- Make no-await tests synchronous to eliminate CS1998

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix formatting: add UTF-8 BOM and remove unused using

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix XML cref: Resources/Scripts are on AgentClassSkill<TSelf>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove HasResources and HasScripts properties from AgentSkill

Drop the virtual HasResources and HasScripts properties from AgentSkill
and all concrete subclasses (AgentFileSkill, AgentInlineSkill,
AgentClassSkill). AgentSkillsProvider now always includes all three
tools (load_skill, read_skill_resource, run_skill_script) and both
instruction blocks, since the tools already handle missing
resources/scripts gracefully.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add blank line for readability in file-based skills sample

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix HostedAgentSkillsPatternTests for always-included tools

Update assertions to expect read_skill_resource and run_skill_script
tools are always present, matching the new behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
08541ee5a9 · 2026-05-25 17:16:03 +00:00
History
..

File-Based Agent Skills Sample

This sample demonstrates how to use file-based Agent Skills with a ChatClientAgent.

What it demonstrates

  • Discovering skills from SKILL.md files on disk via AgentFileSkillsSource
  • The progressive disclosure pattern: advertise → load → read resources → run scripts
  • Using the AgentSkillsProvider constructor with a skill directory path and script runner
  • Running file-based scripts (Python) via a subprocess-based executor

Skills Included

unit-converter

Converts between common units (miles↔km, pounds↔kg) using a multiplication factor.

  • references/conversion-table.md — Conversion factor table
  • scripts/convert.py — Python script that performs the conversion

Running the Sample

Prerequisites

  • .NET 10.0 SDK
  • Azure OpenAI endpoint with a deployed model
  • Python 3 installed and available as python3 on your PATH

Setup

export AZURE_OPENAI_ENDPOINT="https://your-endpoint.openai.azure.com/"
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-5.4-mini"

Run

dotnet run

Expected Output

Converting units with file-based skills
------------------------------------------------------------
Agent: Here are your conversions:

1. **26.2 miles → 42.16 km** (a marathon distance)
2. **75 kg → 165.35 lbs**