// 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 }); } }