-
Notifications
You must be signed in to change notification settings - Fork 2k
.NET: Add .NET Anthropic Claude Skills sample #3497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
0c810ce
74ce68f
8ba1f32
04784f5
e732af4
9903571
093fdf6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net10.0</TargetFramework> | ||
|
|
||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Anthropic\Microsoft.Agents.AI.Anthropic.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| // This sample demonstrates how to use Anthropic-managed Skills with an AI agent. | ||
| // Skills are pre-built capabilities provided by Anthropic that can be used with the Claude API. | ||
| // This sample shows how to: | ||
| // 1. List available Anthropic-managed skills | ||
| // 2. Use the pptx skill to create PowerPoint presentations | ||
| // 3. Download and save generated files | ||
|
|
||
| using Anthropic; | ||
| using Anthropic.Core; | ||
| using Anthropic.Models.Beta; | ||
| using Anthropic.Models.Beta.Files; | ||
| using Anthropic.Models.Beta.Messages; | ||
| using Anthropic.Models.Beta.Skills; | ||
| using Anthropic.Services; | ||
| using Microsoft.Agents.AI; | ||
| using Microsoft.Extensions.AI; | ||
|
|
||
| string apiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY") ?? throw new InvalidOperationException("ANTHROPIC_API_KEY is not set."); | ||
| // Skills require Claude 4.5 models (Sonnet 4.5, Haiku 4.5, or Opus 4.5) | ||
| string model = Environment.GetEnvironmentVariable("ANTHROPIC_MODEL") ?? "claude-sonnet-4-5-20250929"; | ||
|
|
||
| // Create the Anthropic client | ||
| AnthropicClient anthropicClient = new() { APIKey = apiKey }; | ||
|
Check failure on line 25 in dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step04_UsingSkills/Program.cs
|
||
|
|
||
| // List available Anthropic-managed skills (optional - API may not be available in all regions) | ||
| Console.WriteLine("Available Anthropic-managed skills:"); | ||
| try | ||
| { | ||
| SkillListPageResponse skills = await anthropicClient.Beta.Skills.List( | ||
|
Check failure on line 31 in dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step04_UsingSkills/Program.cs
|
||
| new SkillListParams { Source = "anthropic", Betas = [AnthropicBeta.Skills2025_10_02] }); | ||
|
|
||
| foreach (var skill in skills.Data) | ||
| { | ||
| Console.WriteLine($" {skill.Source}: {skill.ID} (version: {skill.LatestVersion})"); | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Console.WriteLine($" (Skills listing not available: {ex.Message})"); | ||
| } | ||
|
|
||
| Console.WriteLine(); | ||
|
|
||
| // Define the pptx skill - the SDK handles all beta flags and container configuration automatically | ||
| // when using AsAITool(), so no manual RawRepresentationFactory configuration is needed. | ||
| BetaSkillParams pptxSkill = new() | ||
| { | ||
| Type = BetaSkillParamsType.Anthropic, | ||
| SkillID = "pptx", | ||
| Version = "latest" | ||
| }; | ||
|
|
||
| // Create an agent with the pptx skill enabled. | ||
| // Skills require extended thinking and higher max tokens for complex file generation. | ||
| // The SDK's AsAITool() handles beta flags and container config automatically. | ||
| ChatClientAgent agent = anthropicClient.Beta.AsAIAgent( | ||
| model: model, | ||
| instructions: "You are a helpful agent for creating PowerPoint presentations.", | ||
| tools: [pptxSkill.AsAITool()], | ||
| clientFactory: (chatClient) => chatClient | ||
| .AsBuilder() | ||
| .ConfigureOptions(options => | ||
| { | ||
| options.RawRepresentationFactory = (_) => new MessageCreateParams() | ||
| { | ||
| Model = model, | ||
| MaxTokens = 20000, | ||
| Messages = [], | ||
| Thinking = new BetaThinkingConfigParam( | ||
| new BetaThinkingConfigEnabled(budgetTokens: 10000)) | ||
| }; | ||
| }) | ||
| .Build()); | ||
|
|
||
| Console.WriteLine("Creating a presentation about renewable energy...\n"); | ||
|
|
||
| // Run the agent with a request to create a presentation | ||
| AgentResponse response = await agent.RunAsync("Create a simple 3-slide presentation about renewable energy sources. Include a title slide, a slide about solar energy, and a slide about wind energy."); | ||
|
|
||
| Console.WriteLine("#### Agent Response ####"); | ||
| Console.WriteLine(response.Text); | ||
|
|
||
| // Display any reasoning/thinking content | ||
| List<TextReasoningContent> reasoningContents = response.Messages.SelectMany(m => m.Contents.OfType<TextReasoningContent>()).ToList(); | ||
| if (reasoningContents.Count > 0) | ||
| { | ||
| Console.WriteLine("\n#### Agent Reasoning ####"); | ||
| Console.WriteLine($"\e[92m{string.Join("\n", reasoningContents.Select(c => c.Text))}\e[0m"); | ||
| } | ||
|
|
||
| // Collect generated files from CodeInterpreterToolResultContent outputs | ||
| List<HostedFileContent> hostedFiles = response.Messages | ||
| .SelectMany(m => m.Contents.OfType<CodeInterpreterToolResultContent>()) | ||
| .Where(c => c.Outputs is not null) | ||
| .SelectMany(c => c.Outputs!.OfType<HostedFileContent>()) | ||
| .ToList(); | ||
|
|
||
| if (hostedFiles.Count > 0) | ||
| { | ||
| Console.WriteLine("\n#### Generated Files ####"); | ||
| foreach (HostedFileContent file in hostedFiles) | ||
| { | ||
| Console.WriteLine($" FileId: {file.FileId}"); | ||
|
|
||
| // Download the file using the Anthropic Files API | ||
| using HttpResponse fileResponse = await anthropicClient.Beta.Files.Download( | ||
| file.FileId, | ||
| new FileDownloadParams { Betas = ["files-api-2025-04-14"] }); | ||
|
|
||
| // Save the file to disk | ||
| string fileName = $"presentation_{file.FileId.Substring(0, 8)}.pptx"; | ||
| using FileStream fileStream = File.Create(fileName); | ||
|
rogerbarreto marked this conversation as resolved.
|
||
| Stream contentStream = await fileResponse.ReadAsStream(); | ||
| await contentStream.CopyToAsync(fileStream); | ||
|
|
||
| Console.WriteLine($" Saved to: {fileName}"); | ||
| } | ||
| } | ||
|
|
||
| Console.WriteLine("\nToken usage:"); | ||
| Console.WriteLine($"Input: {response.Usage?.InputTokenCount}, Output: {response.Usage?.OutputTokenCount}"); | ||
| if (response.Usage?.AdditionalCounts is not null) | ||
| { | ||
| Console.WriteLine($"Additional: {string.Join(", ", response.Usage.AdditionalCounts)}"); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| # Using Anthropic Skills with agents | ||
|
|
||
| This sample demonstrates how to use Anthropic-managed Skills with AI agents. Skills are pre-built capabilities provided by Anthropic that can be used with the Claude API. | ||
|
|
||
| ## What this sample demonstrates | ||
|
|
||
| - Listing available Anthropic-managed skills | ||
| - Creating an AI agent with Anthropic Claude Skills support using the simplified `AsAITool()` approach | ||
| - Using the pptx skill to create PowerPoint presentations | ||
| - Downloading and saving generated files to disk | ||
| - Handling agent responses with generated content | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Before you begin, ensure you have the following prerequisites: | ||
|
|
||
| - .NET 10.0 SDK or later | ||
| - Anthropic API key configured | ||
| - Access to Anthropic Claude models with Skills support | ||
|
|
||
| **Note**: This sample uses Anthropic Claude models with Skills. Skills are a beta feature. For more information, see [Anthropic documentation](https://docs.anthropic.com/). | ||
|
|
||
| Set the following environment variables: | ||
|
|
||
| ```powershell | ||
| $env:ANTHROPIC_API_KEY="your-anthropic-api-key" # Replace with your Anthropic API key | ||
| $env:ANTHROPIC_MODEL="your-anthropic-model" # Replace with your Anthropic model (e.g., claude-sonnet-4-5-20250929) | ||
| ``` | ||
|
|
||
| ## Run the sample | ||
|
|
||
| Navigate to the AgentWithAnthropic sample directory and run: | ||
|
|
||
| ```powershell | ||
| cd dotnet\samples\GettingStarted\AgentWithAnthropic | ||
| dotnet run --project .\Agent_Anthropic_Step04_UsingSkills | ||
| ``` | ||
|
|
||
| ## Available Anthropic Skills | ||
|
|
||
| Anthropic provides several managed skills that can be used with the Claude API: | ||
|
|
||
| - `pptx` - Create PowerPoint presentations | ||
| - `xlsx` - Create Excel spreadsheets | ||
| - `docx` - Create Word documents | ||
| - `pdf` - Create and analyze PDF documents | ||
|
|
||
| You can list available skills using the Anthropic SDK: | ||
|
|
||
| ```csharp | ||
| SkillListPageResponse skills = await anthropicClient.Beta.Skills.List( | ||
| new SkillListParams { Source = "anthropic", Betas = [AnthropicBeta.Skills2025_10_02] }); | ||
|
|
||
| foreach (var skill in skills.Data) | ||
| { | ||
| Console.WriteLine($"{skill.Source}: {skill.ID} (version: {skill.LatestVersion})"); | ||
| } | ||
| ``` | ||
|
|
||
| ## Expected behavior | ||
|
|
||
| The sample will: | ||
|
|
||
| 1. List all available Anthropic-managed skills | ||
| 2. Create an agent with the pptx skill enabled | ||
| 3. Run the agent with a request to create a presentation | ||
| 4. Display the agent's response text | ||
| 5. Download any generated files and save them to disk | ||
| 6. Display token usage statistics | ||
|
|
||
| ## Code highlights | ||
|
|
||
| ### Simplified skill configuration | ||
|
|
||
| The Anthropic SDK handles all beta flags and container configuration automatically when using `AsAITool()`: | ||
|
|
||
| ```csharp | ||
| // Define the pptx skill | ||
| BetaSkillParams pptxSkill = new() | ||
| { | ||
| Type = BetaSkillParamsType.Anthropic, | ||
| SkillID = "pptx", | ||
| Version = "latest" | ||
| }; | ||
|
|
||
| // Create an agent - the SDK handles beta flags automatically! | ||
| ChatClientAgent agent = anthropicClient.Beta.AsAIAgent( | ||
| model: model, | ||
| instructions: "You are a helpful agent for creating PowerPoint presentations.", | ||
| tools: [pptxSkill.AsAITool()]); | ||
| ``` | ||
|
|
||
| **Note**: No manual `RawRepresentationFactory`, `Betas`, or `Container` configuration is needed. The SDK automatically adds the required beta headers (`skills-2025-10-02`, `code-execution-2025-08-25`) and configures the container with the skill. | ||
|
|
||
| ### Handling generated files | ||
|
|
||
| Generated files are returned as `HostedFileContent` within `CodeInterpreterToolResultContent`: | ||
|
|
||
| ```csharp | ||
| // Collect generated files from response | ||
| List<HostedFileContent> hostedFiles = response.Messages | ||
| .SelectMany(m => m.Contents.OfType<CodeInterpreterToolResultContent>()) | ||
| .Where(c => c.Outputs is not null) | ||
| .SelectMany(c => c.Outputs!.OfType<HostedFileContent>()) | ||
| .ToList(); | ||
|
|
||
| // Download and save each file | ||
| foreach (HostedFileContent file in hostedFiles) | ||
| { | ||
| using HttpResponse fileResponse = await anthropicClient.Beta.Files.Download( | ||
| file.FileId, | ||
| new FileDownloadParams { Betas = ["files-api-2025-04-14"] }); | ||
|
|
||
| string fileName = $"presentation_{file.FileId.Substring(0, 8)}.pptx"; | ||
| await using FileStream fileStream = File.Create(fileName); | ||
| Stream contentStream = await fileResponse.ReadAsStream(); | ||
| await contentStream.CopyToAsync(fileStream); | ||
| } | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| using System.Threading.Tasks; | ||
| using AgentConformance.IntegrationTests.Support; | ||
| using Anthropic; | ||
| using Anthropic.Models.Beta; | ||
| using Anthropic.Models.Beta.Messages; | ||
| using Anthropic.Models.Beta.Skills; | ||
| using Anthropic.Services; | ||
| using Microsoft.Agents.AI; | ||
| using Microsoft.Extensions.AI; | ||
| using Shared.IntegrationTests; | ||
|
|
||
| namespace AnthropicChatCompletion.IntegrationTests; | ||
|
|
||
| /// <summary> | ||
| /// Integration tests for Anthropic Skills functionality. | ||
| /// These tests are designed to be run locally with a valid Anthropic API key. | ||
| /// </summary> | ||
| public sealed class AnthropicSkillsIntegrationTests | ||
| { | ||
| // All tests for Anthropic are intended to be ran locally as the CI pipeline for Anthropic is not setup. | ||
| private const string SkipReason = "Integrations tests for local execution only"; | ||
|
|
||
| private static readonly AnthropicConfiguration s_config = TestConfiguration.LoadSection<AnthropicConfiguration>(); | ||
|
|
||
| [Fact(Skip = SkipReason)] | ||
| public async Task CreateAgentWithPptxSkillAsync() | ||
| { | ||
| // Arrange | ||
| AnthropicClient anthropicClient = new() { APIKey = s_config.ApiKey }; | ||
|
Check failure on line 31 in dotnet/tests/AnthropicChatCompletion.IntegrationTests/AnthropicSkillsIntegrationTests.cs
|
||
| string model = s_config.ChatModelId; | ||
|
|
||
| BetaSkillParams pptxSkill = new() | ||
| { | ||
| Type = BetaSkillParamsType.Anthropic, | ||
| SkillID = "pptx", | ||
| Version = "latest" | ||
| }; | ||
|
|
||
| ChatClientAgent agent = anthropicClient.Beta.AsAIAgent( | ||
| model: model, | ||
| instructions: "You are a helpful agent for creating PowerPoint presentations.", | ||
| tools: [pptxSkill.AsAITool()]); | ||
|
|
||
| // Act | ||
| AgentResponse response = await agent.RunAsync( | ||
| "Create a simple 2-slide presentation: a title slide and one content slide about AI."); | ||
|
|
||
| // Assert | ||
| Assert.NotNull(response); | ||
| Assert.NotNull(response.Text); | ||
| Assert.NotEmpty(response.Text); | ||
| } | ||
|
|
||
| [Fact(Skip = SkipReason)] | ||
| public async Task ListAnthropicManagedSkillsAsync() | ||
| { | ||
| // Arrange | ||
| AnthropicClient anthropicClient = new() { APIKey = s_config.ApiKey }; | ||
|
Check failure on line 60 in dotnet/tests/AnthropicChatCompletion.IntegrationTests/AnthropicSkillsIntegrationTests.cs
|
||
|
|
||
| // Act | ||
| SkillListPageResponse skills = await anthropicClient.Beta.Skills.List( | ||
|
Check failure on line 63 in dotnet/tests/AnthropicChatCompletion.IntegrationTests/AnthropicSkillsIntegrationTests.cs
|
||
| new SkillListParams { Source = "anthropic", Betas = [AnthropicBeta.Skills2025_10_02] }); | ||
|
|
||
| // Assert | ||
| Assert.NotNull(skills); | ||
| Assert.NotNull(skills.Data); | ||
| Assert.Contains(skills.Data, skill => skill.ID == "pptx"); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.