What this read moved
26–50 of 51This capture is too large to show at once. Changes 26-50 of 51 are below, significant first; the rest are on the following screens.
build-with-claude/streaming Changed · +20 / -13 lines
from line 1013
10131013 ) as stream:
10141014 for event in stream:
10151015 if event.type == "content_block_delta":
1016 if event.delta.type == "thinking_delta":
1017 print(event.delta.thinking, end="", flush=True)
1018 elif event.delta.type == "text_delta":
1019 print(event.delta.text, end="", flush=True)
1016 delta = event.delta
1017 match delta.type:
1018 case "thinking_delta":
1019 print(delta.thinking, end="", flush=True)
1020 case "text_delta":
1021 print(delta.text, end="", flush=True)
10201022 ```
10211023
10221024 ```typescript TypeScript
from line 1038
10361038
10371039 for await (const event of stream) {
10381040 if (event.type === "content_block_delta") {
1039 if (event.delta.type === "thinking_delta") {
1040 process.stdout.write(event.delta.thinking);
1041 } else if (event.delta.type === "text_delta") {
1042 process.stdout.write(event.delta.text);
1041 switch (event.delta.type) {
1042 case "thinking_delta":
1043 process.stdout.write(event.delta.thinking);
1044 break;
1045 case "text_delta":
1046 process.stdout.write(event.delta.text);
1047 break;
10431048 }
10441049 }
10451050 }
from line 1159
11541159 )
11551160
11561161 stream.each do |event|
1157 if event.type == :content_block_delta
1158 if event.delta.type == :thinking_delta
1159 print(event.delta.thinking)
1160 elsif event.delta.type == :text_delta
1161 print(event.delta.text)
1162 if event.is_a?(Anthropic::Models::RawContentBlockDeltaEvent)
1163 delta = event.delta
1164 case delta
1165 when Anthropic::Models::ThinkingDelta
1166 print(delta.thinking)
1167 when Anthropic::Models::TextDelta
1168 print(delta.text)
11621169 end
11631170 end
11641171 end
build-with-claude/structured-outputs Changed · +7 / -4 lines
from line 2546
25462546 // Claude may call the tool first (tool_use) or respond with JSON (text)
25472547 console.log("Stop reason:", response.stop_reason);
25482548 for (const block of response.content) {
2549 if (block.type === "tool_use") {
2550 console.log(`Tool call: ${block.name}(${JSON.stringify(block.input)})`);
2551 } else if (block.type === "text") {
2552 console.log("Response:", block.text);
2549 switch (block.type) {
2550 case "tool_use":
2551 console.log(`Tool call: ${block.name}(${JSON.stringify(block.input)})`);
2552 break;
2553 case "text":
2554 console.log("Response:", block.text);
2555 break;
25532556 }
25542557 }
25552558 ```
build-with-claude/thinking Changed · +102 / -69 lines
from line 98
9898 )
9999
100100 for block in response.content:
101 if block.type == "thinking":
102 print(f"\nThinking: {block.thinking}")
103 elif block.type == "text":
104 print(f"\nResponse: {block.text}")
101 match block.type:
102 case "thinking":
103 print(f"\nThinking: {block.thinking}")
104 case "text":
105 print(f"\nResponse: {block.text}")
105106 ```
106107
107108 ```typescript TypeScript
from line 124
123124 });
124125
125126 for (const block of response.content) {
126 if (block.type === "thinking") {
127 console.log(`\nThinking: ${block.thinking}`);
128 } else if (block.type === "text") {
129 console.log(`\nResponse: ${block.text}`);
127 switch (block.type) {
128 case "thinking":
129 console.log(`\nThinking: ${block.thinking}`);
130 break;
131 case "text":
132 console.log(`\nResponse: ${block.text}`);
133 break;
130134 }
131135 }
132136 ```
from line 224
220224 ```
221225
222226 ```php PHP
227 use Anthropic\Messages\TextBlock;
228 use Anthropic\Messages\ThinkingBlock;
229
223230 $client = new Client();
224231
225232 $message = $client->messages->create(
from line 242
235242 );
236243
237244 foreach ($message->content as $block) {
238 if ($block->type === 'thinking') {
239 echo "\nThinking: " . $block->thinking;
240 } elseif ($block->type === 'text') {
241 echo "\nResponse: " . $block->text;
245 switch (true) {
246 case $block instanceof ThinkingBlock:
247 echo "\nThinking: " . $block->thinking;
248 break;
249 case $block instanceof TextBlock:
250 echo "\nResponse: " . $block->text;
251 break;
242252 }
243253 }
244254 ```
from line 272
262272 )
263273
264274 message.content.each do |block|
265 case block.type
266 when :thinking
275 case block
276 when Anthropic::Models::ThinkingBlock
267277 puts "\nThinking: #{block.thinking}"
268 when :text
278 when Anthropic::Models::TextBlock
269279 puts "\nResponse: #{block.text}"
270280 end
271281 end
from line 562
552562 ],
553563 ) as stream:
554564 for event in stream:
555 if event.type == "content_block_start":
556 print(f"\nStarting {event.content_block.type} block...")
557 elif event.type == "content_block_delta":
558 if event.delta.type == "thinking_delta":
559 print(event.delta.thinking, end="", flush=True)
560 elif event.delta.type == "text_delta":
561 print(event.delta.text, end="", flush=True)
565 match event.type:
566 case "content_block_start":
567 print(f"\nStarting {event.content_block.type} block...")
568 case "content_block_delta":
569 delta = event.delta
570 match delta.type:
571 case "thinking_delta":
572 print(delta.thinking, end="", flush=True)
573 case "text_delta":
574 print(delta.text, end="", flush=True)
562575 ```
563576
564577 ```typescript TypeScript
from line 585
572585 });
573586
574587 for await (const event of stream) {
575 if (event.type === "content_block_start") {
576 console.log(`\nStarting ${event.content_block.type} block...`);
577 } else if (event.type === "content_block_delta") {
578 if (event.delta.type === "thinking_delta") {
579 process.stdout.write(event.delta.thinking);
580 } else if (event.delta.type === "text_delta") {
581 process.stdout.write(event.delta.text);
582 }
588 switch (event.type) {
589 case "content_block_start":
590 console.log(`\nStarting ${event.content_block.type} block...`);
591 break;
592 case "content_block_delta":
593 switch (event.delta.type) {
594 case "thinking_delta":
595 process.stdout.write(event.delta.thinking);
596 break;
597 case "text_delta":
598 process.stdout.write(event.delta.text);
599 break;
600 }
601 break;
583602 }
584603 }
585604 ```
from line 686
667686
668687 try (var streamResponse = client.messages().createStreaming(params)) {
669688 streamResponse.stream().forEach(event -> {
670 if (event.contentBlockStart().isPresent()) {
671 var startEvent = event.contentBlockStart().get();
672 var block = startEvent.contentBlock();
673 if (block.isThinking()) {
674 IO.println("\nStarting thinking block...");
675 } else if (block.isText()) {
676 IO.println("\nStarting text block...");
689 switch (event.type().value()) {
690 case CONTENT_BLOCK_START -> {
691 var startEvent = event.asContentBlockStart();
692 var block = startEvent.contentBlock();
693 switch (block.type().value()) {
694 case THINKING -> IO.println("\nStarting thinking block...");
695 case TEXT -> IO.println("\nStarting text block...");
696 }
677697 }
678 } else if (event.contentBlockDelta().isPresent()) {
679 var deltaEvent = event.contentBlockDelta().get();
680 deltaEvent.delta().thinking().ifPresent(td ->
681 IO.print(td.thinking())
682 );
683 deltaEvent.delta().text().ifPresent(td ->
684 IO.print(td.text())
685 );
698 case CONTENT_BLOCK_DELTA -> {
699 var deltaEvent = event.asContentBlockDelta();
700 deltaEvent.delta().thinking().ifPresent(td ->
701 IO.print(td.thinking())
702 );
703 deltaEvent.delta().text().ifPresent(td ->
704 IO.print(td.text())
705 );
706 }
686707 }
687708 });
688709 }
from line 711
690711 ```
691712
692713 ```php PHP
714 use Anthropic\Messages\RawContentBlockDeltaEvent;
715 use Anthropic\Messages\RawContentBlockStartEvent;
716 use Anthropic\Messages\TextDelta;
717 use Anthropic\Messages\ThinkingDelta;
718
693719 $client = new Client();
694720
695721 $stream = $client->messages->createStream(
from line 728
702728 );
703729
704730 foreach ($stream as $event) {
705 if ($event->type === 'content_block_start') {
706 echo "\nStarting {$event->contentBlock->type} block...\n";
707 } elseif ($event->type === 'content_block_delta') {
708 if ($event->delta->type === 'thinking_delta') {
709 echo $event->delta->thinking;
710 } elseif ($event->delta->type === 'text_delta') {
711 echo $event->delta->text;
712 }
731 switch (true) {
732 case $event instanceof RawContentBlockStartEvent:
733 echo "\nStarting {$event->contentBlock->type} block...\n";
734 break;
735 case $event instanceof RawContentBlockDeltaEvent:
736 switch (true) {
737 case $event->delta instanceof ThinkingDelta:
738 echo $event->delta->thinking;
739 break;
740 case $event->delta instanceof TextDelta:
741 echo $event->delta->text;
742 break;
743 }
744 break;
713745 }
714746 }
715747 ```
from line 1163
11311163
11321164Each model accepts `max_tokens` up to the ceiling listed here. On the [Message Batches API](https://platform.claude.com/docs/en/build-with-claude/batch-processing#extended-output-beta), the `output-300k-2026-03-24` [beta header](https://platform.claude.com/docs/en/api/beta-headers) raises that ceiling for the models with a batches ceiling listed.
11331165
1134| Model | Max output tokens | Batches beta ceiling |
1135| --------------------- | ----------------- | -------------------- |
1136| Claude Fable 5.1 | 128k | — |
1137| Claude Mythos 5.1 | 128k | — |
1138| Claude Fable 5 | 128k | — |
1139| Claude Mythos 5 | 128k | — |
1140| Claude Mythos Preview | 128k | Not available |
1141| Claude Opus 5 | 128k | 300k |
1142| Claude Opus 4.8 | 128k | 300k |
1143| Claude Opus 4.7 | 128k | 300k |
1144| Claude Sonnet 5 | 128k | 300k |
1145| Claude Opus 4.6 | 128k | 300k |
1146| Claude Sonnet 4.6 | 128k | 300k |
1147| Claude Haiku 4.5 | 64k | Not available |
1148| Claude Sonnet 4.5 | 64k | Not available |
1149| Claude Opus 4.5 | 64k | Not available |
1166| Model | Max output tokens | Batches beta ceiling |
1167| :---------------- | :---------------- | :------------------- |
1168| Claude Fable 5.1 | 128K | — |
1169| Claude Mythos 5.1 | 128K | — |
1170| Claude Fable 5 | 128K | — |
1171| Claude Mythos 5 | 128K | — |
1172| Claude Opus 5 | 128K | 300K |
1173| Claude Opus 4.8 | 128K | 300K |
1174| Claude Opus 4.7 | 128K | 300K |
1175| Claude Opus 4.6 | 128K | 300K |
1176| Claude Opus 4.5 | 64K | Not available |
1177| Claude Sonnet 5 | 128K | 300K |
1178| Claude Sonnet 4.6 | 128K | 300K |
1179| Claude Sonnet 4.5 | 64K | Not available |
1180| Claude Haiku 4.5 | 64K | Not available |
1181
1182[Claude Mythos Preview](https://anthropic.com/glasswing) accepts `max_tokens` up to 128K; the Batches beta ceiling is not available for it.
11501183
11511184See the [models overview](https://platform.claude.com/docs/en/models/overview) for limits on legacy models.
11521185
claude_api_primer Changed · +12 / -10 lines
from line 294
294294
295295 # The response contains summarized thinking blocks and text blocks
296296 for block in response.content:
297 if block.type == "thinking":
298 print(f"\nThinking summary: {block.thinking}")
299 elif block.type == "text":
300 print(f"\nResponse: {block.text}")
297 match block.type:
298 case "thinking":
299 print(f"\nThinking summary: {block.thinking}")
300 case "text":
301 print(f"\nResponse: {block.text}")
301302 ```
302303</CodeGroup>
303304
from line 531
530531 )
531532
532533 for block in response.content:
533 if block.type == "thinking":
534 print(f"Thinking: {block.thinking}")
535 elif block.type == "tool_use":
536 print(f"Tool call: {block.name}({block.input})")
537 elif block.type == "text":
538 print(f"Response: {block.text}")
534 match block.type:
535 case "thinking":
536 print(f"Thinking: {block.thinking}")
537 case "tool_use":
538 print(f"Tool call: {block.name}({block.input})")
539 case "text":
540 print(f"Response: {block.text}")
539541 ```
540542</CodeGroup>
541543
cli-sdks-libraries/sdks/java Changed · +3 / -3 lines
from line 15
1515<Tabs>
1616 <Tab title="Gradle">
1717 ```kotlin
18 implementation("com.anthropic:anthropic-java:2.60.0")
18 implementation("com.anthropic:anthropic-java:2.63.0")
1919 ```
2020 </Tab>
2121
from line 24
2424 <dependency>
2525 <groupId>com.anthropic</groupId>
2626 <artifactId>anthropic-java</artifactId>
27 <version>2.60.0</version>
27 <version>2.63.0</version>
2828 </dependency>
2929 ```
3030 </Tab>
from line 1084
10841084
10851085Use `BedrockMantleBackend` for new projects; `BedrockBackend` remains for existing applications using the Bedrock `InvokeModel` API.
10861086
1087Each `Backend` implementation is passed to the client with `.backend()` on `AnthropicOkHttpClient.builder()`. Each cloud backend pulls in its respective cloud-platform SDK classes as transitive dependencies.
1087The platform artifacts are add-ons to the base `com.anthropic:anthropic-java` dependency, which provides `AnthropicOkHttpClient`, so install both. Each `Backend` implementation is passed to the client with `.backend()` on `AnthropicOkHttpClient.builder()`. Each cloud backend pulls in its respective cloud-platform SDK classes as transitive dependencies.
10881088
10891089## Advanced usage
10901090
manage-claude/compliance-faq Changed · +4 / -4 lines
from line 70
7070 </Accordion>
7171
7272 <Accordion title="Do Cowork, Claude Code, Claude Science, and Claude for Microsoft 365 sessions appear in the Compliance API?">
73 Yes. Cowork sessions in Claude Desktop that run on users' machines, Claude Code sessions (in the terminal, in Claude Desktop, or in an IDE extension), sessions in the Claude Science desktop app, and Claude for Microsoft 365 sessions in Excel, PowerPoint, Word, and Outlook are captured while users are signed in with their Claude Enterprise account and are available through the [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments, are available through the [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions). Each family has a list endpoint that returns session metadata and a messages endpoint that returns the session transcript (user prompts, assistant responses, and tool calls and results). The local family adds a third endpoint that retrieves one session's metadata. All of these endpoints use your existing Compliance Access Key with `read:compliance_user_data`; no new key or scope is needed.
73 Yes. Cowork sessions in Claude Desktop that run on users' machines, Claude Code sessions (in the terminal, in Claude Desktop, or in an IDE extension), sessions in the Claude Science desktop app, Claude for Microsoft 365 sessions (in Excel, PowerPoint, Word, and Outlook), and chats in the Claude in Chrome browser extension are captured while users are signed in with their Claude Enterprise account and are available through the [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments, are available through the [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions). Each family has a list endpoint that returns session metadata and a messages endpoint that returns the session transcript (user prompts, assistant responses, and tool calls and results). The local family adds a third endpoint that retrieves one session's metadata. All of these endpoints use your existing Compliance Access Key with `read:compliance_user_data`; no new key or scope is needed.
7474
75 Local sessions are captured as their requests reach the Claude API, so nothing is installed on the device, and on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and Claude Code on the web are not captured. Claude Code on the web also runs in the cloud in Anthropic-managed environments, but it is not a remote session; the remote session endpoints return Cowork sessions only. Organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled get no local session data, and sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect are excluded.
75 Local sessions are captured as their requests reach the Claude API, so nothing is installed on the device, and on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web), which run on cloud infrastructure instead of the user's machine, are not captured. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only. Organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled get no local session data, and sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect are excluded.
7676
77 The local and remote session endpoints are stable for Cowork and Claude Code sessions; coverage of Claude Science and Claude for Microsoft 365 sessions is in beta.
77 The local and remote session endpoints are stable for Cowork and Claude Code sessions; coverage of Claude Science, Claude for Microsoft 365, and Claude in Chrome sessions is in beta.
7878 </Accordion>
7979
8080 <Accordion title="What do session transcripts include?">
from line 109
109109 <Accordion title="What does the Compliance API not capture?">
110110 The Compliance API has known coverage boundaries: the Activity Feed records resource events but not prompt or response text, Claude Console and Claude API workloads authenticated with an API key expose no message content at all, and content removed by your retention policy, deleted by a user in claude.ai, or hard-deleted through the Compliance API is not recoverable. For the full coverage boundaries and delivery contract, see [Delivery guarantees and completeness](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#delivery-guarantees-and-completeness).
111111
112 Session transcripts have boundaries of their own. Local sessions are captured only as their requests reach the Claude API, so on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and Claude Code on the web are not captured either; organizations with HIPAA readiness enabled get no local session data; and sessions for which zero data retention is in effect are excluded. No session transcript, local or remote, includes thinking blocks or tool definitions. Organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek) receive local session transcripts as usual. While the key cannot be used, the messages endpoint returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead of transcript content, and session metadata is still listed.
112 Session transcripts have boundaries of their own. Local sessions are captured only as their requests reach the Claude API, so on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web), which run on cloud infrastructure instead of the user's machine, are not captured either; organizations with HIPAA readiness enabled get no local session data; and sessions for which zero data retention is in effect are excluded. No session transcript, local or remote, includes thinking blocks or tool definitions. Organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek) receive local session transcripts as usual. While the key cannot be used, the messages endpoint returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead of transcript content, and session metadata is still listed.
113113 </Accordion>
114114</AccordionGroup>
115115
manage-claude/compliance-sessions Changed · +7 / -6 lines
from line 5
55---
66
77<Note>
8 The endpoints on this page are available only to Claude Enterprise organizations. The local and remote session endpoints are stable for Cowork and Claude Code sessions; coverage of Claude Science and Claude for Microsoft 365 sessions is in beta. The endpoints work with the same Compliance Access Key and `read:compliance_user_data` scope as the [chat, file, and project endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-content-data); no new key, scope, setting, or client update is required. See [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
8 The endpoints on this page are available only to Claude Enterprise organizations. The local and remote session endpoints are stable for Cowork and Claude Code sessions; coverage of Claude Science, Claude for Microsoft 365, and Claude in Chrome sessions is in beta. The endpoints work with the same Compliance Access Key and `read:compliance_user_data` scope as the [chat, file, and project endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-content-data); no new key, scope, setting, or client update is required. See [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
99</Note>
1010
1111<Check>
from line 14
1414 **Prerequisite:** None for listing sessions organization-wide. To filter the remote session list (sessions in the cloud) to specific users, you need user IDs from [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users); the local session list has no user filter.
1515</Check>
1616
17The endpoints on this page expose transcripts of the sessions your users run in Claude apps and agents (today: Cowork, Claude Code, Claude Science, and Claude for Microsoft 365) from your Claude Enterprise organizations to compliance reviewers. Each session is a single conversation with Claude; its transcript is the sequence of user prompts, assistant responses, and tool calls and results in that conversation. The endpoints support eDiscovery (electronic discovery) exports and data loss prevention (DLP) enforcement.
17The endpoints on this page expose transcripts of the sessions your users run in Claude apps and agents (today: Cowork, Claude Code, Claude Science, Claude for Microsoft 365, and Claude in Chrome) from your Claude Enterprise organizations to compliance reviewers. Each session is a single conversation with Claude; its transcript is the sequence of user prompts, assistant responses, and tool calls and results in that conversation. The endpoints support eDiscovery (electronic discovery) exports and data loss prevention (DLP) enforcement.
1818
1919The Compliance API groups sessions into two endpoint families according to where they run: local session endpoints for sessions on users' machines, and remote session endpoints for sessions that run in the cloud in Anthropic-managed environments. Both families are read-only, and neither is available to Admin API keys (`sk-ant-admin01-...`): calls authenticated with an Admin API key return [403 Forbidden](https://platform.claude.com/docs/en/manage-claude/compliance-errors#403-forbidden).
2020
from line 26
2626| Claude Code in the terminal, in Claude Desktop, or in an IDE extension, running on the user's machine | Local session endpoints | `claude_code` |
2727| Claude Science desktop app, running on the user's machine | Local session endpoints | `claude_science` |
2828| Claude for Microsoft 365 (the Claude add-ins for Excel, PowerPoint, Word, and Outlook), running in the Microsoft 365 desktop or web apps | Local session endpoints | `office_agents/excel`, `office_agents/powerpoint`, `office_agents/word`, or `office_agents/outlook` (`office_agents` when the app is not identified) |
29| Claude in Chrome (the browser extension's built-in chat), running on the user's machine | Local session endpoints | `claude_in_chrome` |
2930| Cowork sessions started on claude.ai web or mobile, running in the cloud in Anthropic-managed environments | Remote session endpoints (`/v1/compliance/apps/sessions/remote`) | `cowork_remote` |
3031
3132Capture of local sessions is tied to the Compliance API being enabled for your organization and applies while users are signed in with their Claude Enterprise account. The session endpoints do not return the following:
3233
3334* Claude Code sessions authenticated with a Claude Console API key, or run through a third-party cloud platform such as Amazon Bedrock, Google Cloud, or Microsoft Foundry.
34* Claude Code on the web. It also runs in the cloud in Anthropic-managed environments, but it is not a remote session; the remote session endpoints return Cowork sessions only.
35* [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web), which run on cloud infrastructure instead of the user's machine. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only.
3536* Local sessions in organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled. No local session data is captured, so the local session endpoints return no sessions for those organizations.
3637* Local sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect. These sessions are excluded from list results, and the retrieve and messages endpoints return 404 for them.
3738
from line 44
4344| Setup | Works with your existing Compliance Access Key | Works with your existing Compliance Access Key | Admin configures an OTLP endpoint and content-capture settings |
4445| Infrastructure | Anthropic-hosted | Anthropic-hosted | You run the collector and storage |
4546| ID prefix | `clls_` | `cse_` | N/A |
46| `product_surface` values | `cowork`, `claude_code`, `claude_science`, and values beginning with `office_agents` | `cowork_remote` | N/A |
47| `product_surface` values | `cowork`, `claude_code`, `claude_science`, `claude_in_chrome`, and values beginning with `office_agents` | `cowork_remote` | N/A |
4748| Retention | 6 years by default, or your organization's custom conversation retention period when a finite one is set; held by Anthropic | 6 years, unless a user deletes the session sooner; held by Anthropic | Your infrastructure, your policies |
4849| User prompts and assistant responses | Yes | Yes | Yes, subject to content-capture settings |
4950| Tool inputs | Truncated to 10,000 bytes per input by default; up to about 1 MiB on request | Truncated to 10,000 bytes per input by default; up to about 1 MiB on request | Truncated summaries |
from line 55
5455
5556## Sessions on users' machines (local sessions)
5657
57Local sessions run on users' machines while they are signed in with their Claude Enterprise account: today, Cowork in Claude Desktop, Claude Code (in the terminal, in Claude Desktop, or in an IDE extension), the Claude Science desktop app, and Claude for Microsoft 365 in Excel, PowerPoint, Word, and Outlook.
58Local sessions run on users' machines while they are signed in with their Claude Enterprise account: today, Cowork in Claude Desktop, Claude Code (in the terminal, in Claude Desktop, or in an IDE extension), the Claude Science desktop app, Claude for Microsoft 365 (in Excel, PowerPoint, Word, and Outlook), and the Claude in Chrome browser extension.
5859
5960The Compliance API exposes local sessions through three endpoints: `GET /v1/compliance/apps/sessions/local` lists session metadata, `GET /v1/compliance/apps/sessions/local/{session_id}` retrieves one session's metadata, and `GET /v1/compliance/apps/sessions/local/{session_id}/messages` returns one session's transcript. All three require the `read:compliance_user_data` scope and count only against the shared Compliance API rate limit; they are not subject to the second request budget that applies to the remote session endpoints. See [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests). If local sessions are not available to your parent organization, all three endpoints return 404 with the message `Local sessions are not available.` (see [Local session not found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-session-not-found)); while session listings or captured content are temporarily unavailable, they return 503 (see [Local sessions temporarily unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable)).
6061
from line 122
121122
122123To fetch one session's metadata directly, pass its ID to `GET /v1/compliance/apps/sessions/local/{session_id}`. The response is the same session object the list endpoint returns, with no envelope and no transcript content. A malformed session ID returns [400 Bad Request](https://platform.claude.com/docs/en/manage-claude/compliance-errors#400-bad-request). A single [404 Not Found](https://platform.claude.com/docs/en/manage-claude/compliance-errors#404-not-found) covers four cases that the response does not distinguish: the session is not in an organization your key can read (including sessions under another parent organization), it does not exist, zero data retention is in effect for it, or every call in it has aged past retention.
123124
124`product_surface` (string or `null`) identifies the product that created the session: `cowork` (Cowork in Claude Desktop on the user's machine), `claude_code` (Claude Code), `claude_science` (Claude Science), or one of `office_agents/excel`, `office_agents/powerpoint`, `office_agents/word`, and `office_agents/outlook` (Claude for Microsoft 365, by app; `office_agents` alone when the app is not identified). New values appear as coverage expands.
125`product_surface` (string or `null`) identifies the product that created the session: `cowork` (Cowork in Claude Desktop on the user's machine), `claude_code` (Claude Code), `claude_science` (Claude Science), `claude_in_chrome` (the Claude in Chrome browser extension's built-in chat), or one of `office_agents/excel`, `office_agents/powerpoint`, `office_agents/word`, and `office_agents/outlook` (Claude for Microsoft 365, by app; `office_agents` alone when the app is not identified). New values appear as coverage expands.
125126
126127<Note>
127128 **Build forward-compatible handlers.** Pass through unrecognized `product_surface` values, and ignore fields your handler does not expect, so your integration keeps working as new product surfaces ship.
managed-agents/events-and-streaming Changed · +242 / -201 lines
The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.
from line 461
461461 ]
462462 });
463463
464 for await (const event of stream) {
465 if (event.type === "agent.message") {
466 for (const block of event.content) {
467 if (block.type === "text") {
468 process.stdout.write(block.text);
464 events: for await (const event of stream) {
465 switch (event.type) {
466 case "agent.message":
467 for (const block of event.content) {
468 if (block.type === "text") {
469 process.stdout.write(block.text);
470 }
469471 }
470 }
471 } else if (event.type === "session.status_idle") {
472 break;
473 } else if (event.type === "session.error") {
474 console.log(`\n[Error: ${event.error?.message ?? "unknown"}]`);
475 break;
472 break;
473 case "session.status_idle":
474 break events;
475 case "session.error":
476 console.log(`\n[Error: ${event.error?.message ?? "unknown"}]`);
477 break events;
476478 }
477479 }
478480 ```
from line 580
578580 );
579581
580582 Iterable<BetaManagedAgentsStreamSessionEvents> events = stream.stream()::iterator;
583 events:
581584 for (var event : events) {
582 if (event.isAgentMessage()) {
583 event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
584 } else if (event.isSessionStatusIdle()) {
585 break;
586 } else if (event.isSessionError()) {
587 // The `message` field spans all error variants; read it from the raw JSON.
588 var errorMessage =
589 event.asSessionError().error()._json().orElse(null) instanceof JsonObject json
590 ? json.values().get("message").asStringOrThrow()
591 : "unknown";
592 IO.println("\n[Error: " + errorMessage + "]");
593 break;
585 switch (event.type().value()) {
586 case AGENT_MESSAGE -> event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
587 case SESSION_STATUS_IDLE -> {
588 break events;
589 }
590 case SESSION_ERROR -> {
591 // The `message` field spans all error variants; read it from the raw JSON.
592 var errorMessage =
593 event.asSessionError().error()._json().orElse(null) instanceof JsonObject json
594 ? json.values().get("message").asStringOrThrow()
595 : "unknown";
596 IO.println("\n[Error: " + errorMessage + "]");
597 break events;
598 }
594599 }
595600 }
596601 }
from line 615
610615 );
611616
612617 foreach ($stream as $event) {
613 match ($event->type) {
614 'agent.message' => array_walk(
618 match (true) {
619 $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent => array_walk(
615620 $event->content,
616 static fn ($block) => $block->type === 'text' ? print($block->text) : null,
621 static fn ($block) => $block instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock ? print($block->text) : null,
617622 ),
618 'session.error' => printf("\n[Error: %s]", $event->error?->message ?? 'unknown'),
623 $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionErrorEvent => printf("\n[Error: %s]", $event->error?->message ?? 'unknown'),
619624 default => null,
620625 };
621626 if ($event->type === 'session.status_idle' || $event->type === 'session.error') {
from line 643
638643 )
639644
640645 stream.each do |event|
641 case event.type
642 in :"agent.message"
646 case event
647 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
643648 event.content.each { print it.text }
644 in :"session.status_idle"
649 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
645650 break
646 in :"session.error"
651 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionErrorEvent
647652 puts "\n[Error: #{event.error&.message || "unknown"}]"
648653 break
649654 else
from line 746
741746 }
742747
743748 // Tail live events, skipping anything already seen
744 for await (const event of stream) {
749 tail: for await (const event of stream) {
745750 // Preview events (event_start/event_delta) carry no top-level id
746751 if (event.type === "event_start" || event.type === "event_delta") continue;
747752 if (seenEventIds.has(event.id)) continue;
748753 seenEventIds.add(event.id);
749 if (event.type === "agent.message") {
750 for (const block of event.content) {
751 if (block.type === "text") {
752 process.stdout.write(block.text);
754 switch (event.type) {
755 case "agent.message":
756 for (const block of event.content) {
757 if (block.type === "text") {
758 process.stdout.write(block.text);
759 }
753760 }
754 }
755 } else if (event.type === "session.status_idle") {
756 break;
761 break;
762 case "session.status_idle":
763 break tail;
757764 }
758765 }
759766 ```
from line 874
867874 continue;
868875 }
869876 $seenEventIds[$event->id] = true;
870 match ($event->type) {
871 'agent.message' => array_walk(
877 match (true) {
878 $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent => array_walk(
872879 $event->content,
873 static fn ($block) => $block->type === 'text' ? print($block->text) : null,
880 static fn ($block) => $block instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock ? print($block->text) : null,
874881 ),
875882 default => null,
876883 };
from line 898
891898 # Tail live events, skipping anything already seen — Set#add? returns nil for duplicates
892899 stream.each do |event|
893900 next unless seen_event_ids.add?(event.id)
894 case event.type
895 in :"agent.message"
901 case event
902 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
896903 event.content.each { print it.text }
897 in :"session.status_idle"
904 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
898905 break
899906 else
900907 # ignore other event types
from line 1281
12741281 ]
12751282 });
12761283
1277 for await (const event of stream) {
1278 if (event.type === "event_start") {
1279 // 1. Note the announced id and open the snapshot. Deltas and the
1280 // buffered event carry the same id.
1281 const preview = accumulateManagedAgentsEvent(undefined, event);
1282 if (preview) previews.set(event.event.id, preview);
1283 console.log(`event_start ${event.event.type} ${event.event.id}`);
1284 } else if (event.type === "event_delta") {
1285 // 2. Fold the fragment into the snapshot and render it
1286 const preview = accumulateManagedAgentsEvent(previews.get(event.event_id), event);
1287 if (preview) {
1288 previews.set(event.event_id, preview);
1289 const text = preview.content
1284 deltas: for await (const event of stream) {
1285 switch (event.type) {
1286 case "event_start": {
1287 // 1. Note the announced id and open the snapshot. Deltas and the
1288 // buffered event carry the same id.
1289 const preview = accumulateManagedAgentsEvent(undefined, event);
1290 if (preview) previews.set(event.event.id, preview);
1291 console.log(`event_start ${event.event.type} ${event.event.id}`);
1292 break;
1293 }
1294 case "event_delta": {
1295 // 2. Fold the fragment into the snapshot and render it
1296 const preview = accumulateManagedAgentsEvent(previews.get(event.event_id), event);
1297 if (preview) {
1298 previews.set(event.event_id, preview);
1299 const text = preview.content
1300 .map((block) => (block.type === "text" ? block.text : ""))
1301 .join("");
1302 console.log(`event_delta preview: ${JSON.stringify(text)}`);
1303 }
1304 break;
1305 }
1306 case "agent.message": {
1307 // 3. The buffered event is the record: it replaces and closes the preview
1308 const message = accumulateManagedAgentsEvent(previews.get(event.id), event);
1309 previews.delete(event.id);
1310 const text = message.content
12901311 .map((block) => (block.type === "text" ? block.text : ""))
12911312 .join("");
1292 console.log(`event_delta preview: ${JSON.stringify(text)}`);
1293 }
1294 } else if (event.type === "agent.message") {
1295 // 3. The buffered event is the record: it replaces and closes the preview
1296 const message = accumulateManagedAgentsEvent(previews.get(event.id), event);
1297 previews.delete(event.id);
1298 const text = message.content
1299 .map((block) => (block.type === "text" ? block.text : ""))
1300 .join("");
1301 console.log(`agent.message ${event.id} ${JSON.stringify(text)}`);
1302 } else if (event.type === "span.model_request_end") {
1303 // 4. No more deltas are coming. Close any preview that was never reconciled.
1304 for (const eventId of previews.keys()) {
1305 console.log(`span.model_request_end closing preview for ${eventId}`);
1306 }
1307 previews.clear();
1308 } else if (event.type === "session.status_idle") {
1309 break;
1313 console.log(`agent.message ${event.id} ${JSON.stringify(text)}`);
1314 break;
1315 }
1316 case "span.model_request_end":
1317 // 4. No more deltas are coming. Close any preview that was never reconciled.
1318 for (const eventId of previews.keys()) {
1319 console.log(`span.model_request_end closing preview for ${eventId}`);
1320 }
1321 previews.clear();
1322 break;
1323 case "session.status_idle":
1324 break deltas;
13101325 }
13111326 }
13121327 stream.controller.abort();
from line 1483
14681483 );
14691484
14701485 Iterable<BetaManagedAgentsStreamSessionEvents> events = stream.stream()::iterator;
1486 deltas:
14711487 for (var event : events) {
1472 if (event.isEventStart() && event.asEventStart().event().isAgentMessage()) {
1473 var preview = event.asEventStart().event().asAgentMessage();
1474 IO.println("event_start " + preview.type().asString() + " " + preview.id());
1475 } else if (event.isEventDelta()) {
1476 var eventDelta = event.asEventDelta();
1477 var fragment = eventDelta.delta();
1478 var buffer = previews
1479 .computeIfAbsent(eventDelta.eventId(), _ -> new HashMap<>())
1480 .computeIfAbsent(fragment.index().orElse(0L), _ -> new StringBuilder());
1481 buffer.append(fragment.content().text());
1482 IO.println("event_delta preview: " + buffer);
1483 } else if (event.isAgentMessage()) {
1484 // The buffered event is the record: drop its preview, render its content
1485 var message = event.asAgentMessage();
1486 previews.remove(message.id());
1487 var text = message.content().stream()
1488 .flatMap(block -> block.text().stream())
1489 .map(textBlock -> textBlock.text())
1490 .collect(Collectors.joining());
1491 IO.println("agent.message " + message.id() + " " + text);
1492 } else if (event.isSpanModelRequestEnd()) {
1493 // No more deltas are coming. Close any preview whose buffered event never arrived.
1494 previews.keySet().forEach(eventId ->
1495 IO.println("span.model_request_end closing preview for " + eventId));
1496 previews.clear();
1497 } else if (event.isSessionStatusIdle()) {
1498 break;
1488 switch (event.type().value()) {
1489 case EVENT_START -> {
1490 if (event.asEventStart().event().isAgentMessage()) {
1491 var preview = event.asEventStart().event().asAgentMessage();
1492 IO.println("event_start " + preview.type().asString() + " " + preview.id());
1493 }
1494 }
1495 case EVENT_DELTA -> {
1496 var eventDelta = event.asEventDelta();
1497 var fragment = eventDelta.delta();
1498 var buffer = previews
1499 .computeIfAbsent(eventDelta.eventId(), _ -> new HashMap<>())
1500 .computeIfAbsent(fragment.index().orElse(0L), _ -> new StringBuilder());
1501 buffer.append(fragment.content().text());
1502 IO.println("event_delta preview: " + buffer);
1503 }
1504 case AGENT_MESSAGE -> {
1505 // The buffered event is the record: drop its preview, render its content
1506 var message = event.asAgentMessage();
1507 previews.remove(message.id());
1508 var text = message.content().stream()
1509 .flatMap(block -> block.text().stream())
1510 .map(textBlock -> textBlock.text())
1511 .collect(Collectors.joining());
1512 IO.println("agent.message " + message.id() + " " + text);
1513 }
1514 case SPAN_MODEL_REQUEST_END -> {
1515 // No more deltas are coming. Close any preview whose buffered event never arrived.
1516 previews.keySet().forEach(eventId ->
1517 IO.println("span.model_request_end closing preview for " + eventId));
1518 previews.clear();
1519 }
1520 case SESSION_STATUS_IDLE -> {
1521 break deltas;
1522 }
14991523 }
15001524 }
15011525 }
from line 1552
15281552 end
15291553
15301554 stream.each do |event|
1531 case event.type
1532 in :event_start
1555 case event
1556 when Anthropic::Beta::BetaManagedAgentsStartEvent
15331557 puts "event_start #{event.event.type} #{event.event.id}"
1534 in :event_delta
1558 when Anthropic::Beta::BetaManagedAgentsDeltaEvent
15351559 delta = event.delta
15361560 fragment = delta.content.text
15371561 buffers[event.event_id][delta.index || 0] << fragment
15381562 puts "event_delta preview: #{buffers[event.event_id][delta.index || 0].inspect}"
1539 in :"agent.message"
1563 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
15401564 # Replace: drop the accumulated preview and render the complete event.
15411565 buffers.delete(event.id)
15421566 puts "agent.message #{event.id} #{event.content.map(&:text).join.inspect}"
1543 in :"span.model_request_end"
1567 when Anthropic::Beta::Sessions::BetaManagedAgentsSpanModelRequestEndEvent
15441568 # No more deltas are coming. Close any preview that was never reconciled.
15451569 buffers.each_key { |event_id| puts "span.model_request_end closing preview for #{event_id}" }
15461570 buffers.clear
1547 in :"session.status_idle"
1571 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
15481572 break
15491573 else
15501574 # ignore other event types
from line 1718
16941718 event_deltas: ["agent.message"],
16951719 });
16961720
1697 for await (const event of stream) {
1698 if (event.type === "event_delta") {
1699 process.stdout.write(event.delta.content.text);
1700 } else if (event.type === "agent.message") {
1701 // The buffered event is the authoritative record; render its content.
1702 process.stdout.write("\n");
1703 const text = event.content
1704 .map((block) => (block.type === "text" ? block.text : ""))
1705 .join("");
1706 console.log(text);
1707 } else if (event.type === "session.thread_status_idle") {
1708 break;
1721 threadDeltas: for await (const event of stream) {
1722 switch (event.type) {
1723 case "event_delta":
1724 process.stdout.write(event.delta.content.text);
1725 break;
1726 case "agent.message": {
1727 // The buffered event is the authoritative record; render its content.
1728 process.stdout.write("\n");
1729 const text = event.content
1730 .map((block) => (block.type === "text" ? block.text : ""))
1731 .join("");
1732 console.log(text);
1733 break;
1734 }
1735 case "session.thread_status_idle":
1736 break threadDeltas;
17091737 }
17101738 }
17111739 stream.controller.abort();
from line 1838
18101838 .build()
18111839 )) {
18121840 Iterable<BetaManagedAgentsStreamSessionThreadEvents> events = stream.stream()::iterator;
1841 threadDeltas:
18131842 for (var event : events) {
1814 if (event.isEventDelta()) {
1815 IO.print(event.asEventDelta().delta().content().text());
1816 } else if (event.isAgentMessage()) {
1817 // The buffered event is the authoritative record; render its content.
1818 IO.println();
1819 event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
1820 IO.println();
1821 } else if (event.isSessionThreadStatusIdle()) {
1822 break;
1843 switch (event.type().value()) {
1844 case EVENT_DELTA -> IO.print(event.asEventDelta().delta().content().text());
1845 case AGENT_MESSAGE -> {
1846 // The buffered event is the authoritative record; render its content.
1847 IO.println();
1848 event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
1849 IO.println();
1850 }
1851 case SESSION_THREAD_STATUS_IDLE -> {
1852 break threadDeltas;
1853 }
18231854 }
18241855 }
18251856 }
from line 1874
18431874 )
18441875
18451876 stream.each do |event|
1846 case event.type
1847 in :event_delta
1877 case event
1878 when Anthropic::Beta::BetaManagedAgentsDeltaEvent
18481879 print event.delta.content.text
1849 in :"agent.message"
1880 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
18501881 # The buffered event is the authoritative record; render its content.
18511882 puts
18521883 event.content.each { print it.text }
18531884 puts
1854 in :"session.thread_status_idle"
1885 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionThreadStatusIdleEvent
18551886 break
18561887 else
18571888 # ignore other event types
from line 2137
21062137 $stream = $client->beta->sessions->events->streamStream($session->id);
21072138
21082139 foreach ($stream as $event) {
2109 if ($event->type === 'session.status_idle' && $event->stopReason) {
2110 if ($event->stopReason->type === 'requires_action') {
2111 foreach ($event->stopReason->eventIDs as $eventId) {
2112 // Look up the custom tool use event and execute it
2113 $toolEvent = $eventsById[$eventId];
2114 $result = callTool($toolEvent->name, $toolEvent->input);
2115
2116 // Send the result back
2117 $client->beta->sessions->events->send(
2118 $session->id,
2119 events: [
2120 [
2121 'type' => 'user.custom_tool_result',
2122 'custom_tool_use_id' => $eventId,
2123 'content' => [['type' => 'text', 'text' => $result]],
2140 if ($event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent && $event->stopReason) {
2141 switch (true) {
2142 case $event->stopReason instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionRequiresAction:
2143 foreach ($event->stopReason->eventIDs as $eventId) {
2144 // Look up the custom tool use event and execute it
2145 $toolEvent = $eventsById[$eventId];
2146 $result = callTool($toolEvent->name, $toolEvent->input);
2147
2148 // Send the result back
2149 $client->beta->sessions->events->send(
2150 $session->id,
2151 events: [
2152 [
2153 'type' => 'user.custom_tool_result',
2154 'custom_tool_use_id' => $eventId,
2155 'content' => [['type' => 'text', 'text' => $result]],
2156 ],
21242157 ],
2125 ],
2126 );
2127 }
2128 } elseif ($event->stopReason->type === 'end_turn') {
2129 break;
2158 );
2159 }
2160 break;
2161 case $event->stopReason instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionEndTurn:
2162 break 2;
21302163 }
21312164 }
21322165 }
from line 2168
21352168 ```ruby Ruby
21362169 client.beta.sessions.events.stream_events(session.id).each do |event|
21372170 case event
2138 in {type: :"session.status_idle", stop_reason: {type: :requires_action, event_ids:}}
2139 event_ids.each do |event_id|
2140 # Look up the custom tool use event and execute it
2141 tool_event = events_by_id[event_id]
2142 result = call_tool.call(tool_event.name, tool_event.input)
2143 # Send the result back
2144 client.beta.sessions.events.send_(
2145 session.id,
2146 events: [
2147 {
2148 type: "user.custom_tool_result",
2149 custom_tool_use_id: event_id,
2150 content: [{type: "text", text: result}]
2151 }
2152 ]
2153 )
2171 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
2172 stop_reason = event.stop_reason
2173 case stop_reason
2174 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionRequiresAction
2175 stop_reason.event_ids.each do |event_id|
2176 # Look up the custom tool use event and execute it
2177 tool_event = events_by_id[event_id]
2178 result = call_tool.call(tool_event.name, tool_event.input)
2179 # Send the result back
2180 client.beta.sessions.events.send_(
2181 session.id,
2182 events: [
2183 {
2184 type: "user.custom_tool_result",
2185 custom_tool_use_id: event_id,
2186 content: [{type: "text", text: result}]
2187 }
2188 ]
2189 )
2190 end
2191 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionEndTurn
2192 break
21542193 end
2155 in {type: :"session.status_idle", stop_reason: {type: :end_turn}}
2156 break
2157 else
21582194 end
21592195 end
21602196 ```
from line 2401
23652401 $stream = $client->beta->sessions->events->streamStream($session->id);
23662402
23672403 foreach ($stream as $event) {
2368 if ($event->type === 'session.status_idle' && $event->stopReason) {
2369 if ($event->stopReason->type === 'requires_action') {
2370 foreach ($event->stopReason->eventIDs as $eventId) {
2371 // Approve the pending tool call
2372 $client->beta->sessions->events->send(
2373 $session->id,
2374 events: [
2375 [
2376 'type' => 'user.tool_confirmation',
2377 'tool_use_id' => $eventId,
2378 'result' => 'allow',
2404 if ($event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent && $event->stopReason) {
2405 switch (true) {
2406 case $event->stopReason instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionRequiresAction:
2407 foreach ($event->stopReason->eventIDs as $eventId) {
2408 // Approve the pending tool call
2409 $client->beta->sessions->events->send(
2410 $session->id,
2411 events: [
2412 [
2413 'type' => 'user.tool_confirmation',
2414 'tool_use_id' => $eventId,
2415 'result' => 'allow',
2416 ],
23792417 ],
2380 ],
2381 );
2382 }
2383 } elseif ($event->stopReason->type === 'end_turn') {
2384 break;
2418 );
2419 }
2420 break;
2421 case $event->stopReason instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionEndTurn:
2422 break 2;
23852423 }
23862424 }
23872425 }
from line 2428
23902428 ```ruby Ruby
23912429 client.beta.sessions.events.stream_events(session.id).each do |event|
23922430 case event
2393 in {type: :"session.status_idle", stop_reason: {type: :requires_action, event_ids:}}
2394 event_ids.each do |event_id|
2395 # Approve the pending tool call
2396 client.beta.sessions.events.send_(
2397 session.id,
2398 events: [
2399 {type: "user.tool_confirmation", tool_use_id: event_id, result: "allow"}
2400 ]
2401 )
2431 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
2432 stop_reason = event.stop_reason
2433 case stop_reason
2434 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionRequiresAction
2435 stop_reason.event_ids.each do |event_id|
2436 # Approve the pending tool call
2437 client.beta.sessions.events.send_(
2438 session.id,
2439 events: [
2440 {type: "user.tool_confirmation", tool_use_id: event_id, result: "allow"}
2441 ]
2442 )
2443 end
2444 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionEndTurn
2445 break
24022446 end
2403 in {type: :"session.status_idle", stop_reason: {type: :end_turn}}
2404 break
2405 else
24062447 end
24072448 end
24082449 ```
24092450
managed-agents/files Changed · +9 / -6 lines
from line 532
532532 ```java Java
533533 var listed = client.beta().sessions().resources().list(session.id());
534534 for (var entry : listed.data()) {
535 if (entry.isFile()) {
536 var fileResource = entry.asFile();
537 IO.println(fileResource.id() + " " + fileResource.type());
538 } else if (entry.isGitHubRepository()) {
539 var repoResource = entry.asGitHubRepository();
540 IO.println(repoResource.id() + " " + repoResource.type());
535 switch (entry.type().value()) {
536 case FILE -> {
537 var fileResource = entry.asFile();
538 IO.println(fileResource.id() + " " + fileResource.type());
539 }
540 case GITHUB_REPOSITORY -> {
541 var repoResource = entry.asGitHubRepository();
542 IO.println(repoResource.id() + " " + repoResource.type());
543 }
541544 }
542545 }
543546
managed-agents/migration Changed · +108 / -84 lines
from line 739
739739 ],
740740 )
741741 for event in stream:
742 if event.type == "agent.message":
743 print(
744 "".join(block.text for block in event.content if block.type == "text")
745 )
746 elif event.type == "agent.custom_tool_use":
747 result = get_weather(**event.input)
748 client.beta.sessions.events.send(
749 session.id,
750 events=[
751 {
752 "type": "user.custom_tool_result",
753 "custom_tool_use_id": event.id,
754 "content": [{"type": "text", "text": result}],
755 }
756 ],
757 )
758 elif (
759 event.type == "session.status_idle"
760 and event.stop_reason
761 and event.stop_reason.type == "end_turn"
762 ):
763 break
742 match event.type:
743 case "agent.message":
744 print(
745 "".join(
746 block.text for block in event.content if block.type == "text"
747 )
748 )
749 case "agent.custom_tool_use":
750 result = get_weather(**event.input)
751 client.beta.sessions.events.send(
752 session.id,
753 events=[
754 {
755 "type": "user.custom_tool_result",
756 "custom_tool_use_id": event.id,
757 "content": [{"type": "text", "text": result}],
758 }
759 ],
760 )
761 case "session.status_idle":
762 if event.stop_reason and event.stop_reason.type == "end_turn":
763 break
764764 ```
765765
766766 ```typescript TypeScript
from line 810
810810 ]
811811 });
812812
813 for await (const event of stream) {
814 if (event.type === "agent.message") {
815 for (const block of event.content) {
816 if (block.type === "text") {
817 console.log(block.text);
813 loop: for await (const event of stream) {
814 switch (event.type) {
815 case "agent.message":
816 for (const block of event.content) {
817 if (block.type === "text") {
818 console.log(block.text);
819 }
818820 }
821 break;
822 case "agent.custom_tool_use": {
823 const result = getWeather(event.input);
824 await client.beta.sessions.events.send(session.id, {
825 events: [
826 {
827 type: "user.custom_tool_result",
828 custom_tool_use_id: event.id,
829 content: [{ type: "text", text: result }]
830 }
831 ]
832 });
833 break;
819834 }
820 } else if (event.type === "agent.custom_tool_use") {
821 const result = getWeather(event.input);
822 await client.beta.sessions.events.send(session.id, {
823 events: [
824 {
825 type: "user.custom_tool_result",
826 custom_tool_use_id: event.id,
827 content: [{ type: "text", text: result }]
828 }
829 ]
830 });
831 } else if (event.type === "session.status_idle" && event.stop_reason?.type === "end_turn") {
832 break;
835 case "session.status_idle":
836 if (event.stop_reason?.type === "end_turn") {
837 break loop;
838 }
839 break;
833840 }
834841 }
835842 ```
from line 1133
11261133 .build())
11271134 .build());
11281135
1136 loop:
11291137 for (var event : (Iterable<BetaManagedAgentsStreamSessionEvents>) stream.stream()::iterator) {
1130 if (event.isAgentMessage()) {
1131 for (var block : event.asAgentMessage().content()) {
1132 block.text().ifPresent(textBlock -> IO.println(textBlock.text()));
1138 switch (event.type().value()) {
1139 case AGENT_MESSAGE -> {
1140 for (var block : event.asAgentMessage().content()) {
1141 block.text().ifPresent(textBlock -> IO.println(textBlock.text()));
1142 }
11331143 }
1134 } else if (event.isAgentCustomToolUse()) {
1135 var toolUse = event.asAgentCustomToolUse();
1136 var city = toolUse.input()._additionalProperties().get("city").asStringOrThrow();
1137 var result = getWeather.apply(city);
1138 client.beta().sessions().events().send(
1139 session.id(),
1140 EventSendParams.builder()
1141 .addEvent(BetaManagedAgentsUserCustomToolResultEventParams.builder()
1142 .type(BetaManagedAgentsUserCustomToolResultEventParams.Type.USER_CUSTOM_TOOL_RESULT)
1143 .customToolUseId(toolUse.id())
1144 .addTextContent(result)
1145 .build())
1146 .build());
1147 } else if (event.isSessionStatusIdle()
1148 && event.asSessionStatusIdle().stopReason().isEndTurn()) {
1149 break;
1144 case AGENT_CUSTOM_TOOL_USE -> {
1145 var toolUse = event.asAgentCustomToolUse();
1146 var city = toolUse.input()._additionalProperties().get("city").asStringOrThrow();
1147 var result = getWeather.apply(city);
1148 client.beta().sessions().events().send(
1149 session.id(),
1150 EventSendParams.builder()
1151 .addEvent(BetaManagedAgentsUserCustomToolResultEventParams.builder()
1152 .type(BetaManagedAgentsUserCustomToolResultEventParams.Type.USER_CUSTOM_TOOL_RESULT)
1153 .customToolUseId(toolUse.id())
1154 .addTextContent(result)
1155 .build())
1156 .build());
1157 }
1158 case SESSION_STATUS_IDLE -> {
1159 if (event.asSessionStatusIdle().stopReason().isEndTurn()) {
1160 break loop;
1161 }
1162 }
11501163 }
11511164 }
11521165 }
from line 1170
11571170 use Anthropic\Beta\Agents\BetaManagedAgentsCustomToolInputSchema;
11581171 use Anthropic\Beta\Agents\BetaManagedAgentsCustomToolParams;
11591172 use Anthropic\Beta\Sessions\BetaManagedAgentsAgentParams;
1173 use Anthropic\Beta\Sessions\Events\ManagedAgentsAgentCustomToolUseEvent;
1174 use Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent;
1175 use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionEndTurn;
1176 use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent;
1177 use Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock;
11601178
11611179 $client = new Client();
11621180
from line 1226
12081226 );
12091227
12101228 foreach ($stream as $event) {
1211 if ($event->type === 'agent.message') {
1212 foreach ($event->content as $block) {
1213 if ($block->type === 'text') {
1214 echo $block->text . "\n";
1229 switch (true) {
1230 case $event instanceof ManagedAgentsAgentMessageEvent:
1231 foreach ($event->content as $block) {
1232 if ($block instanceof ManagedAgentsTextBlock) {
1233 echo $block->text . "\n";
1234 }
12151235 }
1216 }
1217 } elseif ($event->type === 'agent.custom_tool_use') {
1218 $result = getWeather($event->input['city']);
1219 $client->beta->sessions->events->send(
1220 $session->id,
1221 events: [
1222 [
1223 'type' => 'user.custom_tool_result',
1224 'custom_tool_use_id' => $event->id,
1225 'content' => [['type' => 'text', 'text' => $result]],
1236 break;
1237 case $event instanceof ManagedAgentsAgentCustomToolUseEvent:
1238 $result = getWeather($event->input['city']);
1239 $client->beta->sessions->events->send(
1240 $session->id,
1241 events: [
1242 [
1243 'type' => 'user.custom_tool_result',
1244 'custom_tool_use_id' => $event->id,
1245 'content' => [['type' => 'text', 'text' => $result]],
1246 ],
12261247 ],
1227 ],
1228 );
1229 } elseif ($event->type === 'session.status_idle' && $event->stopReason?->type === 'end_turn') {
1230 break;
1248 );
1249 break;
1250 case $event instanceof ManagedAgentsSessionStatusIdleEvent:
1251 if ($event->stopReason instanceof ManagedAgentsSessionEndTurn) {
1252 break 2;
1253 }
1254 break;
12311255 }
12321256 }
12331257 $stream->close();
from line 1300
12761300 )
12771301
12781302 stream.each do |event|
1279 case event.type
1280 when :"agent.message"
1303 case event
1304 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
12811305 event.content.each do |block|
1282 puts block.text if block.type == :text
1306 puts block.text if block.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsTextBlock)
12831307 end
1284 when :"agent.custom_tool_use"
1308 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentCustomToolUseEvent
12851309 result = get_weather(event.input[:city])
12861310 client.beta.sessions.events.send_(
12871311 session.id,
from line 1317
12931317 }
12941318 ]
12951319 )
1296 when :"session.status_idle"
1297 break if event.stop_reason&.type == :end_turn
1320 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
1321 break if event.stop_reason.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsSessionEndTurn)
12981322 end
12991323 end
13001324 ```
managed-agents/multiagent-orchestration Changed · +32 / -24 lines
from line 1213
12131213 session_id: session.id,
12141214 });
12151215
1216 for await (const event of stream) {
1217 if (event.type === "agent.message") {
1218 for (const block of event.content) {
1219 if (block.type === "text") {
1220 process.stdout.write(block.text);
1216 loop: for await (const event of stream) {
1217 switch (event.type) {
1218 case "agent.message":
1219 for (const block of event.content) {
1220 if (block.type === "text") {
1221 process.stdout.write(block.text);
1222 }
12211223 }
1222 }
1223 } else if (event.type === "session.thread_status_idle") {
1224 break;
1224 break;
1225 case "session.thread_status_idle":
1226 break loop;
12251227 }
12261228 }
12271229 ```
from line 1278
12761278 thread.id(),
12771279 EventStreamParams.builder().sessionId(session.id()).build()
12781280 )) {
1281 loop:
12791282 for (var event : (Iterable<BetaManagedAgentsStreamSessionThreadEvents>) streamResponse.stream()::iterator) {
1280 if (event.isAgentMessage()) {
1281 for (var block : event.asAgentMessage().content()) {
1282 block.text().ifPresent(textBlock -> IO.print(textBlock.text()));
1283 switch (event.type().value()) {
1284 case AGENT_MESSAGE -> {
1285 for (var block : event.asAgentMessage().content()) {
1286 block.text().ifPresent(textBlock -> IO.print(textBlock.text()));
1287 }
12831288 }
1284 } else if (event.isSessionThreadStatusIdle()) {
1285 break;
1289 case SESSION_THREAD_STATUS_IDLE -> {
1290 break loop;
1291 }
12861292 }
12871293 }
12881294 }
from line 1301
12951301 );
12961302
12971303 foreach ($stream as $event) {
1298 if ($event->type === 'agent.message') {
1299 foreach ($event->content as $block) {
1300 if ($block->type === 'text') {
1301 echo $block->text;
1304 switch (true) {
1305 case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent:
1306 foreach ($event->content as $block) {
1307 if ($block instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock) {
1308 echo $block->text;
1309 }
13021310 }
1303 }
1304 } elseif ($event->type === 'session.thread_status_idle') {
1305 break;
1311 break;
1312 case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionThreadStatusIdleEvent:
1313 break 2;
13061314 }
13071315 }
13081316 ```
from line 1317
13091317
13101318 ```ruby Ruby
13111319 client.beta.sessions.threads.events.stream_events(thread.id, session_id: session.id).each do |event|
1312 case event.type
1313 when :"agent.message"
1320 case event
1321 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
13141322 event.content.each do |block|
1315 print block.text if block.type == :text
1323 print block.text if block.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsTextBlock)
13161324 end
1317 when :"session.thread_status_idle"
1325 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionThreadStatusIdleEvent
13181326 break
13191327 end
13201328 end
managed-agents/quickstart Changed · +33 / -29 lines
from line 92
9292
9393 <Tab title="Java">
9494 ```groovy Gradle
95 implementation("com.anthropic:anthropic-java:2.60.0")
95 implementation("com.anthropic:anthropic-java:2.63.0")
9696 ```
9797 </Tab>
9898
from line 651
651651 });
652652
653653 // Process streaming events
654 for await (const event of stream) {
655 if (event.type === "agent.message") {
656 for (const block of event.content) {
657 if (block.type === "text") {
658 process.stdout.write(block.text);
654 loop: for await (const event of stream) {
655 switch (event.type) {
656 case "agent.message":
657 for (const block of event.content) {
658 if (block.type === "text") {
659 process.stdout.write(block.text);
660 }
659661 }
660 }
661 } else if (event.type === "agent.tool_use") {
662 console.log(`\n[Using tool: ${event.name}]`);
663 } else if (event.type === "session.status_idle") {
664 console.log("\n\nAgent finished.");
665 break;
662 break;
663 case "agent.tool_use":
664 console.log(`\n[Using tool: ${event.name}]`);
665 break;
666 case "session.status_idle":
667 console.log("\n\nAgent finished.");
668 break loop;
666669 }
667670 }
668671 ```
from line 773
770773 .build());
771774
772775 // Process streaming events
776 loop:
773777 for (var event : (Iterable<BetaManagedAgentsStreamSessionEvents>) stream.stream()::iterator) {
774 if (event.isAgentMessage()) {
775 event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
776 } else if (event.isAgentToolUse()) {
777 IO.println("\n[Using tool: " + event.asAgentToolUse().name() + "]");
778 } else if (event.isSessionStatusIdle()) {
779 IO.println("\n\nAgent finished.");
780 break;
778 switch (event.type().value()) {
779 case AGENT_MESSAGE -> event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
780 case AGENT_TOOL_USE -> IO.println("\n[Using tool: " + event.asAgentToolUse().name() + "]");
781 case SESSION_STATUS_IDLE -> {
782 IO.println("\n\nAgent finished.");
783 break loop;
784 }
781785 }
782786 }
783787 }
from line 805
801805
802806 // Process streaming events
803807 foreach ($stream as $event) {
804 match ($event->type) {
805 'agent.message' => array_walk(
808 match (true) {
809 $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent => array_walk(
806810 $event->content,
807 static fn ($block) => $block->type === 'text' ? print($block->text) : null,
811 static fn ($block) => $block instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock ? print($block->text) : null,
808812 ),
809 'agent.tool_use' => print("\n[Using tool: {$event->name}]\n"),
810 'session.status_idle' => print("\n\nAgent finished.\n"),
813 $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentToolUseEvent => print("\n[Using tool: {$event->name}]\n"),
814 $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent => print("\n\nAgent finished.\n"),
811815 default => null,
812816 };
813817 if ($event->type === 'session.status_idle') {
from line 834
830834
831835 # Process streaming events
832836 stream.each do |event|
833 case event.type
834 in :"agent.message"
835 event.content.each { print it.text if it.type == :text }
836 in :"agent.tool_use"
837 case event
838 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
839 event.content.each { print it.text if it.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsTextBlock) }
840 when Anthropic::Beta::Sessions::BetaManagedAgentsAgentToolUseEvent
837841 puts "\n[Using tool: #{event.name}]"
838 in :"session.status_idle"
842 when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
839843 puts "\n\nAgent finished."
840844 break
841845 else
managed-agents/skills Changed · +22 / -3 lines
from line 31
3131 -F "files[]=@example_skill.zip"
3232 ```
3333
34 ```bash CLI
35 ant skills create --file example_skill.zip
36 ```
34 <MultiFileExample language="cli" label="CLI">
35 ```bash CLI
36 ant apply skills/pr-summary
37 ```
3738
39 <File filename="skills/pr-summary/SKILL.md">
40 ```markdown
41 ---
42 name: pr-summary
43 description: Summarize a pull request's changes and risks in the team's review format.
44 ---
45
46 # PR summary
47
48 List what changed, why, and anything a reviewer should look at closely, in three short sections.
49 ```
50 </File>
51 </MultiFileExample>
52
3853 ```python Python
3954 import anthropic
4055 from anthropic.lib import files_from_dir
from line 192
177192 puts "Created skill: #{skill.id}"
178193 puts "Latest version: #{skill.latest_version_id}"
179194 ```
195
196 <ForLanguage tab="CLI">
197 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) uploads the `skills/pr-summary` directory, prints the new skill's ID, and records it in `claude-lock.json`. Commit `claude-lock.json` so the next `ant apply` uploads your edits as a new version instead of creating a second skill.
198 </ForLanguage>
180199</CodeGroup>
181200
182201To list, retrieve, delete, and version custom skills, see [Managing custom skills](https://platform.claude.com/docs/en/build-with-claude/skills-guide#managing-custom-skills). For the full request and response schemas, see the [Create Skill API reference](https://platform.claude.com/docs/en/api/skills/create). Skill bundles upload directly to the Skills API rather than through the [Files API](https://platform.claude.com/docs/en/build-with-claude/files).
models/opus-5/overview Changed · +7 / -6 lines
from line 47
4747| [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock) | `anthropic.claude-opus-5` |
4848| [Google Cloud](https://platform.claude.com/docs/en/build-with-claude/claude-on-vertex-ai) | `claude-opus-5` |
4949| [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) | `claude-opus-5` |
50| [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws) | `claude-opus-5` |
5051
5152### Pricing
5253
from line 77
7677
7778### Availability
7879
79| Feature | Value |
80| :---------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
81| [Status](https://platform.claude.com/docs/en/about-claude/model-deprecations) | Active (latest) |
82| Released | July 24, 2026 |
83| Retirement | Not sooner than July 24, 2027 |
84| Platforms | Claude API, [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Google Cloud](https://platform.claude.com/docs/en/build-with-claude/claude-on-vertex-ai), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) |
80| Feature | Value |
81| :---------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82| [Status](https://platform.claude.com/docs/en/about-claude/model-deprecations) | Active (latest) |
83| Released | July 24, 2026 |
84| Retirement | Not sooner than July 24, 2027 |
85| Platforms | Claude API, [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Google Cloud](https://platform.claude.com/docs/en/build-with-claude/claude-on-vertex-ai), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry), [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws) |
8586
8687## Good to know
8788
models/sonnet-5/migration-guide Changed · +31 / -24 lines
from line 144
144144
145145 // The response contains summarized thinking blocks and text blocks
146146 for (const block of response.content) {
147 if (block.type === "thinking") {
148 console.log(`\nThinking summary: ${block.thinking}`);
149 } else if (block.type === "text") {
150 console.log(`\nResponse: ${block.text}`);
147 switch (block.type) {
148 case "thinking":
149 console.log(`\nThinking summary: ${block.thinking}`);
150 break;
151 case "text":
152 console.log(`\nResponse: ${block.text}`);
153 break;
151154 }
152155 }
153156 ```
from line 258
255258 ```
256259
257260 ```php PHP
261 use Anthropic\Messages\TextBlock;
262 use Anthropic\Messages\ThinkingBlock;
263
258264 $client = new Client();
259265
260266 $response = $client->messages->create(
from line 278
272278
273279 // The response contains summarized thinking blocks and text blocks
274280 foreach ($response->content as $block) {
275 echo match ($block->type) {
276 'thinking' => "\nThinking summary: {$block->thinking}",
277 'text' => "\nResponse: {$block->text}",
281 echo match (true) {
282 $block instanceof ThinkingBlock => "\nThinking summary: {$block->thinking}",
283 $block instanceof TextBlock => "\nResponse: {$block->text}",
278284 default => '',
279285 };
280286 }
from line 305
299305 # The response contains summarized thinking blocks and text blocks
300306 response.content.each do |block|
301307 case block
302 in {type: :thinking, thinking:}
303 puts "\nThinking summary: #{thinking}"
304 in {type: :text, text:}
305 puts "\nResponse: #{text}"
306 else
308 when Anthropic::Models::ThinkingBlock
309 puts "\nThinking summary: #{block.thinking}"
310 when Anthropic::Models::TextBlock
311 puts "\nResponse: #{block.text}"
307312 end
308313 end
309314 ```
from line 396
391396
392397 // The response contains summarized thinking blocks and text blocks
393398 for (const block of response.content) {
394 if (block.type === "thinking") {
395 console.log(`\nThinking summary: ${block.thinking}`);
396 } else if (block.type === "text") {
397 console.log(`\nResponse: ${block.text}`);
399 switch (block.type) {
400 case "thinking":
401 console.log(`\nThinking summary: ${block.thinking}`);
402 break;
403 case "text":
404 console.log(`\nResponse: ${block.text}`);
405 break;
398406 }
399407 }
400408 ```
from line 511
503511
504512 // The response contains summarized thinking blocks and text blocks
505513 foreach ($response->content as $block) {
506 echo match ($block->type) {
507 'thinking' => "\nThinking summary: {$block->thinking}",
508 'text' => "\nResponse: {$block->text}",
514 echo match (true) {
515 $block instanceof \Anthropic\Messages\ThinkingBlock => "\nThinking summary: {$block->thinking}",
516 $block instanceof \Anthropic\Messages\TextBlock => "\nResponse: {$block->text}",
509517 default => '',
510518 };
511519 }
from line 540
532540 # The response contains summarized thinking blocks and text blocks
533541 response.content.each do |block|
534542 case block
535 in {type: :thinking, thinking:}
536 puts "\nThinking summary: #{thinking}"
537 in {type: :text, text:}
538 puts "\nResponse: #{text}"
539 else
543 when Anthropic::Models::ThinkingBlock
544 puts "\nThinking summary: #{block.thinking}"
545 when Anthropic::Models::TextBlock
546 puts "\nResponse: #{block.text}"
540547 end
541548 end
542549 ```
release-notes/overview Changed · +4 / -0 lines
### September 18, 2026
from line 12
1212 For updates to Claude Code, see the [complete CHANGELOG.md](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md) in the `claude-code` repository.
1313</Tip>
1414
15### September 18, 2026
16
17* The [Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api) local session endpoints now also return transcripts of Claude in Chrome sessions (`product_surface` value `claude_in_chrome`), in beta for Claude Enterprise organizations, with your existing Compliance Access Key and the `read:compliance_user_data` scope. See [Sessions on users' machines](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions).
18
1519### September 14, 2026
1620
1721* The Messages API can now [compact a conversation on demand](https://platform.claude.com/docs/en/build-with-claude/compaction#compact-on-demand-with-the-compaction-parameter) on the Claude API, in beta with the `compact-2026-09-04` beta header. Send the top-level `compaction` parameter, and the API returns a signed `compaction` block that summarizes the messages you sent. On later requests, send that block first, in place of those messages. You choose when to compact, the request can run in the background, and you can keep recent turns word for word after the summary. On models with preserved thinking, the thinking in those kept turns can stay valid.
test-and-evaluate/develop-tests Changed · +6 / -6 lines
from line 418
418418 {
419419 $text = '';
420420 foreach ($message->content as $block) {
421 if ($block instanceof TextBlock) {
421 if ($block instanceof \Anthropic\Messages\TextBlock) {
422422 $text .= $block->text;
423423 }
424424 }
from line 1074
10741074 {
10751075 $text = '';
10761076 foreach ($message->content as $block) {
1077 if ($block instanceof TextBlock) {
1077 if ($block instanceof \Anthropic\Messages\TextBlock) {
10781078 $text .= $block->text;
10791079 }
10801080 }
from line 1556
15561556 {
15571557 $text = '';
15581558 foreach ($message->content as $block) {
1559 if ($block instanceof TextBlock) {
1559 if ($block instanceof \Anthropic\Messages\TextBlock) {
15601560 $text .= $block->text;
15611561 }
15621562 }
from line 2093
20932093 {
20942094 $text = '';
20952095 foreach ($message->content as $block) {
2096 if ($block instanceof TextBlock) {
2096 if ($block instanceof \Anthropic\Messages\TextBlock) {
20972097 $text .= $block->text;
20982098 }
20992099 }
from line 2726
27262726 {
27272727 $text = '';
27282728 foreach ($message->content as $block) {
2729 if ($block instanceof TextBlock) {
2729 if ($block instanceof \Anthropic\Messages\TextBlock) {
27302730 $text .= $block->text;
27312731 }
27322732 }
from line 3229
32293229 {
32303230 $text = '';
32313231 foreach ($message->content as $block) {
3232 if ($block instanceof TextBlock) {
3232 if ($block instanceof \Anthropic\Messages\TextBlock) {
32333233 $text .= $block->text;
32343234 }
32353235 }
about-claude/pricing Changed · +1 / -1 lines
from line 186
186186The Batch API allows asynchronous processing of large volumes of requests with a 50% discount on both input and output tokens.
187187
188188| Model | Batch input | Batch output |
189| ------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------- |
189| :------------------------------------------------------------------------------------------------------------------------------------ | :----------- | :------------ |
190190| Claude Fable 5.1 | $5 / MTok | $25 / MTok |
191191| Claude Mythos 5.1 ([limited availability](https://anthropic.com/glasswing)) | $5 / MTok | $25 / MTok |
192192| Claude Fable 5 | $5 / MTok | $25 / MTok |
agents-and-tools/tool-use/browser-use-tool Changed · +2 / -2 lines
from line 978
978978 $failed = false;
979979 foreach ($response->content as $block) {
980980 // This example declares only the browser toolset; route other tools here if you add them.
981 if (!($block instanceof ToolUseBlock) || $block->toolsetName !== 'browser') {
981 if (!($block instanceof \Anthropic\Messages\ToolUseBlock) || $block->toolsetName !== 'browser') {
982982 continue;
983983 }
984984 $result = ['type' => 'tool_result', 'tool_use_id' => $block->id, 'toolset_name' => 'browser'];
from line 1120
11201120 1. Run the browser and your executor in a dedicated container or virtual machine with minimal privileges, a fresh profile that holds no credentials, and no access to sensitive filesystems or internal networks; isolate any tool you run alongside it the same way.
11211121 2. Restrict the hosts the browser can reach to a domain allowlist enforced at the network layer and re-checked in your `navigate` handler after redirects, and block loopback, link-local, and private ranges unless the task needs them.
11221122 3. Treat everything a page supplies as untrusted input, including the tab titles and URLs, and each download's `url`, `path`, and `error`, that you report in a [`browser_state`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#track-tabs-and-page-state) block, and build page reads from what the page renders (the accessibility tree or visible text), not raw DOM source, so hidden text doesn't reach Claude.
1123 4. In your `navigate` handler, accept the history keywords `"back"`, `"forward"`, and `"reload"`, treat a URL without a scheme as `https://`, then parse the URL and refuse any scheme other than `http` or `https` (`javascript:`, `file:`, `data:`, `chrome:`, and so on) with an [error result](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#return-errors-from-your-executor). Check the scheme with a URL parser rather than a string prefix; the API never sees the navigation and can't reject it for you.
1123 4. In your `navigate` handler, accept the history keywords `"back"`, `"forward"`, and `"reload"`, treat a URL without a scheme as `https://`, then parse the URL and refuse any scheme other than `http` or `https` (`javascript:`, `file:`, `data:`, `chrome:`, and so on) with an [error result](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#return-errors-from-your-executor). Check the scheme with a URL parser rather than a string prefix; the API doesn't filter the URLs Claude opens, so it can't reject one for you.
11241124 5. Leave `javascript_exec` and `file_upload` disabled unless you need them, and read [Enable optional members](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#enable-optional-member-tools) before turning either on.
11251125 6. Have a human confirm consequential actions and anything that requires affirmative consent (purchasing, modifying accounts, messaging, and accepting terms), and make that check in your executor before each call, because one turn can carry several.
11261126</Warning>
api/rate-limits Changed · +1 / -1 lines
from line 5
55---
66
77<Note>
8 **[Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws):** The rate limits on this page apply to Claude Platform on AWS, but billing and limit management differ. Billing is through AWS Marketplace (not Anthropic credit purchases). Organizations on Claude Platform on AWS are placed on the Start tier and do not move between usage tiers automatically. To request higher limits, contact your Anthropic account representative or [Anthropic support](https://support.claude.com); the **Request rate limit increase** flow is not available. Per-workspace rate limit configuration and [fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) are not available on Claude Platform on AWS. For details, see [Rate limits and quotas on Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws#rate-limits-and-quotas).
8 **[Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws):** The rate limits on this page apply to Claude Platform on AWS, but billing and limit management differ. Billing is through AWS Marketplace (not Anthropic credit purchases). Organizations on Claude Platform on AWS are placed on the Start tier and can move to a higher tier automatically as they build a history of paid AWS Marketplace invoices. To request higher limits, contact your Anthropic account representative or [Anthropic support](https://support.claude.com); the **Request rate limit increase** flow is not available. Per-workspace rate limit configuration and [fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) are not available on Claude Platform on AWS. For details, see [Rate limits and quotas on Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws#rate-limits-and-quotas).
99</Note>
1010
1111There are two types of limits:
get-started Changed · +2 / -2 lines
from line 436
436436 }
437437
438438 dependencies {
439 implementation("com.anthropic:anthropic-java:2.60.0")
439 implementation("com.anthropic:anthropic-java:2.63.0")
440440 }
441441
442442 application {
from line 462
462462 <dependency>
463463 <groupId>com.anthropic</groupId>
464464 <artifactId>anthropic-java</artifactId>
465 <version>2.60.0</version>
465 <version>2.63.0</version>
466466 </dependency>
467467 </dependencies>
468468 </project>
manage-claude/compliance-api Changed · +2 / -2 lines
from line 4
44description: Programmatic access to your organization's Claude activity, chats, files, projects, sessions in Claude apps, and users for compliance, audit, and governance.
55---
66
7The Compliance API gives Claude Enterprise and Claude Console customers programmatic access to their organization's Activity Feed. For Claude Enterprise organizations, it also covers the directory of users, roles, and groups across every linked organization; the effective settings in force for each organization; the underlying chats, files, and projects in claude.ai organizations; and Cowork, Claude Code, Claude Science, and Claude for Microsoft 365 sessions. Security, legal, and compliance teams use it to audit activity, retrieve or delete content, and feed events into downstream tooling.
7The Compliance API gives Claude Enterprise and Claude Console customers programmatic access to their organization's Activity Feed. For Claude Enterprise organizations, it also covers the directory of users, roles, and groups across every linked organization; the effective settings in force for each organization; the underlying chats, files, and projects in claude.ai organizations; and Cowork, Claude Code, Claude Science, Claude for Microsoft 365, and Claude in Chrome sessions. Security, legal, and compliance teams use it to audit activity, retrieve or delete content, and feed events into downstream tooling.
88
99<Note>
1010 Two key types unlock the Compliance API. A **Compliance Access Key** (created in claude.ai) reaches every endpoint, and an **Admin API key** (created in Claude Console) reaches the Activity Feed only. See [Which key do you need?](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#which-key-do-you-need) for the full key-type comparison.
from line 55
5555
5656The Activity Feed (`GET /v1/compliance/activities`) is available to any key that carries the `read:compliance_activities` scope; see [Query the Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) for filters, pagination, and the full `Activity` object. The remaining endpoints require a Compliance Access Key carrying the relevant scope.
5757
58A Claude Enterprise tenant has one parent organization (the top-level container that centralizes identity) with linked organizations of two kinds: claude.ai organizations, where users chat and store content, and Claude Console organizations, where users manage Claude API workloads. For a key that covers the parent organization, the directory endpoints (organizations, users, roles, and groups) return data from every linked organization of either kind. The content endpoints (chats, files, projects, project attachments, and sessions) serve Claude Enterprise data only. The chat, file, and project endpoints return claude.ai chats, files, and projects. The session endpoints return transcripts of Cowork, Claude Code, Claude Science, and Claude for Microsoft 365 sessions on users' machines (local sessions), captured while users are signed in with their Claude Enterprise account. They also return transcripts of Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments (remote sessions). A standalone Claude Console organization (one with no parent organization) is not part of a Claude Enterprise tenant; it uses Admin API keys and can query the Activity Feed only.
58A Claude Enterprise tenant has one parent organization (the top-level container that centralizes identity) with linked organizations of two kinds: claude.ai organizations, where users chat and store content, and Claude Console organizations, where users manage Claude API workloads. For a key that covers the parent organization, the directory endpoints (organizations, users, roles, and groups) return data from every linked organization of either kind. The content endpoints (chats, files, projects, project attachments, and sessions) serve Claude Enterprise data only. The chat, file, and project endpoints return claude.ai chats, files, and projects. The session endpoints return transcripts of Cowork, Claude Code, Claude Science, Claude for Microsoft 365, and Claude in Chrome sessions on users' machines (local sessions), captured while users are signed in with their Claude Enterprise account. They also return transcripts of Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments (remote sessions). A standalone Claude Console organization (one with no parent organization) is not part of a Claude Enterprise tenant; it uses Admin API keys and can query the Activity Feed only.
5959
6060All `/v1/compliance/*` endpoints share a rate limit of 600 requests per minute per parent organization (for a standalone Claude Console organization, per organization). The local session endpoints count only against that shared limit, and the remote session endpoints carry a second request budget on top. See [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests) for the response headers and retry contract.
6161
manage-claude/compliance-integration-patterns Changed · +1 / -1 lines
from line 147
147147
148148* Prompt text or model responses from Claude Console, or from Claude API workloads authenticated with an API key.
149149* On-device activity in local sessions that is never sent to Anthropic, such as local files that Claude did not read.
150* Claude Code usage authenticated with a Claude Console API key, run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), or run in Claude Code on the web.
150* Claude Code usage authenticated with a Claude Console API key, run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), or run in a [Claude Code cloud session](https://code.claude.com/docs/en/claude-code-on-the-web), which runs on cloud infrastructure instead of the user's machine.
151151* Local sessions from organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled, and local sessions for which [zero data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect.
152152* Thinking blocks, and images or other binary content, inside session transcripts (transcripts carry user prompts, assistant responses, and tool activity only; local session transcripts show a placeholder `text` block where binary content was omitted).
153153* The original file for a chat attachment that claude.ai stored as extracted text, such as some Word, PowerPoint, and PDF uploads (the file content endpoint returns the extracted text; see [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts)).
managed-agents/vaults Changed · +1 / -1 lines
from line 673
673673 injectionLocation: ManagedAgentsInjectionLocationParams::with(header: true),
674674 ),
675675 );
676 if ($envVarCredential->auth instanceof ManagedAgentsEnvironmentVariableAuthResponse) {
676 if ($envVarCredential->auth instanceof \Anthropic\Beta\Vaults\Credentials\ManagedAgentsEnvironmentVariableAuthResponse) {
677677 $injectionLocation = $envVarCredential->auth->injectionLocation;
678678 echo 'header: ' . json_encode($injectionLocation->header) . "\n"; // header: true
679679 echo 'body: ' . json_encode($injectionLocation->body) . "\n"; // body: false
models/opus-5/migration-guide Changed · +1 / -1 lines
from line 223
223223* Audit requests that disable thinking: `thinking: {type: "disabled"}` with effort `xhigh` or `max` returns a 400 error, enforced on each request. Re-enable thinking or lower the effort to `high` or below.
224224* If you removed sampling parameters during the Opus 4.7 migration, no action is needed. If you re-added them with a 400-retry path, remove that retry path.
225225* Re-evaluate your `effort` setting: run a fresh [effort](https://platform.claude.com/docs/en/build-with-claude/effort) sweep on your own evals rather than carrying over a setting tuned for Claude Opus 4.7. Test `low` and `medium` effort as cost and latency controls, and `max` effort where maximum capability matters more than token spend. If you run at `xhigh` or `max` effort, raise `max_tokens` to at least 64k as a starting point.
226* Remove any context-window beta header. The 1M context window is the default on the Claude API, Amazon Bedrock, Google Cloud, and Microsoft Foundry.
226* Remove any context-window beta header. The 1M context window is the default on the Claude API, Amazon Bedrock, Claude Platform on AWS, Google Cloud, and Microsoft Foundry.
227227* If you rebuild conversation history to update instructions, consider switching to a mid-conversation system message to preserve prompt cache hits.
228228* Verify your stop-reason handling reads `stop_details` on refusals (available since Claude Opus 4.7; now publicly documented), and consider `fallbacks: "default"` (beta) to re-run refused requests on a recommended fallback model automatically.
229229* Review prompts near the caching minimum: prompts of 512 tokens or more can now create cache entries.