Search for a command to run...
Compiled from 33 nodes · est. 62 min read
Updated
This is the documentation for the Claude SDK for Python (anthropic-sdk-python, published to PyPI as anthropic) — Anthropic's official Python client for the Claude API and its surrounding platform services. The SDK covers the direct Anthropic API plus first-party cloud backends (AWS Bedrock, Google Vertex AI, Microsoft Azure Foundry, and AnthropicAWS for Claude Platform on AWS) and the Managed Agents (CMA) platform for hosted agent orchestration. The bulk of the surface is generated by Stainless codegen, with substantial hand-written helpers layered on top for streaming, tool-running, credential resolution, and middleware; Python 3.9 or later is required.
Client setup is the entry point: Installation and packaging covers install and extras, Client construction and credentials shows the minimal Anthropic() usage, Credential providers and chain details the full precedence order, and Base client and pagination documents shared client machinery. Messages and streaming groups the core inference surface — Messages API and Beta messages surface describe the resources, while Raw stream primitives, MessageStream helpers, and Streaming event types cover synchronous and asynchronous streaming. HTTP and middleware covers the plumbing: HTTP core and models for BaseModel and response parsing, Exceptions for the error hierarchy, Middleware system for the extension point, and Refusal fallback middleware for the built-in BetaRefusalFallbackMiddleware. Function tools covers agentic helpers — the beta_tool decorators, the Tool runner loop, Agent toolset and skills (bash, read, write, edit, glob, grep), and MCP integration for Model Context Protocol servers. Managed Agents platform documents the CMA surface: the Agents resource and Sessions resource, plus the self-hosted execution helpers Environment worker, Work poller, and Session event accumulation. Cloud and deployment covers Cloud backends (Bedrock and Vertex clients) and Upgrading and version history, and Development and examples covers Development and CI plus runnable Examples.
If you came here to send your first request, read Installation and packaging and then Client construction and credentials — the quickstart shows the canonical client.messages.create(...) call in a few lines. If you came here to build an agent that calls tools in a loop, start with Function tools and then Tool runner, and consult Agent toolset and skills or MCP integration depending on where your tools come from. If you came here to stream responses or handle events incrementally, read MessageStream helpers first and then Streaming event types to understand the ParsedMessageStreamEvent union that iteration yields. If you came here to debug an HTTP failure, customize retries, or plug in auth logic, read Exceptions and Middleware system; for Bedrock or Vertex specifics jump to Cloud backends. If you came here to contribute, read Development and CI for the uv-based toolchain and lint/test setup, and browse Examples for the canonical multi-turn, tool-use, and streaming patterns.
Updated
Updated
The Anthropic Python SDK is installed from PyPI and brings httpx, pydantic, and other core HTTP and type-handling dependencies; optional extras add support for aiohttp transport, Google Cloud and AWS backends, model context protocol tooling, and webhook signing. The public API re-exports all symbols at the top-level anthropic package, including middleware for fallback behavior and decorators for tool definition, with versioning and MIT licensing documented at the official SDK guide.
The SDK is installable from PyPI as anthropic (version 0.121.0) via pip install anthropic.[1][2] Python 3.9 or later is required.[1] The SDK is licensed under the MIT License.[1] Full API documentation is available at platform.claude.com/docs/en/api/sdks/python.[1]
Core runtime dependencies are: httpx>=0.25.0,<1, pydantic>=1.9.0,<3, typing-extensions>=4.14,<5, anyio>=3.5.0,<5, distro>=1.7.0,<2, sniffio>=1,<2, jiter>=0.4.0,<1, and docstring-parser>=0.15,<1.[2]
The anthropic[aiohttp] extra adds aiohttp>=3,<4 and httpx_aiohttp>=0.1.9,<1 to enable the aiohttp transport.[2] The anthropic[vertex] and anthropic[google_cloud] extras both add google-auth[requests]>=2,<3 for Google Vertex AI and Google Cloud backends — see Cloud backends for usage details.[2] The anthropic[bedrock] and anthropic[aws] extras both add boto3>=1.28.57,<2 and botocore>=1.31.57,<2 for AWS Bedrock.[2] The anthropic[mcp] extra requires mcp>=1.0,<3 and is restricted to Python 3.10+ via its environment marker.[2] The anthropic[webhooks] extra adds standardwebhooks>=1.0.1,<2 for webhook signature validation.[2]
The top-level src/anthropic/__init__.py re-exports all public symbols and updates their __module__ attribute to "anthropic" so that error messages point to the top-level package rather than the defining sub-module.[3] BetaRefusalFallbackMiddleware and BetaFallbackState are part of the public API surface, exported from src/anthropic/__init__.py via lib.middleware.[3] The resources attribute is exposed as a runtime-only proxy — not visible to type checkers — via from ._utils._resources_proxy import resources as resources.[3]
Sources
Updated
The Anthropic client reads credentials from a priority chain: explicit constructor args, ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN env vars, ANTHROPIC_PROFILE, workload identity federation, or disk profile — resolving them upfront so subsequent API calls are authenticated. The client accepts optional credentials, HTTP, and header customization via constructor kwargs and environment variables; explicit credential args suppress env var lookups to prevent accidental shadowing.
The canonical minimal usage of the SDK is to create an Anthropic client (reading ANTHROPIC_API_KEY from the environment by default), call client.messages.create() with model, max_tokens, and messages, and read message.content:
import os
from anthropic import Anthropic
client = Anthropic(
api_key=os.environ.get("ANTHROPIC_API_KEY"), # This is the default and can be omitted
)
message = client.messages.create(
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Hello, Claude",
}
],
model="claude-opus-4-6",
)
print(message.content)
The Anthropic client resolves credentials in priority order: (1) explicit constructor arguments (api_key, auth_token, credentials, config, or profile); (2) ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN environment variables; (3) the ANTHROPIC_PROFILE environment variable, which loads a named profile from disk; (4) workload identity federation environment variables (ANTHROPIC_IDENTITY_TOKEN[_FILE], ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID); (5) the active profile on disk. Full details are on Credential providers and chain.[2] When any explicit credential argument is passed to the Anthropic constructor, the ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN environment variables are not consulted.[2] When an explicit api_key= or auth_token= argument shadows an explicit credentials= provider, the client emits a one-shot warning via warn_explicit_static_shadows_credentials.[2] The credential-resolution path (auto-discovery via default_credentials) is invoked only for the base Anthropic / AsyncAnthropic classes; subclasses such as AnthropicAWS and AnthropicFoundry have their own auth paths and do not accept the credentials kwarg.[2] If a credential provider exposes a bind_base_url method, the client calls it with the resolved base_url so token exchange and API calls target the same deployment without requiring duplicate URL configuration; providers without this hook must resolve their own token-exchange base_url.[2] A credential provider is an object that supplies authentication tokens on demand — for example, by fetching short-lived tokens from an identity service — allowing the Anthropic client to refresh credentials automatically without restarting, unlike a static api_key.
The ANTHROPIC_WEBHOOK_SIGNING_KEY environment variable is read as the default value for webhook_key when that constructor argument is not provided.[2] Custom HTTP headers can be injected via the ANTHROPIC_CUSTOM_HEADERS environment variable; each header is a Name: Value line, newline-delimited, and these are merged with any default_headers kwarg — the environment variable takes lower priority than the kwarg.[2]
The Anthropic client exposes instance attributes api_key, auth_token, webhook_key, credentials, _token_cache, and _custom_auth.[2] A custom http_client (an httpx.Client instance) can be passed to the Anthropic constructor; the SDK recommends using DefaultHttpxClient to retain the default limits, timeout, and follow_redirects settings.[2] The Anthropic class provides HUMAN_PROMPT and AI_PROMPT as class-level constants sourced from _constants.[2] _strict_response_validation is an undocumented, experimental constructor parameter that raises APIResponseValidationError when the API returns data not matching the expected schema; it defaults to False and may be removed or changed in the future.[2]
Sources
Updated
Credential providers in src/anthropic/lib/credentials/ resolve authentication through a chain: explicit credentials argument → ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN env vars → named profile (from env or pointer file) → workload identity federation → fallback default profile, with each source returning credentials or None to advance the chain. Providers like CredentialsFile, StaticToken, and EnvToken implement AccessTokenProvider for OAuth and federation flows, while env var synthesis via _fill_missing_from_env() lets explicit API keys and identity tokens override profile settings.
The credential resolution chain in src/anthropic/lib/credentials/_chain.py implements steps 2–5 of the precedence spec; step 1 (the explicit credentials= argument) is handled at the client constructor level, above this function.[1] default_credentials() in _chain.py returns None when no credential source matches, so the client falls back to its normal "no auth configured" error.[1]
Step 2a of default_credentials() returns None when ANTHROPIC_API_KEY is set, leaving the base client to handle the X-Api-Key header path directly — API keys are not Bearer tokens and cannot flow through the credential chain.[1] Step 2b wraps ANTHROPIC_AUTH_TOKEN in a StaticToken provider and returns it as a CredentialResult, taking the Bearer token path.[1] Step 3 triggers when ANTHROPIC_PROFILE, ANTHROPIC_CONFIG_DIR, or an active_config pointer file is present; failures at this step propagate rather than being swallowed, because a user who explicitly names a profile expects a broken config to surface.[1] Step 4 (workload identity federation via env vars) sits between explicit profile selection (step 3) and the fallback on-disk profile (step 5), so a machine with WIF env vars set uses WIF even if a leftover default profile exists on disk.[1] Step 5 (fallback active profile from disk) swallows AnthropicError exceptions and returns None, so a corrupt auto-discovered config file does not break an otherwise-explicit api_key= path.[1]
Workload identity federation via env vars requires the trio ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, and either ANTHROPIC_IDENTITY_TOKEN or ANTHROPIC_IDENTITY_TOKEN_FILE to all be present; missing any of these causes _build_federation_result() to return None.[1] When ANTHROPIC_IDENTITY_TOKEN is used (not a file), _build_federation_result() reads the env var on every call rather than capturing it at construction time, so a rotated value is picked up at the next token exchange.[1] ANTHROPIC_WORKSPACE_ID is coerced from empty-string to None when building a WorkloadIdentityCredentials from env vars, so a defaulted-but-empty CI variable does not put "workspace_id": "" on the wire.[1] Workload identity federation (WIF) is an authentication mechanism that lets a workload (e.g., a CI job or cloud VM) prove its identity using a short-lived token issued by a trusted identity provider, exchanging it for Anthropic credentials without embedding long-lived secrets.
The credential provider module src/anthropic/lib/credentials/_providers.py exports StaticToken, EnvToken, CredentialsFile, InMemoryConfig, and IdentityTokenFile as its public API.[2] StaticToken is an AccessTokenProvider that always returns the same fixed token with no expiry; the force_refresh argument is accepted but ignored because there is no provider-side cache to bypass.[2] EnvToken reads ANTHROPIC_AUTH_TOKEN (or a configured env var) at every call and raises AnthropicError if the variable is unset.[2]
CredentialsFile dispatches on the authentication.type discriminator field: "oidc_federation" triggers OIDC workload identity federation via a WorkloadIdentityCredentials delegate; "user_oauth" handles interactive PKCE login tokens with optional refresh-token grant rotation.[2] For user_oauth profiles without a client_id, CredentialsFile treats the credentials file as externally rotated — it re-reads the file on every invocation and returns whatever access_token is present, with no refresh grant attempted. This is the sidecar/daemon pattern.[2] CredentialsFile resolves its profile name at construction time in this order: explicit profile argument → ANTHROPIC_PROFILE env var → active_config pointer file → "default".[2] Config loading is lazy: CredentialsFile._load_config() populates the config on first call, keeping construction cheap and exception-free so the credential chain can construct the provider optimistically after an existence check.[2] CredentialsFile.extra_headers() returns an anthropic-workspace-id header derived from the config file, but only for non-federation profiles; for oidc_federation profiles the workspace ID is sent in the jwt-bearer exchange body instead, because the minted token is already workspace-scoped.[2] _fill_missing_from_env() in _providers.py fills unset profile config fields from ANTHROPIC_* env vars, treating the profile file as authoritative; empty-string env values are treated as unset.[2] For oidc_federation profiles, _fill_missing_from_env() synthesizes an identity_token object {"source": "file", "path": <value>} from ANTHROPIC_IDENTITY_TOKEN_FILE when the auth block has no identity_token key.[2]
CredentialsFile.resolved_base_url returns None when the profile config has no base_url key, so a profile that omits base_url never overrides an explicit client setting.[2] CredentialsFile.bind_base_url() establishes base_url precedence as: profile config file field → bound value → hard-coded default. The owning client binds exactly once at construction; sharing one instance across clients with different base_url values is unsupported.[2] URL validation in bind_base_url() runs eagerly at bind time against HTTPS rules rather than being deferred to _load_config(), so a misconfigured base_url fails fast rather than at first token exchange.[2]
Both the config file and credentials file are versioned at "1.0" (CONFIG_FILE_VERSION and CREDENTIALS_FILE_VERSION); an absent version field on read is treated as version 1.[2] The credentials file discriminator constant is "oauth_token" (CREDENTIALS_FILE_TYPE), the only type value in v1; future credential shapes (e.g. private key material) are intended to use their own discriminator values.[2] The expires_at field in the credentials file must be an integer Unix timestamp in seconds; the SDK does not parse ISO 8601 strings and raises AnthropicError with the actionable message to use int(datetime.timestamp()) if the value cannot be coerced.[2]
Sources
Updated
The SDK exports eight pagination classes (sync/async pairs for cursor-based, offset-based, token-based, and bidirectional traversal) that wrap API responses and provide methods to fetch the next or previous page of results. Pagination classes inherit from BasePage in _base_client.py, storing the client and request options privately, and delegate page-building logic to a PageInfo object that encodes the URL, params, or JSON needed for the next request.
Eight pagination types are publicly exported from src/anthropic/pagination.py: SyncPage, AsyncPage, SyncTokenPage, AsyncTokenPage, SyncPageCursor, AsyncPageCursor, SyncBidirectionalPageCursor, and AsyncBidirectionalPageCursor.[1] SyncPage and AsyncPage expose data, has_more, first_id, and last_id fields; has_next_page() returns False immediately when has_more is explicitly False, otherwise delegates to the base class.[1] SyncBidirectionalPageCursor and AsyncBidirectionalPageCursor carry both next_page and prev_page token fields to enable forward and backward traversal, but next_page_info() surfaces only the forward next_page token.[1]
SyncPage.next_page_info() uses before_id/first_id for reverse pagination when the before_id param is active, and after_id/last_id for forward pagination.[1] All page classes in src/anthropic/pagination.py return an empty list from _get_page_items() when the data field is falsy, preventing iteration errors on empty responses.[1] BasePage.has_next_page() returns False when the current page yields no items, regardless of what next_page_info() would return.[2] BasePage._info_to_options() calls options._strip_raw_response_header() before building next-page options, ensuring the internal raw-response header is not forwarded to the next request.[2]
BaseSyncPage and BaseAsyncPage in src/anthropic/_base_client.py are pydantic GenericModel subclasses that store their client, model type, and request options as pydantic PrivateAttr fields.[2] The PageInfo class in src/anthropic/_base_client.py stores the information needed to build the next-page request, requiring exactly one of url, params, or json to be set.[2] Retry and timeout constants (DEFAULT_TIMEOUT, MAX_RETRY_DELAY, DEFAULT_MAX_RETRIES, INITIAL_RETRY_DELAY) are imported from ._constants, centralizing those defaults in one place.[2] Middleware types (Middleware, AsyncMiddlewareCallable, validate_sync_middleware, and related symbols) are imported from ._middleware, with request middleware validation handled in that dedicated module — see Middleware system for full details.[2]
BaseSyncPage.get_next_page() raises RuntimeError if called when there is no next page; callers must check .has_next_page() first.[2] BaseSyncPage.__iter__ overrides pydantic's __iter__ (which normally supports dict(model)) to enable for item in page iteration; as a result, dict(page) will not work, but page.dict() still does.[2] BasePage._info_to_options() raises TypeError with the message "Pagination is only supported with mappings" if a json-typed PageInfo is used but either the new or existing json_data is not a mapping.[2]
Sources
Updated
Pages in this section:
Updated
The SDK's BaseModel extends Pydantic with lenient field handling, version-agnostic deserialization, and API-aligned serialization (camelCase keys by default) so callers can work uniformly across Pydantic v1 and v2. BaseAPIResponse wraps HTTP responses with retry counts, elapsed time, and lazy parsed-result caching, while _parse() intelligently deserializes JSON, primitives, and SSE streams—falling back to raw text when strict validation is disabled.
BaseModel in src/anthropic/_models.py extends pydantic.BaseModel and is configured with extra='allow' so that unknown API fields are stored rather than rejected.[1] The public exports from src/anthropic/_models.py are BaseModel and GenericModel, declared via __all__.[1] Pydantic v1 compatibility shims (model_dump, model_dump_json, model_fields_set) are defined on BaseModel so callers can always use the Pydantic v2 API regardless of which Pydantic version is installed.[1]
BaseModel.to_dict() defaults to use_api_names=True, meaning keys match the API response names (e.g. "fooBar") rather than Python property names (e.g. foo_bar), and exclude_unset=True so fields not returned by the API are omitted.[1] BaseModel.to_dict(mode='json') serializes all values to JSON-safe types (e.g. datetime becomes the string "2024-3-22T18:11:19.117000Z"); mode='python' (the default) returns native Python objects.[1] BaseModel.to_json() generates an indented JSON string matching API field names, with indent=2 by default; pass indent=None for compact output.[1]
BaseModel.construct() / model_construct() supports recursive parsing without validation; model_construct is an alias for construct at runtime (type checkers see them as different).[1] The construct() method respects the populate_by_name (Pydantic v2) / allow_population_by_field_name (Pydantic v1) config option when resolving alias vs. field-name lookups.[1] Pydantic model schema build in src/anthropic/_models.py is deferred by default; set the DEFER_PYDANTIC_BUILD environment variable to false to build schemas eagerly (only applies to Pydantic v2).[1]
BaseModel._request_id exposes the request-id response header on the top-level response object only; accessing it on nested objects raises AttributeError.[1] Despite its _ prefix, BaseModel._request_id is a documented public property; all other _-prefixed attributes on SDK models are private.[1]
BaseAPIResponse in src/anthropic/_response.py exposes a retries_taken attribute counting the number of retries made for the request; it is 0 when no retries occurred.[2] BaseAPIResponse.elapsed returns the total datetime.timedelta for the complete request/response cycle.[2] APIResponse.request_id reads the request-id response header and returns it as str | None.[2] BaseAPIResponse.is_closed indicates whether the response body has been fully consumed; callers must either consume the body or call .close() to avoid resource leaks.[2] BaseAPIResponse caches parsed results per type in _parsed_by_type to avoid repeated deserialization of the same response body.[2] BaseAPIResponse.__repr__ renders as <ClassName [STATUS_CODE REASON] type=CAST_TO>.[2]
In src/anthropic/_response.py, _parse() unwraps both TypeAlias and Annotated wrappers before dispatching to the appropriate deserialization path.[2] The Content-Type header is split on ; before checking for json, so application/json; charset=utf-8 is accepted as a JSON response.[2] When parsing a non-JSON Content-Type response into a BaseModel, the SDK attempts to parse the body as JSON anyway; if that succeeds the parsed data is returned, otherwise it falls back to raw text (or raises if strict_response_validation is enabled).[2] _parse() supports primitive cast targets: str returns response.text, bytes returns response.content, int and float parse response.text, and bool compares response.text.lower() to "true".[2] SSE stream responses in src/anthropic/_response.py are dispatched to the configured _stream_cls; if none is set the client's _default_stream_cls is used, raising MissingStreamClassError when both are absent.[2] In src/anthropic/_files.py, when a file is supplied as a two-element tuple (content, mime_type) without a filename, the SDK derives a filename automatically to avoid malformed Content-Disposition headers in the multipart body. To control the filename explicitly in a multipart file upload, callers can pass a three-element tuple (filename, content, mime_type) instead of a two-element tuple, overriding any filename the SDK would derive.
Subclasses of httpx.Response cannot be passed as cast_to; only httpx.Response itself is accepted, raising ValueError otherwise.[2] Passing a Pydantic model that does not subclass the SDK's own BaseModel raises TypeError with the message: "Pydantic models must subclass our base model type, e.g. 'from anthropic import BaseModel'".[2] unwrap() in src/anthropic/resources/beta/webhooks.py requires a headers argument; omitting headers bypasses HMAC signature verification, allowing unverified payloads to be treated as authentic. UnwrapWebhookEvent in src/anthropic/types/beta/unwrap_webhook_event.py reflects the unwrap() contract that mandates headers for HMAC signature verification. In src/anthropic/types/beta/ and its sub-packages, header and path parameters must not carry wire alias annotations; such unused aliases are disallowed on param files (including agents, deployments, files, sessions, and workspaces).
Sources
Updated
The Anthropic SDK's exception hierarchy roots at AnthropicError and splits into two main branches: APIError for API failures (with APIStatusError for HTTP errors and specialized subclasses like RateLimitError), and APIConnectionError for transport failures like timeouts and overloads. RetryableError is a separate class that opts requests into automatic retry logic, allowing middleware to signal transient failures that should be retried up to max_retries before propagating to the caller.
The exception hierarchy in src/anthropic/_exceptions.py is rooted at AnthropicError(Exception), with APIError(AnthropicError) as the base for all API-related errors and APIStatusError(APIError) as the base for HTTP 4xx/5xx status errors.[1] APIError exposes a body property that holds the decoded JSON object if the API returned valid JSON, the raw response if the body is not valid JSON, or None if no response was associated with the error.[1] APIStatusError attempts to extract the error type field from a nested error key in the response body JSON, storing it as self.type (an ErrorType or None).[1]
The publicly exported exception names from src/anthropic/_exceptions.py (via __all__) are BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, and InternalServerError — notably excluding OverloadedError, RequestTooLargeError, ServiceUnavailableError, and DeadlineExceededError.[1] OverloadedError uses the non-standard HTTP status code 529, which is Anthropic's custom code indicating the API is overloaded.[1]
APIConnectionError defaults its message to "Connection error." and always sets body=None.[1] APITimeoutError inherits from APIConnectionError (not directly from APIStatusError) and uses a specific message directing users to Anthropic's long-requests documentation.[1] APIResponseValidationError defaults its message to "Data returned by API invalid for expected schema." when no custom message is provided.[1] APIWebhookValidationError extends APIError and is used for webhook validation failures, carrying no additional behavior beyond the base class.[1]
RetryableError is a special class rooted directly at AnthropicError that opts into the SDK's retry policy: raising it — for example from middleware — causes the current request attempt to be retried, subject to max_retries exhaustion, after which it propagates to the caller as-is.[1] Middleware is custom code inserted into the SDK's request pipeline to inspect or modify requests and responses; in the Anthropic Python SDK context, middleware can raise RetryableError to signal that a request attempt should be retried.
Sources
Updated
src/anthropic/_middleware.py defines the middleware system for the Anthropic SDK, exporting Middleware (base class), CallNext, AsyncCallNext, MiddlewareCallable, AsyncMiddlewareCallable, and MiddlewareInput as its public API surface.[1] MiddlewareInput accepts three forms: a Middleware subclass instance, a sync callable (MiddlewareCallable), or an async callable (AsyncMiddlewareCallable).[1] A middleware is a composable interceptor layer that runs before and after each HTTP attempt, enabling custom logic such as logging, header injection, or retry augmentation within the Anthropic SDK's request pipeline.
The middleware chain runs inside the SDK's retry loop — once per HTTP attempt — so each middleware sees individual attempts, not the full retry sequence.[1] CallNext returns an APIResponse for every HTTP response, including 4xx/5xx; middleware should inspect response.status_code to react to API errors, because the SDK raises its typed errors to the original caller only after the chain completes.[1] Connection failures — where no response object exists — raise exceptions directly from CallNext: either APITimeoutError or APIConnectionError.[1]
validate_sync_middleware raises TypeError if a Middleware subclass has not overridden handle, if handle is defined as an async function, or if a plain callable middleware is async — enforcing that the sync client receives only sync-capable middleware.[1] validate_async_middleware raises TypeError if a Middleware subclass has not overridden handle_async, if handle_async is defined as a sync function, or if a plain callable middleware is not async — enforcing that the async client receives only async-capable middleware.[1]
Sources
Updated
BetaRefusalFallbackMiddleware is a middleware layer for client.beta.messages that automatically retries refusals against a chain of fallback models; it patches the original request params and splices fallback seam blocks into the response, while BetaFallbackState pins subsequent requests to whichever fallback accepted via a context-local token. The middleware injects the fallback-credit beta into requests, strips fallback seam blocks from conversation history to avoid re-processing, and degrades gracefully when all fallbacks exhaust — replaying the original refusal with recommended model metadata and logging the failure.
BetaRefusalFallbackMiddleware, located in src/anthropic/lib/middleware/_fallbacks.py, only processes client.beta.messages requests to /v1/messages; first-party client.messages refusals carry no fallback_credit_token and pass through untouched.[1] The module's __all__ exports exactly two names: BetaFallbackState and BetaRefusalFallbackMiddleware.[1]
BetaRefusalFallbackMiddleware.__init__ accepts a fallbacks iterable (the ordered chain of model patches tried on refusal) and a betas keyword argument; an empty fallbacks iterable disables the middleware entirely.[1] The betas argument defaults to DEFAULT_BETAS — the tuple ("fallback-credit-2026-07-01",) — which is injected into the anthropic-beta header of every /v1/messages request the middleware handles, including the original request, because refusals only carry a fallback_credit_token when the beta is enabled; pass () to suppress it entirely.[1] Log output from BetaRefusalFallbackMiddleware is emitted under the logger name "anthropic.lib.middleware" — the public package path, not the private submodule path.[1]
Each fallbacks entry is a patch against the ORIGINAL request params: a field set to a value overrides it, a field explicitly None unsets it, and an absent field keeps the original value; output_config patches its subfields the same way one level deep. Hops never compound — every hop patches the original params, never the previous hop's patched request.[1] The fallback_credit_token carried on retries is always wrapped as {"token": ..., "mode": "best_effort"} so that token-layer failures degrade gracefully rather than returning an HTTP 400.[1] A refusal before any output has streamed causes BetaRefusalFallbackMiddleware to retry even without a credit token, and the serving hop's message_start opens the wire carrying the primary model's message id.[1] When every remaining fallback entry fails over HTTP, BetaRefusalFallbackMiddleware replays the suppressed refusal to the client with recommended_model stamped from the final failure — the failed model for capacity errors, null otherwise — and reports the event through the anthropic.lib.middleware logger.[1]
In non-streaming mode, BetaRefusalFallbackMiddleware prepends a fallback seam block per model boundary to the serving hop's content when the chain succeeds; the served hop's usage is left verbatim.[1] In streaming mode, fallback events are spliced onto the still-open original stream so the client sees one continuous message: a fallback content block at each model boundary, monotonic block indices, and per-hop usage.iterations on the final message_delta.[1]
BetaFallbackState is the only stickiness mechanism — fallback seam blocks replayed in the request history are stripped from the outgoing request and never read back as a pin.[1] An assistant turn left empty after seam-block stripping is dropped whole from the outgoing request history.[1]
BetaFallbackState is a context manager that pins subsequent requests in the same with block to the fallback model that accepted; it can be shared across sync and async clients and works correctly across threads and tasks via a ContextVar.[1] BetaFallbackState.index holds the index into the fallback chain the requests are pinned to; None (or -1) means the original request params are targeted, and the middleware sets it to the index of the fallback that accepted.[1] Reset tokens for BetaFallbackState context managers are stored in a ContextVar — not on the state instance — so a single state shared across threads and tasks has per-context enter/exit; a Token can only be reset in the context that created it.[1]
Canonical usage of BetaRefusalFallbackMiddleware with a BetaFallbackState pin for conversation stickiness:
client = Anthropic(middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])])
state = BetaFallbackState()
with state:
message = client.beta.messages.create(**params)
Sources
Updated
Pages in this section:
Updated
The Messages API (client.messages) is the primary interface for sending messages to Claude; it accepts a message array with optional system prompt, handles content shorthand and turn merging, and provides streaming and batch sub-resources. The API enforces practical limits (100k messages per request) and offers cache warming, inference geo-targeting, service tier selection, and deprecation warnings for older models.
The Messages resource (src/anthropic/resources/messages/messages.py) exposes a batches sub-resource accessible via client.messages.batches, plus streaming helpers via .with_streaming_response that don't eagerly read the response body.[1]
Messages.create enforces a hard limit of 100,000 messages in a single request.[1] A string value for content in a message is shorthand for an array containing one content block of type "text": {"role": "user", "content": "Hello"} is equivalent to {"role": "user", "content": [{"type": "text", "text": "Hello"}]}.[1] System prompts are passed as a top-level system parameter (a string or array of TextBlockParam); there is no "system" role for input messages in the Messages API.[1] Consecutive user or assistant turns in the messages parameter are automatically combined into a single turn by the model.[1] When the final message uses the assistant role, the response content continues immediately from that message's content, enabling prefilling and partial response constraining.[1] The top-level cache_control parameter automatically applies a cache_control marker to the last cacheable block in the request.[1] The service_tier parameter ("auto" or "standard_only") selects between priority capacity and standard capacity for a request.[1] The inference_geo parameter specifies the geographic region for inference processing; if omitted, the workspace's default_inference_geo is used.[1] In src/anthropic/resources/messages/batches.py, the GA (non-beta) message batch response wrapper classes — both raw and streaming — expose a results property for accessing batch result lines, matching the accessor already present on the beta wrapper.
The deprecated model list is exported from anthropic.resources.messages as DEPRECATED_MODELS; the streaming layer imports it to emit deprecation warnings — see MessageStream helpers for streaming-side behaviour.[2] Models claude-3-sonnet-20240229, claude-2.1, and claude-2.0 are marked deprecated as of July 21st, 2025; claude-3-opus-20240229 is marked deprecated as of January 5th, 2026.[1] claude-opus-4-0, claude-opus-4-20250514, claude-sonnet-4-0, and claude-sonnet-4-20250514 are marked deprecated as of June 15th, 2026.[1] The constant MODELS_TO_WARN_WITH_THINKING_ENABLED flags claude-opus-4-6 and claude-mythos-preview as models that emit a warning when extended thinking is enabled.[1]
Sources
Updated
The beta messages surface (client.beta.messages) extends the standard messages API with experimental capabilities: agentic tool loops, server-side fallback chaining, structured output, context management, MCP integration, and inference tier control. Server-side fallback chaining automatically retries a request with an alternative model from the fallbacks list when the primary model is unavailable or rate-limited, eliminating the need for extra client-side retry logic. The beta messages surface (client.beta) is the programmatic interface for Organization management in the SDK, supporting admin tooling and multi-tenant access control.
src/anthropic/resources/beta/messages/messages.py implements Messages and AsyncMessages, the client.beta.messages surface, with batches available via the batches cached property.[1] The beta messages module imports tool-runner helpers BetaToolRunner, BetaAsyncToolRunner, BetaStreamingToolRunner, and BetaAsyncStreamingToolRunner from lib/tools, exposing agentic tool-loop capabilities on the beta messages surface — see Tool runner for full semantics.[1] Deprecated-model lists DEPRECATED_MODELS and MODELS_TO_WARN_WITH_THINKING_ENABLED are imported from resources.messages.messages so that the beta surface issues the same model warnings as the non-beta surface.[1] tests/api_resources/beta/test_output_format_conversion.py and tests/lib/_parse/test_beta_messages.py cover the output_format= warning-suppression logic for the beta parse and stream surface. src/anthropic/resources/beta/organization/ exposes Organization management endpoints — API keys, external keys, users, invites, workspaces, service accounts, federation rules, and rate limits. Type definitions for Organization management endpoints live in src/anthropic/types/beta/organization/ and src/anthropic/types/beta/; AnthropicBetaParam is extended to cover Organization-related feature flag values. BetaThinkingConfigEnabledParam and BetaThinkingConfigAdaptiveParam are the beta thinking config parameter types, defined in src/anthropic/types/beta/beta_thinking_config_enabled_param.py and src/anthropic/types/beta/beta_thinking_config_adaptive_param.py; AnthropicBetaParam in src/anthropic/types/anthropic_beta_param.py is kept in sync with these definitions. Type definitions in src/anthropic/types/beta/ for files and skills — including BetaFileMetadata, BetaSkill, BetaSkillSource, BetaContainerSkill, BetaSkillVersion, and BetaDeletedSkillVersion — mirror the stable API contract and are the authoritative shapes for those resources.
client.beta.messages.create accepts fallbacks (type BetaFallbacksParam) and fallback_credit_token as optional parameters for server-side fallback chaining.[1] client.beta.messages.create accepts output_config (BetaOutputConfigParam) and output_format (BetaJSONOutputFormatParam) for structured output control.[1] client.beta.messages.create accepts context_management (BetaContextManagementConfigParam) for server-side context management such as compaction.[1] client.beta.messages.create accepts mcp_servers (Iterable[BetaRequestMCPServerURLDefinitionParam]) for MCP connector integration — full MCP semantics are covered on MCP integration.[1] client.beta.messages.create supports service_tier ("auto" or "standard_only") and speed ("standard" or "fast") for inference tier control.[1] Setting max_tokens=0 on client.beta.messages.create pre-warms the prompt cache without generating a response.[1] In src/anthropic/resources/beta/messages/messages.py, the output_format= deprecation warning is suppressed when .parse(), .stream(), or tool-runner helpers manage output_format internally; the warning fires only when a caller explicitly passes output_format= at the top-level API. BetaThinkingConfigEnabledParam and BetaThinkingConfigAdaptiveParam each expose a display field; supported values include an updates mode that streams intermediate reasoning steps to the caller. The client.beta.files and client.beta.skills resource namespaces use GA (generally available) type shapes; the anthropic-beta header requirement has been removed for both namespaces.
Sources
Updated
Stream and AsyncStream are generic iterators over SSE (Server-Sent Event) responses that handle ping/error events, type-field injection, response cleanup, and backward-compatible isinstance checks via metaclasses. Stream.stream() silently skips pings, raises errors with parsed JSON or fallback text, injects missing type fields into events, and always closes the HTTP connection—either at iteration end or via context manager exit. SSE (Server-Sent Event) is a protocol in which a server pushes newline-delimited text events to the client over a single persistent HTTP connection; each event carries an event name, a data payload, and an optional id.
Stream in src/anthropic/_streaming.py provides the core interface to iterate over a synchronous SSE stream response and is generic over the yielded item type _T.[1] AsyncStream in the same file provides the core interface to iterate over an asynchronous SSE stream response and is likewise generic over _T.[1]
Stream.__stream__() silently skips SSE ping events and raises an API status error on error events — attempting to parse the error body as JSON first, falling back to the raw data string or a "Error code: {status_code}" message.[1] When a structured SSE event's JSON payload lacks a "type" key, Stream.__stream__() injects data["type"] = sse.event before forwarding the data to process_data.[1] Stream.__stream__() also yields completion events (the legacy text-completions API event type) alongside current Messages API events.[1]
Stream.__stream__() always closes the HTTP response in a finally block, releasing the connection even if the consumer exits the iterator early.[1] Stream also supports use as a context manager: __enter__ returns self and __exit__ calls self.close() to release the connection.[1]
Stream.raw_events() and AsyncStream.raw_events() are static methods that iterate raw ServerSentEvent objects directly from an httpx.Response, before any JSON parsing or event-name filtering, consuming the response body in the process.[1]
_SyncStreamMeta and _AsyncStreamMeta are metaclasses that preserve backward-compatible isinstance checks after MessageStream and AsyncMessageStream stopped inheriting from Stream and AsyncStream respectively.[1] Using isinstance(obj, Stream) to test whether a MessageStream is a Stream is deprecated and will be removed in the next major version; a DeprecationWarning is issued at check time.[1] Likewise, using isinstance(obj, AsyncStream) to test whether an AsyncMessageStream is an AsyncStream is deprecated and will be removed in the next major version, also raising a DeprecationWarning at check time.[1]
Sources
Updated
MessageStream and AsyncMessageStream are iterable wrappers around raw SSE events that accumulate a final message and expose higher-level events (message_start, content_block_delta, etc.), text filters, and final-message accessors for synchronous and asynchronous streaming responses. The SDK provides paired context managers—MessageStreamManager (sync) and AsyncMessageStreamManager (async)—that defer the API request until entry, then yield a stream object for iterating events or draining text deltas with stream.text_stream. SSE (Server-Sent Events) is a protocol in which a server pushes a stream of newline-delimited text events over a single persistent HTTP connection, enabling real-time data delivery without repeated client polling. The Anthropic Python SDK wraps raw SSE events into higher-level ParsedMessageStreamEvent objects, so callers never need to parse the wire format directly.
client.messages.stream() returns a MessageStreamManager context manager that yields a MessageStream, which is iterable, emits events, and accumulates a final message object.[1] MessageStream (in src/anthropic/lib/streaming/_messages.py) is a synchronous, generic, context-manager-compatible iterator over ParsedMessageStreamEvent objects, wrapping a raw Stream[RawMessageStreamEvent].[2] AsyncMessageStream is the async counterpart to MessageStream, implementing __aiter__, __aenter__, and __aexit__ for use with async for and async with.[2]
MessageStreamManager is a synchronous context manager returned by .stream() that lazily invokes the API request on __enter__ and closes the stream on __exit__, deferring the actual HTTP call until the with block is entered.[2]
MessageStreamManager usage example — synchronous streaming context manager:
with client.messages.stream(...) as stream:
for chunk in stream:
...
AsyncMessageStreamManager is an async context manager wrapper returned by .stream() that does NOT require await-ing the original client call — the await is deferred to __aenter__.[2]
AsyncMessageStreamManager usage example — async streaming context manager:
async with client.messages.stream(...) as stream:
async for chunk in stream:
...
Inside MessageStream.__stream__, every raw SSE event is passed to accumulate_event() to build up __final_message_snapshot, and then build_events() maps the raw event plus snapshot into the higher-level ParsedMessageStreamEvent items that callers iterate over.[2] Iterating over a MessageStream (sync or async) yields ParsedMessageStreamEvent objects whose .type attribute follows the sequence message_start, content_block_start, interleaved content_block_delta/text pairs, content_block_stop, message_delta for a basic text response.[3] For a tool-use streaming response, ParsedMessageStreamEvent objects follow the sequence: message_start, text block events, content_block_stop, then a second block sequence with content_block_start, interleaved content_block_delta/input_json pairs, content_block_stop, message_delta.[3] anthropic.lib.streaming._messages exposes a TRACKS_TOOL_INPUT flag controlling whether tool input is tracked during streaming.[3]
MessageStream.text_stream is a synchronous Iterator[str] that yields only the text delta strings from content_block_delta events with delta.type == "text_delta", filtering out all other event types.[2]
MessageStream.text_stream usage example — iterate text-only deltas from a synchronous stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
AsyncMessageStream.text_stream is an AsyncIterator[str] that yields only text delta strings, mirroring the synchronous MessageStream.text_stream but for async usage.[2]
Canonical async streaming usage with client.messages.stream() and stream.text_stream:
async with client.messages.stream(
max_tokens=1024,
messages=[{"role": "user", "content": "Say hello there!"}],
model="claude-sonnet-5",
) as stream:
async for text in stream.text_stream:
print(text, end="", flush=True)
print()
MessageStream.get_final_message() calls until_done() to drain the stream before returning the accumulated ParsedMessage snapshot; it can also be called outside the context manager as long as the stream was fully consumed inside it.[2][1] MessageStream.get_final_text() blocks until the stream is fully consumed and returns all text-type content blocks concatenated together; the API currently returns only a single content block.[2][1] MessageStream.get_final_text() raises RuntimeError if the API response contains no text content blocks, with an error message listing the actual block types returned.[2] MessageStream.until_done() blocks until the stream has been read to completion without returning a value.[1] MessageStream.current_message_snapshot asserts that __final_message_snapshot is not None, so accessing it before the first SSE event has been processed will raise AssertionError.[2] MessageStream.request_id reads the request-id response header from the underlying httpx.Response, providing easy access to the API's request identifier for debugging.[2] MessageStream.close() delegates to self._raw_stream.close() and is automatically called when the response body is read to completion; the stream is also automatically cancelled when the context manager exits.[2][1]
Using a deprecated model with messages.stream() raises a DeprecationWarning matching "The model '{deprecated_model}' is deprecated"; the warning is triggered when the stream is consumed (e.g. via stream.until_done()).[3] The MessageStream object returned by messages.stream() is an instance of Stream (sync) or AsyncStream (async), but accessing the stream as such emits a DeprecationWarning.[3] When a refusal stop occurs, stream.get_final_message() returns a Message whose .stop_reason is "refusal", .stop_details.type is "refusal", and .stop_details carries category and explanation fields.[3] Tool-use streaming responses include cache_creation_input_tokens, cache_read_input_tokens, service_tier, and server_tool_use fields on message.usage in the final assembled message.[3]
Sources
Updated
Streaming events from the Python SDK are distinguished by type field (text, thinking, citation, etc.) and follow a delta-plus-snapshot pattern: a delta carries the new incremental data while snapshot holds the full accumulated state, allowing callers to consume either progressive or complete values without manual concatenation. The SDK's Raw events mirror the API's native protocol, while synthesized events like TextEvent, ThinkingEvent, and InputJsonEvent add snapshot tracking and convenience methods such as TextEvent.parsed_snapshot() for incremental JSON parsing of structured output.
All streaming event types for MessageStream and AsyncMessageStream are defined in src/anthropic/lib/streaming/_types.py and exported from anthropic.lib.streaming; the top-level union type ParsedMessageStreamEvent is what iteration yields.[1][2] The Raw prefix distinguishes the API's native protocol events (RawMessageStartEvent, RawContentBlockDeltaEvent, etc.) from the higher-level, SDK-synthesized events (TextEvent, ThinkingEvent, and their peers).[1]
TextEvent (type literal "text") carries both text — the incremental delta — and snapshot — the full accumulated text so far — giving callers access to either progressive or complete text without manual concatenation.[1][3] TextEvent.parsed_snapshot() parses snapshot as JSON using jiter.from_json with partial_mode="trailing-strings", enabling incremental JSON parsing of structured output during streaming.[1] CitationEvent (type literal "citation") follows the same delta-plus-snapshot pattern: citation holds the single new Citation, while snapshot holds the full list of all accumulated citations.[1] ThinkingEvent (type literal "thinking") carries both the incremental thinking delta and the full accumulated snapshot, supporting streaming of extended-thinking output.[1] SignatureEvent (type literal "signature") carries only the signature of a thinking block — no delta or snapshot — marking it as a terminal event for a thinking content block's signature.[1] InputJsonEvent (type literal "input_json") carries partial_json — a raw partial JSON string delta (e.g. '"San Francisco,') — and snapshot, the currently accumulated parsed object (e.g. {'location': 'San Francisco, CA'}), enabling callers to observe tool-input JSON as it streams in.[1][3]
At stream end, a message_stop event fires with a fully accumulated Message accessible as event.message.[3] A content_block_stop event fires when a full ContentBlock has been accumulated, accessible as event.content_block.[3] ParsedMessageStopEvent and ParsedContentBlockStopEvent are generic subclasses of those raw stop events that substitute ParsedMessage[ResponseFormatT] and ParsedContentBlock[ResponseFormatT] for the plain Message and ContentBlock, carrying structured-output parse results at stream end.[1]
ParsedMessageStreamEvent is the discriminated union (discriminator field: type) of TextEvent, CitationEvent, ThinkingEvent, SignatureEvent, InputJsonEvent, RawMessageStartEvent, RawMessageDeltaEvent, ParsedMessageStopEvent[ResponseFormatT], RawContentBlockStartEvent, RawContentBlockDeltaEvent, and ParsedContentBlockStopEvent[ResponseFormatT]; event-handler code branches on event.type to narrow to the concrete type — see MessageStream helpers for the handler API.[1]
Sources
Updated
Pages in this section:
Updated
AnthropicBedrock and AnthropicVertex are cloud-specific clients that adapt the SDK to AWS Bedrock and Google Vertex AI respectively, rewriting requests, managing cloud-native auth schemes (SigV4, OAuth), and omitting or unsupporting features unavailable on those platforms. Both clients override request preparation to default the anthropic_version header, translate authentication into request bodies, select base URLs by region, and apply cloud-specific error mappings and wire formats. The AnthropicBetaParam enum in src/anthropic/types/anthropic_beta_param.py defines the set of recognized anthropic-beta header values used across the SDK's beta parameter types. Beta parameter type files beta_cloud_config_params.py, beta_limited_network_params.py, and beta_packages_params.py each declare the corresponding anthropic-beta header values required for cloud execution, sandboxed network access, and package installation respectively.
AnthropicBedrock (in src/anthropic/lib/bedrock/_client.py) exposes messages, completions, and beta as top-level resource attributes, consistent with the main Anthropic client surface.[1] Every POST request body sent by AnthropicBedrock has its anthropic_version field defaulted to "bedrock-2023-05-31" via _prepare_options.[1] _prepare_options rewrites the request URL for /v1/messages and /v1/complete POST calls: streaming requests become /model/{model}/invoke-with-response-stream and non-streaming requests become /model/{model}/invoke, after URL-encoding the model name.[1] The anthropic-beta header value is propagated into the anthropic_beta JSON field as a comma-split list by _prepare_options, so beta feature flags survive the header-to-body translation for Bedrock.[1] _prepare_options raises AnthropicError("The Batch API is not supported in Bedrock yet") for any URL starting with /v1/messages/batches.[1] _prepare_options raises AnthropicError("Token counting is not supported in Bedrock yet") for /v1/messages/count_tokens requests.[1]
AnthropicBedrock supports two mutually exclusive authentication modes: a bearer token via api_key (or the AWS_BEARER_TOKEN_BEDROCK env var) and AWS SigV4 credentials (aws_access_key, aws_secret_key, aws_session_token, aws_profile); specifying both raises ValueError.[1] When api_key is set, _prepare_request authenticates by writing Authorization: Bearer {api_key} and skips AWS SigV4 signing entirely.[1] _infer_region() resolves the AWS region in priority order: the AWS_REGION env var, then the boto3 session region, then falls back to "us-east-1" with a warning.[1] The base URL is taken from the ANTHROPIC_BEDROCK_BASE_URL env var when set; otherwise it defaults to https://bedrock-runtime.{aws_region}.amazonaws.com.[1] Because Bedrock uses the AWS event-stream wire format, AnthropicBedrock overrides the default SSE decoder with AWSEventStreamDecoder.[1] SigV4 (AWS Signature Version 4) is a request-signing protocol that authenticates API calls by cryptographically signing request headers with AWS credentials; AWS Bedrock rejects requests that lack a valid SigV4 signature. The SigV4 signing path in src/anthropic/lib/bedrock/_auth.py, src/anthropic/lib/aws/_auth.py, and src/anthropic/lib/bedrock/_mantle.py operates on raw request body bytes throughout, so binary request bodies such as multipart file uploads authenticate correctly with AWS Bedrock without signature mismatches. In src/anthropic/lib/aws/_client.py, base URL derivation from aws_region is applied correctly when the client is reconfigured via .with_options(aws_region=...) or when skip_auth=True bypasses the SigV4 credential flow.
AnthropicBedrock.copy() creates a new client instance re-using the current client's settings with optional overrides; with_options is an alias for copy intended for fluent inline usage.[1]
AnthropicVertex (in src/anthropic/lib/vertex/_client.py) exposes messages and beta as top-level resource attributes, but does NOT expose completions, unlike AnthropicBedrock.[2] Every request body sent by AnthropicVertex has its anthropic_version defaulted to "vertex-2023-10-16" (the DEFAULT_VERSION constant).[2] A region argument or the CLOUD_ML_REGION environment variable is required; omitting both causes AnthropicVertex.__init__ to raise ValueError.[2] The base URL is taken from ANTHROPIC_VERTEX_BASE_URL when set; otherwise it is selected by region: "global" → https://aiplatform.googleapis.com/v1, "us" → https://aiplatform.us.rep.googleapis.com/v1, "eu" → https://aiplatform.eu.rep.googleapis.com/v1, and any other region → https://{region}-aiplatform.googleapis.com/v1.[2]
AnthropicVertex._ensure_access_token resolves auth in order: an explicit access_token argument → a Google credentials object (loaded via load_auth if not already set) → raises RuntimeError if no token can be resolved.[2] project_id is resolved from the ANTHROPIC_VERTEX_PROJECT_ID environment variable when not passed explicitly.[2] _prepare_request skips auth injection if an Authorization header is already present; otherwise it writes Authorization: Bearer {access_token}, allowing callers to override auth manually.[2] BaseVertexClient maps HTTP 504 to DeadlineExceededError, a Vertex-specific error not present in the Bedrock client's status-error mapping.[2]
AnthropicVertex.with_middleware returns a new client with the given middleware appended after the existing middleware, enabling per-request middleware injection inline — see Middleware system for middleware semantics.[2] AnthropicVertex.with_options is an alias for copy, designed for fluent inline usage such as client.with_options(timeout=10).messages.create(...).[2]
Sources
Updated
The Anthropic Python SDK's version history tracks deprecations and removals of older Claude models, new integrations with AWS Bedrock and Microsoft platforms, and auth/credential handling improvements across releases. Versions also document fixes for streaming, token counting, agent toolsets, and MCP compatibility, alongside new features like Workload Identity Federation and self-hosted sandbox support. v1.1.0 adds Organization API endpoints, an updates thinking display mode, missing beta header values, and fixes for the pause_turn tool runner. v1.3.0 adds beta thinking-config types (BetaThinkingConfigAdaptiveParam, BetaThinkingConfigEnabledParam, BetaThinkingBlockBindingParam, BetaThinkingDroppedInputTransformation, BetaThinkingPrefixMismatchBehavior) and managed-agents model types (BetaManagedAgentsModel and param counterparts) to src/anthropic/types/beta/. v1.3.0 updates BetaUserProfile by adding external_user_onboarded_at and replacing the relationship field with access_type in user_profile_create_params.py and user_profile_update_params.py. v1.3.0 adds organization compliance settings as a compliance_settings sub-resource under beta.organization, exposing BetaComplianceSettings, BetaComplianceSettingsStateEnabled, and BetaComplianceSettingsStateDisabled types in src/anthropic/resources/beta/organization/compliance_settings.py.
Claude Sonnet 4 and Opus 4 were marked as deprecated in v0.95.0.[1] Claude Opus 4.1 was marked as deprecated in v0.106.0.[2] Claude Opus 4.1 models (claude-opus-4-1 and claude-opus-4-1-20250805) reached end-of-life on August 5, 2026 and were removed from the API and SDK in v0.121.0.[3] A new stop reason 'model_context_window_exceeded' was added to the API in v0.119.0.[4]
Support for Workload Identity Federation, interactive OAuth, and auth profiles was added to the client in v0.98.0.[5] In v0.117.0, credential material is kept out of traceback frame locals by wrapping secrets in SecretStr, preventing accidental credential leakage in error tracebacks.[6] In v1.0.0, the SDK's HTTP transport layer was rebuilt on httpx2 (replacing httpx 0.x), touching _base_client.py, _client.py, _streaming.py, _request.py, _response.py, _types.py, and over 130 additional files. The httpx2 upgrade in v1.0.0 introduces breaking changes to the public surface for constructing clients, passing custom transports, and handling responses; code that subclasses or monkey-patches the base client will likely require updates. A vendored httpx_aiohttp transport (src/anthropic/_vendor/httpx_aiohttp/) was added in v1.0.0 to support aiohttp-backed async HTTP usage.
The Microsoft Foundry SDK was added in v0.74.0 (November 2025).[7] A dedicated AWS client for Claude Platform on AWS was added in v0.101.0.[8] Support for self-hosted sandboxes in Claude Managed Agents (CMA) with sandbox helpers was added in v0.103.0.[9]
In v0.120.1, the MCP extra dependency was pinned to <2 due to a compatibility issue; v0.120.2 then added proper support for MCP SDK v2 alongside v1.[10]
Prior to v0.110.0, multiple calls to helper header merges would clobber the x-stainless-helper header instead of appending; the fix ensures existing tags are extended, never replaced.[11] The Bedrock client was not preserving stream event type; this was fixed in v0.110.0.[12] The async count_tokens method was missing the output_format/output_config merge block; this was fixed in v0.113.0.[13] The agent toolset read/edit tools previously raised UnicodeDecodeError on binary files; v0.119.0 fixed this by returning images and PDFs as base64 content blocks and erroring cleanly on other non-UTF-8 files.[14]
Python 3.8 support was dropped from the SDK.[15]
Sources
github.com…nthropic-sdk-python/releases/tag/v0.95.0github.com…pics/anthropic-sdk-python/commit/85068ccgithub.com…pics/anthropic-sdk-python/commit/e271587github.com…thropic-sdk-python/releases/tag/v0.119.0github.com…nthropic-sdk-python/releases/tag/v0.98.0github.com…pics/anthropic-sdk-python/commit/aa93a4dgithub.com…pics/anthropic-sdk-python/commit/4721bd5github.com…thropic-sdk-python/releases/tag/v0.101.0github.com…thropic-sdk-python/releases/tag/v0.103.0github.com…thropic-sdk-python/releases/tag/v0.120.2github.com…pics/anthropic-sdk-python/commit/e8a5c84github.com…pics/anthropic-sdk-python/commit/ed0af5bgithub.com…thropic-sdk-python/releases/tag/v0.113.0github.com…pics/anthropic-sdk-python/commit/d2bad4fgithub.com…pics/anthropic-sdk-python/commit/1283ba7Updated
Pages in this section:
Updated
The SDK uses uv as its package manager with Ruff for linting and mypy/Pyright for type-checking; pydantic-v1 and pydantic-v2 dependency groups are kept separate via conflict enforcement, and the project's own lru_cache replaces functools.lru_cache to preserve type information. The CI pipeline in .github/workflows/ci.yml runs lint, build, and test jobs on each push and pull request, with branch-filtering that skips internal codegen branches, while a separate breaking-change detection job checks compatibility against main.
The project uses uv as its package manager, requiring uv>=0.9 enforced via required-version.[1] The uv configuration pins the index to public PyPI to ensure consistent resolution regardless of a contributor's global uv config.[1] The pydantic-v1 and pydantic-v2 dependency groups conflict with each other, and pydantic-v1 also conflicts with the mcp extra — uv enforces both via its conflicts setting.[1]
Ruff is configured with line length 120, targeting Python 3.8 syntax, and enforces isort, bugbear rules, unused-import removal, missing future annotations, bare excepts, unused arguments, print statements, TYPE_CHECKING misuse, and import rules.[1] functools.lru_cache is banned by ruff because it does not retain type information for wrapped function arguments; the project's own lru_cache from _utils must be used instead.[1] src/anthropic/_files.py is excluded from mypy type-checking because mypy cannot apply correct type narrowing to it; Pyright is relied on instead for that internal module.[1]
Tests are run with pytest using --tb=short -n auto (parallel by default via pytest-xdist), with asyncio_mode = "auto" and all warnings treated as errors.[1]
The CI pipeline in .github/workflows/ci.yml runs three core jobs — lint, build, and test — all on ubuntu-latest with a 10-minute timeout, triggered on pushes to most branches and on pull requests from forks.[2] Pushes to branches named integrated/**, stl-preview-head/**, stl-preview-base/**, generated, and codegen/** (except codegen/stl/**) are skipped by the CI workflow.[2] CI pins uv at version 0.10.2 via astral-sh/setup-uv, installs dependencies with uv sync --all-extras, and invokes ./scripts/lint, ./scripts/bootstrap, ./scripts/test, and uv build for the respective jobs.[2] The build job uploads a build artifact to https://pkg.stainless.com/s using a GitHub OIDC token, but only when running in the anthropics/anthropic-sdk-python-private repository and not on a branch starting with refs/heads/stl/.[2]
The detect_breaking_changes_vs_main job runs on depot-ubuntu-24.04 for the internal stainless-sdks/anthropic-python repository and falls back to ubuntu-latest for all other forks and mirrors.[2] The job uses fetch-depth: 0 and filter: blob:none on checkout so git merge-base HEAD origin/main can resolve the fork point cheaply without downloading all file blobs.[2] Before running detection, the job checks out the breaking-change detection script from the base SHA, ensuring detection still works even when entire detection scripts are removed in the current branch.[2] The detect_breaking_changes_vs_main job is skipped on release-please-- branches to avoid false positives during automated releases.[2]
Sources
Updated
The Examples section demonstrates core SDK patterns: building multi-turn conversations by echoing previous messages, handling tool-use responses with matching content blocks and tool_use_id references, streaming events asynchronously, and enabling extended thinking via the thinking parameter. Managed Agents examples show the canonical workflow of creating an environment and agent, starting a session, sending user events, and streaming session events until idle—see the Sessions and Agents resources for the full API.
In examples/messages.py, a multi-turn conversation is built by passing the previous response's role and content directly back into the next messages list, demonstrating the canonical pattern for multi-turn message exchanges.
response2 = client.messages.create(
max_tokens=1024,
messages=[
{"role": "user", "content": "Hello!"},
{"role": response.role, "content": response.content},
{"role": "user", "content": "How are you?"},
],
model="claude-sonnet-5",
)
In examples/tools.py, after a stop_reason == "tool_use" response, the canonical tool-result reply sends the assistant's content block back verbatim and adds a tool_result user turn with tool_use_id referencing the tool block's id.
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[
user_message,
{"role": message.role, "content": message.content},
{
"role": "user",
"content": [{"type": "tool_result", "tool_use_id": tool.id, "content": [{"type": "text", "text": "The weather is 73f"}]}],
},
],
tools=tools,
)
Streaming events carry a type discriminator field: "text" events expose a .text attribute and "content_block_stop" events expose a .content_block attribute containing the fully accumulated block.[3] After the async with block exits, stream.get_final_message() can still be called to retrieve the fully accumulated message, provided the entire stream was consumed inside the context manager.[3]
examples/thinking.py demonstrates enabling extended thinking by passing thinking={"type": "enabled", "budget_tokens": 1600} to client.messages.create(); budget_tokens must be less than max_tokens (the example uses budget_tokens=1600 with max_tokens=3200).
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=3200,
thinking={"type": "enabled", "budget_tokens": 1600},
messages=[{"role": "user", "content": "Create a haiku about Anthropic."}],
)
for block in response.content:
if block.type == "thinking":
print(f"Thinking: {block.thinking}")
elif block.type == "text":
print(f"Text: {block.text}")
When extended thinking is enabled in examples/thinking.py, the response's content list contains both "thinking" blocks (exposing block.thinking) and "text" blocks (exposing block.text); iterating code must check block.type to distinguish them.
The examples/agents.py script demonstrates the canonical end-to-end Managed Agents workflow: create an environment, create an agent, create a session referencing both, send a user.message event, then stream session events until session.status_idle is received — see Sessions resource and Agents resource for the full API surface.
environment = anthropic.beta.environments.create(name="simple-example-environment")
agent = anthropic.beta.agents.create(name="simple-example-agent", model="claude-sonnet-5")
session = anthropic.beta.sessions.create(
environment_id=environment.id,
agent={"type": "agent", "id": agent.id, "version": agent.version},
)
anthropologic.beta.sessions.events.send(
session.id,
events=[{"type": "user.message", "content": [{"type": "text", "text": "Hello Claude!"}]}],
)
with anthropic.beta.sessions.events.stream(session.id) as stream:
for event in stream:
if event.type == "session.status_idle":
break
Sources
Updated
Function tools in the Anthropic SDK are registered via @beta_tool and @beta_async_tool decorators, which automatically derive the tool schema from Python type annotations and docstrings, apply runtime validation via Pydantic, and support rich error handling through ToolError. Tools decorated with @beta_tool can declare cleanup logic via BaseFunctionTool.close, which is invoked by session-aware runners but not by the Messages API tool runner—stateful tools must use Sessions APIs to avoid resource leaks.
The beta_tool (sync) and beta_async_tool (async) decorators are both exported from the top-level anthropic package and register plain Python functions as tools whose schema is derived from their docstrings and type annotations.[1]
BaseFunctionTool requires Pydantic v2 and raises RuntimeError at instantiation time if Pydantic v1 is detected.[2] At construction, BaseFunctionTool.__init__ wraps the user's function with pydantic.validate_call, so type coercion and required-field checks are applied automatically on every tool call.[2] BaseFunctionTool accepts an input_schema that may be either a raw InputSchema dict or a Pydantic BaseModel subclass; when a BaseModel is provided, model_json_schema() is called automatically.[2] When no explicit description is supplied, BaseFunctionTool derives one from the function's docstring (short and long description via docstring_parser).[2] The JSON input schema is derived from the function's type annotations via pydantic.TypeAdapter, with per-parameter descriptions injected from the docstring's Args section.[2] BaseFunctionTool.to_dict produces a BetaToolParam dict and conditionally includes optional fields — defer_loading, cache_control, allowed_callers, eager_input_streaming, input_examples, and strict — only when they were explicitly set.[2]
BetaFunctionTool.call raises RuntimeError if the wrapped function is a coroutine function, directing callers to use @async_tool instead.[2] BetaAsyncFunctionTool.call raises RuntimeError if the wrapped function is NOT a coroutine function, directing callers to use the synchronous @tool decorator instead.[2] BetaFunctionTool.call raises ValueError (wrapping pydantic.ValidationError) when the tool's input arguments fail validation.[2]
ToolError allows a tool to return structured error content with is_error: True; when the tool runner catches it, the exception's content property is used as the tool result rather than repr(exc).[2] ToolError accepts either a plain string or an iterable of content blocks (BetaContent) as its content argument, supporting rich error payloads including images.[2]
BetaFunctionToolResultType is the return type annotation for @beta_tool-decorated functions and is exported from anthropic.lib.tools.[1] BetaBuiltinFunctionTool.name returns mcp_server_name when that key is present in the tool dict (MCP tools), otherwise falls back to the name key.[2]
BaseFunctionTool.close is an optional cleanup hook for tools that own resources; it is called by SessionToolRunner and EnvironmentWorker at run end, but NOT by the Messages BetaToolRunner / BetaAsyncToolRunner. Stateful tools (e.g. a bash subprocess) handed to the Messages tool runner therefore leak their resource — see Tool runner and Sessions resource for the alternatives.[2]
Sources
Updated
Tool runner is a Python SDK feature invoked via client.beta.messages.tool_runner(...) that executes an agentic loop: it sends a message to the model, parses tool-use blocks, executes the tools, routes results back, and repeats until the model stops requesting tools or hits a termination condition like max_iterations or model refusal. The runner manages message state across iterations (propagating container IDs, tracking token usage against a context_token_threshold, and compacting context when needed), tracks tool availability as the conversation adds or removes tools, and returns a final ParsedBetaMessage with usage metrics including cache and iteration counts.
The tool runner is invoked via client.beta.messages.tool_runner(...) and returns an object with an .until_done() method that executes the agent loop and returns the final ParsedBetaMessage.[1] The final ParsedBetaMessage contains ParsedBetaTextBlock items alongside fields including container, context_management, diagnostics, stop_details, and a BetaUsage object with cache_creation, inference_geo, iterations, server_tool_use, and speed fields.[1] The RequestOptions TypedDict in src/anthropic/lib/tools/_beta_runner.py defines the extra per-call options accepted by the tool runner: extra_headers, extra_query, extra_body, and timeout.[2]
BaseToolRunner supports a max_iterations parameter; once _iteration_count reaches or exceeds max_iterations, _should_stop() returns True and the tool loop terminates.[2] BaseSyncToolRunner.__run__ terminates the tool loop immediately when the model's stop_reason is "refusal", rather than attempting to execute the tool-use blocks, to avoid firing unconfirmed side effects.[2] After each turn, BaseSyncToolRunner.__run__ propagates the container.id from the last assistant message back into params["container"] to support programmatic tool calling with containers.[2] BaseSyncToolRunner.__run__ in src/anthropic/lib/tools/_beta_runner.py treats a pause_turn stop reason as non-terminal and continues iterating, supporting long-running or async tools that temporarily yield control without halting the agent loop.
BaseToolRunner._available_tool_names computes the currently active tool set after applying any mid-conversation tool_removal / tool_addition blocks; tools absent from this set are routed down the unknown-tool path even if the model still emits a tool_use for them.[2] available_tool_names is exported from anthropic.lib.tools._tool_dispatch, indicating the tool-dispatch module maintains a registry of recognized tool names.[1] BaseToolRunner.set_messages_params accepts either a new params dict or a callable that receives the existing params and returns updated params, and invalidates any cached tool call response.[2] BaseToolRunner.append_messages similarly invalidates the cached tool call response, causing tools to be called again on the next loop iteration.[2] BaseToolRunner attaches an x-stainless-helper header to every API call via stainless_helper_header, merged on top of any extra_headers the caller supplies.[2]
BaseSyncToolRunner._check_and_compact computes total token usage as input_tokens + cache_creation_input_tokens + cache_read_input_tokens + output_tokens and triggers compaction only when this sum exceeds context_token_threshold.[2] During client-side compaction, if the last message is from the assistant and contains only tool_use blocks, the entire message is dropped before issuing the compaction request to avoid a 400 error caused by an unpaired tool_use / tool_result.[2] BaseSyncToolRunner.__init__ emits a DeprecationWarning when compaction_control is enabled, directing users to server-side compaction via edits=[{'type': 'compact_20260112'}] in the params passed to tool_runner() instead.[2]
The tool runner is not supported with Pydantic v1; the entire TestSyncRunTools test class is skipped when Pydantic v1 is active.[1] Tool runner snapshot tests are auto-generated from the live API and can be updated by running ANTHROPIC_LIVE=1 ./scripts/test --inline-snapshot=fix -n0.[1]
Sources
Updated
Agent tools in the Python SDK — bash, file operations, and skills — are exposed through beta_agent_toolset_20260401, which returns async-only tools for use with async session runners and requires explicit import to avoid loading heavy stdlib dependencies. File tools confine operations to a workdir; bash runs unrestricted and requires OS-level sandboxing, while skill downloads are managed separately in _skills.py with restrictive permissions.
src/anthropic/lib/tools/agent_toolset.py is not exported from anthropic.lib.tools.__init__ — because importing it pulls in subprocess and other heavy stdlib modules, it must be depended on explicitly: from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401.[1] The public surface of agent_toolset.py (its __all__) exports: AgentToolContext, BashSession, BashResult, resolve_path, beta_agent_toolset_20260401, beta_bash_tool, beta_read_tool, beta_write_tool, beta_edit_tool, beta_glob_tool, and beta_grep_tool.[1] src/anthropic/lib/tools/_skills.py is split out from agent_toolset to keep skill download and archive extraction as a separate concern from the tool implementations themselves.[2] Memory-related types BetaManagedAgentsMemory, BetaManagedAgentsMemoryVersion, and BetaManagedAgentsDeletedMemory (in src/anthropic/types/beta/memory_stores/) document version-retention behaviour when memories are updated or deleted. In src/anthropic/resources/skills/versions.py, the string "latest" is a valid value for skill version references, as documented in the resource's docstrings.
beta_agent_toolset_20260401 returns a list[BetaAsyncFunctionTool] — async function tools only — so it is compatible exclusively with async runners: client.beta.sessions.events.tool_runner(...) (the SessionToolRunner) for a managed-agents session, or the EnvironmentWorker for self-hosted environments. The sync messages.tool_runner(...) accepts BetaRunnableTool, which excludes async function tools, and therefore cannot consume this toolset.[1]
The file tools (read, write, edit, glob, grep) confine all paths to workdir (symlink-aware) and are considered safe without a sandbox; the bash tool is unrestricted regardless of path settings and must be sandboxed at the OS layer.[1] Skill directories created by _skills.py are assigned mode 0o700 (owner-only) rather than inheriting the process umask, because they may contain downloaded third-party content.[2] In src/anthropic/lib/tools/_files.py, the read tool permits a view_range-bounded read to succeed even when the total file size exceeds the size cap; only unbounded reads of oversized files are refused. File tools in src/anthropic/lib/tools/_files.py and the beta built-in memory tool in src/anthropic/lib/tools/_beta_builtin_memory_tool.py read and write files in binary mode (rb/wb) to preserve exact byte sequences and avoid OS line-ending translation (e.g., \r\n → \n on Windows) that would corrupt non-text payloads.
Sources
Updated
MCP integration helpers in anthropic.lib.tools.mcp convert MCP tools, prompts, and resources into Anthropic SDK types for use with the tool runner and Files API, with async_mcp_tool, mcp_message, and mcp_resource_to_file as the entry points. The module supports both MCP SDK v1 and v2 field naming conventions and validates content types, raising UnsupportedMCPValueError for unsupported formats like audio or unsupported image MIME types. MCP (Model Context Protocol) is an open protocol that standardizes communication between AI models and external tools, prompt libraries, and data resources through a client/server interface.
MCP integration helpers live in src/anthropic/lib/tools/mcp.py, part of the optional anthropic[mcp] extra, and require Python 3.10 or higher; if the mcp package is absent the module raises an ImportError with the instruction pip install anthropic[mcp].[1][2] The recommended import is from anthropic.lib.tools.mcp import mcp_tool, async_mcp_tool, mcp_message; the full public API also includes mcp_content, mcp_resource_to_content, mcp_resource_to_file, and UnsupportedMCPValueError.[1]
Internally, mcp.py supports both MCP SDK v1 (camelCase field names: inputSchema, mimeType, isError, structuredContent) and MCP SDK v2 (snake_case: input_schema, mime_type, is_error, structured_content) through the _mcp_field_v1_or_v2 helper.[1]
Canonical usage converts an MCP tool list with async_mcp_tool and passes the results to client.beta.messages.tool_runner — see Tool runner for the runner API:
tools_result = await mcp_client.list_tools()
runner = await client.beta.messages.tool_runner(
model="claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Use the available tools"}],
tools=[async_mcp_tool(t, mcp_client) for t in tools_result.tools],
)
async for message in runner:
print(message)
mcp_content converts a single MCP ContentBlock to an Anthropic beta content block, handling TextContent, ImageContent, and EmbeddedResource; it accepts an optional cache_control: BetaCacheControlEphemeralParam parameter that is forwarded onto the returned block.[1] mcp_content raises UnsupportedMCPValueError for audio, resource_link, and unknown content types, and also raises it when an ImageContent block carries a MIME type outside the supported set of image/jpeg, image/png, image/gif, and image/webp.[1][2] For image or PDF resources, _resource_contents_to_block requires BlobResourceContents and raises UnsupportedMCPValueError if TextResourceContents is found instead, because those MIME types require binary data.[1] Text resources delivered as BlobResourceContents are base64-decoded and then decoded as UTF-8 before being placed into a BetaPlainTextSourceParam.[1]
mcp_message converts an MCP PromptMessage to an Anthropic BetaMessageParam-compatible dict by wrapping the message's single content block (via mcp_content) in a list under the content key, preserving the original role.[1]
MCP prompts can be converted to Anthropic messages using mcp_message:
from anthropic.lib.tools.mcp import mcp_message
prompt = await mcp_client.get_prompt(name="my-prompt")
response = await client.beta.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[mcp_message(m) for m in prompt.messages],
)
mcp_resource_to_content iterates result.contents and returns a content block for the first item with a supported MIME type (text/*, application/pdf, or a supported image type); it raises UnsupportedMCPValueError if the list is empty or no item has a supported MIME type.[1] mcp_resource_to_file converts MCP resource contents to a (filename, content_bytes, mime_type) tuple compatible with the SDK's FileTypes, extracting the filename from the URI path; it always uses the first item in result.contents and raises UnsupportedMCPValueError if that array is empty.[1]
MCP resources can be uploaded to the Files API by passing mcp_resource_to_file(resource) directly to client.beta.files.upload:
from anthropic.lib.tools.mcp import mcp_resource_to_file
resource = await mcp_client.read_resource(uri="file:///path/to/data.json")
uploaded = await client.beta.files.upload(file=mcp_resource_to_file(resource))
All content blocks produced by the MCP helpers are _TaggedDict instances — a dict subclass that carries a _stainless_helper attribute (set via tag_helper) for SDK telemetry; the attribute does not appear in JSON serialization.[1]
Sources
Updated
Pages in this section:
Updated
The Sessions resource exposes managed-agent conversations with three nested sub-resources (events, resources, threads), supporting creation with an agent and environment, real-time event streaming, and tool dispatch via SessionToolRunner. The Anthropic Python SDK's Sessions API is gated by the managed-agents-2026-04-01 beta header and manages spend budgets, metadata, and updatable agent tooling — with SessionToolRunner handling async tool dispatch, permission gates, and idle timeouts on the event stream.
The Sessions resource in src/anthropic/resources/beta/sessions/sessions.py exposes three nested sub-resources — events, resources, and threads — each accessible as a @cached_property attribute on the Sessions class.[1] Every request made via Sessions automatically includes the anthropic-beta: managed-agents-2026-04-01 header; if additional betas are supplied they are prepended to that fixed value before it is set to the constant.[1] List pagination for Sessions uses SyncBidirectionalPageCursor / AsyncBidirectionalPageCursor.[1]
Sessions.create() requires agent and environment_id; all other parameters — budget, initial_events, metadata, resources, title, vault_ids, and betas — are optional and use the omit sentinel to exclude them from the serialized request body.[1] Sessions.create() posts to /v1/sessions?beta=true and returns a BetaManagedAgentsSession object.[1] The initial_events parameter of Sessions.create() accepts up to 50 events of types user.message or user.define_outcome, processed in order when the session is created.[1] The budget parameter of Sessions.create() sets a hard spend ceiling: the session stops issuing new model requests once the tracked list cost reaches max_list_cost.[1] The metadata parameter of Sessions.create() accepts a dict with a maximum of 16 key-value pairs, keys up to 64 characters and values up to 512 characters.[1] Sessions.retrieve() issues a GET to /v1/sessions/{session_id}?beta=true and returns a BetaManagedAgentsSession.[1] Both Sessions.retrieve() and Sessions.update() raise ValueError with a descriptive message if session_id is an empty string.[1] Sessions.update() accepts an agent param of type BetaManagedAgentsSessionAgentUpdateParam; only tools and mcp_servers fields within it are updatable, and the update is a full replacement — to preserve existing entries, GET the session, modify the array, and POST it back.[1] The metadata parameter of Sessions.update() is a patch: setting a key to a string upserts it, setting it to null deletes it, and omitting the field preserves existing metadata.[1] The vault_ids parameter of Sessions.update() is reserved for future use — requests setting this field are currently rejected.[1]
Sessions.with_raw_response returns a SessionsWithRawResponse wrapper that gives access to raw HTTP response objects rather than parsed content.[1] Sessions.with_streaming_response returns a SessionsWithStreamingResponse wrapper that does not eagerly read the response body, suitable for streaming use cases.[1]
SessionToolRunner (in src/anthropic/lib/tools/_beta_session_runner.py) attaches to a Managed Agents session's event stream, dispatches agent.tool_use and agent.custom_tool_use events against a local tool registry, posts results back via user.tool_result / user.custom_tool_result, and yields one DispatchedToolCall per completed call.[2] The tool type accepted by SessionToolRunner is BetaAnyRunnableTool, a union of BetaRunnableTool (sync) and BetaAsyncRunnableTool (async).[2] DispatchedToolCall is a frozen dataclass with an event field (the originating agent.tool_use or agent.custom_tool_use event), a result field (the posted-back result params, or None if nothing was posted), and convenience fields name and tool_use_id.[2]
Confirmation-gated tool calls — those with evaluated_permission of ask, e.g. always_ask tools — are held by SessionToolRunner until a user.tool_confirmation event arrives: executed on allow, never executed on deny.[2] SessionToolRunner stops itself after the session has been idle (with stop_reason end_turn) for max_idle seconds; the default is 60.0 seconds, and max_idle=None disables the timeout.[2] The per-tool-call timeout is TOOL_TIMEOUT = 150.0 seconds — intentionally larger than the bash tool's own 120-second timeout so the inner bash timeout can clean up before the outer one fires.[2] Stream reconnect backoff starts at STREAM_BACKOFF_START = 0.5 seconds and is capped at STREAM_BACKOFF_CAP = 10.0 seconds.[2] Result-posting to the session is retried up to SEND_RETRIES = 3 times.[2] SessionToolRunner does not manage work-item leases (heartbeating / force-stop); wrap it in anthropic.lib.environments.EnvironmentWorker if that behavior is needed — see Environment worker.[2]
The MANAGED_AGENTS_BETA constant ("managed-agents-2026-04-01") is the anthropic-beta header value that gates Sessions access to self-hosted environments; it is also required for work-item stop calls issued by EnvironmentWorker.[2]
Sources
Updated
The Agents resource exposes methods to create, retrieve, and update managed agents through the Beta Managed Agents API; all requests include the anthropic-beta: managed-agents-2026-04-01 header and post to /v1/agents?beta=true. Agent creation requires model and name, with optional parameters controlling tools, MCP servers, coordinator topology via multiagent, and metadata; the mcp_servers array (max 20) and tools array (max 128) must satisfy strict uniqueness and cross-reference constraints. A managed agent is a server-side, reusable configuration pairing a model with its tools and instructions; stored remotely, the same agent definition can be invoked across multiple sessions without re-sending the full configuration.
The Agents resource (in src/anthropic/resources/beta/agents/agents.py) exposes a versions nested sub-resource accessible as a @cached_property.[1] List operations on Agents use SyncPageCursor / AsyncPageCursor for pagination — see Base client and pagination for pagination mechanics.[1]
Agents.create() requires model and name; all other parameters (description, mcp_servers, metadata, multiagent, skills, system, tools, betas) are optional.[1] The model parameter accepts either a model ID string (e.g. claude-opus-4-6) or a model_config object for additional configuration control.[1] Agents.create() posts to /v1/agents?beta=true and returns a BetaManagedAgentsAgent object.[1] The mcp_servers parameter accepts a maximum of 20 entries; names must be unique within the array, and every server must be referenced by an mcp_toolset in tools — unreferenced servers are rejected.[1] The tools array accepts a maximum of 128 tools across all toolsets.[1] The multiagent parameter defines a coordinator topology where the session's primary thread orchestrates work by spawning session threads, each running an agent drawn from the agents roster.[1]
Agents.retrieve() raises ValueError if agent_id is an empty string.[1] An optional version integer query parameter controls which version is fetched; omitting it returns the most recent version, and the value must be at least 1 if specified.[1] Agents.retrieve() issues a GET to /v1/agents/{agent_id}?beta=true, passing version as a query parameter, and returns a BetaManagedAgentsAgent.[1]
In Agents.update(), the description field follows a preserve-or-clear pattern: omit it to preserve the existing value, or send an empty string or null to clear it.[1] The mcp_servers field in update() is a full replacement: omit to preserve, send an empty array or null to clear; the same uniqueness and cross-reference constraints as create() apply, with a maximum of 20 entries.[1] The metadata field in update() is a patch: setting a key to a string upserts it, setting it to null deletes it, and omitting the field preserves existing metadata. The stored bag is limited to 16 keys (up to 64 chars each) with values up to 512 chars.[1]
Sources
Updated
accumulate_managed_agents_event in src/anthropic/lib/sessions/_accumulate.py folds one streaming preview event into a BetaManagedAgentsAgentMessageEvent snapshot, always returning a fresh object — the accumulated argument is never mutated.[1] AccumulatedEvent is a type alias for BetaManagedAgentsAgentMessageEvent — the only event type this accumulator tracks.[1]
On an event_start for an agent.message, accumulate_managed_agents_event returns a new snapshot with empty content and processed_at set to the Unix epoch (1970-01-01T00:00:00Z) as a placeholder; the buffered final event later replaces this with the real server timestamp.[1] When an agent.message (buffered final event) is received, accumulate_managed_agents_event returns a deep copy of that event, replacing whatever the preview had accumulated — the buffered final event is canonical.[1]
An event_delta received before its event_start — i.e., when accumulated is None — causes accumulate_managed_agents_event to raise AnthropicError.[1] An event_delta whose index exceeds the current content length also raises AnthropicError, indicating deltas arrived out of order or were mis-routed.[1] The exhaustiveness guard uses assert_never inside if TYPE_CHECKING blocks, so type checkers receive exhaustive-union validation at lint time with zero runtime overhead.[1] When accumulate_managed_agents_event encounters an unrecognized event type, it silently ignores that event rather than raising an error, leaving the accumulated state unchanged — making the accumulator forward-compatible with new server-side event variants.
Sources
Updated
An EnvironmentWorker claims work items from a self-hosted CMA environment, downloads the agent's skills, runs a session tool runner per claimed item, and keeps its lease alive via parallel heartbeats—terminating only on control-plane stop or unrecoverable failure. The worker is configured via factory method client.beta.environments.work.worker() with credentials (environment_key), an optional tools factory to bind context-aware tools per session, and a working directory for tool path resolution. A CMA (Computer Management Agent) environment is a self-hosted server that queues agent sessions as work items for workers to claim and process. By running agent tools locally and returning results to the CMA environment, an EnvironmentWorker keeps compute off Anthropic's infrastructure.
EnvironmentWorker (in src/anthropic/lib/environments/_worker.py) polls a self-hosted CMA environment for work items and, for each claimed session item, builds a per-session AgentToolContext, downloads the session agent's skills, runs a SessionToolRunner, and heartbeats the work-item lease in parallel — then force-stops the item and loops to the next one.[1] EnvironmentWorker is async-only: run() loops forever and must be cancelled or wrapped in asyncio.wait_for to stop.[1]
The preferred way to build an EnvironmentWorker is via client.beta.environments.work.worker(environment_id=..., environment_key=...), which is equivalent to calling the constructor directly.[1] A single environment_key is the worker's only credential: a Bearer-only scoped sub-client is built once per call (one for polling, one for heartbeat/force-stop; the session tool runner builds its own internally), with the parent client's X-Api-Key cleared on every request.[1]
The tools parameter accepts either a fixed Sequence[BetaAnyRunnableTool] or a factory Callable[[AgentToolContext], Sequence[BetaAnyRunnableTool]] invoked once per claimed session; it defaults to beta_agent_toolset_20260401(env). Use the factory form to bind tools that need the workdir or session ID to the right session.[1] The workdir parameter defaults to os.getcwd() captured at construction time, so a chdir between constructing the worker and serving a session does not change where tools resolve paths.[1]
EnvironmentWorker.handle_item() runs the same per-work-item flow for a single already-claimed item. Called with no arguments, it reads the ANTHROPIC_* environment variables that ant worker poll --on-work sets on the spawned process.[1] The internal _require helper resolves a parameter value by falling back to the named environment variable (e.g. ANTHROPIC_ENVIRONMENT_KEY), raising a descriptive ValueError if neither the argument nor the variable is set.[1]
The heartbeat interval defaults to 30 s (_HEARTBEAT_DEFAULT) and is dynamically adjusted to min(ttl_seconds / 2, 30) once the server reports the real TTL; the assumed TTL before the first response is 90 s (_HEARTBEAT_TTL_DEFAULT).[1] Each heartbeat call is bounded by anyio.fail_after(interval) so a network blackhole cannot leave the loop awaiting while the lease TTL expires; TimeoutError is treated as a transient error alongside the SDK's TRANSIENT_ERRORS.[1] The _heartbeat_loop sets a stop event and returns when the control plane reports state == 'stopping' or 'stopped', the lease is not extended, a permanent (non-transient) heartbeat failure occurs, or transient failures persist longer than the lease TTL without a successful heartbeat — preventing two runners from serving the same work.[1]
agent_toolset (which pulls in host-only modules such as subprocess and tarfile) is imported lazily — never at module level — so EnvironmentWorker can be exposed on the generated work resource without dragging those imports into import anthropic.[1]
Example of running a long-lived EnvironmentWorker daemon and the single-item handle_item variant:
from anthropic import AsyncAnthropic
client = AsyncAnthropic()
# Long-running daemon: poll for work, serve each session, loop.
await client.beta.environments.work.worker(
environment_id=environment_id,
environment_key=environment_key,
workdir="/workspace",
).run()
# Already-claimed item (e.g. inside `ant worker poll --on-work ...`):
await client.beta.environments.work.worker(workdir="/workspace").handle_item()
Canonical EnvironmentWorker usage that adds a custom tool alongside the standard agent toolset:
await client.beta.environments.work.worker(
environment_id=os.environ["ANTHROPIC_ENVIRONMENT_ID"],
environment_key=os.environ["ANTHROPIC_ENVIRONMENT_KEY"],
workdir="/workspace",
tools=lambda env: [*beta_agent_toolset_20260401(env), deploy],
).run()
When invoked from an ant worker poll --on-work script (where credentials are already in the environment), calling handle_item() with no arguments is sufficient:
await client.beta.environments.work.worker(workdir="/workspace", tools=tools).handle_item()
When iterating the poller manually, pass all IDs and the key explicitly to handle_item:
await client.beta.environments.work.worker(workdir="/workspace", tools=tools).handle_item(
work_id=work.id,
environment_id=work.environment_id,
session_id=work.data.id,
environment_key=environment_key,
)
Sources
Updated
A work poller repeatedly calls the API's poll endpoint with a capped block timeout, yields each received BetaSelfHostedWork item after acknowledging it, and manages backoff and error recovery for both poll and ack failures. When auto_stop=True, the poller ensures cleanup via work.stop even on consumer exceptions, and silently tolerates 409 responses (already-stopped work) while logging other errors and continuing the poll loop. In the poller, backpressure refers to slowing the request rate — via jitter sleep on empty polls and capped exponential backoff on errors — to avoid overwhelming the API endpoint.
src/anthropic/lib/environments/_poller.py exports three public symbols: iter_work, aiter_work, and POLL_BLOCK_MS.[1] aiter_work is the async counterpart to iter_work with identical semantics; it uses anyio.sleep instead of time.sleep for async-safe waiting.[1]
POLL_BLOCK_MS is set to 999 ms because the API caps block_ms at 999; client-side jitter is used between empty polls instead of relying on a higher server-side value.[1] On an empty poll, iter_work sleeps for a random jitter between 1 and 3 seconds before re-polling, to avoid a tight busy-loop.[1] The backoff cap for failed polls is 60 seconds (_POLL_BACKOFF_CAP = 60.0).[1]
Each BetaSelfHostedWork item yielded by iter_work / aiter_work has already been ack'd by the poller before it is yielded to the caller.[1] When auto_stop=True, iter_work wraps each yield in a try/finally so work.stop is called even if the consumer's loop body raises an exception; a 409 on stop is silently ignored.[1] The extra_headers parameter is threaded into every poll, ack, and stop call per-request without mutating the bound client; a header given here overrides the bound client's same-named default for that one request only.[1]
If a poll fails with a fatal 4xx error, iter_work / aiter_work re-raises immediately and stops the loop — unlike ack failures, fatal poll errors are not swallowed.[1] If an ack fails with a fatal 4xx error, the poller calls work.stop(force=True) on the item via _force_stop_quietly and then continues polling — it does not raise or stop the loop.[1] _force_stop_quietly calls work.stop(force=True) on an item that cannot be processed; a 409 response is silently ignored (meaning the work already stopped), but any other error is logged at ERROR level and not re-raised, so the poll loop can continue.[1]
Sources