From 3c1288bf9202a04f5a93591c203dd6b72795b627 Mon Sep 17 00:00:00 2001
From: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
Date: Wed, 1 Apr 2026 11:51:52 +0000
Subject: [PATCH 1/7] add class-based skills
---
dotnet/agent-framework-dotnet.slnx | 4 +
dotnet/filtered-unit.slnx | 342 ++++++++++++++++
.../Agent_Step01_FileBasedSkills/README.md | 2 +-
.../Agent_Step03_ClassBasedSkills.csproj | 21 +
.../Agent_Step03_ClassBasedSkills/Program.cs | 102 +++++
.../Agent_Step03_ClassBasedSkills/README.md | 49 +++
.../Agent_Step04_MixedSkills.csproj | 32 ++
.../Agent_Step04_MixedSkills/Program.cs | 149 +++++++
.../Agent_Step04_MixedSkills/README.md | 67 +++
.../skills/unit-converter/SKILL.md | 11 +
.../references/unit-conversion-table.md | 10 +
.../unit-converter/scripts/convert-units.py | 29 ++
...gent_Step05_CodeDefinedSkillsWithDI.csproj | 22 +
.../Program.cs | 116 ++++++
.../README.md | 38 ++
...Agent_Step06_ClassBasedSkillsWithDI.csproj | 22 +
.../Program.cs | 140 +++++++
.../README.md | 58 +++
.../samples/02-agents/AgentSkills/README.md | 34 +-
.../Skills/AgentSkillScript.cs | 6 +
.../Skills/AgentSkillsProvider.cs | 16 +-
.../Skills/AgentSkillsProviderBuilder.cs | 18 +-
.../Skills/Programmatic/AgentClassSkill.cs | 95 +++++
.../Skills/Programmatic/AgentInlineSkill.cs | 95 +----
.../AgentInlineSkillContentBuilder.cs | 118 ++++++
.../Programmatic/AgentInlineSkillScript.cs | 2 +-
.../AgentSkills/AgentClassSkillTests.cs | 382 ++++++++++++++++++
.../AgentSkills/AgentSkillsProviderTests.cs | 74 ++++
.../DeduplicatingAgentSkillsSourceTests.cs | 8 +-
.../FilteringAgentSkillsSourceTests.cs | 10 +-
30 files changed, 1949 insertions(+), 123 deletions(-)
create mode 100644 dotnet/filtered-unit.slnx
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Agent_Step03_ClassBasedSkills.csproj
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Program.cs
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/README.md
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Agent_Step04_MixedSkills.csproj
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Program.cs
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/README.md
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/SKILL.md
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/references/unit-conversion-table.md
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/scripts/convert-units.py
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Agent_Step05_CodeDefinedSkillsWithDI.csproj
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Program.cs
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/README.md
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Agent_Step06_ClassBasedSkillsWithDI.csproj
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Program.cs
create mode 100644 dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/README.md
create mode 100644 dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs
create mode 100644 dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentClassSkillTests.cs
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index b9755dac83..f81fd55d58 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -106,6 +106,10 @@
+
+
+
+
diff --git a/dotnet/filtered-unit.slnx b/dotnet/filtered-unit.slnx
new file mode 100644
index 0000000000..1a3ad7e6b2
--- /dev/null
+++ b/dotnet/filtered-unit.slnx
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step01_FileBasedSkills/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step01_FileBasedSkills/README.md
index 41b813b98f..592aca4a27 100644
--- a/dotnet/samples/02-agents/AgentSkills/Agent_Step01_FileBasedSkills/README.md
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step01_FileBasedSkills/README.md
@@ -6,7 +6,7 @@ This sample demonstrates how to use **file-based Agent Skills** with a `ChatClie
- 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 executor
+- Using the `AgentSkillsProvider` constructor with a skill directory path and script runner
- Running file-based scripts (Python) via a subprocess-based executor
## Skills Included
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Agent_Step03_ClassBasedSkills.csproj b/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Agent_Step03_ClassBasedSkills.csproj
new file mode 100644
index 0000000000..fd3d71fe7e
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Agent_Step03_ClassBasedSkills.csproj
@@ -0,0 +1,21 @@
+
+
+
+ Exe
+ net10.0
+
+ enable
+ enable
+ $(NoWarn);MAAI001
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Program.cs
new file mode 100644
index 0000000000..fb0f202230
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Program.cs
@@ -0,0 +1,102 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates how to define Agent Skills as C# classes using AgentClassSkill.
+// Class-based skills bundle all components into a single class implementation.
+
+using System.Text.Json;
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+using OpenAI.Responses;
+
+// --- Configuration ---
+string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+
+// --- Class-Based Skill ---
+// Instantiate the skill class.
+var unitConverter = new UnitConverterSkill();
+
+// --- Skills Provider ---
+var skillsProvider = new AgentSkillsProvider(unitConverter);
+
+// --- Agent Setup ---
+AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
+ .GetResponsesClient()
+ .AsAIAgent(new ChatClientAgentOptions
+ {
+ Name = "UnitConverterAgent",
+ ChatOptions = new()
+ {
+ Instructions = "You are a helpful assistant that can convert units.",
+ },
+ AIContextProviders = [skillsProvider],
+ },
+ model: deploymentName);
+
+// --- Example: Unit conversion ---
+Console.WriteLine("Converting units with class-based skills");
+Console.WriteLine(new string('-', 60));
+
+AgentResponse response = await agent.RunAsync(
+ "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
+
+Console.WriteLine($"Agent: {response.Text}");
+
+///
+/// A unit-converter skill defined as a C# class.
+///
+///
+/// Class-based skills bundle all components (name, description, body, resources, scripts)
+/// into a single class.
+///
+internal sealed class UnitConverterSkill : AgentClassSkill
+{
+ private IReadOnlyList? _resources;
+ private IReadOnlyList? _scripts;
+
+ ///
+ public override AgentSkillFrontmatter Frontmatter { get; } = new(
+ "unit-converter",
+ "Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.");
+
+ ///
+ protected override string Instructions => """
+ Use this skill when the user asks to convert between units.
+
+ 1. Review the conversion-table resource to find the factor for the requested conversion.
+ 2. Use the convert script, passing the value and factor from the table.
+ 3. Present the result clearly with both units.
+ """;
+
+ ///
+ public override IReadOnlyList? Resources => this._resources ??=
+ [
+ CreateResource(
+ "conversion-table",
+ """
+ # 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 |
+ """),
+ ];
+
+ ///
+ public override IReadOnlyList? Scripts => this._scripts ??=
+ [
+ CreateScript("convert", ConvertUnits),
+ ];
+
+ private static string ConvertUnits(double value, double factor)
+ {
+ double result = Math.Round(value * factor, 4);
+ return JsonSerializer.Serialize(new { value, factor, result });
+ }
+}
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/README.md
new file mode 100644
index 0000000000..506784256a
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/README.md
@@ -0,0 +1,49 @@
+# Class-Based Agent Skills Sample
+
+This sample demonstrates how to define **Agent Skills as C# classes** using `AgentClassSkill`.
+
+## What it demonstrates
+
+- Creating skills as classes that extend `AgentClassSkill`
+- Bundling name, description, body, resources, and scripts into a single class
+- Using the `AgentSkillsProvider` constructor with class-based skills
+
+## Skills Included
+
+### unit-converter (class-based)
+
+A `UnitConverterSkill` class that converts between common units. Defined in `Program.cs`:
+
+- `conversion-table` — Static resource with factor table
+- `convert` — Script that performs `value × factor` conversion
+
+## Running the Sample
+
+### Prerequisites
+
+- .NET 10.0 SDK
+- Azure OpenAI endpoint with a deployed model
+
+### Setup
+
+```bash
+export AZURE_OPENAI_ENDPOINT="https://your-endpoint.openai.azure.com/"
+export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
+```
+
+### Run
+
+```bash
+dotnet run
+```
+
+### Expected Output
+
+```
+Converting units with class-based skills
+------------------------------------------------------------
+Agent: Here are your conversions:
+
+1. **26.2 miles → 42.16 km** (a marathon distance)
+2. **75 kg → 165.35 lbs**
+```
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Agent_Step04_MixedSkills.csproj b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Agent_Step04_MixedSkills.csproj
new file mode 100644
index 0000000000..7e7e9ef0fa
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Agent_Step04_MixedSkills.csproj
@@ -0,0 +1,32 @@
+
+
+
+ Exe
+ net10.0
+
+ enable
+ enable
+ $(NoWarn);MAAI001
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Program.cs
new file mode 100644
index 0000000000..b8a9e8fbb1
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Program.cs
@@ -0,0 +1,149 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates an advanced scenario: combining multiple skill types in a single agent
+// using AgentSkillsProviderBuilder. The builder is designed for cases where the simple
+// AgentSkillsProvider constructors are insufficient — for example, when you need to mix skill
+// sources, apply filtering, or configure cross-cutting options in one place.
+//
+// Three different skill sources are registered here:
+// 1. File-based: unit-converter (miles↔km, pounds↔kg) from SKILL.md on disk
+// 2. Code-defined: volume-converter (gallons↔liters) using AgentInlineSkill
+// 3. Class-based: temperature-converter (°F↔°C↔K) using AgentClassSkill
+//
+// For simpler, single-source scenarios, see the earlier steps in this sample series
+// (e.g., Step01 for file-based, Step02 for code-defined, Step03 for class-based).
+
+using System.Text.Json;
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+using OpenAI.Responses;
+
+// --- Configuration ---
+string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
+ ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+
+// --- 1. Code-Defined Skill: volume-converter ---
+var volumeConverterSkill = new AgentInlineSkill(
+ name: "volume-converter",
+ description: "Convert between gallons and liters using a multiplication factor.",
+ instructions: """
+ Use this skill when the user asks to convert between gallons and liters.
+
+ 1. Review the volume-conversion-table resource to find the correct factor.
+ 2. Use the convert-volume script, passing the value and factor.
+ """)
+ .AddResource("volume-conversion-table",
+ """
+ # Volume Conversion Table
+
+ Formula: **result = value × factor**
+
+ | From | To | Factor |
+ |---------|---------|---------|
+ | gallons | liters | 3.78541 |
+ | liters | gallons | 0.264172|
+ """)
+ .AddScript("convert-volume", (double value, double factor) =>
+ {
+ double result = Math.Round(value * factor, 4);
+ return JsonSerializer.Serialize(new { value, factor, result });
+ });
+
+// --- 2. Class-Based Skill: temperature-converter ---
+var temperatureConverter = new TemperatureConverterSkill();
+
+// --- 3. Build provider combining all three source types ---
+var skillsProvider = new AgentSkillsProviderBuilder()
+ .UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills")) // File-based: unit-converter
+ .UseSkill(volumeConverterSkill) // Code-defined: volume-converter
+ .UseSkill(temperatureConverter) // Class-based: temperature-converter
+ .UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
+ .Build();
+
+// --- Agent Setup ---
+AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
+ .GetResponsesClient()
+ .AsAIAgent(new ChatClientAgentOptions
+ {
+ Name = "MultiConverterAgent",
+ ChatOptions = new()
+ {
+ Instructions = "You are a helpful assistant that can convert units, volumes, and temperatures.",
+ },
+ AIContextProviders = [skillsProvider],
+ },
+ model: deploymentName);
+
+// --- Example: Use all three skills ---
+Console.WriteLine("Converting with mixed skills (file + code + class)");
+Console.WriteLine(new string('-', 60));
+
+AgentResponse response = await agent.RunAsync(
+ "I need three conversions: " +
+ "1) How many kilometers is a marathon (26.2 miles)? " +
+ "2) How many liters is a 5-gallon bucket? " +
+ "3) What is 98.6°F in Celsius?");
+
+Console.WriteLine($"Agent: {response.Text}");
+
+///
+/// A temperature-converter skill defined as a C# class.
+///
+internal sealed class TemperatureConverterSkill : AgentClassSkill
+{
+ private IReadOnlyList? _resources;
+ private IReadOnlyList? _scripts;
+
+ ///
+ public override AgentSkillFrontmatter Frontmatter { get; } = new(
+ "temperature-converter",
+ "Convert between temperature scales (Fahrenheit, Celsius, Kelvin).");
+
+ ///
+ protected override string Instructions => """
+ Use this skill when the user asks to convert temperatures.
+
+ 1. Review the temperature-conversion-formulas resource for the correct formula.
+ 2. Use the convert-temperature script, passing the value, source scale, and target scale.
+ 3. Present the result clearly with both temperature scales.
+ """;
+
+ ///
+ public override IReadOnlyList? Resources => this._resources ??=
+ [
+ CreateResource(
+ "temperature-conversion-formulas",
+ """
+ # Temperature Conversion Formulas
+
+ | From | To | Formula |
+ |-------------|-------------|---------------------------|
+ | Fahrenheit | Celsius | °C = (°F − 32) × 5/9 |
+ | Celsius | Fahrenheit | °F = (°C × 9/5) + 32 |
+ | Celsius | Kelvin | K = °C + 273.15 |
+ | Kelvin | Celsius | °C = K − 273.15 |
+ """),
+ ];
+
+ ///
+ public override IReadOnlyList? Scripts => this._scripts ??=
+ [
+ CreateScript("convert-temperature", ConvertTemperature),
+ ];
+
+ private static string ConvertTemperature(double value, string from, string to)
+ {
+ double result = (from.ToUpperInvariant(), to.ToUpperInvariant()) switch
+ {
+ ("FAHRENHEIT", "CELSIUS") => Math.Round((value - 32) * 5.0 / 9.0, 2),
+ ("CELSIUS", "FAHRENHEIT") => Math.Round(value * 9.0 / 5.0 + 32, 2),
+ ("CELSIUS", "KELVIN") => Math.Round(value + 273.15, 2),
+ ("KELVIN", "CELSIUS") => Math.Round(value - 273.15, 2),
+ _ => throw new ArgumentException($"Unsupported conversion: {from} → {to}")
+ };
+
+ return JsonSerializer.Serialize(new { value, from, to, result });
+ }
+}
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/README.md
new file mode 100644
index 0000000000..14a0d089b9
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/README.md
@@ -0,0 +1,67 @@
+# Mixed Agent Skills Sample (Advanced)
+
+This sample demonstrates an **advanced scenario**: combining multiple skill types in a single agent using `AgentSkillsProviderBuilder`.
+
+> **Tip:** For simpler, single-source scenarios, use the `AgentSkillsProvider` constructors directly — see [Step01](../Agent_Step01_FileBasedSkills/) (file-based), [Step02](../Agent_Step02_CodeDefinedSkills/) (code-defined), or [Step03](../Agent_Step03_ClassBasedSkills/) (class-based).
+
+## What it demonstrates
+
+- Combining file-based, code-defined, and class-based skills in one provider
+- Using `UseFileSkill` and `UseSkill` on the builder to register different skill types
+- Aggregating skills from all sources into a single provider with automatic deduplication
+
+## When to use `AgentSkillsProviderBuilder`
+
+The builder is intended for advanced scenarios where the simple `AgentSkillsProvider` constructors are insufficient:
+
+| Scenario | Builder method |
+|----------|---------------|
+| **Mixed skill types** — combine file-based, code-defined, and class-based skills | `UseFileSkill` + `UseSkill` / `UseSkills` |
+| **Multiple file script runners** — use different script runners for different file skill directories | `UseFileSkill` / `UseFileSkills` with per-source `scriptRunner` |
+| **Skill filtering** — include/exclude skills using a predicate | `UseFilter(predicate)` |
+
+## Skills Included
+
+### unit-converter (file-based)
+
+Discovered from `skills/unit-converter/SKILL.md` on disk. Converts miles↔km, pounds↔kg.
+
+### volume-converter (code-defined)
+
+Defined as `AgentInlineSkill` in `Program.cs`. Converts gallons↔liters.
+
+### temperature-converter (class-based)
+
+Defined as `TemperatureConverterSkill` class in `Program.cs`. Converts °F↔°C↔K.
+
+## Running the Sample
+
+### Prerequisites
+
+- .NET 10.0 SDK
+- Azure OpenAI endpoint with a deployed model
+
+### Setup
+
+```bash
+export AZURE_OPENAI_ENDPOINT="https://your-endpoint.openai.azure.com/"
+export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
+```
+
+### Run
+
+```bash
+dotnet run
+```
+
+### Expected Output
+
+```
+Converting with mixed skills (file + code + class)
+------------------------------------------------------------
+Agent: Here are your conversions:
+
+1. **26.2 miles → 42.16 km** (a marathon distance)
+2. **5 gallons → 18.93 liters**
+3. **98.6°F → 37.0°C**
+```
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/SKILL.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/SKILL.md
new file mode 100644
index 0000000000..246a3392f7
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/SKILL.md
@@ -0,0 +1,11 @@
+---
+name: unit-converter
+description: Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.
+---
+
+## Usage
+
+When the user requests a unit conversion:
+1. First, review `references/unit-conversion-table.md` to find the correct factor
+2. Run the `scripts/convert-units.py` script with `--value --factor ` (e.g. `--value 26.2 --factor 1.60934`)
+3. Present the converted value clearly with both units
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/references/unit-conversion-table.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/references/unit-conversion-table.md
new file mode 100644
index 0000000000..7a0160b854
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/references/unit-conversion-table.md
@@ -0,0 +1,10 @@
+# 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 |
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/scripts/convert-units.py b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/scripts/convert-units.py
new file mode 100644
index 0000000000..ac271dd594
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/skills/unit-converter/scripts/convert-units.py
@@ -0,0 +1,29 @@
+# Unit conversion script
+# Converts a value using a multiplication factor: result = value × factor
+#
+# Usage:
+# python scripts/convert-units.py --value 26.2 --factor 1.60934
+# python scripts/convert-units.py --value 75 --factor 2.20462
+
+import argparse
+import json
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(
+ description="Convert a value using a multiplication factor.",
+ epilog="Examples:\n"
+ " python scripts/convert-units.py --value 26.2 --factor 1.60934\n"
+ " python scripts/convert-units.py --value 75 --factor 2.20462",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+ parser.add_argument("--value", type=float, required=True, help="The numeric value to convert.")
+ parser.add_argument("--factor", type=float, required=True, help="The conversion factor from the table.")
+ args = parser.parse_args()
+
+ result = round(args.value * args.factor, 4)
+ print(json.dumps({"value": args.value, "factor": args.factor, "result": result}))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Agent_Step05_CodeDefinedSkillsWithDI.csproj b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Agent_Step05_CodeDefinedSkillsWithDI.csproj
new file mode 100644
index 0000000000..959fa29167
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Agent_Step05_CodeDefinedSkillsWithDI.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ net10.0
+
+ enable
+ enable
+ $(NoWarn);MAAI001;CA1812
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Program.cs
new file mode 100644
index 0000000000..9424b1acaa
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Program.cs
@@ -0,0 +1,116 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates how to use Dependency Injection (DI) with Agent Skills.
+// Skill script and resource functions can resolve services from the DI container via
+// IServiceProvider, enabling clean separation of concerns and testability.
+//
+// The sample registers a ConversionRateService in the DI container. A code-defined skill
+// resource resolves this service to list supported conversions dynamically, and a skill
+// script resolves it to look up live conversion rates at execution time.
+
+using System.Text.Json;
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.DependencyInjection;
+using OpenAI.Responses;
+
+// --- Configuration ---
+string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+
+// --- Build the code-defined skill ---
+// The skill uses DI to resolve ConversionRateService in both its resource and script functions.
+var unitConverterSkill = new AgentInlineSkill(
+ name: "unit-converter",
+ description: "Convert between common units. Use when asked to convert miles, kilometers, pounds, or kilograms.",
+ instructions: """
+ Use this skill when the user asks to convert between units.
+
+ 1. Review the conversion-table resource to find the factor for the requested conversion.
+ 2. Check the conversion-policy resource for rounding and formatting rules.
+ 3. Use the convert script, passing the value and factor from the table.
+ """)
+ // Dynamic resource with DI: resolves ConversionRateService to build conversion table
+ .AddResource("conversion-table", (IServiceProvider serviceProvider) =>
+ {
+ var rateService = serviceProvider.GetRequiredService();
+ return rateService.GetConversionTable();
+ })
+ // Script with DI: resolves ConversionRateService to perform the conversion
+ .AddScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
+ {
+ var rateService = serviceProvider.GetRequiredService();
+ return rateService.Convert(value, factor);
+ });
+
+// --- Skills Provider ---
+var skillsProvider = new AgentSkillsProvider(unitConverterSkill);
+
+// --- DI Container ---
+// Register application services that skill scripts can resolve at execution time.
+ServiceCollection services = new();
+services.AddSingleton();
+
+// --- Agent Setup ---
+AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
+ .GetResponsesClient()
+ .AsAIAgent(
+ options: new ChatClientAgentOptions
+ {
+ Name = "UnitConverterAgent",
+ ChatOptions = new()
+ {
+ Instructions = "You are a helpful assistant that can convert units.",
+ },
+ AIContextProviders = [skillsProvider],
+ },
+ model: deploymentName,
+ services: services.BuildServiceProvider());
+
+// --- Example: Unit conversion ---
+Console.WriteLine("Converting units with DI-powered skills");
+Console.WriteLine(new string('-', 60));
+
+AgentResponse response = await agent.RunAsync(
+ "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
+
+Console.WriteLine($"Agent: {response.Text}");
+
+// ---------------------------------------------------------------------------
+// Services
+// ---------------------------------------------------------------------------
+
+///
+/// Provides conversion rates between units.
+/// In a real application this could call an external API, read from a database,
+/// or apply time-varying exchange rates.
+///
+internal sealed class ConversionRateService
+{
+ ///
+ /// Returns a static markdown table of all supported conversions with factors.
+ ///
+ public string GetConversionTable() =>
+ """
+ # 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 |
+ """;
+
+ ///
+ /// Converts a value by the given factor and returns a JSON result.
+ ///
+ public string Convert(double value, double factor)
+ {
+ double result = Math.Round(value * factor, 4);
+ return JsonSerializer.Serialize(new { value, factor, result });
+ }
+}
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/README.md
new file mode 100644
index 0000000000..aa4281ca00
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/README.md
@@ -0,0 +1,38 @@
+# Agent Skills with Dependency Injection
+
+This sample demonstrates how to use **Dependency Injection (DI)** with Agent Skills resources and script functions.
+
+## What It Shows
+
+- Registering application services in a `ServiceCollection`
+- Defining a code-defined skill resource that resolves services from `IServiceProvider`
+- Defining a code-defined skill script that resolves services from `IServiceProvider`
+- Passing the built `IServiceProvider` to the agent so skills can access DI services at execution time
+
+## How It Works
+
+1. A `ConversionRateService` is registered as a singleton in the DI container
+2. A code-defined skill resource declares `IServiceProvider` as a parameter — the framework injects it automatically
+3. The resource resolves `ConversionRateService` from the provider to build a supported-conversions table dynamically
+4. A code-defined skill script also declares `IServiceProvider` as a parameter to look up conversion factors at runtime
+5. The agent is created with the service provider, which flows through to skill resource and script execution
+
+## Prerequisites
+
+- .NET 10
+- An Azure OpenAI deployment
+
+## Configuration
+
+Set the following environment variables:
+
+| Variable | Description |
+|---|---|
+| `AZURE_OPENAI_ENDPOINT` | Your Azure OpenAI endpoint URL |
+| `AZURE_OPENAI_DEPLOYMENT_NAME` | Model deployment name (defaults to `gpt-4o-mini`) |
+
+## Running the Sample
+
+```bash
+dotnet run
+```
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Agent_Step06_ClassBasedSkillsWithDI.csproj b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Agent_Step06_ClassBasedSkillsWithDI.csproj
new file mode 100644
index 0000000000..959fa29167
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Agent_Step06_ClassBasedSkillsWithDI.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ net10.0
+
+ enable
+ enable
+ $(NoWarn);MAAI001;CA1812
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Program.cs
new file mode 100644
index 0000000000..08044ddfc7
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Program.cs
@@ -0,0 +1,140 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates how to use Dependency Injection (DI) with class-based Agent Skills.
+// Unlike code-defined skills (Step05), class-based skills bundle all components into a single
+// class extending AgentClassSkill. Skill script and resource functions can still resolve
+// services from the DI container via IServiceProvider, combining class-based organization
+// with the flexibility of DI.
+
+using System.Text.Json;
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.DependencyInjection;
+using OpenAI.Responses;
+
+// --- Configuration ---
+string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+
+// --- Class-Based Skill with DI ---
+// Instantiate the skill class. Its resources and scripts will resolve services from
+// the DI container at execution time.
+var unitConverter = new UnitConverterSkill();
+
+// --- Skills Provider ---
+var skillsProvider = new AgentSkillsProvider(unitConverter);
+
+// --- DI Container ---
+// Register application services that skill scripts can resolve at execution time.
+ServiceCollection services = new();
+services.AddSingleton();
+
+// --- Agent Setup ---
+AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
+ .GetResponsesClient()
+ .AsAIAgent(
+ options: new ChatClientAgentOptions
+ {
+ Name = "UnitConverterAgent",
+ ChatOptions = new()
+ {
+ Instructions = "You are a helpful assistant that can convert units.",
+ },
+ AIContextProviders = [skillsProvider],
+ },
+ model: deploymentName,
+ services: services.BuildServiceProvider());
+
+// --- Example: Unit conversion ---
+Console.WriteLine("Converting units with DI-powered class-based skills");
+Console.WriteLine(new string('-', 60));
+
+AgentResponse response = await agent.RunAsync(
+ "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
+
+Console.WriteLine($"Agent: {response.Text}");
+
+///
+/// A unit-converter skill defined as a C# class that uses Dependency Injection.
+///
+///
+/// This skill resolves from the DI container
+/// in both its resource and script functions. This enables clean separation of
+/// concerns and testability while retaining the class-based skill pattern.
+///
+internal sealed class UnitConverterSkill : AgentClassSkill
+{
+ private IReadOnlyList? _resources;
+ private IReadOnlyList? _scripts;
+
+ ///
+ public override AgentSkillFrontmatter Frontmatter { get; } = new(
+ "unit-converter",
+ "Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.");
+
+ ///
+ protected override string Instructions => """
+ Use this skill when the user asks to convert between units.
+
+ 1. Review the conversion-table resource to find the factor for the requested conversion.
+ 2. Use the convert script, passing the value and factor from the table.
+ 3. Present the result clearly with both units.
+ """;
+
+ ///
+ public override IReadOnlyList? Resources => this._resources ??=
+ [
+ // Dynamic resource with DI: resolves ConversionRateService to build conversion table
+ CreateResource("conversion-table", (IServiceProvider serviceProvider) =>
+ {
+ var rateService = serviceProvider.GetRequiredService();
+ return rateService.GetConversionTable();
+ }),
+ ];
+
+ ///
+ public override IReadOnlyList? Scripts => this._scripts ??=
+ [
+ // Script with DI: resolves ConversionRateService to perform the conversion
+ CreateScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
+ {
+ var rateService = serviceProvider.GetRequiredService();
+ return rateService.Convert(value, factor);
+ }),
+ ];
+}
+
+///
+/// Provides conversion rates between units.
+/// In a real application this could call an external API, read from a database,
+/// or apply time-varying exchange rates.
+///
+internal sealed class ConversionRateService
+{
+ ///
+ /// Returns a static markdown table of all supported conversions with factors.
+ ///
+ public string GetConversionTable() =>
+ """
+ # 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 |
+ """;
+
+ ///
+ /// Converts a value by the given factor and returns a JSON result.
+ ///
+ public string Convert(double value, double factor)
+ {
+ double result = Math.Round(value * factor, 4);
+ return JsonSerializer.Serialize(new { value, factor, result });
+ }
+}
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/README.md
new file mode 100644
index 0000000000..1406dbb309
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/README.md
@@ -0,0 +1,58 @@
+# Class-Based Agent Skills with Dependency Injection
+
+This sample demonstrates how to use **Dependency Injection (DI)** with **class-based Agent Skills** (`AgentClassSkill`).
+
+## What It Shows
+
+- Defining a skill as a class that extends `AgentClassSkill`
+- Using `IServiceProvider` in skill resource delegates to resolve services from the DI container
+- Using `IServiceProvider` in skill script delegates to resolve services from the DI container
+- Registering application services in a `ServiceCollection` and passing the built provider to the agent
+
+## How It Works
+
+1. A `ConversionRateService` is registered as a singleton in the DI container
+2. `UnitConverterSkill` extends `AgentClassSkill` and declares its resources and scripts using `CreateResource` and `CreateScript` factory methods
+3. The resource delegate declares `IServiceProvider` as a parameter — the framework injects it automatically
+4. The resource resolves `ConversionRateService` from the provider to build a supported-conversions table dynamically
+5. The script delegate also declares `IServiceProvider` as a parameter to look up conversion factors at runtime
+6. The agent is created with the service provider, which flows through to skill resource and script execution
+
+## How It Differs from Other Samples
+
+| Sample | Skill Type | DI Support |
+|--------|-----------|------------|
+| [Step03](../Agent_Step03_ClassBasedSkills/) | Class-based (`AgentClassSkill`) | No — static resources |
+| [Step05](../Agent_Step05_CodeDefinedSkillsWithDI/) | Code-defined (`AgentInlineSkill`) | Yes — inline delegates |
+| **Step06 (this)** | **Class-based (`AgentClassSkill`)** | **Yes — class delegates** |
+
+## Prerequisites
+
+- .NET 10
+- An Azure OpenAI deployment
+
+## Configuration
+
+Set the following environment variables:
+
+| Variable | Description |
+|---|---|
+| `AZURE_OPENAI_ENDPOINT` | Your Azure OpenAI endpoint URL |
+| `AZURE_OPENAI_DEPLOYMENT_NAME` | Model deployment name (defaults to `gpt-4o-mini`) |
+
+## Running the Sample
+
+```bash
+dotnet run
+```
+
+### Expected Output
+
+```
+Converting units with DI-powered class-based skills
+------------------------------------------------------------
+Agent: Here are your conversions:
+
+1. **26.2 miles → 42.16 km** (a marathon distance)
+2. **75 kg → 165.35 lbs**
+```
diff --git a/dotnet/samples/02-agents/AgentSkills/README.md b/dotnet/samples/02-agents/AgentSkills/README.md
index 6011384997..bcdcf6be81 100644
--- a/dotnet/samples/02-agents/AgentSkills/README.md
+++ b/dotnet/samples/02-agents/AgentSkills/README.md
@@ -6,19 +6,33 @@ Samples demonstrating Agent Skills capabilities. Each sample shows a different w
|--------|-------------|
| [Agent_Step01_FileBasedSkills](Agent_Step01_FileBasedSkills/) | Define skills as `SKILL.md` files on disk with reference documents. Uses a unit-converter skill. |
| [Agent_Step02_CodeDefinedSkills](Agent_Step02_CodeDefinedSkills/) | Define skills entirely in C# code using `AgentInlineSkill`, with static/dynamic resources and scripts. |
+| [Agent_Step03_ClassBasedSkills](Agent_Step03_ClassBasedSkills/) | Define skills as C# classes using `AgentClassSkill`. |
+| [Agent_Step04_MixedSkills](Agent_Step04_MixedSkills/) | **(Advanced)** Combine file-based, code-defined, and class-based skills using `AgentSkillsProviderBuilder`. |
+| [Agent_Step05_CodeDefinedSkillsWithDI](Agent_Step05_CodeDefinedSkillsWithDI/) | Use Dependency Injection with code-defined skills (`AgentInlineSkill`). |
+| [Agent_Step06_ClassBasedSkillsWithDI](Agent_Step06_ClassBasedSkillsWithDI/) | Use Dependency Injection with class-based skills (`AgentClassSkill`). |
## Key Concepts
-### File-Based vs Code-Defined Skills
+### Skill Types
-| Aspect | File-Based | Code-Defined |
-|--------|-----------|--------------|
-| Definition | `SKILL.md` files on disk | `AgentInlineSkill` instances in C# |
-| Resources | All files in skill directory (filtered by extension) | `AddResource` (static value or delegate-backed) |
-| Scripts | Supported via script executor delegate | `AddScript` delegates |
-| Discovery | Automatic from directory path | Explicit via constructor |
-| Dynamic content | No (static files only) | Yes (factory delegates) |
-| Reusability | Copy skill directory | Inline or shared instances |
+| Aspect | File-Based | Code-Defined | Class-Based |
+|--------|-----------|--------------|-------------|
+| Definition | `SKILL.md` files on disk | `AgentInlineSkill` instances in C# | Classes extending `AgentClassSkill` |
+| Resources | All files in skill directory (filtered by extension) | `AddResource` (static value or delegate-backed) | `CreateResource` factory methods |
+| Scripts | Supported via script runner delegate | `AddScript` delegates | `CreateScript` factory methods |
+| Discovery | Automatic from directory path | Explicit via constructor | Explicit via constructor |
+| Dynamic content | No (static files only) | Yes (factory delegates) | Yes (factory delegates) |
+| Sharing pattern | Copy skill directory | Inline or shared instances | Package in shared assemblies/NuGet |
+| DI support | No | Yes (via `IServiceProvider` parameter) | Yes (via `IServiceProvider` parameter) |
-For single-source scenarios, use the `AgentSkillsProvider` constructors directly. To combine multiple skill types, use the `AgentSkillsProviderBuilder`.
+### `AgentSkillsProvider` vs `AgentSkillsProviderBuilder`
+For single-source scenarios, use the `AgentSkillsProvider` constructors directly — they accept a skill directory path, a set of skills, or a custom source.
+
+Use `AgentSkillsProviderBuilder` for advanced scenarios where simple constructors are insufficient:
+
+- **Mixed skill types** — combine file-based, code-defined, and class-based skills in one provider
+- **Multiple file script runners** — use different script runners for different file skill directories
+- **Skill filtering** — include or exclude skills using a predicate
+
+See [Agent_Step04_MixedSkills](Agent_Step04_MixedSkills/) for a working example.
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillScript.cs b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillScript.cs
index ad647d2eb0..1ac44bfac8 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillScript.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillScript.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Diagnostics.CodeAnalysis;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
@@ -36,6 +37,11 @@ protected AgentSkillScript(string name, string? description = null)
///
public string? Description { get; }
+ ///
+ /// Gets the JSON schema describing the parameters accepted by this script, or if not available.
+ ///
+ public virtual JsonElement? ParametersSchema => null;
+
///
/// Runs the script with the given arguments.
///
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs
index 70d7939227..b5598e19d3 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs
@@ -117,26 +117,24 @@ public AgentSkillsProvider(
}
///
- /// Initializes a new instance of the class
- /// with one or more inline (code-defined) skills.
+ /// Initializes a new instance of the class.
/// Duplicate skill names are automatically deduplicated (first occurrence wins).
///
- /// The inline skills to include.
- public AgentSkillsProvider(params AgentInlineSkill[] skills)
- : this(skills as IEnumerable)
+ /// The skills to include.
+ public AgentSkillsProvider(params AgentSkill[] skills)
+ : this(skills as IEnumerable)
{
}
///
- /// Initializes a new instance of the class
- /// with inline (code-defined) skills.
+ /// Initializes a new instance of the class.
/// Duplicate skill names are automatically deduplicated (first occurrence wins).
///
- /// The inline skills to include.
+ /// The skills to include.
/// Optional provider configuration.
/// Optional logger factory.
public AgentSkillsProvider(
- IEnumerable skills,
+ IEnumerable skills,
AgentSkillsProviderOptions? options = null,
ILoggerFactory? loggerFactory = null)
: this(
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs
index 8e52cc522e..0da54d0426 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs
@@ -11,15 +11,31 @@ namespace Microsoft.Agents.AI;
///
/// Fluent builder for constructing an backed by a composite source.
+/// Intended for advanced scenarios where the simple constructors are insufficient.
///
///
///
-/// Use this builder to combine multiple skill sources into a single provider:
+/// For simple, single-source scenarios, prefer the constructors directly
+/// (e.g., passing a skill directory path or a set of skills). Use this builder when you need one or more
+/// of the following advanced capabilities:
+///
+///
+/// Mixed skill types — combine file-based, code-defined (),
+/// and class-based () skills in a single provider.
+/// Multiple file script runners — use different script runners for different
+/// file skill directories via per-source scriptRunner parameters on
+/// / .
+/// Skill filtering — include or exclude skills using a predicate
+/// via .
+///
+///
+/// Example — combining file-based and code-defined skills:
///
///
/// var provider = new AgentSkillsProviderBuilder()
/// .UseFileSkills("/path/to/skills")
/// .UseSkills(myInlineSkill1, myInlineSkill2)
+/// .UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
/// .Build();
///
///
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs
new file mode 100644
index 0000000000..47f12d5ea5
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.Shared.DiagnosticIds;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Abstract base class for defining skills as C# classes that bundle all components together.
+///
+///
+///
+/// Inherit from this class to create a self-contained skill definition. Override the abstract
+/// properties to provide name, description, and instructions. Use ,
+/// , and to define
+/// inline resources and scripts.
+///
+///
+///
+///
+/// public class PdfFormatterSkill : AgentClassSkill
+/// {
+/// private IReadOnlyList<AgentSkillResource>? _resources;
+/// private IReadOnlyList<AgentSkillScript>? _scripts;
+///
+/// public override AgentSkillFrontmatter Frontmatter { get; } = new("pdf-formatter", "Format documents as PDF.");
+/// protected override string Instructions => "Use this skill to format documents...";
+///
+/// public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
+/// [
+/// CreateResource("template", "Use this template..."),
+/// ];
+///
+/// public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
+/// [
+/// CreateScript("format-pdf", FormatPdf),
+/// ];
+///
+/// private static string FormatPdf(string content) => content;
+/// }
+///
+///
+[Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
+public abstract class AgentClassSkill : AgentSkill
+{
+ private string? _content;
+
+ ///
+ /// Gets the raw instructions text for this skill.
+ ///
+ protected abstract string Instructions { get; }
+
+ ///
+ ///
+ /// Returns a synthesized XML document containing name, description, instructions, resources, and scripts.
+ /// The result is cached after the first access. Override to provide custom content.
+ ///
+ public override string Content => this._content ??= AgentInlineSkillContentBuilder.Build(
+ this.Frontmatter.Name,
+ this.Frontmatter.Description,
+ this.Instructions,
+ this.Resources,
+ this.Scripts);
+
+ ///
+ /// Creates a skill resource backed by a static value.
+ ///
+ /// The resource name.
+ /// The static resource value.
+ /// An optional description of the resource.
+ /// A new instance.
+ protected static AgentSkillResource CreateResource(string name, object value, string? description = null)
+ => new AgentInlineSkillResource(name, value, description);
+
+ ///
+ /// Creates a skill resource backed by a delegate that produces a dynamic value.
+ ///
+ /// The resource name.
+ /// A method that produces the resource value when requested.
+ /// An optional description of the resource.
+ /// A new instance.
+ protected static AgentSkillResource CreateResource(string name, Delegate method, string? description = null)
+ => new AgentInlineSkillResource(name, method, description);
+
+ ///
+ /// Creates a skill script backed by a delegate.
+ ///
+ /// The script name.
+ /// A method to execute when the script is invoked.
+ /// An optional description of the script.
+ /// A new instance.
+ protected static AgentSkillScript CreateScript(string name, Delegate method, string? description = null)
+ => new AgentInlineSkillScript(name, method, description);
+}
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs
index d326a47a59..f24d41c362 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs
@@ -3,8 +3,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using System.Text;
-using System.Text.Json;
using Microsoft.Extensions.AI;
using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
@@ -27,8 +25,8 @@ namespace Microsoft.Agents.AI;
public sealed class AgentInlineSkill : AgentSkill
{
private readonly string _instructions;
- private List? _resources;
- private List? _scripts;
+ private List? _resources;
+ private List? _scripts;
private string? _cachedContent;
///
@@ -77,7 +75,7 @@ public AgentInlineSkill(
public override AgentSkillFrontmatter Frontmatter { get; }
///
- public override string Content => this._cachedContent ??= this.BuildContent();
+ public override string Content => this._cachedContent ??= AgentInlineSkillContentBuilder.Build(this.Frontmatter.Name, this.Frontmatter.Description, this._instructions, this._resources, this._scripts);
///
public override IReadOnlyList? Resources => this._resources;
@@ -125,91 +123,4 @@ public AgentInlineSkill AddScript(string name, Delegate method, string? descript
(this._scripts ??= []).Add(new AgentInlineSkillScript(name, method, description));
return this;
}
-
- private string BuildContent()
- {
- var sb = new StringBuilder();
-
- sb.Append($"{EscapeXmlString(this.Frontmatter.Name)}\n")
- .Append($"{EscapeXmlString(this.Frontmatter.Description)}\n\n")
- .Append("\n")
- .Append(EscapeXmlString(this._instructions))
- .Append("\n");
-
- if (this.Resources is { Count: > 0 })
- {
- sb.Append("\n\n\n");
- foreach (var resource in this.Resources)
- {
- if (resource.Description is not null)
- {
- sb.Append($" \n");
- }
- else
- {
- sb.Append($" \n");
- }
- }
-
- sb.Append("");
- }
-
- if (this.Scripts is { Count: > 0 })
- {
- sb.Append("\n\n\n");
- foreach (var script in this.Scripts)
- {
- JsonElement? parametersSchema = ((AgentInlineSkillScript)script).ParametersSchema;
-
- if (script.Description is null && parametersSchema is null)
- {
- sb.Append($" \n");
- }
- }
-
- sb.Append("");
- }
-
- return sb.ToString();
- }
-
- ///
- /// Escapes XML special characters: always escapes &, <, >,
- /// ", and '. When is ,
- /// quotes are left unescaped to preserve readability of embedded content such as JSON.
- ///
- /// The string to escape.
- ///
- /// When , leaves " and ' unescaped for use in XML element content (e.g., JSON).
- /// When (default), escapes all XML special characters including quotes.
- ///
- private static string EscapeXmlString(string value, bool preserveQuotes = false)
- {
- var result = value
- .Replace("&", "&")
- .Replace("<", "<")
- .Replace(">", ">");
-
- if (!preserveQuotes)
- {
- result = result
- .Replace("\"", """)
- .Replace("'", "'");
- }
-
- return result;
- }
}
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs
new file mode 100644
index 0000000000..f90d67dd1d
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs
@@ -0,0 +1,118 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Internal helper that builds XML-structured content strings for code-defined and class-based skills.
+///
+internal static class AgentInlineSkillContentBuilder
+{
+ ///
+ /// Builds the complete skill content containing name, description, instructions, resources, and scripts.
+ ///
+ /// The skill name.
+ /// The skill description.
+ /// The raw instructions text.
+ /// Optional resources associated with the skill.
+ /// Optional scripts associated with the skill.
+ /// An XML-structured content string.
+ public static string Build(
+ string name,
+ string description,
+ string instructions,
+ IReadOnlyList? resources,
+ IReadOnlyList? scripts)
+ {
+ _ = Throw.IfNullOrWhitespace(name);
+ _ = Throw.IfNullOrWhitespace(description);
+ _ = Throw.IfNullOrWhitespace(instructions);
+
+ var sb = new StringBuilder();
+
+ sb.Append($"{EscapeXmlString(name)}\n")
+ .Append($"{EscapeXmlString(description)}\n\n")
+ .Append("\n")
+ .Append(EscapeXmlString(instructions))
+ .Append("\n");
+
+ if (resources is { Count: > 0 })
+ {
+ sb.Append("\n\n\n");
+ foreach (var resource in resources)
+ {
+ if (resource.Description is not null)
+ {
+ sb.Append($" \n");
+ }
+ else
+ {
+ sb.Append($" \n");
+ }
+ }
+
+ sb.Append("");
+ }
+
+ if (scripts is { Count: > 0 })
+ {
+ sb.Append("\n\n\n");
+ foreach (var script in scripts)
+ {
+ var parametersSchema = script.ParametersSchema;
+
+ if (script.Description is null && parametersSchema is null)
+ {
+ sb.Append($" \n");
+ }
+ }
+
+ sb.Append("");
+ }
+
+ return sb.ToString();
+ }
+
+ ///
+ /// Escapes XML special characters: always escapes &, <, >,
+ /// ", and '. When is ,
+ /// quotes are left unescaped to preserve readability of embedded content such as JSON.
+ ///
+ /// The string to escape.
+ ///
+ /// When , leaves " and ' unescaped for use in XML element content (e.g., JSON).
+ /// When (default), escapes all XML special characters including quotes.
+ ///
+ private static string EscapeXmlString(string value, bool preserveQuotes = false)
+ {
+ var result = value
+ .Replace("&", "&")
+ .Replace("<", "<")
+ .Replace(">", ">");
+
+ if (!preserveQuotes)
+ {
+ result = result
+ .Replace("\"", """)
+ .Replace("'", "'");
+ }
+
+ return result;
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillScript.cs b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillScript.cs
index acb4f4780b..e851c6f9fc 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillScript.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillScript.cs
@@ -36,7 +36,7 @@ public AgentInlineSkillScript(string name, Delegate method, string? description
///
/// Gets the JSON schema describing the parameters accepted by this script, or if not available.
///
- public JsonElement? ParametersSchema => this._function.JsonSchema;
+ public override JsonElement? ParametersSchema => this._function.JsonSchema;
///
public override async Task
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Program.cs
deleted file mode 100644
index 9424b1acaa..0000000000
--- a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Program.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-// This sample demonstrates how to use Dependency Injection (DI) with Agent Skills.
-// Skill script and resource functions can resolve services from the DI container via
-// IServiceProvider, enabling clean separation of concerns and testability.
-//
-// The sample registers a ConversionRateService in the DI container. A code-defined skill
-// resource resolves this service to list supported conversions dynamically, and a skill
-// script resolves it to look up live conversion rates at execution time.
-
-using System.Text.Json;
-using Azure.AI.OpenAI;
-using Azure.Identity;
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.DependencyInjection;
-using OpenAI.Responses;
-
-// --- Configuration ---
-string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
-string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
-
-// --- Build the code-defined skill ---
-// The skill uses DI to resolve ConversionRateService in both its resource and script functions.
-var unitConverterSkill = new AgentInlineSkill(
- name: "unit-converter",
- description: "Convert between common units. Use when asked to convert miles, kilometers, pounds, or kilograms.",
- instructions: """
- Use this skill when the user asks to convert between units.
-
- 1. Review the conversion-table resource to find the factor for the requested conversion.
- 2. Check the conversion-policy resource for rounding and formatting rules.
- 3. Use the convert script, passing the value and factor from the table.
- """)
- // Dynamic resource with DI: resolves ConversionRateService to build conversion table
- .AddResource("conversion-table", (IServiceProvider serviceProvider) =>
- {
- var rateService = serviceProvider.GetRequiredService();
- return rateService.GetConversionTable();
- })
- // Script with DI: resolves ConversionRateService to perform the conversion
- .AddScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
- {
- var rateService = serviceProvider.GetRequiredService();
- return rateService.Convert(value, factor);
- });
-
-// --- Skills Provider ---
-var skillsProvider = new AgentSkillsProvider(unitConverterSkill);
-
-// --- DI Container ---
-// Register application services that skill scripts can resolve at execution time.
-ServiceCollection services = new();
-services.AddSingleton();
-
-// --- Agent Setup ---
-AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
- .GetResponsesClient()
- .AsAIAgent(
- options: new ChatClientAgentOptions
- {
- Name = "UnitConverterAgent",
- ChatOptions = new()
- {
- Instructions = "You are a helpful assistant that can convert units.",
- },
- AIContextProviders = [skillsProvider],
- },
- model: deploymentName,
- services: services.BuildServiceProvider());
-
-// --- Example: Unit conversion ---
-Console.WriteLine("Converting units with DI-powered skills");
-Console.WriteLine(new string('-', 60));
-
-AgentResponse response = await agent.RunAsync(
- "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
-
-Console.WriteLine($"Agent: {response.Text}");
-
-// ---------------------------------------------------------------------------
-// Services
-// ---------------------------------------------------------------------------
-
-///
-/// Provides conversion rates between units.
-/// In a real application this could call an external API, read from a database,
-/// or apply time-varying exchange rates.
-///
-internal sealed class ConversionRateService
-{
- ///
- /// Returns a static markdown table of all supported conversions with factors.
- ///
- public string GetConversionTable() =>
- """
- # 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 |
- """;
-
- ///
- /// Converts a value by the given factor and returns a JSON result.
- ///
- public string Convert(double value, double factor)
- {
- double result = Math.Round(value * factor, 4);
- return JsonSerializer.Serialize(new { value, factor, result });
- }
-}
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/README.md
deleted file mode 100644
index aa4281ca00..0000000000
--- a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/README.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# Agent Skills with Dependency Injection
-
-This sample demonstrates how to use **Dependency Injection (DI)** with Agent Skills resources and script functions.
-
-## What It Shows
-
-- Registering application services in a `ServiceCollection`
-- Defining a code-defined skill resource that resolves services from `IServiceProvider`
-- Defining a code-defined skill script that resolves services from `IServiceProvider`
-- Passing the built `IServiceProvider` to the agent so skills can access DI services at execution time
-
-## How It Works
-
-1. A `ConversionRateService` is registered as a singleton in the DI container
-2. A code-defined skill resource declares `IServiceProvider` as a parameter — the framework injects it automatically
-3. The resource resolves `ConversionRateService` from the provider to build a supported-conversions table dynamically
-4. A code-defined skill script also declares `IServiceProvider` as a parameter to look up conversion factors at runtime
-5. The agent is created with the service provider, which flows through to skill resource and script execution
-
-## Prerequisites
-
-- .NET 10
-- An Azure OpenAI deployment
-
-## Configuration
-
-Set the following environment variables:
-
-| Variable | Description |
-|---|---|
-| `AZURE_OPENAI_ENDPOINT` | Your Azure OpenAI endpoint URL |
-| `AZURE_OPENAI_DEPLOYMENT_NAME` | Model deployment name (defaults to `gpt-4o-mini`) |
-
-## Running the Sample
-
-```bash
-dotnet run
-```
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Agent_Step05_CodeDefinedSkillsWithDI.csproj b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Agent_Step05_SkillsWithDI.csproj
similarity index 100%
rename from dotnet/samples/02-agents/AgentSkills/Agent_Step05_CodeDefinedSkillsWithDI/Agent_Step05_CodeDefinedSkillsWithDI.csproj
rename to dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Agent_Step05_SkillsWithDI.csproj
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs
new file mode 100644
index 0000000000..eedbbbda41
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs
@@ -0,0 +1,208 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates how to use Dependency Injection (DI) with Agent Skills.
+// It shows two approaches side-by-side, each handling a different conversion domain:
+//
+// 1. Code-defined skill (AgentInlineSkill) — converts distances (miles ↔ kilometers).
+// Resources and scripts are inline delegates that resolve services from IServiceProvider.
+//
+// 2. Class-based skill (AgentClassSkill) — converts weights (pounds ↔ kilograms).
+// Resources and scripts are encapsulated in a class, also resolving services from IServiceProvider.
+//
+// Both skills share the same ConversionService registered in the DI container,
+// showing that DI works identically regardless of how the skill is defined.
+// When prompted with a question spanning both domains, the agent uses both skills.
+
+using System.Text.Json;
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.DependencyInjection;
+using OpenAI.Responses;
+
+// --- Configuration ---
+string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+
+// --- DI Container ---
+// Register application services that skill resources and scripts can resolve at execution time.
+ServiceCollection services = new();
+services.AddSingleton();
+
+IServiceProvider serviceProvider = services.BuildServiceProvider();
+
+// =====================================================================
+// Approach 1: Code-Defined Skill with DI (AgentInlineSkill)
+// =====================================================================
+// Handles distance conversions (miles ↔ kilometers).
+// Resources and scripts are inline delegates. Each delegate can declare
+// an IServiceProvider parameter that the framework injects automatically.
+
+var distanceSkill = new AgentInlineSkill(
+ name: "distance-converter",
+ description: "Convert between distance units. Use when asked to convert miles to kilometers or kilometers to miles.",
+ instructions: """
+ Use this skill when the user asks to convert between distance units (miles and kilometers).
+
+ 1. Review the distance-table resource to find the factor for the requested conversion.
+ 2. Use the convert script, passing the value and factor from the table.
+ """)
+ .AddResource("distance-table", (IServiceProvider serviceProvider) =>
+ {
+ var service = serviceProvider.GetRequiredService();
+ return service.GetDistanceTable();
+ })
+ .AddScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
+ {
+ var service = serviceProvider.GetRequiredService();
+ return service.Convert(value, factor);
+ });
+
+// =====================================================================
+// Approach 2: Class-Based Skill with DI (AgentClassSkill)
+// =====================================================================
+// Handles weight conversions (pounds ↔ kilograms).
+// Resources and scripts are encapsulated in a class. Factory methods
+// CreateResource and CreateScript accept delegates with IServiceProvider.
+//
+// Alternatively, class-based skills can accept dependencies through their
+// constructor. Register the skill class itself in the ServiceCollection and
+// resolve it from the container:
+//
+// services.AddSingleton();
+// var weightSkill = serviceProvider.GetRequiredService();
+
+var weightSkill = new WeightConverterSkill();
+
+// --- Skills Provider ---
+// Both skills are registered with the same provider so the agent can use either one.
+var skillsProvider = new AgentSkillsProvider(distanceSkill, weightSkill);
+
+// --- Agent Setup ---
+AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
+ .GetResponsesClient()
+ .AsAIAgent(
+ options: new ChatClientAgentOptions
+ {
+ Name = "UnitConverterAgent",
+ ChatOptions = new()
+ {
+ Instructions = "You are a helpful assistant that can convert units.",
+ },
+ AIContextProviders = [skillsProvider],
+ },
+ model: deploymentName,
+ services: serviceProvider);
+
+// --- Example: Unit conversion ---
+// This prompt spans both domains, so the agent will use both skills.
+Console.WriteLine("Converting units with DI-powered skills");
+Console.WriteLine(new string('-', 60));
+
+AgentResponse response = await agent.RunAsync(
+ "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
+
+Console.WriteLine($"Agent: {response.Text}");
+
+// ---------------------------------------------------------------------------
+// Class-Based Skill
+// ---------------------------------------------------------------------------
+
+///
+/// A weight-converter skill defined as a C# class that uses Dependency Injection.
+///
+///
+/// This skill resolves from the DI container
+/// in both its resource and script functions. This enables clean separation of
+/// concerns and testability while retaining the class-based skill pattern.
+///
+internal sealed class WeightConverterSkill : AgentClassSkill
+{
+ private IReadOnlyList? _resources;
+ private IReadOnlyList? _scripts;
+
+ ///
+ public override AgentSkillFrontmatter Frontmatter { get; } = new(
+ "weight-converter",
+ "Convert between weight units. Use when asked to convert pounds to kilograms or kilograms to pounds.");
+
+ ///
+ protected override string Instructions => """
+ Use this skill when the user asks to convert between weight units (pounds and kilograms).
+
+ 1. Review the weight-table resource to find the factor for the requested conversion.
+ 2. Use the convert script, passing the value and factor from the table.
+ 3. Present the result clearly with both units.
+ """;
+
+ ///
+ public override IReadOnlyList? Resources => this._resources ??=
+ [
+ CreateResource("weight-table", (IServiceProvider serviceProvider) =>
+ {
+ var service = serviceProvider.GetRequiredService();
+ return service.GetWeightTable();
+ }),
+ ];
+
+ ///
+ public override IReadOnlyList? Scripts => this._scripts ??=
+ [
+ CreateScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
+ {
+ var service = serviceProvider.GetRequiredService();
+ return service.Convert(value, factor);
+ }),
+ ];
+}
+
+// ---------------------------------------------------------------------------
+// Services
+// ---------------------------------------------------------------------------
+
+///
+/// Provides conversion rates between units.
+/// In a real application this could call an external API, read from a database,
+/// or apply time-varying exchange rates.
+///
+internal sealed class ConversionService
+{
+ ///
+ /// Returns a markdown table of supported distance conversions.
+ ///
+ public string GetDistanceTable() =>
+ """
+ # Distance Conversions
+
+ Formula: **result = value × factor**
+
+ | From | To | Factor |
+ |-------------|-------------|----------|
+ | miles | kilometers | 1.60934 |
+ | kilometers | miles | 0.621371 |
+ """;
+
+ ///
+ /// Returns a markdown table of supported weight conversions.
+ ///
+ public string GetWeightTable() =>
+ """
+ # Weight Conversions
+
+ Formula: **result = value × factor**
+
+ | From | To | Factor |
+ |-------------|-------------|----------|
+ | pounds | kilograms | 0.453592 |
+ | kilograms | pounds | 2.20462 |
+ """;
+
+ ///
+ /// Converts a value by the given factor and returns a JSON result.
+ ///
+ public string Convert(double value, double factor)
+ {
+ double result = Math.Round(value * factor, 4);
+ return JsonSerializer.Serialize(new { value, factor, result });
+ }
+}
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/README.md
new file mode 100644
index 0000000000..b284b745d5
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/README.md
@@ -0,0 +1,65 @@
+# Agent Skills with Dependency Injection
+
+This sample demonstrates how to use **Dependency Injection (DI)** with Agent Skills. It shows two approaches side-by-side, each handling a different conversion domain:
+
+1. **Code-defined skill** (`AgentInlineSkill`) — converts **distances** (miles ↔ kilometers)
+2. **Class-based skill** (`AgentClassSkill`) — converts **weights** (pounds ↔ kilograms)
+
+Both skills resolve the same `ConversionService` from the DI container. When prompted with a question spanning both domains, the agent uses both skills.
+
+## What It Shows
+
+- Registering application services in a `ServiceCollection`
+- Defining a **code-defined** skill (distance converter) with resources and scripts that resolve services from `IServiceProvider`
+- Defining a **class-based** skill (weight converter) with resources and scripts that resolve services from `IServiceProvider`
+- Passing the built `IServiceProvider` to the agent so skills can access DI services at execution time
+- Running a single prompt that exercises both skills to show they work together
+
+## How It Works
+
+1. A `ConversionService` is registered as a singleton in the DI container
+2. **Code-defined skill**: An `AgentInlineSkill` for distance conversions declares `IServiceProvider` as a parameter in its `AddResource` and `AddScript` delegates — the framework injects it automatically
+3. **Class-based skill**: A `WeightConverterSkill` class extends `AgentClassSkill` for weight conversions and uses `CreateResource`/`CreateScript` factory methods with `IServiceProvider` parameters
+4. Both skills resolve `ConversionService` from the provider — one for distance tables, the other for weight tables
+5. A single agent is created with both skills registered, and the service provider flows through to skill execution
+
+> **Tip:** Class-based skills can also accept dependencies through their **constructor**. Register the skill class in the `ServiceCollection` and resolve it from the container instead of calling `new` directly. This is useful when the skill itself needs injected services beyond what the resource/script delegates use.
+
+## How It Differs from Other Samples
+
+| Sample | Skill Type | DI Support |
+|--------|------------|------------|
+| [Step02](../Agent_Step02_CodeDefinedSkills/) | Code-defined (`AgentInlineSkill`) | No — static resources |
+| [Step03](../Agent_Step03_ClassBasedSkills/) | Class-based (`AgentClassSkill`) | No — static resources |
+| **Step05 (this)** | **Both code-defined and class-based** | **Yes — DI via `IServiceProvider`** |
+
+## Prerequisites
+
+- .NET 10
+- An Azure OpenAI deployment
+
+## Configuration
+
+Set the following environment variables:
+
+| Variable | Description |
+|---|---|
+| `AZURE_OPENAI_ENDPOINT` | Your Azure OpenAI endpoint URL |
+| `AZURE_OPENAI_DEPLOYMENT_NAME` | Model deployment name (defaults to `gpt-4o-mini`) |
+
+## Running the Sample
+
+```bash
+dotnet run
+```
+
+### Expected Output
+
+```
+Converting units with DI-powered skills
+------------------------------------------------------------
+Agent: Here are your conversions:
+
+1. **26.2 miles → 42.16 km** (a marathon distance)
+2. **75 kg → 165.35 lbs**
+```
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Agent_Step06_ClassBasedSkillsWithDI.csproj b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Agent_Step06_ClassBasedSkillsWithDI.csproj
deleted file mode 100644
index 959fa29167..0000000000
--- a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Agent_Step06_ClassBasedSkillsWithDI.csproj
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- Exe
- net10.0
-
- enable
- enable
- $(NoWarn);MAAI001;CA1812
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Program.cs
deleted file mode 100644
index 08044ddfc7..0000000000
--- a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/Program.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-// This sample demonstrates how to use Dependency Injection (DI) with class-based Agent Skills.
-// Unlike code-defined skills (Step05), class-based skills bundle all components into a single
-// class extending AgentClassSkill. Skill script and resource functions can still resolve
-// services from the DI container via IServiceProvider, combining class-based organization
-// with the flexibility of DI.
-
-using System.Text.Json;
-using Azure.AI.OpenAI;
-using Azure.Identity;
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.DependencyInjection;
-using OpenAI.Responses;
-
-// --- Configuration ---
-string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
-string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
-
-// --- Class-Based Skill with DI ---
-// Instantiate the skill class. Its resources and scripts will resolve services from
-// the DI container at execution time.
-var unitConverter = new UnitConverterSkill();
-
-// --- Skills Provider ---
-var skillsProvider = new AgentSkillsProvider(unitConverter);
-
-// --- DI Container ---
-// Register application services that skill scripts can resolve at execution time.
-ServiceCollection services = new();
-services.AddSingleton();
-
-// --- Agent Setup ---
-AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
- .GetResponsesClient()
- .AsAIAgent(
- options: new ChatClientAgentOptions
- {
- Name = "UnitConverterAgent",
- ChatOptions = new()
- {
- Instructions = "You are a helpful assistant that can convert units.",
- },
- AIContextProviders = [skillsProvider],
- },
- model: deploymentName,
- services: services.BuildServiceProvider());
-
-// --- Example: Unit conversion ---
-Console.WriteLine("Converting units with DI-powered class-based skills");
-Console.WriteLine(new string('-', 60));
-
-AgentResponse response = await agent.RunAsync(
- "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
-
-Console.WriteLine($"Agent: {response.Text}");
-
-///
-/// A unit-converter skill defined as a C# class that uses Dependency Injection.
-///
-///
-/// This skill resolves from the DI container
-/// in both its resource and script functions. This enables clean separation of
-/// concerns and testability while retaining the class-based skill pattern.
-///
-internal sealed class UnitConverterSkill : AgentClassSkill
-{
- private IReadOnlyList? _resources;
- private IReadOnlyList? _scripts;
-
- ///
- public override AgentSkillFrontmatter Frontmatter { get; } = new(
- "unit-converter",
- "Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.");
-
- ///
- protected override string Instructions => """
- Use this skill when the user asks to convert between units.
-
- 1. Review the conversion-table resource to find the factor for the requested conversion.
- 2. Use the convert script, passing the value and factor from the table.
- 3. Present the result clearly with both units.
- """;
-
- ///
- public override IReadOnlyList? Resources => this._resources ??=
- [
- // Dynamic resource with DI: resolves ConversionRateService to build conversion table
- CreateResource("conversion-table", (IServiceProvider serviceProvider) =>
- {
- var rateService = serviceProvider.GetRequiredService();
- return rateService.GetConversionTable();
- }),
- ];
-
- ///
- public override IReadOnlyList? Scripts => this._scripts ??=
- [
- // Script with DI: resolves ConversionRateService to perform the conversion
- CreateScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
- {
- var rateService = serviceProvider.GetRequiredService();
- return rateService.Convert(value, factor);
- }),
- ];
-}
-
-///
-/// Provides conversion rates between units.
-/// In a real application this could call an external API, read from a database,
-/// or apply time-varying exchange rates.
-///
-internal sealed class ConversionRateService
-{
- ///
- /// Returns a static markdown table of all supported conversions with factors.
- ///
- public string GetConversionTable() =>
- """
- # 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 |
- """;
-
- ///
- /// Converts a value by the given factor and returns a JSON result.
- ///
- public string Convert(double value, double factor)
- {
- double result = Math.Round(value * factor, 4);
- return JsonSerializer.Serialize(new { value, factor, result });
- }
-}
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/README.md b/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/README.md
deleted file mode 100644
index 1406dbb309..0000000000
--- a/dotnet/samples/02-agents/AgentSkills/Agent_Step06_ClassBasedSkillsWithDI/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# Class-Based Agent Skills with Dependency Injection
-
-This sample demonstrates how to use **Dependency Injection (DI)** with **class-based Agent Skills** (`AgentClassSkill`).
-
-## What It Shows
-
-- Defining a skill as a class that extends `AgentClassSkill`
-- Using `IServiceProvider` in skill resource delegates to resolve services from the DI container
-- Using `IServiceProvider` in skill script delegates to resolve services from the DI container
-- Registering application services in a `ServiceCollection` and passing the built provider to the agent
-
-## How It Works
-
-1. A `ConversionRateService` is registered as a singleton in the DI container
-2. `UnitConverterSkill` extends `AgentClassSkill` and declares its resources and scripts using `CreateResource` and `CreateScript` factory methods
-3. The resource delegate declares `IServiceProvider` as a parameter — the framework injects it automatically
-4. The resource resolves `ConversionRateService` from the provider to build a supported-conversions table dynamically
-5. The script delegate also declares `IServiceProvider` as a parameter to look up conversion factors at runtime
-6. The agent is created with the service provider, which flows through to skill resource and script execution
-
-## How It Differs from Other Samples
-
-| Sample | Skill Type | DI Support |
-|--------|-----------|------------|
-| [Step03](../Agent_Step03_ClassBasedSkills/) | Class-based (`AgentClassSkill`) | No — static resources |
-| [Step05](../Agent_Step05_CodeDefinedSkillsWithDI/) | Code-defined (`AgentInlineSkill`) | Yes — inline delegates |
-| **Step06 (this)** | **Class-based (`AgentClassSkill`)** | **Yes — class delegates** |
-
-## Prerequisites
-
-- .NET 10
-- An Azure OpenAI deployment
-
-## Configuration
-
-Set the following environment variables:
-
-| Variable | Description |
-|---|---|
-| `AZURE_OPENAI_ENDPOINT` | Your Azure OpenAI endpoint URL |
-| `AZURE_OPENAI_DEPLOYMENT_NAME` | Model deployment name (defaults to `gpt-4o-mini`) |
-
-## Running the Sample
-
-```bash
-dotnet run
-```
-
-### Expected Output
-
-```
-Converting units with DI-powered class-based skills
-------------------------------------------------------------
-Agent: Here are your conversions:
-
-1. **26.2 miles → 42.16 km** (a marathon distance)
-2. **75 kg → 165.35 lbs**
-```
diff --git a/dotnet/samples/02-agents/AgentSkills/README.md b/dotnet/samples/02-agents/AgentSkills/README.md
index bcdcf6be81..bbf511da4e 100644
--- a/dotnet/samples/02-agents/AgentSkills/README.md
+++ b/dotnet/samples/02-agents/AgentSkills/README.md
@@ -8,8 +8,7 @@ Samples demonstrating Agent Skills capabilities. Each sample shows a different w
| [Agent_Step02_CodeDefinedSkills](Agent_Step02_CodeDefinedSkills/) | Define skills entirely in C# code using `AgentInlineSkill`, with static/dynamic resources and scripts. |
| [Agent_Step03_ClassBasedSkills](Agent_Step03_ClassBasedSkills/) | Define skills as C# classes using `AgentClassSkill`. |
| [Agent_Step04_MixedSkills](Agent_Step04_MixedSkills/) | **(Advanced)** Combine file-based, code-defined, and class-based skills using `AgentSkillsProviderBuilder`. |
-| [Agent_Step05_CodeDefinedSkillsWithDI](Agent_Step05_CodeDefinedSkillsWithDI/) | Use Dependency Injection with code-defined skills (`AgentInlineSkill`). |
-| [Agent_Step06_ClassBasedSkillsWithDI](Agent_Step06_ClassBasedSkillsWithDI/) | Use Dependency Injection with class-based skills (`AgentClassSkill`). |
+| [Agent_Step05_SkillsWithDI](Agent_Step05_SkillsWithDI/) | Use Dependency Injection with both code-defined (`AgentInlineSkill`) and class-based (`AgentClassSkill`) skills. |
## Key Concepts
From 56a625aa6c089b03df91a351530543075e40dda1 Mon Sep 17 00:00:00 2001
From: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
Date: Fri, 3 Apr 2026 10:50:36 +0000
Subject: [PATCH 6/7] fix file encoding
---
.../02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs
index eedbbbda41..f0c5a4c8a5 100644
--- a/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs
+++ b/dotnet/samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Program.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
// This sample demonstrates how to use Dependency Injection (DI) with Agent Skills.
// It shows two approaches side-by-side, each handling a different conversion domain:
From b758b3cfa26de23fae93d83575c52ef819849b24 Mon Sep 17 00:00:00 2001
From: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
Date: Fri, 3 Apr 2026 11:12:29 +0000
Subject: [PATCH 7/7] suppress compatibility warning
---
.../CompatibilitySuppressions.xml | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/dotnet/src/Microsoft.Agents.AI/CompatibilitySuppressions.xml b/dotnet/src/Microsoft.Agents.AI/CompatibilitySuppressions.xml
index ba6315295e..8b7fd65d4c 100644
--- a/dotnet/src/Microsoft.Agents.AI/CompatibilitySuppressions.xml
+++ b/dotnet/src/Microsoft.Agents.AI/CompatibilitySuppressions.xml
@@ -1,6 +1,20 @@
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])
+ lib/net10.0/Microsoft.Agents.AI.dll
+ lib/net10.0/Microsoft.Agents.AI.dll
+ true
+
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)
+ lib/net10.0/Microsoft.Agents.AI.dll
+ lib/net10.0/Microsoft.Agents.AI.dll
+ true
+ CP0002M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory
@@ -22,6 +36,20 @@
lib/net10.0/Microsoft.Agents.AI.dlltrue
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])
+ lib/net472/Microsoft.Agents.AI.dll
+ lib/net472/Microsoft.Agents.AI.dll
+ true
+
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)
+ lib/net472/Microsoft.Agents.AI.dll
+ lib/net472/Microsoft.Agents.AI.dll
+ true
+ CP0002M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory
@@ -43,6 +71,20 @@
lib/net472/Microsoft.Agents.AI.dlltrue
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])
+ lib/net8.0/Microsoft.Agents.AI.dll
+ lib/net8.0/Microsoft.Agents.AI.dll
+ true
+
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)
+ lib/net8.0/Microsoft.Agents.AI.dll
+ lib/net8.0/Microsoft.Agents.AI.dll
+ true
+ CP0002M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory
@@ -64,6 +106,20 @@
lib/net8.0/Microsoft.Agents.AI.dlltrue
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])
+ lib/net9.0/Microsoft.Agents.AI.dll
+ lib/net9.0/Microsoft.Agents.AI.dll
+ true
+
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)
+ lib/net9.0/Microsoft.Agents.AI.dll
+ lib/net9.0/Microsoft.Agents.AI.dll
+ true
+ CP0002M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory
@@ -85,6 +141,20 @@
lib/net9.0/Microsoft.Agents.AI.dlltrue
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])
+ lib/netstandard2.0/Microsoft.Agents.AI.dll
+ lib/netstandard2.0/Microsoft.Agents.AI.dll
+ true
+
+
+ CP0002
+ M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)
+ lib/netstandard2.0/Microsoft.Agents.AI.dll
+ lib/netstandard2.0/Microsoft.Agents.AI.dll
+ true
+ CP0002M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory