Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build LLM-powered apps with the Anthropic Claude API or SDK across Python, TypeScript, Java, Go, Ruby, C#, and PHP.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
csharp/claude-api/README.md
1# Claude API — C#23> **Note:** The C# SDK is the official Anthropic SDK for C#. Tool use is supported via the Messages API with a beta `BetaToolRunner` for automatic tool execution loops. The SDK also supports Microsoft.Extensions.AI IChatClient integration with function invocation and Managed Agents (beta).45## Namespace Reference67Types are organized by namespace. If a type you need isn't shown in an example below, locate it via this table first — don't block on fetching SDK source over the network.89| `using` | Contains |10|---|---|11| `Anthropic` | `AnthropicClient`, top-level options |12| `Anthropic.Models.Messages` | non-beta request/response types — `MessageCreateParams`, `Model`, `Role`, `ContentBlock`, `TextBlock`, `ToolUseBlock`, `ToolResultBlockParam`, `Tool*` (tool definition classes) |13| `Anthropic.Models.Beta.Messages` | beta-endpoint equivalents — `MessageCreateParams`, `BetaMessage`, `BetaTool*`, `Speed`, `BetaRequestMcpServerUrlDefinition`, context-editing/compaction configs |14| `Anthropic.Models.Beta` | shared beta constants |15| `Anthropic.Models.Beta.Files` | Files API types |16| `Anthropic.Models.Messages.Batches` | Batch API types |17| `Anthropic.Helpers.Beta` | `BetaToolRunner`, beta helper utilities |18| `Anthropic.Exceptions` | `AnthropicApiException`, `AnthropicRateLimitException`, `Anthropic5xxException`, etc. — see `shared/error-codes.md` |19| `Anthropic.Bedrock` / `Anthropic.Vertex` / `Anthropic.Foundry` / `Anthropic.Aws` | platform clients (separate NuGet packages): `AnthropicBedrockMantleClient`, `AnthropicFoundryClient`, `AnthropicAwsClient` |2021`client.Messages.*` uses non-beta types; `client.Beta.Messages.*` uses the `Anthropic.Models.Beta.Messages` types. Both namespaces define a `MessageCreateParams` — pick the one matching the client path you call.2223### Key types per feature2425Write from this table instead of reflecting the SDK assembly. Endpoint column tells you whether to use `client.Messages.*` or `client.Beta.Messages.*`.2627| Feature | Endpoint | Key C# types (namespace per table above) |28|---|---|---|29| User profiles | beta | `client.Beta.UserProfiles.Create(...)` / `.Retrieve(id)` / `.List()`. Pass the returned profile id on the beta messages call. Requires a beta header — check the SDK's beta-headers reference for the current flag. |30| Agent Skills | beta | `BetaContainerParams` (with `Skills = [new BetaSkillParams { ... }]`), `BetaCodeExecutionTool20250825`. `Betas = ["code-execution-2025-08-25", "skills-2025-10-02"]`. Download the output via `client.Beta.Files.Download(fileId)`. |31| Advisor tool | beta | `BetaAdvisorTool20260301` — may not be in all SDK releases yet |32| Cache diagnostics | beta | `Diagnostics = new() { PreviousMessageID = … }`, `BetaCacheControlEphemeral`, `BetaContentBlockParam` |33| Context editing | beta | `ContextManagement = new BetaContextManagementConfig { Edits = [new BetaClearToolUses20250919Edit()] }`. `Betas = ["context-management-2025-06-27"]` (not `compact-2026-01-12` — that's for `BetaCompact20260112Edit`). |34| Memory tool | non-beta | `Tools = [new ToolUnion(new MemoryTool20250818())]` |35| Programmatic tool calling | non-beta | `CodeExecutionTool20260120`, `ToolResultBlockParam`, `ContentBlockParam` |36| Task budgets | beta | `BetaOutputConfig` with `TaskBudget = new BetaTokenTaskBudget { ... }` |37| Tool search | non-beta | `new ToolUnion(new ToolSearchToolRegex20251119 { Type = ToolSearchToolRegex20251119Type.ToolSearchToolRegex20251119 })` — `Type` must be set explicitly. |38| Web search | non-beta | `new ToolUnion(new WebSearchTool20260209())` — the latest variant with dynamic filtering (Opus 4.8/4.7/4.6 + Sonnet 4.6). For older models or Vertex, use `WebSearchTool20250305()` |3940### Discovering type and member names4142If a type or member you need isn't in the tables above, `strings ~/.nuget/packages/anthropic/*/lib/*/Anthropic.dll | grep -i <term>` is fast and sufficient for locating class and property names. **Do not escalate to a `dotnet run` reflection probe** to dump members precisely — the first compile is slow enough to be backgrounded in many environments, trapping you in a polling loop. Instead, write `Program.cs` using the names `strings | grep` found; if a member name is wrong the compiler error (`error CS1061: 'X' does not contain a definition for 'Y'`) points at it in a few seconds, faster than any reflection probe.4344Note that `strings` will not surface wire-format snake_case field names (`output_tokens`, `stop_reason`) — those are stored in the DLL differently. **C# properties are the PascalCase equivalent of the wire field** (`response.Usage.OutputTokens`, `response.StopReason`). If you know the wire field name from the docs, write the PascalCase property and compile; do not probe for the snake_case string.4546### Minimal working skeleton4748**Write a plain `Program.cs` body** — `using` statements followed by top-level statements, as below. Do **not** add a `#!/usr/bin/env dotnet` shebang or `#:package Anthropic@*` directive: those are .NET file-based-app syntax and fail with `CS1024: Preprocessor directive expected` when the file is compiled via an existing `.csproj`. The standard project setup (per the [C# quickstart](https://docs.claude.com/en/docs/get-started): `dotnet new console` → `dotnet add package Anthropic` → edit `Program.cs` → `dotnet run`) provides the `.csproj` and package reference.4950Start from this — it compiles as-is. Fill in the feature-specific fields; do not spend turns running reflection or XML-doc inspection to discover type names first.5152```csharp53using System;54using Anthropic;55using Anthropic.Models.Messages; // or Anthropic.Models.Beta.Messages for beta endpoints5657AnthropicClient client = new();5859var message = await client.Messages.Create(new MessageCreateParams60{61Model = Model.ClaudeOpus4_8,62MaxTokens = 1024,63Messages = [ new() { Role = Role.User, Content = "Hello, Claude" } ],64});6566Console.WriteLine(message);67```6869For beta features (anything behind an `anthropic-beta` header), use the beta client path and namespace — same overall shape:7071```csharp72using System;73using Anthropic;74using Anthropic.Models.Beta.Messages;7576AnthropicClient client = new();7778var response = await client.Beta.Messages.Create(new MessageCreateParams79{80Model = "claude-opus-4-8",81MaxTokens = 4096,82Betas = ["<beta-flag>"],83Messages = [ new() { Role = Role.User, Content = "…" } ],84// Tools = new BetaToolUnion[] { new BetaSomeTool { … } }, // for tool features85});8687Console.WriteLine(response);88```8990If a type name the feature needs isn't in this file, write it following the naming pattern in the Namespace Reference above and fix from compiler output — producing a `Program.cs` and iterating beats researching.9192### Common C# compile errors9394- **CS8803 (top-level statements must precede type declarations):** put any `record`/`class`/`struct` definitions **after** the last top-level statement, at the end of the file. A record defined above `var client = new AnthropicClient()` will not compile.95- **`await foreach` on a `Task<…Page>`:** `client.Models.List()` returns a `Task<ModelListPage>`, which is not directly async-enumerable. Await it first, then iterate: `var page = await client.Models.List(); foreach (var m in page.Items) {…}`. For auto-pagination, check whether the page type exposes `AutoPagingEachAsync()` or similar before reaching for `await foreach`.9697## Installation9899```bash100dotnet add package Anthropic101```102103## Client Initialization104105```csharp106using Anthropic;107108// Default (uses ANTHROPIC_API_KEY env var)109AnthropicClient client = new();110111// Explicit API key (use environment variables — never hardcode keys)112AnthropicClient client = new() {113ApiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY")114};115```116117---118119## Basic Message Request120121```csharp122using Anthropic.Models.Messages;123124var parameters = new MessageCreateParams125{126Model = Model.ClaudeOpus4_8,127MaxTokens = 16000,128Messages = [new() { Role = Role.User, Content = "What is the capital of France?" }]129};130var response = await client.Messages.Create(parameters);131132// ContentBlock is a union wrapper. .Value unwraps to the variant object,133// then OfType<T> filters to the type you want. Or use the TryPick* idiom134// shown in the Thinking section below.135foreach (var text in response.Content.Select(b => b.Value).OfType<TextBlock>())136{137Console.WriteLine(text.Text);138}139```140141---142143## Thinking144145**Adaptive thinking is the recommended mode for Claude 4.6+ models.** Claude decides dynamically when and how much to think.146147> **Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6:** Use adaptive thinking (below). `new ThinkingConfigEnabled { BudgetTokens = N }` is removed on Fable 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6.148> **Older models:** Use `new ThinkingConfigEnabled { BudgetTokens = N }` (budget must be < `MaxTokens`, min 1024).149150```csharp151using Anthropic.Models.Messages;152153var response = await client.Messages.Create(new MessageCreateParams154{155Model = Model.ClaudeOpus4_8,156MaxTokens = 16000,157// ThinkingConfigParam? implicitly converts from the concrete variant classes —158// no wrapper needed.159// display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Opus 4.8 / 4.7160Thinking = new ThinkingConfigAdaptive { Display = Display.Summarized },161Messages =162[163new() { Role = Role.User, Content = "Solve: 27 * 453" },164],165});166167// ThinkingBlock(s) precede TextBlock in Content. TryPick* narrows the union.168foreach (var block in response.Content)169{170if (block.TryPickThinking(out ThinkingBlock? t))171{172Console.WriteLine($"[thinking] {t.Thinking}");173}174else if (block.TryPickText(out TextBlock? text))175{176Console.WriteLine(text.Text);177}178}179```180181Alternative to `TryPick*`: `.Select(b => b.Value).OfType<ThinkingBlock>()` (same LINQ pattern as the Basic Message example).182183---184185## Context Editing / Compaction (Beta)186187**Beta-namespace prefix is inconsistent** (source-verified against `src/Anthropic/Models/Beta/Messages/*.cs` @ 12.9.0). No prefix: `MessageCreateParams`, `MessageCountTokensParams`, `Role`, `Speed`. **Everything else has the `Beta` prefix**: `BetaMessageParam`, `BetaMessage`, `BetaContentBlock`, `BetaToolUseBlock`, all block param types. The unprefixed `Role` WILL collide with `Anthropic.Models.Messages.Role` if you import both namespaces (CS0104). Safest: import only Beta; if mixing, alias the beta `Role`:188189```csharp190using Anthropic.Models.Beta.Messages;191using NonBeta = Anthropic.Models.Messages; // only if you also need non-beta types192// Now: MessageCreateParams, BetaMessageParam, Role (beta's), NonBeta.Role (if needed)193```194195196`BetaMessage.Content` is `IReadOnlyList<BetaContentBlock>` — a 15-variant discriminated union. Narrow with `TryPick*`. **Response `BetaContentBlock` is NOT assignable to param `BetaContentBlockParam`** — there's no `.ToParam()` in C#. Round-trip by converting each block:197198```csharp199using Anthropic.Models.Beta.Messages;200201var betaParams = new MessageCreateParams // no Beta prefix — see unprefixed list above202{203Model = Model.ClaudeOpus4_8,204MaxTokens = 16000,205Betas = ["compact-2026-01-12"],206ContextManagement = new BetaContextManagementConfig207{208Edits = [new BetaCompact20260112Edit()],209},210Messages = messages,211};212BetaMessage resp = await client.Beta.Messages.Create(betaParams);213214foreach (BetaContentBlock block in resp.Content)215{216if (block.TryPickCompaction(out BetaCompactionBlock? compaction))217{218// Content is nullable — compaction can fail server-side219Console.WriteLine($"compaction summary: {compaction.Content}");220}221}222223// Context-edit metadata lives on a separate nullable field224if (resp.ContextManagement is { } ctx)225{226foreach (var edit in ctx.AppliedEdits)227Console.WriteLine($"cleared {edit.ClearedInputTokens} tokens");228}229230// ROUND-TRIP: BetaMessageParam.Content is BetaMessageParamContent (a string|list231// union). It implicit-converts from List<BetaContentBlockParam>, NOT from the232// response's IReadOnlyList<BetaContentBlock>. Convert each block:233List<BetaContentBlockParam> paramBlocks = [];234foreach (var b in resp.Content)235{236if (b.TryPickText(out var t)) paramBlocks.Add(new BetaTextBlockParam { Text = t.Text });237else if (b.TryPickCompaction(out var c)) paramBlocks.Add(new BetaCompactionBlockParam { Content = c.Content });238// ... other variants as needed239}240messages.Add(new BetaMessageParam { Role = Role.Assistant, Content = paramBlocks });241```242243All 15 `BetaContentBlock.TryPick*` variants: `Text`, `Thinking`, `RedactedThinking`, `ToolUse`, `ServerToolUse`, `WebSearchToolResult`, `WebFetchToolResult`, `CodeExecutionToolResult`, `BashCodeExecutionToolResult`, `TextEditorCodeExecutionToolResult`, `ToolSearchToolResult`, `McpToolUse`, `McpToolResult`, `ContainerUpload`, `Compaction`.244245**`BetaToolUseBlock.Input` is `IReadOnlyDictionary<string, JsonElement>`** — index by key then call the `JsonElement` extractor:246247```csharp248if (block.TryPickToolUse(out BetaToolUseBlock? tu))249{250int a = tu.Input["a"].GetInt32();251string s = tu.Input["name"].GetString()!;252}253```254255---256257## Effort Parameter258259Effort is nested under `OutputConfig`, NOT a top-level property. `ApiEnum<string, Effort>` has an implicit conversion from the enum, so assign `Effort.High` directly.260261```csharp262OutputConfig = new OutputConfig { Effort = Effort.High },263```264265Values: `Effort.Low`, `Effort.Medium`, `Effort.High`, `Effort.Max`. Combine with `Thinking = new ThinkingConfigAdaptive()` for cost-quality control.266267---268269## Prompt Caching270271`System` takes `MessageCreateParamsSystem?` — a union of `string` or `List<TextBlockParam>`. There is no `SystemTextBlockParam`; use plain `TextBlockParam`. The implicit conversion needs the concrete `List<TextBlockParam>` type (array literals won't convert). For placement patterns and the silent-invalidator audit checklist, see `shared/prompt-caching.md`.272273```csharp274System = new List<TextBlockParam> {275new() {276Text = longSystemPrompt,277CacheControl = new CacheControlEphemeral(), // auto-sets Type = "ephemeral"278},279},280```281282Optional `Ttl` on `CacheControlEphemeral`: `new() { Ttl = Ttl.Ttl1h }` or `Ttl.Ttl5m`. `CacheControl` also exists on `Tool.CacheControl` and top-level `MessageCreateParams.CacheControl`.283284Verify hits via `response.Usage.CacheCreationInputTokens` / `response.Usage.CacheReadInputTokens`.285286---287288## Token Counting289290```csharp291MessageTokensCount result = await client.Messages.CountTokens(new MessageCountTokensParams {292Model = Model.ClaudeOpus4_8,293Messages = [new() { Role = Role.User, Content = "Hello" }],294});295long tokens = result.InputTokens;296```297298`MessageCountTokensParams.Tools` uses a different union type (`MessageCountTokensTool`) than `MessageCreateParams.Tools` (`ToolUnion`) — if you're passing tools, the compiler will tell you when it matters.299300---301302## PDF / Document Input303304`DocumentBlockParam` takes a `DocumentBlockParamSource` union: `Base64PdfSource` / `UrlPdfSource` / `PlainTextSource` / `ContentBlockSource`. `Base64PdfSource` auto-sets `MediaType = "application/pdf"` and `Type = "base64"`.305306```csharp307new MessageParam {308Role = Role.User,309Content = new List<ContentBlockParam> {310new DocumentBlockParam { Source = new Base64PdfSource { Data = base64String } },311new TextBlockParam { Text = "Summarize this PDF" },312},313}314```315316---317318## Fast Mode (Beta)319320```csharp321var response = await client.Beta.Messages.Create(new MessageCreateParams {322Model = "claude-opus-4-8", MaxTokens = 4096,323Speed = Speed.Fast,324Betas = ["fast-mode-2026-02-01"],325Messages = [...],326});327```328329## Models API330331```csharp332var page = await client.Models.List();333foreach (var m in page.Items) { Console.WriteLine(m.ID); }334var one = await client.Models.Retrieve("claude-opus-4-8");335```336337## Long Output (128k) + Prefill338339Set `MaxTokens = 128000` on `client.Messages` and use the streaming path (see `streaming.md`). On Claude 4+ models, 128k output is native — no `output-128k-*` beta header or beta namespace is needed.340341**Prefilling the assistant message** (putting a trailing `Role.Assistant` message in the input) is **not supported** on Claude Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6 — requests return a 400. Use `OutputConfig.Format` (structured outputs) instead.342343## Stop Details344345When `StopReason` is `"refusal"`, the response includes structured `StopDetails`:346347```csharp348if (response.StopReason == "refusal" && response.StopDetails is { } details)349{350Console.WriteLine($"Category: {details.Category}");351Console.WriteLine($"Explanation: {details.Explanation}");352}353```354355**Refusal fallbacks (Claude Fable 5) — opt in by default.** Fallbacks are opt-in: without them a refused request simply stops. In `claude-fable-5` code, include `Fallbacks = [new(Model.ClaudeOpus4_8)]` plus the `AnthropicBeta.ServerSideFallback2026_06_01` beta on the beta messages call by default — a policy decline is re-served by the fallback model inside the same call. Not available on Amazon Bedrock, Vertex AI, or Microsoft Foundry — use the client-side handler there: `new AnthropicClient { Handlers = [new BetaRefusalFallbackHandler { Fallbacks = [new(Model.ClaudeOpus4_8)] }] }` (namespace `Anthropic.Helpers`), with per-conversation state via `BetaFallbackState.Create()` scoped with `using (fallbackState.Use()) { ... }`. Full semantics (billing, sticky routing, streaming) and a runnable example: `shared/model-migration.md` → Migrating to Claude Fable 5 → `refusal` stop reason, and the C# SDK repo's `examples/` (WebFetch via `shared/live-sources.md`).356357---358359## Managed Agents (Beta)360361The C# SDK supports Managed Agents via `client.Beta.Agents`, `client.Beta.Sessions`, `client.Beta.Environments`, and related namespaces. See `shared/managed-agents-overview.md` for the architecture and `curl/managed-agents.md` for the wire-level reference.362