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.
java/claude-api.md
1# Claude API — Java23> **Note:** The Java SDK supports the Claude API and beta tool use with annotated classes. Agent SDK is not yet available for Java.45## Installation67Maven:89```xml10<dependency>11<groupId>com.anthropic</groupId>12<artifactId>anthropic-java</artifactId>13<version>2.17.0</version>14</dependency>15```1617Gradle:1819```groovy20implementation("com.anthropic:anthropic-java:2.17.0")21```2223## Client Initialization2425```java26import com.anthropic.client.AnthropicClient;27import com.anthropic.client.okhttp.AnthropicOkHttpClient;2829// Default (reads ANTHROPIC_API_KEY from environment)30AnthropicClient client = AnthropicOkHttpClient.fromEnv();3132// Explicit API key33AnthropicClient client = AnthropicOkHttpClient.builder()34.apiKey("your-api-key")35.build();36```3738---3940## Basic Message Request4142```java43import com.anthropic.models.messages.MessageCreateParams;44import com.anthropic.models.messages.Message;45import com.anthropic.models.messages.Model;4647MessageCreateParams params = MessageCreateParams.builder()48.model(Model.CLAUDE_OPUS_4_6)49.maxTokens(16000L)50.addUserMessage("What is the capital of France?")51.build();5253Message response = client.messages().create(params);54response.content().stream()55.flatMap(block -> block.text().stream())56.forEach(textBlock -> System.out.println(textBlock.text()));57```5859---6061## Streaming6263```java64import com.anthropic.core.http.StreamResponse;65import com.anthropic.models.messages.RawMessageStreamEvent;6667MessageCreateParams params = MessageCreateParams.builder()68.model(Model.CLAUDE_OPUS_4_6)69.maxTokens(64000L)70.addUserMessage("Write a haiku")71.build();7273try (StreamResponse<RawMessageStreamEvent> streamResponse = client.messages().createStreaming(params)) {74streamResponse.stream()75.flatMap(event -> event.contentBlockDelta().stream())76.flatMap(deltaEvent -> deltaEvent.delta().text().stream())77.forEach(textDelta -> System.out.print(textDelta.text()));78}79```8081---8283## Thinking8485**Adaptive thinking is the recommended mode for Claude 4.6+ models.** Claude decides dynamically when and how much to think. The builder has a direct `.thinking(ThinkingConfigAdaptive)` overload — no manual union wrapping.8687```java88import com.anthropic.models.messages.ContentBlock;89import com.anthropic.models.messages.MessageCreateParams;90import com.anthropic.models.messages.Model;91import com.anthropic.models.messages.ThinkingConfigAdaptive;9293MessageCreateParams params = MessageCreateParams.builder()94.model(Model.CLAUDE_SONNET_4_6)95.maxTokens(16000L)96.thinking(ThinkingConfigAdaptive.builder().build())97.addUserMessage("Solve this step by step: 27 * 453")98.build();99100for (ContentBlock block : client.messages().create(params).content()) {101block.thinking().ifPresent(t -> System.out.println("[thinking] " + t.thinking()));102block.text().ifPresent(t -> System.out.println(t.text()));103}104```105106> **Deprecated:** `ThinkingConfigEnabled.builder().budgetTokens(N)` (and the `.enabledThinking(N)` shortcut) still works on Claude 4.6 but is deprecated. Use adaptive thinking above.107108`ContentBlock` narrowing: `.thinking()` / `.text()` return `Optional<T>` — use `.ifPresent(...)` or `.stream().flatMap(...)`. Alternative: `isThinking()` / `asThinking()` boolean+unwrap pairs (throws on wrong variant).109110---111112## Tool Use (Beta)113114The Java SDK supports beta tool use with annotated classes. Tool classes implement `Supplier<String>` for automatic execution via `BetaToolRunner`.115116### Tool Runner (automatic loop)117118```java119import com.anthropic.models.beta.messages.MessageCreateParams;120import com.anthropic.models.beta.messages.BetaMessage;121import com.anthropic.helpers.BetaToolRunner;122import com.fasterxml.jackson.annotation.JsonClassDescription;123import com.fasterxml.jackson.annotation.JsonPropertyDescription;124import java.util.function.Supplier;125126@JsonClassDescription("Get the weather in a given location")127static class GetWeather implements Supplier<String> {128@JsonPropertyDescription("The city and state, e.g. San Francisco, CA")129public String location;130131@Override132public String get() {133return "The weather in " + location + " is sunny and 72°F";134}135}136137BetaToolRunner toolRunner = client.beta().messages().toolRunner(138MessageCreateParams.builder()139.model("claude-opus-4-7")140.maxTokens(16000L)141.putAdditionalHeader("anthropic-beta", "structured-outputs-2025-11-13")142.addTool(GetWeather.class)143.addUserMessage("What's the weather in San Francisco?")144.build());145146for (BetaMessage message : toolRunner) {147System.out.println(message);148}149```150151### Memory Tool152153The Java SDK provides `BetaMemoryToolHandler` for implementing the memory tool backend. You supply a handler that manages file storage, and the `BetaToolRunner` handles memory tool calls automatically.154155```java156import com.anthropic.helpers.BetaMemoryToolHandler;157import com.anthropic.helpers.BetaToolRunner;158import com.anthropic.models.beta.messages.BetaMemoryTool20250818;159import com.anthropic.models.beta.messages.BetaMessage;160import com.anthropic.models.beta.messages.MessageCreateParams;161import com.anthropic.models.beta.messages.ToolRunnerCreateParams;162163// Implement BetaMemoryToolHandler with your storage backend (e.g., filesystem)164BetaMemoryToolHandler memoryHandler = new FileSystemMemoryToolHandler(sandboxRoot);165166MessageCreateParams createParams = MessageCreateParams.builder()167.model("claude-opus-4-7")168.maxTokens(4096L)169.addTool(BetaMemoryTool20250818.builder().build())170.addUserMessage("Remember that my favorite color is blue")171.build();172173BetaToolRunner toolRunner = client.beta().messages().toolRunner(174ToolRunnerCreateParams.builder()175.betaMemoryToolHandler(memoryHandler)176.initialMessageParams(createParams)177.build());178179for (BetaMessage message : toolRunner) {180System.out.println(message);181}182```183184See the [shared memory tool concepts](../shared/tool-use-concepts.md) for more details on the memory tool.185186### Non-Beta Tool Declaration (manual JSON schema)187188`Tool.InputSchema.Properties` is a freeform `Map<String, JsonValue>` wrapper — build property schemas via `putAdditionalProperty`. `type: "object"` is the default. The builder has a direct `.addTool(Tool)` overload that wraps in `ToolUnion` automatically.189190```java191import com.anthropic.core.JsonValue;192import com.anthropic.models.messages.Tool;193194Tool tool = Tool.builder()195.name("get_weather")196.description("Get the current weather in a given location")197.inputSchema(Tool.InputSchema.builder()198.properties(Tool.InputSchema.Properties.builder()199.putAdditionalProperty("location", JsonValue.from(Map.of("type", "string")))200.build())201.required(List.of("location"))202.build())203.build();204205MessageCreateParams params = MessageCreateParams.builder()206.model(Model.CLAUDE_SONNET_4_6)207.maxTokens(16000L)208.addTool(tool)209.addUserMessage("Weather in Paris?")210.build();211```212213For manual tool loops, handle `tool_use` blocks in the response, send `tool_result` back, loop until `stop_reason` is `"end_turn"`. See [shared tool use concepts](../shared/tool-use-concepts.md).214215### Building `MessageParam` with Content Blocks (Tool Result Round-Trip)216217`MessageParam.Content` is an inner union class (string | list). Use the builder's `.contentOfBlockParams(List<ContentBlockParam>)` alias — there is NO separate `MessageParamContent` class with a static `ofBlockParams`:218219```java220import com.anthropic.models.messages.MessageParam;221import com.anthropic.models.messages.ContentBlockParam;222import com.anthropic.models.messages.ToolResultBlockParam;223224List<ContentBlockParam> results = List.of(225ContentBlockParam.ofToolResult(ToolResultBlockParam.builder()226.toolUseId(toolUseBlock.id())227.content(yourResultString)228.build())229);230231MessageParam toolResultMsg = MessageParam.builder()232.role(MessageParam.Role.USER)233.contentOfBlockParams(results) // builder alias for Content.ofBlockParams(...)234.build();235```236237---238239## Effort Parameter240241Effort is nested inside `OutputConfig` — there is NO `.effort()` directly on `MessageCreateParams.Builder`.242243```java244import com.anthropic.models.messages.OutputConfig;245246.outputConfig(OutputConfig.builder()247.effort(OutputConfig.Effort.HIGH) // or LOW, MEDIUM, MAX248.build())249```250251Combine with `Thinking = ThinkingConfigAdaptive` for cost-quality control.252253---254255## Prompt Caching256257System message as a list of `TextBlockParam` with `CacheControlEphemeral`. Use `.systemOfTextBlockParams(...)` — the plain `.system(String)` overload can't carry cache control. For placement patterns and the silent-invalidator audit checklist, see `shared/prompt-caching.md`.258259```java260import com.anthropic.models.messages.TextBlockParam;261import com.anthropic.models.messages.CacheControlEphemeral;262263.systemOfTextBlockParams(List.of(264TextBlockParam.builder()265.text(longSystemPrompt)266.cacheControl(CacheControlEphemeral.builder()267.ttl(CacheControlEphemeral.Ttl.TTL_1H) // optional; also TTL_5M268.build())269.build()))270```271272There's also a top-level `.cacheControl(CacheControlEphemeral)` on `MessageCreateParams.Builder` and on `Tool.builder()`.273274Verify hits via `response.usage().cacheCreationInputTokens()` / `response.usage().cacheReadInputTokens()`.275276---277278## Token Counting279280```java281import com.anthropic.models.messages.MessageCountTokensParams;282283long tokens = client.messages().countTokens(284MessageCountTokensParams.builder()285.model(Model.CLAUDE_SONNET_4_6)286.addUserMessage("Hello")287.build()288).inputTokens();289```290291---292293## Structured Output294295The class-based overload auto-derives the JSON schema from your POJO and gives you a typed `.text()` return — no manual schema, no manual parsing.296297```java298import com.anthropic.models.messages.StructuredMessageCreateParams;299300record Book(String title, String author) {}301record BookList(List<Book> books) {}302303StructuredMessageCreateParams<BookList> params = MessageCreateParams.builder()304.model(Model.CLAUDE_SONNET_4_6)305.maxTokens(16000L)306.outputConfig(BookList.class) // returns a typed builder307.addUserMessage("List 3 classic novels")308.build();309310client.messages().create(params).content().stream()311.flatMap(cb -> cb.text().stream())312.forEach(typed -> {313// typed.text() returns BookList, not String314for (Book b : typed.text().books()) System.out.println(b.title());315});316```317318Supports Jackson annotations: `@JsonPropertyDescription`, `@JsonIgnore`, `@ArraySchema(minItems=...)`. Manual schema path: `OutputConfig.builder().format(JsonOutputFormat.builder().schema(...).build())`.319320---321322## PDF / Document Input323324`DocumentBlockParam` builder has source shortcuts. Wrap in `ContentBlockParam.ofDocument()` and pass via `.addUserMessageOfBlockParams()`.325326```java327import com.anthropic.models.messages.DocumentBlockParam;328import com.anthropic.models.messages.ContentBlockParam;329import com.anthropic.models.messages.TextBlockParam;330331DocumentBlockParam doc = DocumentBlockParam.builder()332.base64Source(base64String) // or .urlSource("https://...") or .textSource("...")333.title("My Document") // optional334.build();335336.addUserMessageOfBlockParams(List.of(337ContentBlockParam.ofDocument(doc),338ContentBlockParam.ofText(TextBlockParam.builder().text("Summarize this").build())))339```340341---342343## Server-Side Tools344345Version-suffixed types; `name`/`type` auto-set by builder. Direct `.addTool()` overloads exist for every type — no manual `ToolUnion` wrapping.346347```java348import com.anthropic.models.messages.WebSearchTool20260209;349import com.anthropic.models.messages.ToolBash20250124;350import com.anthropic.models.messages.ToolTextEditor20250728;351import com.anthropic.models.messages.CodeExecutionTool20260120;352353.addTool(WebSearchTool20260209.builder()354.maxUses(5L) // optional355.allowedDomains(List.of("example.com")) // optional356.build())357.addTool(ToolBash20250124.builder().build())358.addTool(ToolTextEditor20250728.builder().build())359.addTool(CodeExecutionTool20260120.builder().build())360```361362Also available: `WebFetchTool20260209`, `MemoryTool20250818`, `ToolSearchToolBm25_20251119`.363364### Beta namespace (MCP, compaction)365366For beta-only features use `com.anthropic.models.beta.messages.*` — class names have a `Beta` prefix AND live in the beta package. The beta `MessageCreateParams.Builder` has direct `.addTool(BetaToolBash20250124)` overloads AND `.addMcpServer()`:367368```java369import com.anthropic.models.beta.messages.MessageCreateParams;370import com.anthropic.models.beta.messages.BetaToolBash20250124;371import com.anthropic.models.beta.messages.BetaCodeExecutionTool20260120;372import com.anthropic.models.beta.messages.BetaRequestMcpServerUrlDefinition;373374MessageCreateParams params = MessageCreateParams.builder()375.model(Model.CLAUDE_OPUS_4_6)376.maxTokens(16000L)377.addBeta("mcp-client-2025-11-20")378.addTool(BetaToolBash20250124.builder().build())379.addTool(BetaCodeExecutionTool20260120.builder().build())380.addMcpServer(BetaRequestMcpServerUrlDefinition.builder()381.name("my-server")382.url("https://example.com/mcp")383.build())384.addUserMessage("...")385.build();386387client.beta().messages().create(params);388```389390`BetaTool*` types are NOT interchangeable with non-beta `Tool*` — pick one namespace per request.391392**Reading server-tool blocks in the response:** `ServerToolUseBlock` has `.id()`, `.name()` (enum), and `._input()` returning raw `JsonValue` — there is NO typed `.input()`. For code execution results, unwrap two levels:393394```java395for (ContentBlock block : response.content()) {396block.serverToolUse().ifPresent(stu -> {397System.out.println("tool: " + stu.name() + " input: " + stu._input());398});399block.codeExecutionToolResult().ifPresent(r -> {400r.content().resultBlock().ifPresent(result -> {401System.out.println("stdout: " + result.stdout());402System.out.println("stderr: " + result.stderr());403System.out.println("exit: " + result.returnCode());404});405});406}407```408409---410411## Files API (Beta)412413Under `client.beta().files()`. File references in messages need the beta message types (non-beta `DocumentBlockParam.Source` has no file-ID variant).414415```java416import com.anthropic.models.beta.files.FileUploadParams;417import com.anthropic.models.beta.files.FileMetadata;418import com.anthropic.models.beta.messages.BetaRequestDocumentBlock;419import java.nio.file.Paths;420421FileMetadata meta = client.beta().files().upload(422FileUploadParams.builder()423.file(Paths.get("/path/to/doc.pdf")) // or .file(InputStream) or .file(byte[])424.build());425426// Reference in a beta message:427BetaRequestDocumentBlock doc = BetaRequestDocumentBlock.builder()428.fileSource(meta.id())429.build();430```431432Other methods: `.list()`, `.delete(String fileId)`, `.download(String fileId)`, `.retrieveMetadata(String fileId)`.433