chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
# Claude API — Java
|
||||
|
||||
> **Note:** The Java SDK supports the Claude API and beta tool use with annotated classes. Agent SDK is not yet available for Java.
|
||||
|
||||
## Installation
|
||||
|
||||
Maven:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.anthropic</groupId>
|
||||
<artifactId>anthropic-java</artifactId>
|
||||
<version>2.17.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Gradle:
|
||||
|
||||
```groovy
|
||||
implementation("com.anthropic:anthropic-java:2.17.0")
|
||||
```
|
||||
|
||||
## Client Initialization
|
||||
|
||||
```java
|
||||
import com.anthropic.client.AnthropicClient;
|
||||
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
|
||||
|
||||
// Default (reads ANTHROPIC_API_KEY from environment)
|
||||
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
|
||||
|
||||
// Explicit API key
|
||||
AnthropicClient client = AnthropicOkHttpClient.builder()
|
||||
.apiKey("your-api-key")
|
||||
.build();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Basic Message Request
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.MessageCreateParams;
|
||||
import com.anthropic.models.messages.Message;
|
||||
import com.anthropic.models.messages.Model;
|
||||
|
||||
MessageCreateParams params = MessageCreateParams.builder()
|
||||
.model(Model.CLAUDE_OPUS_4_6)
|
||||
.maxTokens(16000L)
|
||||
.addUserMessage("What is the capital of France?")
|
||||
.build();
|
||||
|
||||
Message response = client.messages().create(params);
|
||||
response.content().stream()
|
||||
.flatMap(block -> block.text().stream())
|
||||
.forEach(textBlock -> System.out.println(textBlock.text()));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Streaming
|
||||
|
||||
```java
|
||||
import com.anthropic.core.http.StreamResponse;
|
||||
import com.anthropic.models.messages.RawMessageStreamEvent;
|
||||
|
||||
MessageCreateParams params = MessageCreateParams.builder()
|
||||
.model(Model.CLAUDE_OPUS_4_6)
|
||||
.maxTokens(64000L)
|
||||
.addUserMessage("Write a haiku")
|
||||
.build();
|
||||
|
||||
try (StreamResponse<RawMessageStreamEvent> streamResponse = client.messages().createStreaming(params)) {
|
||||
streamResponse.stream()
|
||||
.flatMap(event -> event.contentBlockDelta().stream())
|
||||
.flatMap(deltaEvent -> deltaEvent.delta().text().stream())
|
||||
.forEach(textDelta -> System.out.print(textDelta.text()));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Thinking
|
||||
|
||||
**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.
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.ContentBlock;
|
||||
import com.anthropic.models.messages.MessageCreateParams;
|
||||
import com.anthropic.models.messages.Model;
|
||||
import com.anthropic.models.messages.ThinkingConfigAdaptive;
|
||||
|
||||
MessageCreateParams params = MessageCreateParams.builder()
|
||||
.model(Model.CLAUDE_SONNET_4_6)
|
||||
.maxTokens(16000L)
|
||||
.thinking(ThinkingConfigAdaptive.builder().build())
|
||||
.addUserMessage("Solve this step by step: 27 * 453")
|
||||
.build();
|
||||
|
||||
for (ContentBlock block : client.messages().create(params).content()) {
|
||||
block.thinking().ifPresent(t -> System.out.println("[thinking] " + t.thinking()));
|
||||
block.text().ifPresent(t -> System.out.println(t.text()));
|
||||
}
|
||||
```
|
||||
|
||||
> **Deprecated:** `ThinkingConfigEnabled.builder().budgetTokens(N)` (and the `.enabledThinking(N)` shortcut) still works on Claude 4.6 but is deprecated. Use adaptive thinking above.
|
||||
|
||||
`ContentBlock` narrowing: `.thinking()` / `.text()` return `Optional<T>` — use `.ifPresent(...)` or `.stream().flatMap(...)`. Alternative: `isThinking()` / `asThinking()` boolean+unwrap pairs (throws on wrong variant).
|
||||
|
||||
---
|
||||
|
||||
## Tool Use (Beta)
|
||||
|
||||
The Java SDK supports beta tool use with annotated classes. Tool classes implement `Supplier<String>` for automatic execution via `BetaToolRunner`.
|
||||
|
||||
### Tool Runner (automatic loop)
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.messages.MessageCreateParams;
|
||||
import com.anthropic.models.beta.messages.BetaMessage;
|
||||
import com.anthropic.helpers.BetaToolRunner;
|
||||
import com.fasterxml.jackson.annotation.JsonClassDescription;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@JsonClassDescription("Get the weather in a given location")
|
||||
static class GetWeather implements Supplier<String> {
|
||||
@JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
|
||||
public String location;
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return "The weather in " + location + " is sunny and 72°F";
|
||||
}
|
||||
}
|
||||
|
||||
BetaToolRunner toolRunner = client.beta().messages().toolRunner(
|
||||
MessageCreateParams.builder()
|
||||
.model("claude-opus-4-7")
|
||||
.maxTokens(16000L)
|
||||
.putAdditionalHeader("anthropic-beta", "structured-outputs-2025-11-13")
|
||||
.addTool(GetWeather.class)
|
||||
.addUserMessage("What's the weather in San Francisco?")
|
||||
.build());
|
||||
|
||||
for (BetaMessage message : toolRunner) {
|
||||
System.out.println(message);
|
||||
}
|
||||
```
|
||||
|
||||
### Memory Tool
|
||||
|
||||
The 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.
|
||||
|
||||
```java
|
||||
import com.anthropic.helpers.BetaMemoryToolHandler;
|
||||
import com.anthropic.helpers.BetaToolRunner;
|
||||
import com.anthropic.models.beta.messages.BetaMemoryTool20250818;
|
||||
import com.anthropic.models.beta.messages.BetaMessage;
|
||||
import com.anthropic.models.beta.messages.MessageCreateParams;
|
||||
import com.anthropic.models.beta.messages.ToolRunnerCreateParams;
|
||||
|
||||
// Implement BetaMemoryToolHandler with your storage backend (e.g., filesystem)
|
||||
BetaMemoryToolHandler memoryHandler = new FileSystemMemoryToolHandler(sandboxRoot);
|
||||
|
||||
MessageCreateParams createParams = MessageCreateParams.builder()
|
||||
.model("claude-opus-4-7")
|
||||
.maxTokens(4096L)
|
||||
.addTool(BetaMemoryTool20250818.builder().build())
|
||||
.addUserMessage("Remember that my favorite color is blue")
|
||||
.build();
|
||||
|
||||
BetaToolRunner toolRunner = client.beta().messages().toolRunner(
|
||||
ToolRunnerCreateParams.builder()
|
||||
.betaMemoryToolHandler(memoryHandler)
|
||||
.initialMessageParams(createParams)
|
||||
.build());
|
||||
|
||||
for (BetaMessage message : toolRunner) {
|
||||
System.out.println(message);
|
||||
}
|
||||
```
|
||||
|
||||
See the [shared memory tool concepts](../shared/tool-use-concepts.md) for more details on the memory tool.
|
||||
|
||||
### Non-Beta Tool Declaration (manual JSON schema)
|
||||
|
||||
`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.
|
||||
|
||||
```java
|
||||
import com.anthropic.core.JsonValue;
|
||||
import com.anthropic.models.messages.Tool;
|
||||
|
||||
Tool tool = Tool.builder()
|
||||
.name("get_weather")
|
||||
.description("Get the current weather in a given location")
|
||||
.inputSchema(Tool.InputSchema.builder()
|
||||
.properties(Tool.InputSchema.Properties.builder()
|
||||
.putAdditionalProperty("location", JsonValue.from(Map.of("type", "string")))
|
||||
.build())
|
||||
.required(List.of("location"))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
MessageCreateParams params = MessageCreateParams.builder()
|
||||
.model(Model.CLAUDE_SONNET_4_6)
|
||||
.maxTokens(16000L)
|
||||
.addTool(tool)
|
||||
.addUserMessage("Weather in Paris?")
|
||||
.build();
|
||||
```
|
||||
|
||||
For 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).
|
||||
|
||||
### Building `MessageParam` with Content Blocks (Tool Result Round-Trip)
|
||||
|
||||
`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`:
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.MessageParam;
|
||||
import com.anthropic.models.messages.ContentBlockParam;
|
||||
import com.anthropic.models.messages.ToolResultBlockParam;
|
||||
|
||||
List<ContentBlockParam> results = List.of(
|
||||
ContentBlockParam.ofToolResult(ToolResultBlockParam.builder()
|
||||
.toolUseId(toolUseBlock.id())
|
||||
.content(yourResultString)
|
||||
.build())
|
||||
);
|
||||
|
||||
MessageParam toolResultMsg = MessageParam.builder()
|
||||
.role(MessageParam.Role.USER)
|
||||
.contentOfBlockParams(results) // builder alias for Content.ofBlockParams(...)
|
||||
.build();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Effort Parameter
|
||||
|
||||
Effort is nested inside `OutputConfig` — there is NO `.effort()` directly on `MessageCreateParams.Builder`.
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.OutputConfig;
|
||||
|
||||
.outputConfig(OutputConfig.builder()
|
||||
.effort(OutputConfig.Effort.HIGH) // or LOW, MEDIUM, MAX
|
||||
.build())
|
||||
```
|
||||
|
||||
Combine with `Thinking = ThinkingConfigAdaptive` for cost-quality control.
|
||||
|
||||
---
|
||||
|
||||
## Prompt Caching
|
||||
|
||||
System 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`.
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.TextBlockParam;
|
||||
import com.anthropic.models.messages.CacheControlEphemeral;
|
||||
|
||||
.systemOfTextBlockParams(List.of(
|
||||
TextBlockParam.builder()
|
||||
.text(longSystemPrompt)
|
||||
.cacheControl(CacheControlEphemeral.builder()
|
||||
.ttl(CacheControlEphemeral.Ttl.TTL_1H) // optional; also TTL_5M
|
||||
.build())
|
||||
.build()))
|
||||
```
|
||||
|
||||
There's also a top-level `.cacheControl(CacheControlEphemeral)` on `MessageCreateParams.Builder` and on `Tool.builder()`.
|
||||
|
||||
Verify hits via `response.usage().cacheCreationInputTokens()` / `response.usage().cacheReadInputTokens()`.
|
||||
|
||||
---
|
||||
|
||||
## Token Counting
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.MessageCountTokensParams;
|
||||
|
||||
long tokens = client.messages().countTokens(
|
||||
MessageCountTokensParams.builder()
|
||||
.model(Model.CLAUDE_SONNET_4_6)
|
||||
.addUserMessage("Hello")
|
||||
.build()
|
||||
).inputTokens();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Structured Output
|
||||
|
||||
The class-based overload auto-derives the JSON schema from your POJO and gives you a typed `.text()` return — no manual schema, no manual parsing.
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.StructuredMessageCreateParams;
|
||||
|
||||
record Book(String title, String author) {}
|
||||
record BookList(List<Book> books) {}
|
||||
|
||||
StructuredMessageCreateParams<BookList> params = MessageCreateParams.builder()
|
||||
.model(Model.CLAUDE_SONNET_4_6)
|
||||
.maxTokens(16000L)
|
||||
.outputConfig(BookList.class) // returns a typed builder
|
||||
.addUserMessage("List 3 classic novels")
|
||||
.build();
|
||||
|
||||
client.messages().create(params).content().stream()
|
||||
.flatMap(cb -> cb.text().stream())
|
||||
.forEach(typed -> {
|
||||
// typed.text() returns BookList, not String
|
||||
for (Book b : typed.text().books()) System.out.println(b.title());
|
||||
});
|
||||
```
|
||||
|
||||
Supports Jackson annotations: `@JsonPropertyDescription`, `@JsonIgnore`, `@ArraySchema(minItems=...)`. Manual schema path: `OutputConfig.builder().format(JsonOutputFormat.builder().schema(...).build())`.
|
||||
|
||||
---
|
||||
|
||||
## PDF / Document Input
|
||||
|
||||
`DocumentBlockParam` builder has source shortcuts. Wrap in `ContentBlockParam.ofDocument()` and pass via `.addUserMessageOfBlockParams()`.
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.DocumentBlockParam;
|
||||
import com.anthropic.models.messages.ContentBlockParam;
|
||||
import com.anthropic.models.messages.TextBlockParam;
|
||||
|
||||
DocumentBlockParam doc = DocumentBlockParam.builder()
|
||||
.base64Source(base64String) // or .urlSource("https://...") or .textSource("...")
|
||||
.title("My Document") // optional
|
||||
.build();
|
||||
|
||||
.addUserMessageOfBlockParams(List.of(
|
||||
ContentBlockParam.ofDocument(doc),
|
||||
ContentBlockParam.ofText(TextBlockParam.builder().text("Summarize this").build())))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Server-Side Tools
|
||||
|
||||
Version-suffixed types; `name`/`type` auto-set by builder. Direct `.addTool()` overloads exist for every type — no manual `ToolUnion` wrapping.
|
||||
|
||||
```java
|
||||
import com.anthropic.models.messages.WebSearchTool20260209;
|
||||
import com.anthropic.models.messages.ToolBash20250124;
|
||||
import com.anthropic.models.messages.ToolTextEditor20250728;
|
||||
import com.anthropic.models.messages.CodeExecutionTool20260120;
|
||||
|
||||
.addTool(WebSearchTool20260209.builder()
|
||||
.maxUses(5L) // optional
|
||||
.allowedDomains(List.of("example.com")) // optional
|
||||
.build())
|
||||
.addTool(ToolBash20250124.builder().build())
|
||||
.addTool(ToolTextEditor20250728.builder().build())
|
||||
.addTool(CodeExecutionTool20260120.builder().build())
|
||||
```
|
||||
|
||||
Also available: `WebFetchTool20260209`, `MemoryTool20250818`, `ToolSearchToolBm25_20251119`.
|
||||
|
||||
### Beta namespace (MCP, compaction)
|
||||
|
||||
For 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()`:
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.messages.MessageCreateParams;
|
||||
import com.anthropic.models.beta.messages.BetaToolBash20250124;
|
||||
import com.anthropic.models.beta.messages.BetaCodeExecutionTool20260120;
|
||||
import com.anthropic.models.beta.messages.BetaRequestMcpServerUrlDefinition;
|
||||
|
||||
MessageCreateParams params = MessageCreateParams.builder()
|
||||
.model(Model.CLAUDE_OPUS_4_6)
|
||||
.maxTokens(16000L)
|
||||
.addBeta("mcp-client-2025-11-20")
|
||||
.addTool(BetaToolBash20250124.builder().build())
|
||||
.addTool(BetaCodeExecutionTool20260120.builder().build())
|
||||
.addMcpServer(BetaRequestMcpServerUrlDefinition.builder()
|
||||
.name("my-server")
|
||||
.url("https://example.com/mcp")
|
||||
.build())
|
||||
.addUserMessage("...")
|
||||
.build();
|
||||
|
||||
client.beta().messages().create(params);
|
||||
```
|
||||
|
||||
`BetaTool*` types are NOT interchangeable with non-beta `Tool*` — pick one namespace per request.
|
||||
|
||||
**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:
|
||||
|
||||
```java
|
||||
for (ContentBlock block : response.content()) {
|
||||
block.serverToolUse().ifPresent(stu -> {
|
||||
System.out.println("tool: " + stu.name() + " input: " + stu._input());
|
||||
});
|
||||
block.codeExecutionToolResult().ifPresent(r -> {
|
||||
r.content().resultBlock().ifPresent(result -> {
|
||||
System.out.println("stdout: " + result.stdout());
|
||||
System.out.println("stderr: " + result.stderr());
|
||||
System.out.println("exit: " + result.returnCode());
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files API (Beta)
|
||||
|
||||
Under `client.beta().files()`. File references in messages need the beta message types (non-beta `DocumentBlockParam.Source` has no file-ID variant).
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.files.FileUploadParams;
|
||||
import com.anthropic.models.beta.files.FileMetadata;
|
||||
import com.anthropic.models.beta.messages.BetaRequestDocumentBlock;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
FileMetadata meta = client.beta().files().upload(
|
||||
FileUploadParams.builder()
|
||||
.file(Paths.get("/path/to/doc.pdf")) // or .file(InputStream) or .file(byte[])
|
||||
.build());
|
||||
|
||||
// Reference in a beta message:
|
||||
BetaRequestDocumentBlock doc = BetaRequestDocumentBlock.builder()
|
||||
.fileSource(meta.id())
|
||||
.build();
|
||||
```
|
||||
|
||||
Other methods: `.list()`, `.delete(String fileId)`, `.download(String fileId)`, `.retrieveMetadata(String fileId)`.
|
||||
@@ -0,0 +1,442 @@
|
||||
# Managed Agents — Java
|
||||
|
||||
> **Bindings not shown here:** This README covers the most common managed-agents flows for Java. If you need a class, method, namespace, field, or behavior that isn't shown, WebFetch the Java SDK repo **or the relevant docs page** from `shared/live-sources.md` rather than guess. Do not extrapolate from cURL shapes or another language's SDK.
|
||||
|
||||
> **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `client.beta().agents().create` and pass it to every subsequent `client.beta().sessions().create`; do not call `agents().create` in the request path. The Anthropic CLI is one convenient way to create agents and environments from version-controlled YAML — its URL is in `shared/live-sources.md`. The examples below show in-code creation for completeness; in production the create call belongs in setup, not in the request path.
|
||||
|
||||
## Installation
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.anthropic</groupId>
|
||||
<artifactId>anthropic-java</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Client Initialization
|
||||
|
||||
```java
|
||||
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
|
||||
|
||||
// Default (uses ANTHROPIC_API_KEY env var)
|
||||
var client = AnthropicOkHttpClient.fromEnv();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create an Environment
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.environments.BetaCloudConfigParams;
|
||||
import com.anthropic.models.beta.environments.EnvironmentCreateParams;
|
||||
import com.anthropic.models.beta.environments.UnrestrictedNetwork;
|
||||
|
||||
var environment = client.beta().environments().create(EnvironmentCreateParams.builder()
|
||||
.name("my-dev-env")
|
||||
.config(BetaCloudConfigParams.builder()
|
||||
.networking(UnrestrictedNetwork.builder().build())
|
||||
.build())
|
||||
.build());
|
||||
System.out.println("Environment ID: " + environment.id()); // env_...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create an Agent (required first step)
|
||||
|
||||
> ⚠️ **There is no inline agent config.** Model, system, and tools live on the agent object, not the session. Always start with `client.beta().agents().create()` — the session takes either `.agent(agent.id())` or the typed `BetaManagedAgentsAgentParams.builder()...build()`.
|
||||
|
||||
### Minimal
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.agents.AgentCreateParams;
|
||||
import com.anthropic.models.beta.agents.BetaManagedAgentsAgentToolset20260401Params;
|
||||
import com.anthropic.models.beta.sessions.BetaManagedAgentsAgentParams;
|
||||
import com.anthropic.models.beta.sessions.SessionCreateParams;
|
||||
|
||||
// 1. Create the agent (reusable, versioned)
|
||||
var agent = client.beta().agents().create(AgentCreateParams.builder()
|
||||
.name("Coding Assistant")
|
||||
.model("claude-opus-4-7")
|
||||
.system("You are a helpful coding assistant.")
|
||||
.addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
|
||||
.type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
|
||||
.build())
|
||||
.build());
|
||||
|
||||
// 2. Start a session
|
||||
var session = client.beta().sessions().create(SessionCreateParams.builder()
|
||||
.agent(BetaManagedAgentsAgentParams.builder()
|
||||
.type(BetaManagedAgentsAgentParams.Type.AGENT)
|
||||
.id(agent.id())
|
||||
.version(agent.version())
|
||||
.build())
|
||||
.environmentId(environment.id())
|
||||
.title("Quickstart session")
|
||||
.build());
|
||||
System.out.println("Session ID: " + session.id());
|
||||
```
|
||||
|
||||
### Updating an Agent
|
||||
|
||||
Updates create new versions; the agent object is immutable per version.
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.agents.AgentUpdateParams;
|
||||
|
||||
var updatedAgent = client.beta().agents().update(agent.id(), AgentUpdateParams.builder()
|
||||
.version(agent.version())
|
||||
.system("You are a helpful coding agent. Always write tests.")
|
||||
.build());
|
||||
System.out.println("New version: " + updatedAgent.version());
|
||||
|
||||
// List all versions
|
||||
for (var version : client.beta().agents().versions().list(agent.id()).autoPager()) {
|
||||
System.out.println("Version " + version.version() + ": " + version.updatedAt());
|
||||
}
|
||||
|
||||
// Archive the agent
|
||||
var archived = client.beta().agents().archive(agent.id());
|
||||
System.out.println("Archived at: " + archived.archivedAt().orElseThrow());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Send a User Message
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserMessageEventParams;
|
||||
import com.anthropic.models.beta.sessions.events.EventSendParams;
|
||||
|
||||
client.beta().sessions().events().send(session.id(), EventSendParams.builder()
|
||||
.addEvent(BetaManagedAgentsUserMessageEventParams.builder()
|
||||
.type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
|
||||
.addTextContent("Review the auth module")
|
||||
.build())
|
||||
.build());
|
||||
```
|
||||
|
||||
> 💡 **Stream-first:** Open the stream *before* (or concurrently with) sending the message. The stream only delivers events that occur after it opens — stream-after-send means early events arrive buffered in one batch. See [Steering Patterns](../../shared/managed-agents-events.md#steering-patterns).
|
||||
|
||||
---
|
||||
|
||||
## Stream Events (SSE)
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.sessions.events.StreamEvents;
|
||||
|
||||
// Open the stream first, then send the user message
|
||||
try (var stream = client.beta().sessions().events().streamStreaming(session.id())) {
|
||||
client.beta().sessions().events().send(session.id(), EventSendParams.builder()
|
||||
.addEvent(BetaManagedAgentsUserMessageEventParams.builder()
|
||||
.type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
|
||||
.addTextContent("Summarize the repo README")
|
||||
.build())
|
||||
.build());
|
||||
|
||||
for (var event : (Iterable<StreamEvents>) stream.stream()::iterator) {
|
||||
if (event.isAgentMessage()) {
|
||||
event.asAgentMessage().content().forEach(block -> System.out.print(block.text()));
|
||||
} else if (event.isAgentToolUse()) {
|
||||
System.out.println("\n[Using tool: " + event.asAgentToolUse().name() + "]");
|
||||
} else if (event.isSessionStatusIdle()) {
|
||||
break;
|
||||
} else if (event.isSessionError()) {
|
||||
System.out.println("\n[Error]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reconnecting and Tailing
|
||||
|
||||
When reconnecting mid-session, list past events first to dedupe, then tail live events. The cross-variant `id` field is read from the raw `_json()` value:
|
||||
|
||||
```java
|
||||
import com.anthropic.core.JsonValue;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
try (var stream = client.beta().sessions().events().streamStreaming(session.id())) {
|
||||
// Stream is open and buffering. List history before tailing live.
|
||||
var seenEventIds = new HashSet<String>();
|
||||
for (var past : client.beta().sessions().events().list(session.id()).autoPager()) {
|
||||
Optional<Map<String, JsonValue>> obj = past._json().orElseThrow().asObject();
|
||||
seenEventIds.add(obj.orElseThrow().get("id").asStringOrThrow());
|
||||
}
|
||||
|
||||
// Tail live events, skipping anything already seen
|
||||
for (var event : (Iterable<StreamEvents>) stream.stream()::iterator) {
|
||||
Optional<Map<String, JsonValue>> obj = event._json().orElseThrow().asObject();
|
||||
if (!seenEventIds.add(obj.orElseThrow().get("id").asStringOrThrow())) continue;
|
||||
if (event.isAgentMessage()) {
|
||||
event.asAgentMessage().content().forEach(block -> System.out.print(block.text()));
|
||||
} else if (event.isSessionStatusIdle()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Provide Custom Tool Result
|
||||
|
||||
> ℹ️ The Java managed-agents bindings for `user.custom_tool_result` are not yet documented in this skill or in the apps source examples. Refer to `shared/managed-agents-events.md` for the wire format and the `anthropic-java` repository for the corresponding params types.
|
||||
|
||||
---
|
||||
|
||||
## Poll Events
|
||||
|
||||
```java
|
||||
for (var event : client.beta().sessions().events().list(session.id()).autoPager()) {
|
||||
System.out.println(event.type() + ": " + event);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Upload a File
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.files.FileUploadParams;
|
||||
import com.anthropic.models.beta.sessions.BetaManagedAgentsFileResourceParams;
|
||||
import java.nio.file.Path;
|
||||
|
||||
var dataCsv = Path.of("data.csv");
|
||||
|
||||
var file = client.beta().files().upload(FileUploadParams.builder()
|
||||
.file(dataCsv)
|
||||
.build());
|
||||
System.out.println("File ID: " + file.id());
|
||||
|
||||
// Mount in a session
|
||||
var session = client.beta().sessions().create(SessionCreateParams.builder()
|
||||
.agent(agent.id())
|
||||
.environmentId(environment.id())
|
||||
.addResource(BetaManagedAgentsFileResourceParams.builder()
|
||||
.type(BetaManagedAgentsFileResourceParams.Type.FILE)
|
||||
.fileId(file.id())
|
||||
.mountPath("/workspace/data.csv")
|
||||
.build())
|
||||
.build());
|
||||
```
|
||||
|
||||
### Add and Manage Resources on an Existing Session
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.sessions.resources.ResourceAddParams;
|
||||
import com.anthropic.models.beta.sessions.resources.ResourceDeleteParams;
|
||||
|
||||
// Attach an additional file to an open session
|
||||
var resource = client.beta().sessions().resources().add(session.id(), ResourceAddParams.builder()
|
||||
.betaManagedAgentsFileResourceParams(BetaManagedAgentsFileResourceParams.builder()
|
||||
.type(BetaManagedAgentsFileResourceParams.Type.FILE)
|
||||
.fileId(file.id())
|
||||
.build())
|
||||
.build());
|
||||
System.out.println(resource.id()); // "sesrsc_01ABC..."
|
||||
|
||||
// List resources on the session — entries are a discriminated union
|
||||
var listed = client.beta().sessions().resources().list(session.id());
|
||||
for (var entry : listed.data()) {
|
||||
if (entry.isFile()) {
|
||||
var fileResource = entry.asFile();
|
||||
System.out.println(fileResource.id() + " " + fileResource.type());
|
||||
} else if (entry.isGitHubRepository()) {
|
||||
var repoResource = entry.asGitHubRepository();
|
||||
System.out.println(repoResource.id() + " " + repoResource.type());
|
||||
}
|
||||
}
|
||||
|
||||
// Detach a resource
|
||||
client.beta().sessions().resources().delete(resource.id(), ResourceDeleteParams.builder()
|
||||
.sessionId(session.id())
|
||||
.build());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## List and Download Session Files
|
||||
|
||||
> ℹ️ Listing and downloading files an agent wrote during a session is not yet documented for Java in this skill or in the apps source examples. See `shared/managed-agents-events.md` and the `anthropic-java` repository for the file list/download bindings.
|
||||
|
||||
---
|
||||
|
||||
## Session Management
|
||||
|
||||
```java
|
||||
// List environments
|
||||
var environments = client.beta().environments().list();
|
||||
|
||||
// Retrieve a specific environment
|
||||
var env = client.beta().environments().retrieve(environment.id());
|
||||
|
||||
// Archive an environment (read-only, existing sessions continue)
|
||||
client.beta().environments().archive(environment.id());
|
||||
|
||||
// Delete an environment (only if no sessions reference it)
|
||||
client.beta().environments().delete(environment.id());
|
||||
|
||||
// Delete a session
|
||||
client.beta().sessions().delete(session.id());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MCP Server Integration
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.agents.BetaManagedAgentsMcpToolsetParams;
|
||||
import com.anthropic.models.beta.agents.BetaManagedAgentsUrlmcpServerParams;
|
||||
|
||||
// Agent declares MCP server (no auth here — auth goes in a vault)
|
||||
var agent = client.beta().agents().create(AgentCreateParams.builder()
|
||||
.name("GitHub Assistant")
|
||||
.model("claude-opus-4-7")
|
||||
.addMcpServer(BetaManagedAgentsUrlmcpServerParams.builder()
|
||||
.type(BetaManagedAgentsUrlmcpServerParams.Type.URL)
|
||||
.name("github")
|
||||
.url("https://api.githubcopilot.com/mcp/")
|
||||
.build())
|
||||
.addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
|
||||
.type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
|
||||
.build())
|
||||
.addTool(BetaManagedAgentsMcpToolsetParams.builder()
|
||||
.type(BetaManagedAgentsMcpToolsetParams.Type.MCP_TOOLSET)
|
||||
.mcpServerName("github")
|
||||
.build())
|
||||
.build());
|
||||
|
||||
// Session attaches vault(s) containing credentials for those MCP server URLs
|
||||
var session = client.beta().sessions().create(SessionCreateParams.builder()
|
||||
.agent(BetaManagedAgentsAgentParams.builder()
|
||||
.type(BetaManagedAgentsAgentParams.Type.AGENT)
|
||||
.id(agent.id())
|
||||
.version(agent.version())
|
||||
.build())
|
||||
.environmentId(environment.id())
|
||||
.addVaultId(vault.id())
|
||||
.build());
|
||||
```
|
||||
|
||||
See `shared/managed-agents-tools.md` §Vaults for creating vaults and adding credentials.
|
||||
|
||||
---
|
||||
|
||||
## Vaults
|
||||
|
||||
```java
|
||||
import com.anthropic.core.JsonValue;
|
||||
import com.anthropic.models.beta.vaults.VaultCreateParams;
|
||||
import com.anthropic.models.beta.vaults.credentials.BetaManagedAgentsMcpOAuthCreateParams;
|
||||
import com.anthropic.models.beta.vaults.credentials.BetaManagedAgentsMcpOAuthRefreshParams;
|
||||
import com.anthropic.models.beta.vaults.credentials.BetaManagedAgentsMcpOAuthRefreshUpdateParams;
|
||||
import com.anthropic.models.beta.vaults.credentials.BetaManagedAgentsMcpOAuthUpdateParams;
|
||||
import com.anthropic.models.beta.vaults.credentials.CredentialCreateParams;
|
||||
import com.anthropic.models.beta.vaults.credentials.CredentialUpdateParams;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
// Create a vault
|
||||
var vault = client.beta().vaults().create(VaultCreateParams.builder()
|
||||
.displayName("Alice")
|
||||
.metadata(VaultCreateParams.Metadata.builder()
|
||||
.putAdditionalProperty("external_user_id", JsonValue.from("usr_abc123"))
|
||||
.build())
|
||||
.build());
|
||||
System.out.println(vault.id()); // "vlt_01ABC..."
|
||||
|
||||
// Add an OAuth credential
|
||||
var credential = client.beta().vaults().credentials().create(vault.id(),
|
||||
CredentialCreateParams.builder()
|
||||
.displayName("Alice's Slack")
|
||||
.auth(BetaManagedAgentsMcpOAuthCreateParams.builder()
|
||||
.type(BetaManagedAgentsMcpOAuthCreateParams.Type.MCP_OAUTH)
|
||||
.mcpServerUrl("https://mcp.slack.com/mcp")
|
||||
.accessToken("xoxp-...")
|
||||
.expiresAt(OffsetDateTime.parse("2026-04-15T00:00:00Z"))
|
||||
.refresh(BetaManagedAgentsMcpOAuthRefreshParams.builder()
|
||||
.tokenEndpoint("https://slack.com/api/oauth.v2.access")
|
||||
.clientId("1234567890.0987654321")
|
||||
.scope("channels:read chat:write")
|
||||
.refreshToken("xoxe-1-...")
|
||||
.clientSecretPostTokenEndpointAuth("abc123...")
|
||||
.build())
|
||||
.build())
|
||||
.build());
|
||||
|
||||
// Rotate the credential (e.g., after a token refresh)
|
||||
client.beta().vaults().credentials().update(credential.id(),
|
||||
CredentialUpdateParams.builder()
|
||||
.vaultId(vault.id())
|
||||
.auth(BetaManagedAgentsMcpOAuthUpdateParams.builder()
|
||||
.type(BetaManagedAgentsMcpOAuthUpdateParams.Type.MCP_OAUTH)
|
||||
.accessToken("xoxp-new-...")
|
||||
.expiresAt(OffsetDateTime.parse("2026-05-15T00:00:00Z"))
|
||||
.refresh(BetaManagedAgentsMcpOAuthRefreshUpdateParams.builder()
|
||||
.refreshToken("xoxe-1-new-...")
|
||||
.build())
|
||||
.build())
|
||||
.build());
|
||||
|
||||
// Archive a vault
|
||||
client.beta().vaults().archive(vault.id());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GitHub Repository Integration
|
||||
|
||||
Mount a GitHub repository as a session resource (a vault holds the GitHub MCP credential):
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.sessions.BetaManagedAgentsGitHubRepositoryResourceParams;
|
||||
|
||||
var session = client.beta().sessions().create(SessionCreateParams.builder()
|
||||
.agent(agent.id())
|
||||
.environmentId(environment.id())
|
||||
.addVaultId(vault.id())
|
||||
.addResource(BetaManagedAgentsGitHubRepositoryResourceParams.builder()
|
||||
.type(BetaManagedAgentsGitHubRepositoryResourceParams.Type.GITHUB_REPOSITORY)
|
||||
.url("https://github.com/org/repo")
|
||||
.mountPath("/workspace/repo")
|
||||
.authorizationToken("ghp_your_github_token")
|
||||
.build())
|
||||
.build());
|
||||
```
|
||||
|
||||
Multiple repositories on the same session:
|
||||
|
||||
```java
|
||||
import java.util.List;
|
||||
|
||||
var resources = List.of(
|
||||
BetaManagedAgentsGitHubRepositoryResourceParams.builder()
|
||||
.type(BetaManagedAgentsGitHubRepositoryResourceParams.Type.GITHUB_REPOSITORY)
|
||||
.url("https://github.com/org/frontend")
|
||||
.mountPath("/workspace/frontend")
|
||||
.authorizationToken("ghp_your_github_token")
|
||||
.build(),
|
||||
BetaManagedAgentsGitHubRepositoryResourceParams.builder()
|
||||
.type(BetaManagedAgentsGitHubRepositoryResourceParams.Type.GITHUB_REPOSITORY)
|
||||
.url("https://github.com/org/backend")
|
||||
.mountPath("/workspace/backend")
|
||||
.authorizationToken("ghp_your_github_token")
|
||||
.build());
|
||||
```
|
||||
|
||||
Rotating a repository's authorization token:
|
||||
|
||||
```java
|
||||
import com.anthropic.models.beta.sessions.resources.ResourceUpdateParams;
|
||||
|
||||
var listed = client.beta().sessions().resources().list(session.id());
|
||||
var repoResourceId = listed.data().get(0).asGitHubRepository().id();
|
||||
|
||||
client.beta().sessions().resources().update(repoResourceId, ResourceUpdateParams.builder()
|
||||
.sessionId(session.id())
|
||||
.authorizationToken("ghp_your_new_github_token")
|
||||
.build());
|
||||
```
|
||||
Reference in New Issue
Block a user