// 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 with attributes
//
// 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.ComponentModel;
using System.Text.Json;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
// --- Configuration ---
string endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-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 ---
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(new ChatClientAgentOptions
{
Name = "MultiConverterAgent",
ChatOptions = new()
{
ModelId = deploymentName,
Instructions = "You are a helpful assistant that can convert units, volumes, and temperatures.",
},
AIContextProviders = [skillsProvider],
});
// --- 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 using attributes for discovery.
///
///
/// Properties annotated with are automatically
/// discovered as skill resources, and methods annotated with
/// are automatically discovered as skill scripts.
///
internal sealed class TemperatureConverterSkill : AgentClassSkill
{
///
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.
""";
///
/// A reference table of temperature conversion formulas.
///
[AgentSkillResource("temperature-conversion-formulas")]
[Description("Formulas for converting between Fahrenheit, Celsius, and Kelvin.")]
public string ConversionFormulas => """
# 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 |
""";
///
/// Converts a temperature value between scales.
///
[AgentSkillScript("convert-temperature")]
[Description("Converts a temperature value from one scale to another.")]
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 });
}
}