Skip to content

Commit de78348

Browse files
.NET: Add .NET Anthropic Claude Skills sample (#3497)
* Initial plan * Add Claude Skills sample and integration tests for Anthropic - Add Agent_Anthropic_Step04_UsingSkills sample demonstrating pptx skill usage - Add integration tests for skills functionality - Update README.md with new sample reference - Update solution file to include new sample project Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> * Simplify Anthropic Skills sample with AsAITool and add file download * Remove excessive comments from integration tests * Update README with correct model name and syntax * Fix Anthropic SDK 12.3.0 API changes: APIKey->ApiKey, SkillListPageResponse->SkillListPage, Data->Items --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
1 parent e8902c0 commit de78348

File tree

6 files changed

+334
-0
lines changed

6 files changed

+334
-0
lines changed

dotnet/agent-framework-dotnet.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
<Project Path="samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step01_Running/Agent_Anthropic_Step01_Running.csproj" />
132132
<Project Path="samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step02_Reasoning/Agent_Anthropic_Step02_Reasoning.csproj" />
133133
<Project Path="samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step03_UsingFunctionTools/Agent_Anthropic_Step03_UsingFunctionTools.csproj" />
134+
<Project Path="samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step04_UsingSkills/Agent_Anthropic_Step04_UsingSkills.csproj" />
134135
</Folder>
135136
<Folder Name="/Samples/GettingStarted/AgentWithMemory/">
136137
<File Path="samples/GettingStarted/AgentWithMemory/README.md" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
7+
<Nullable>enable</Nullable>
8+
<ImplicitUsings>enable</ImplicitUsings>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Anthropic\Microsoft.Agents.AI.Anthropic.csproj" />
13+
</ItemGroup>
14+
15+
</Project>
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
// This sample demonstrates how to use Anthropic-managed Skills with an AI agent.
4+
// Skills are pre-built capabilities provided by Anthropic that can be used with the Claude API.
5+
// This sample shows how to:
6+
// 1. List available Anthropic-managed skills
7+
// 2. Use the pptx skill to create PowerPoint presentations
8+
// 3. Download and save generated files
9+
10+
using Anthropic;
11+
using Anthropic.Core;
12+
using Anthropic.Models.Beta;
13+
using Anthropic.Models.Beta.Files;
14+
using Anthropic.Models.Beta.Messages;
15+
using Anthropic.Models.Beta.Skills;
16+
using Anthropic.Services;
17+
using Microsoft.Agents.AI;
18+
using Microsoft.Extensions.AI;
19+
20+
string apiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY") ?? throw new InvalidOperationException("ANTHROPIC_API_KEY is not set.");
21+
// Skills require Claude 4.5 models (Sonnet 4.5, Haiku 4.5, or Opus 4.5)
22+
string model = Environment.GetEnvironmentVariable("ANTHROPIC_MODEL") ?? "claude-sonnet-4-5-20250929";
23+
24+
// Create the Anthropic client
25+
AnthropicClient anthropicClient = new() { ApiKey = apiKey };
26+
27+
// List available Anthropic-managed skills (optional - API may not be available in all regions)
28+
Console.WriteLine("Available Anthropic-managed skills:");
29+
try
30+
{
31+
SkillListPage skills = await anthropicClient.Beta.Skills.List(
32+
new SkillListParams { Source = "anthropic", Betas = [AnthropicBeta.Skills2025_10_02] });
33+
34+
foreach (var skill in skills.Items)
35+
{
36+
Console.WriteLine($" {skill.Source}: {skill.ID} (version: {skill.LatestVersion})");
37+
}
38+
}
39+
catch (Exception ex)
40+
{
41+
Console.WriteLine($" (Skills listing not available: {ex.Message})");
42+
}
43+
44+
Console.WriteLine();
45+
46+
// Define the pptx skill - the SDK handles all beta flags and container configuration automatically
47+
// when using AsAITool(), so no manual RawRepresentationFactory configuration is needed.
48+
BetaSkillParams pptxSkill = new()
49+
{
50+
Type = BetaSkillParamsType.Anthropic,
51+
SkillID = "pptx",
52+
Version = "latest"
53+
};
54+
55+
// Create an agent with the pptx skill enabled.
56+
// Skills require extended thinking and higher max tokens for complex file generation.
57+
// The SDK's AsAITool() handles beta flags and container config automatically.
58+
ChatClientAgent agent = anthropicClient.Beta.AsAIAgent(
59+
model: model,
60+
instructions: "You are a helpful agent for creating PowerPoint presentations.",
61+
tools: [pptxSkill.AsAITool()],
62+
clientFactory: (chatClient) => chatClient
63+
.AsBuilder()
64+
.ConfigureOptions(options =>
65+
{
66+
options.RawRepresentationFactory = (_) => new MessageCreateParams()
67+
{
68+
Model = model,
69+
MaxTokens = 20000,
70+
Messages = [],
71+
Thinking = new BetaThinkingConfigParam(
72+
new BetaThinkingConfigEnabled(budgetTokens: 10000))
73+
};
74+
})
75+
.Build());
76+
77+
Console.WriteLine("Creating a presentation about renewable energy...\n");
78+
79+
// Run the agent with a request to create a presentation
80+
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.");
81+
82+
Console.WriteLine("#### Agent Response ####");
83+
Console.WriteLine(response.Text);
84+
85+
// Display any reasoning/thinking content
86+
List<TextReasoningContent> reasoningContents = response.Messages.SelectMany(m => m.Contents.OfType<TextReasoningContent>()).ToList();
87+
if (reasoningContents.Count > 0)
88+
{
89+
Console.WriteLine("\n#### Agent Reasoning ####");
90+
Console.WriteLine($"\e[92m{string.Join("\n", reasoningContents.Select(c => c.Text))}\e[0m");
91+
}
92+
93+
// Collect generated files from CodeInterpreterToolResultContent outputs
94+
List<HostedFileContent> hostedFiles = response.Messages
95+
.SelectMany(m => m.Contents.OfType<CodeInterpreterToolResultContent>())
96+
.Where(c => c.Outputs is not null)
97+
.SelectMany(c => c.Outputs!.OfType<HostedFileContent>())
98+
.ToList();
99+
100+
if (hostedFiles.Count > 0)
101+
{
102+
Console.WriteLine("\n#### Generated Files ####");
103+
foreach (HostedFileContent file in hostedFiles)
104+
{
105+
Console.WriteLine($" FileId: {file.FileId}");
106+
107+
// Download the file using the Anthropic Files API
108+
using HttpResponse fileResponse = await anthropicClient.Beta.Files.Download(
109+
file.FileId,
110+
new FileDownloadParams { Betas = ["files-api-2025-04-14"] });
111+
112+
// Save the file to disk
113+
string fileName = $"presentation_{file.FileId.Substring(0, 8)}.pptx";
114+
using FileStream fileStream = File.Create(fileName);
115+
Stream contentStream = await fileResponse.ReadAsStream();
116+
await contentStream.CopyToAsync(fileStream);
117+
118+
Console.WriteLine($" Saved to: {fileName}");
119+
}
120+
}
121+
122+
Console.WriteLine("\nToken usage:");
123+
Console.WriteLine($"Input: {response.Usage?.InputTokenCount}, Output: {response.Usage?.OutputTokenCount}");
124+
if (response.Usage?.AdditionalCounts is not null)
125+
{
126+
Console.WriteLine($"Additional: {string.Join(", ", response.Usage.AdditionalCounts)}");
127+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Using Anthropic Skills with agents
2+
3+
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.
4+
5+
## What this sample demonstrates
6+
7+
- Listing available Anthropic-managed skills
8+
- Creating an AI agent with Anthropic Claude Skills support using the simplified `AsAITool()` approach
9+
- Using the pptx skill to create PowerPoint presentations
10+
- Downloading and saving generated files to disk
11+
- Handling agent responses with generated content
12+
13+
## Prerequisites
14+
15+
Before you begin, ensure you have the following prerequisites:
16+
17+
- .NET 10.0 SDK or later
18+
- Anthropic API key configured
19+
- Access to Anthropic Claude models with Skills support
20+
21+
**Note**: This sample uses Anthropic Claude models with Skills. Skills are a beta feature. For more information, see [Anthropic documentation](https://docs.anthropic.com/).
22+
23+
Set the following environment variables:
24+
25+
```powershell
26+
$env:ANTHROPIC_API_KEY="your-anthropic-api-key" # Replace with your Anthropic API key
27+
$env:ANTHROPIC_MODEL="your-anthropic-model" # Replace with your Anthropic model (e.g., claude-sonnet-4-5-20250929)
28+
```
29+
30+
## Run the sample
31+
32+
Navigate to the AgentWithAnthropic sample directory and run:
33+
34+
```powershell
35+
cd dotnet\samples\GettingStarted\AgentWithAnthropic
36+
dotnet run --project .\Agent_Anthropic_Step04_UsingSkills
37+
```
38+
39+
## Available Anthropic Skills
40+
41+
Anthropic provides several managed skills that can be used with the Claude API:
42+
43+
- `pptx` - Create PowerPoint presentations
44+
- `xlsx` - Create Excel spreadsheets
45+
- `docx` - Create Word documents
46+
- `pdf` - Create and analyze PDF documents
47+
48+
You can list available skills using the Anthropic SDK:
49+
50+
```csharp
51+
SkillListPage skills = await anthropicClient.Beta.Skills.List(
52+
new SkillListParams { Source = "anthropic", Betas = [AnthropicBeta.Skills2025_10_02] });
53+
54+
foreach (var skill in skills.Items)
55+
{
56+
Console.WriteLine($"{skill.Source}: {skill.ID} (version: {skill.LatestVersion})");
57+
}
58+
```
59+
60+
## Expected behavior
61+
62+
The sample will:
63+
64+
1. List all available Anthropic-managed skills
65+
2. Create an agent with the pptx skill enabled
66+
3. Run the agent with a request to create a presentation
67+
4. Display the agent's response text
68+
5. Download any generated files and save them to disk
69+
6. Display token usage statistics
70+
71+
## Code highlights
72+
73+
### Simplified skill configuration
74+
75+
The Anthropic SDK handles all beta flags and container configuration automatically when using `AsAITool()`:
76+
77+
```csharp
78+
// Define the pptx skill
79+
BetaSkillParams pptxSkill = new()
80+
{
81+
Type = BetaSkillParamsType.Anthropic,
82+
SkillID = "pptx",
83+
Version = "latest"
84+
};
85+
86+
// Create an agent - the SDK handles beta flags automatically!
87+
ChatClientAgent agent = anthropicClient.Beta.AsAIAgent(
88+
model: model,
89+
instructions: "You are a helpful agent for creating PowerPoint presentations.",
90+
tools: [pptxSkill.AsAITool()]);
91+
```
92+
93+
**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.
94+
95+
### Handling generated files
96+
97+
Generated files are returned as `HostedFileContent` within `CodeInterpreterToolResultContent`:
98+
99+
```csharp
100+
// Collect generated files from response
101+
List<HostedFileContent> hostedFiles = response.Messages
102+
.SelectMany(m => m.Contents.OfType<CodeInterpreterToolResultContent>())
103+
.Where(c => c.Outputs is not null)
104+
.SelectMany(c => c.Outputs!.OfType<HostedFileContent>())
105+
.ToList();
106+
107+
// Download and save each file
108+
foreach (HostedFileContent file in hostedFiles)
109+
{
110+
using HttpResponse fileResponse = await anthropicClient.Beta.Files.Download(
111+
file.FileId,
112+
new FileDownloadParams { Betas = ["files-api-2025-04-14"] });
113+
114+
string fileName = $"presentation_{file.FileId.Substring(0, 8)}.pptx";
115+
await using FileStream fileStream = File.Create(fileName);
116+
Stream contentStream = await fileResponse.ReadAsStream();
117+
await contentStream.CopyToAsync(fileStream);
118+
}
119+
```

dotnet/samples/GettingStarted/AgentWithAnthropic/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ To use Anthropic with Azure Foundry, you can check the sample [AgentProviders/Ag
2929
|[Running a simple agent](./Agent_Anthropic_Step01_Running/)|This sample demonstrates how to create and run a basic agent with Anthropic Claude|
3030
|[Using reasoning with an agent](./Agent_Anthropic_Step02_Reasoning/)|This sample demonstrates how to use extended thinking/reasoning capabilities with Anthropic Claude agents|
3131
|[Using function tools with an agent](./Agent_Anthropic_Step03_UsingFunctionTools/)|This sample demonstrates how to use function tools with an Anthropic Claude agent|
32+
|[Using Skills with an agent](./Agent_Anthropic_Step04_UsingSkills/)|This sample demonstrates how to use Anthropic-managed Skills (e.g., pptx) with an Anthropic Claude agent|
3233

3334
## Running the samples from the console
3435

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Threading.Tasks;
4+
using AgentConformance.IntegrationTests.Support;
5+
using Anthropic;
6+
using Anthropic.Models.Beta;
7+
using Anthropic.Models.Beta.Messages;
8+
using Anthropic.Models.Beta.Skills;
9+
using Anthropic.Services;
10+
using Microsoft.Agents.AI;
11+
using Microsoft.Extensions.AI;
12+
using Shared.IntegrationTests;
13+
14+
namespace AnthropicChatCompletion.IntegrationTests;
15+
16+
/// <summary>
17+
/// Integration tests for Anthropic Skills functionality.
18+
/// These tests are designed to be run locally with a valid Anthropic API key.
19+
/// </summary>
20+
public sealed class AnthropicSkillsIntegrationTests
21+
{
22+
// All tests for Anthropic are intended to be ran locally as the CI pipeline for Anthropic is not setup.
23+
private const string SkipReason = "Integrations tests for local execution only";
24+
25+
private static readonly AnthropicConfiguration s_config = TestConfiguration.LoadSection<AnthropicConfiguration>();
26+
27+
[Fact(Skip = SkipReason)]
28+
public async Task CreateAgentWithPptxSkillAsync()
29+
{
30+
// Arrange
31+
AnthropicClient anthropicClient = new() { ApiKey = s_config.ApiKey };
32+
string model = s_config.ChatModelId;
33+
34+
BetaSkillParams pptxSkill = new()
35+
{
36+
Type = BetaSkillParamsType.Anthropic,
37+
SkillID = "pptx",
38+
Version = "latest"
39+
};
40+
41+
ChatClientAgent agent = anthropicClient.Beta.AsAIAgent(
42+
model: model,
43+
instructions: "You are a helpful agent for creating PowerPoint presentations.",
44+
tools: [pptxSkill.AsAITool()]);
45+
46+
// Act
47+
AgentResponse response = await agent.RunAsync(
48+
"Create a simple 2-slide presentation: a title slide and one content slide about AI.");
49+
50+
// Assert
51+
Assert.NotNull(response);
52+
Assert.NotNull(response.Text);
53+
Assert.NotEmpty(response.Text);
54+
}
55+
56+
[Fact(Skip = SkipReason)]
57+
public async Task ListAnthropicManagedSkillsAsync()
58+
{
59+
// Arrange
60+
AnthropicClient anthropicClient = new() { ApiKey = s_config.ApiKey };
61+
62+
// Act
63+
SkillListPage skills = await anthropicClient.Beta.Skills.List(
64+
new SkillListParams { Source = "anthropic", Betas = [AnthropicBeta.Skills2025_10_02] });
65+
66+
// Assert
67+
Assert.NotNull(skills);
68+
Assert.NotNull(skills.Items);
69+
Assert.Contains(skills.Items, skill => skill.ID == "pptx");
70+
}
71+
}

0 commit comments

Comments
 (0)