Anthropic.SDK

repository·main·Indexed 42 days ago

https://github.com/tghamm/anthropic.sdk

An unofficial C# client for interacting with the Claude AI API. It provides a simplified interface for integrating Claude into .NET applications, supporting NetStandard 2.0, .NET 8.0, and .NET 10.0. Features include support for streaming, multimodal inputs (images and PDFs), prompt caching, extended thinking, and integration with Microsoft Semantic Kernel and the Model Context Protocol (MCP).

Tokens
14.5K
Snippets
37
Records
40
Agent score
3%

What's inside Anthropic.SDK

  1. How prompt caching works in AnthropicClient

    main

    The AnthropicClient supports prompt caching for system messages, user messages (including images), assistant messages, tool_results, documents, and tools. There are two primary mechanisms for caching:

    1. AutomaticToolsAndSystem: Automatically caches the System prompt and Tools when present. You can still manually add additional set-points in Messages if desired.
    2. FineGrained: Provides complete manual control. You declare cache control settings at the message and tool level using CacheControl. Note that Anthropic allows a maximum of 4 cache points in total.

    Important Considerations:

    • Caches have a 5-minute expiry enforced by Anthropic.
    • You can monitor cache performance by checking Usage.CacheCreationInputTokens and Usage.CacheReadInputTokens in the response.
    • Cache misses can occur due to various model limitations.
    // Example of Automatic caching
    var parameters = new MessageParameters()
    {
        // ... other params
        PromptCaching = PromptCacheType.AutomaticToolsAndSystem
    };
    
    // Example of Fine-Grained manual caching
    var systemMessages = new List<SystemMessage>()
    {
        new SystemMessage("You are an expert."),
        new SystemMessage(content, new CacheControl() { Type = CacheControlType.ephemeral })
    };
    var parameters = new MessageParameters()
    {
        // ... other params
        PromptCaching = PromptCacheType.FineGrained
    };
  2. How the Skills API works

    main

    The Skills API allows Claude to execute code in a containerized environment to perform tasks like generating PowerPoint (pptx), Excel (xlsx), Word (docx), or PDF documents.

    Key Concepts:

    • Container: A Container object holds the requested Skills. You can pass a new container in a request to start a session, or reuse an existing container by its Id to maintain state across multiple turns.
    • Skills: Skills are identified by a SkillId (e.g., pptx, xlsx) and a Type (usually anthropic or custom).
    • Results: Skill execution results are returned as BashCodeExecutionToolResultContent. You can access Stdout, Stderr, and file outputs.
    • File Outputs: If a skill generates files, you can use the DownloadFilesAsync extension method to download them to a local directory or use the Files API to manage them manually.
    // Create a container with skills
    var container = new Container
    {
        Skills = new List<Skill>
        {
            new Skill { Type = "anthropic", SkillId = "pptx", Version = "latest" }
        }
    };
    
    var parameters = new MessageParameters
    {
        Model = AnthropicModels.Claude4Sonnet,
        Messages = new List<Message> { new Message(RoleType.User, "Create a presentation") },
        Container = container,
        Tools = new List<Common.Tool> { new Function("code_execution", "code_execution_20250825", new Dictionary<string, object> { { "name", "code_execution" } }) }
    };
    
    var response = await client.Messages.GetClaudeMessageAsync(parameters);
  3. Implement custom request logic with IRequestInterceptor

    main

    If you are not using Dependency Injection or need advanced per-request control (like custom logging or metrics), implement the IRequestInterceptor interface and pass it to the AnthropicClient constructor.

    When to use IRequestInterceptor:

    • Custom retry logic beyond HttpClient capabilities.
    • Request/Response logging.
    • Tracking metrics or custom rate limiting.
    • Scenarios where HttpClientFactory is not available.
    public class MyCustomInterceptor : IRequestInterceptor
    {
        public async Task<HttpResponseMessage> InvokeAsync(
            HttpRequestMessage request,
            Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> next,
            CancellationToken cancellationToken = default)
        {
            // Custom logic before the request
            Console.WriteLine($"Sending request to {request.RequestUri}");
    
            // Execute the request
            var response = await next(request, cancellationToken);
    
            // Custom logic after the request
            Console.WriteLine($"Received response: {response.StatusCode}");
    
            return response;
        }
    }
    
    // Usage
    var client = new AnthropicClient(
        apiKeys: new APIAuthentication("your-api-key"),
        requestInterceptor: new MyCustomInterceptor()
    );
  4. Use Web Search with Dynamic Filtering

    main

    The AnthropicClient supports the Web Search API. When using Claude Opus 4.6 or Sonnet 4.6, the default tool version (web_search_20260209) supports dynamic filtering. This allows Claude to write and execute code to filter search results before they enter the context window.

    Note: Dynamic filtering requires the code execution tool to be enabled alongside web search. Citations are automatically enabled when web search is used.

  5. Customize Standard Resilience settings

    main

    You can fine-tune the default resilience parameters (timeouts, retry attempts, backoff types, and circuit breaker thresholds) using .Configure() on the resilience handler.

    services.AddHttpClient<AnthropicClient>()
        .AddStandardResilienceHandler()
        .Configure(options =>
        {
            // Increase total timeout for longer conversations
            options.TotalRequestTimeout.Timeout = TimeSpan.FromMinutes(2);
    
            // Customize retry behavior
            options.Retry.MaxRetryAttempts = 5;
            options.Retry.Delay = TimeSpan.FromSeconds(1);
            options.Retry.BackoffType = DelayBackoffType.Exponential;
            options.Retry.UseJitter = true;
    
            // Adjust circuit breaker for Claude API
            options.CircuitBreaker.SamplingDuration = TimeSpan.FromSeconds(60);
            options.CircuitBreaker.MinimumThroughput = 10;
            options.CircuitBreaker.FailureRatio = 0.5; // Open circuit if 50% fail
            options.CircuitBreaker.BreakDuration = TimeSpan.FromSeconds(30);
    
            // Individual attempt timeout
            options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(30);
        });
  6. Manage batches with the Batching API

    main

    The AnthropicClient supports the Batching API for processing large volumes of requests asynchronously. You can list existing batches, create new batches using BatchRequest, cancel batches, and retrieve results. Results can be streamed as strongly typed messages or as JSONL.

    // create batch
    var messages = new List<Message>();
    messages.Add(new Message(RoleType.User, "Write me a sonnet about the Statue of Liberty"));
    var parameters = new MessageParameters()
    {
        Messages = messages,
        MaxTokens = 512,
        Model = AnthropicModels.Claude46Sonnet,
        Stream = false,
        Temperature = 1.0m,
    };
    
    var batchRequest = new BatchRequest()
    {
        CustomId = "BatchTester",
        MessageParameters = parameters
    };
    
    var response = await client.Batches.CreateBatchAsync(new List<BatchRequest> { batchRequest });
    
    // stream strongly typed batch results when complete
    await foreach (var result in client.Batches.RetrieveBatchResultsAsync(response.Id))
    {
        // result is a wrapped message
    }
    
    // stream jsonl batch results when complete
    await foreach (var result in client.Batches.RetrieveBatchResultsJsonlAsync(response.Id))
    {
        Console.WriteLine("Result: " + result);
    }
  7. Integrate client-side MCP with IChatClient

    main

    You can integrate client-side MCP using the ModelContextProtocol C# SDK to connect to MCP servers directly from your application and use their tools with the IChatClient interface.

    1. Install the MCP package

    dotnet add package ModelContextProtocol --prerelease

    2. Basic Usage Pattern

    1. Create an AnthropicClient and build it using .UseFunctionInvocation() to enable tool support.
    2. Connect to an MCP server (via HttpClientTransport or StdioClientTransport).
    3. Retrieve tools using mcpServer.ListToolsAsync().
    4. Pass these tools into ChatOptions.Tools when calling chatClient.GetResponseAsync().

    3. Combining MCP Tools with Local Functions

    You can merge MCP tools with local AIFunction objects by adding them both to the ChatOptions.Tools list.

    // 1. Setup Client
    IChatClient chatClient = new AnthropicClient()
        .Messages
        .AsBuilder()
        .UseFunctionInvocation()
        .Build();
    
    // 2. Connect to MCP
    await using McpClient mcpServer = await McpClient.CreateAsync(
        new HttpClientTransport(new HttpClientTransportOptions 
        { 
            Endpoint = new Uri("https://learn.microsoft.com/api/mcp") 
        }));
    
    // 3. Get Tools
    var mcpTools = await mcpServer.ListToolsAsync();
    
    // 4. Use in Chat
    ChatOptions options = new()
    {
        ModelId = AnthropicModels.Claude45Haiku,
        Tools = [.. mcpTools]
    };
    
    var response = await chatClient.GetResponseAsync("Tell me about IChatClient", options);
  8. Use Web Fetch to retrieve web page or PDF content

    main

    The AnthropicClient supports the Web Fetch API, enabling Claude to retrieve full content from URLs and PDF documents. The default version (web_fetch_20260209) supports dynamic filtering with Claude Opus 4.6 and Sonnet 4.6. To use the version without dynamic filtering, specify ServerTools.WebFetchVersionLegacy.

    var client = new AnthropicClient();
    var parameters = new MessageParameters()
    {
        Model = AnthropicModels.Claude46Sonnet,
        MaxTokens = 4096,
        Temperature = 1,
        Tools = new List<Common.Tool>()
        {
            ServerTools.GetWebFetchTool(maxUses: 5, enableCitations: true,
                toolVersion: ServerTools.WebFetchVersionLegacy)
        },
        ToolChoice = new ToolChoice()
        {
            Type = ToolChoiceType.Auto
        },
    };
    var messages = new List<Message>
    {
        new Message
        {
            Role = RoleType.User,
            Content = new List<ContentBase>
            {
                new TextContent { Text = "Fetch the content at https://example.com and tell me what it says." }
            }
        }
    };
    parameters.Messages = messages;
    var res = await client.Messages.GetClaudeMessageAsync(parameters);
    Console.WriteLine(res.Content.OfType<TextContent>().Last().Text);
  9. Authenticate with Vertex AI

    main

    To use Claude models via Google Cloud's Vertex AI, you can authenticate using environment variables or via Google Application Default Credentials (ADC).

    ### 1. Environment Variables
    - `GOOGLE_CLOUD_PROJECT`: Your Google Cloud Project ID
    - `GOOGLE_CLOUD_REGION`: Your Google Cloud Region (e.g., "us-east5")
    - `GOOGLE_API_KEY`: (Optional) Your Google Cloud API Key
    - `GOOGLE_ACCESS_TOKEN`: (Optional) Your OAuth2 Access Token
    
    ### 2. gcloud CLI or Service Account (Recommended)
    If using `gcloud` or a service account, use the `Google.Cloud.AIPlatform.V1` NuGet package to obtain credentials.
    
    ```csharp
    using Google.Apis.Auth.OAuth2;
    
    var credential = (await GoogleCredential.GetApplicationDefaultAsync())
        .CreateScoped("https://www.googleapis.com/auth/cloud-platform");
    
    var accessToken = await credential.UnderlyingCredential.GetAccessTokenForRequestAsync();
    
    var client = new VertexAIClient(
        new VertexAIAuthentication(
            projectId: "your-google-cloud-project-id",
            region: "us-east5",
            accessToken: accessToken
        )
    );
  10. Calculate request costs and token usage

    main

    The SDK provides utilities to estimate the USD cost of a request based on token usage and model pricing. You can calculate costs directly from a MessageResponse or from a Usage object by providing a model ID. Pricing includes support for cache reads, cache creation, and web search costs.

    using Anthropic.SDK.Extensions;
    
    var client = new AnthropicClient();
    var parameters = new MessageParameters()
    {
        Messages = new List<Message> { new Message(RoleType.User, "Hello!") },
        MaxTokens = 1024,
        Model = AnthropicModels.Claude46Sonnet,
    };
    var response = await client.Messages.GetClaudeMessageAsync(parameters);
    
    // Calculate estimated cost directly from the response
    var cost = response.CalculateCost();
    Console.WriteLine($"Total cost: ${cost.TotalCostUsd:F6}");
    
    // Or calculate from a Usage object directly with a model ID
    var breakdown = response.Usage.CalculateCost(AnthropicModels.Claude46Sonnet);
  11. Add HTTP Resilience using Microsoft.Extensions.Http.Resilience

    main

    For production applications using .NET 8+, it is recommended to add resilience patterns (retries, circuit breakers, timeouts) to the AnthropicClient via HttpClientFactory.

    First, install the package:

    dotnet add package Microsoft.Extensions.Http.Resilience

    Then, register the client in your service collection using .AddStandardResilienceHandler() to enable default protections.

    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Http.Resilience;
    
    var services = new ServiceCollection();
    
    // Add AnthropicClient with standard resilience (includes retry, circuit breaker, timeouts)
    services.AddHttpClient<AnthropicClient>()
        .AddStandardResilienceHandler();
    
    var serviceProvider = services.BuildServiceProvider();
    var client = serviceProvider.GetRequiredService<AnthropicClient>();
  12. Register custom or enterprise model pricing

    main

    If you have negotiated pricing or need to support a model not in the built-in table, you can register custom pricing at runtime using ModelPricing.Register. You can also pass an override ModelPricing object directly to the CalculateCost method. Use ModelPricing.ClearCustomPricing() to revert to default pricing.

    using Anthropic.SDK.Messaging;
    
    // Register custom pricing for a model prefix
    ModelPricing.Register("claude-sonnet-4-6", new ModelPricing(
        inputTokenCostPerMillion: 2.5m,
        outputTokenCostPerMillion: 12.5m));
    
    // Or pass override pricing directly
    var customPricing = new ModelPricing(
        inputTokenCostPerMillion: 4m,
        outputTokenCostPerMillion: 20m);
    var cost = response.CalculateCost(overridePricing: customPricing);
    
    // Clear all custom registrations to revert to built-in pricing
    ModelPricing.ClearCustomPricing();