# Anthropic Python SDK v1.0: What Breaks and How to Migrate

> Source: <https://www.digitalapplied.com/blog/anthropic-python-sdk-v1-breaking-change-migration>
> Published: 2026-08-20 00:00:00+00:00

The Anthropic Python SDK v1.0 landed on August 20, 2026, and the [release-notes entry](https://platform.claude.com/docs/en/release-notes/overview) is blunt about what it is: the HTTP layer moves from httpx to httpx2, the package now requires Python 3.10 or later, and a set of long-deprecated surface is removed outright — the legacy Text Completions API, the `temperature`

, `top_p`

and `top_k`

parameters on Messages methods, and the tool runner’s client-side `compaction_control`

.

The easy compression of that list is “Anthropic removed sampling controls.” It did not. The Messages API reference still documents and accepts all three parameters, and the SDK ships a documented workaround. What actually changed is one layer deeper: seven current Claude models reject any non-default sampling value with a 400 regardless of how the request reaches them. The SDK removal lands alongside that model-level rule, and the workaround only buys you anything on older models. That distinction is the whole story, and this guide leads with it.

Below: what shipped and what did not (this is Python only), the sampling split by model, a migration matrix with before-and-after code for every breaking change in the SDK’s own [MIGRATION.md](https://github.com/anthropics/anthropic-sdk-python/blob/main/MIGRATION.md), the one change that can break a running agent loop with nothing raised, the instrumentation that quietly stops seeing your Anthropic calls alongside it, the Bedrock construction that now fails at startup instead, and a real hold-back pin for teams that cannot move today.

- 01This is a Python-only event.anthropic 1.0.0 was uploaded to PyPI on August 20, 2026 and the v1.0.0 GitHub tag was published the same day. The TypeScript SDK’s GitHub Releases show v0.120.0 (Aug 19) as newest with no v1.0.0 tag. The last 0.x Python release, v0.125.0, went out on August 19 and is the hold-back pin.
- 02httpx2 is a maintained, API-compatible fork — not an official successor.Anthropic’s release notes and SDK docs both use fork language. httpx2 is stewarded by Pydantic Services Inc. Build custom http_client, Timeout and transport objects from httpx2, and call httpx2.alias_httpx() at startup if tracing or mocking libraries patch httpx directly.
- 03Sampling parameters left the SDK signatures, not the API.temperature, top_p and top_k are gone from messages.create(), messages.stream() and messages.parse(). The Messages API reference still accepts them, and extra_body is the documented path. But seven current models return a 400 on any non-default value, thinking on or off, so extra_body only helps on older models.
- 04Two changes fail quietly; the Bedrock one fails at startup.Tool-runner compaction moved from a client-side kwarg to a server-side beta (context_management with betas=['compact-2026-01-12'], trigger at 50,000 input tokens or more) — a loop that simply drops the old argument keeps running and raises nothing. The httpx2 move is the other quiet one: tracing and mocking libraries that patch httpx by module name keep patching a module the SDK no longer uses unless you call alias_httpx(). AnthropicBedrock is the loud one — it now raises an error when no AWS region is configured instead of silently using us-east-1, so it announces itself the moment the client is constructed.
- 05The floor is Python 3.10, and the 0.x line is your only 3.9 path.PyPI metadata for anthropic 1.0.0 lists Requires-Python >=3.10 with classifiers for 3.10 through 3.14. If a service is stuck on 3.9, pin anthropic==0.125.0 (or anthropic>=0.125,<1) and schedule the runtime upgrade before the SDK upgrade.

## 01 — What ShippedA 1.0 that is a *deprecation gate*, not a feature drop.

The v1.0.0 tag on [anthropic-sdk-python](https://github.com/anthropics/anthropic-sdk-python/releases) was published on August 20, 2026 at 19:58 UTC, and its Conventional-Commits body is almost comically short: a single BREAKING CHANGES line pointing at the httpx2 upgrade and “some minor breaking changes,” a bug fix that stops the helpers warning about `output_format=`

, and a chore restoring the original streaming-event imports. Everything of substance lives in MIGRATION.md, which the release notes name as the canonical source “for every change with before-and-after snippets.”

Read the timing alongside the last 0.x release and the shape of the event becomes clear. v0.125.0 went out on August 19 at 22:00 UTC — less than a day earlier — carrying managed-agents web-search configuration and self-hosted-sandbox memory-store support, none of it migration-related. v1.0 adds no comparable capability. It is the moment Anthropic chose to cash in a backlog of deprecations at once, which is exactly what a major version is for under the SemVer policy in Anthropic’s own [Python SDK docs](https://platform.claude.com/docs/en/cli-sdks-libraries/sdks/python): the package “generally follows SemVer,” with the caveat that some backward-incompatible type-only or internal changes may ship as minor versions.

Three scope notes matter before you touch anything. First, this is the Python `anthropic`

package only. The TypeScript SDK’s [GitHub Releases](https://github.com/anthropics/anthropic-sdk-typescript/releases) show `v0.120.0`

(August 19) as the newest entry and no `v1.0.0`

tag exists there. Second, it is separate from the Aug-19 wave that moved computer use, browser use, the Files API, Agent Skills and Admin API user management to GA — [our post on that GA wave covers it](/blog/claude-platform-betas-ga-computer-use-files-skills) and nothing in it is restated here. Third, this is not Claude Code, which has its own changelog and version line.

##### Up from 3.9

PyPI metadata for anthropic 1.0.0 lists Requires-Python >=3.10, with classifiers for Python 3.10, 3.11, 3.12, 3.13 and 3.14 — five supported minors. The 0.x line remains the only path for 3.9 services.

##### Last 0.x release

Published August 19 at 22:00 UTC, under 24 hours before v1.0.0. Still installable from PyPI. Pin it if you cannot migrate today, and treat the pin as a dated exception with an owner.

##### Optional extras on 1.0.0

aiohttp, aws, bedrock, google-cloud, mcp, vertex and webhooks. The base package still ships five platform client classes, including the AnthropicBedrock class whose region behaviour changed.

Anthropic’s own install line for the new major is `pip install --upgrade "anthropic>=1,<2"`

. The upper bound is the point: it lets you take future 1.x releases without being carried into a future 2.0 by a loose constraint. The rest of this post assumes you are deciding whether to run that command this week or pin and schedule it.

## 02 — SDK vs APISampling parameters: the *decisive* distinction.

Here is the sentence that is easiest to get wrong. MIGRATION.md removes `temperature`

, `top_p`

and `top_k`

from the typed method signatures of `messages.create()`

, `messages.stream()`

and `messages.parse()`

. The [Messages API reference](https://platform.claude.com/docs/en/api/messages) still lists all three as optional number fields with full descriptions — defaults, ranges, the nucleus-sampling explanation. Nothing on that page says they were removed from the API. The SDK dropped the parameters; the wire protocol did not.

The documented escape hatch is `extra_body`

, and MIGRATION.md gives the before-and-after itself:

```
# Before (0.x): typed keyword argument
message = client.messages.create(
    model=MODEL,
    max_tokens=1024,
    temperature=0.2,
    messages=[{"role": "user", "content": "Summarise this contract."}],
)

# After (1.x): pass it through to the request body
message = client.messages.create(
    model=MODEL,
    max_tokens=1024,
    extra_body={"temperature": 0.2},
    messages=[{"role": "user", "content": "Summarise this contract."}],
)
```

So far, an SDK-only story, and the release notes give it a one-line rationale: v1.0 “removes long-deprecated surface.” What makes it more than a signature change sits in a different document entirely. The [Thinking docs](https://platform.claude.com/docs/en/build-with-claude/thinking)’ “Limits and feature compatibility” section — evergreen reference documentation describing the current model line, not an August 20 announcement — states the model-level rule that makes the workaround moot for most production traffic:

Put the two documents together and the picture is exact. **Seven current models hard-reject any non-default sampling value, through the SDK, through raw HTTP, with thinking on or off.** On those models, `extra_body={"temperature": 0.2}`

produces the same 400 the typed argument would have. There, the SDK removal takes away nothing the API would have honoured — the typed surface and the model behaviour now agree. `extra_body`

exists for the older models where sampling is still honoured, and for default values everywhere. The table below is that rule extracted into something you can scan.

| Model | temperature | top_p | top_k | Non-default value sent |
|---|---|---|---|---|
| Current models · hard 400, thinking on or off | ||||
| Claude Fable 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |
| Claude Mythos 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |
| Claude Mythos Preview | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |
| Claude Opus 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |
| Claude Opus 4.8 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |
| Claude Opus 4.7 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |
| Claude Sonnet 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |
| Older models · restriction applies only while thinking is on | ||||
| Older models, thinking on | Incompatible with thinking | Allowed between 0.95 and 1 | Incompatible with thinking | temperature / top_k rejected; top_p accepted only inside the 0.95–1 band |
| Older models, thinking off | Accepted as documented | Accepted as documented | Accepted as documented | Honoured per the Messages API reference — reach it via `extra_body` in SDK 1.x |

The practical consequence for a migration: grep your codebase for the three parameter names before you upgrade, and sort each hit by the model it targets. Hits against the seven current models were already failing or were sitting at default values — delete them. Hits against older models move to `extra_body`

, with a comment naming the model dependency, because the moment that call is repointed at a current model it becomes a 400 in production. Teams that went through [our Opus 4.6 to 4.7 migration playbook](/blog/claude-opus-4-6-to-4-7-migration-playbook-breaking-changes-2026) will recognise the shape: the model boundary, not the SDK boundary, is where sampling assumptions break.

## 03 — Migration MatrixEvery breaking change, with its *scope* and its fallback.

MIGRATION.md documents each change but never says whether it is confined to the SDK or reflects something at the API or model layer. That column is the synthesis this table adds. “SDK-only” means a raw HTTP caller is unaffected; “SDK + model” means the behaviour you hit is enforced below the SDK; “client to server” means a capability moved rather than disappeared; “SDK client removed” means the typed wrapper is gone and MIGRATION.md does not state what the underlying endpoint does. The last column is the minimum action if you pin to 0.125.0 instead of migrating.

| What broke | Scope | Before (0.x) | After (1.x) | If you pin to 0.125.0 |
|---|---|---|---|---|
| Transport and runtime | ||||
| HTTP layer | SDK-only | import httpx | import httpx2 as httpx or httpx2.alias_httpx() at startup | Nothing now; audit every lib that patches httpx (respx, pytest-httpx, OpenTelemetry, Sentry) before you migrate |
| Python floor | SDK-only | Python >= 3.9 | Python >= 3.10 | Pin is the only 3.9 path; schedule the runtime upgrade first |
| Transport / proxy types | SDK-only | anthropic.Transport anthropic.ProxiesTypes | httpx2.BaseTransport httpx2.Proxy | Find-and-replace when you migrate; no runtime risk before |
| Removed surface | ||||
| Text Completions | SDK client removed | client.completions.create(...) HUMAN_PROMPT / AI_PROMPT | client.messages.create(...) | Highest-pressure item: port to Messages now, migrate SDK after |
| temperature / top_p / top_k | SDK + model | messages.create(..., temperature=0.2) | messages.create(..., extra_body={"temperature": 0.2}) — older models only | Seven current models already 400 on non-default values; delete or default those calls regardless of SDK version |
| output_format schema dict | SDK-only | output_format=SCHEMA_DICT | output_config={"format": SCHEMA_DICT} (helpers take types only for output_format=) | Move dict schemas to output_config ahead of time; types keep working |
| messages.parse(stream=True) | SDK-only (never worked) | messages.parse(..., stream=True) | messages.stream(..., output_format=Type) stream.get_final_message().parsed_output | None — MIGRATION.md says it crashed on 0.x too |
| isinstance(obj, Stream) shim | SDK-only | isinstance(obj, Stream) | from anthropic.lib.streaming import MessageStream isinstance(obj, MessageStream) | Switch the check early; MessageStream is the right type on both lines |
| Raw HTTP body= bytes | SDK-only | client.post(..., body=b"...") | client.post(..., content=b"...") | Rename when you migrate |
| Behaviour changes | ||||
| Tool-runner compaction | Client to server | compaction_control={"enabled": True, "context_token_threshold": 100_000} | betas=["compact-2026-01-12"], context_management={"edits": [...]} trigger >= 50,000 input tokens | Re-test any long agent loop on the server-side path before migrating; this one fails quietly |
| AnthropicBedrock region | SDK-only | AnthropicBedrock() silently used us-east-1 | AnthropicBedrock(aws_region="...") or AWS_REGION / AWS_DEFAULT_REGION / boto3 profile | Set the region explicitly today — it documents the intent and is a no-op on 0.x |
| Bedrock unknown stream events | SDK-only | amazon-bedrock-invocationMetrics yielded | Unknown events skipped, not yielded | If you read invocation metrics off the raw stream, that consumer needs a new source |
| Async raw responses | SDK-only | response.parse() response.text / response.content | await response.parse() response.text() / response.read() | Wrap raw-response access in one helper so the await lands in one place |
| HTTP headers | SDK-only | Case-sensitive names; bytes values tolerated | Case-insensitive names; bytes values raise | Decode header values to str now |
| Renames | ||||
| Type aliases | SDK-only | BetaBase64PDFBlockParam agent_toolset.READ_MAX_BYTES | BetaRequestDocumentBlockParam agent_toolset.DEFAULT_MAX_FILE_BYTES | Rename when you migrate |

Fifteen rows, and only one of them — sampling — is enforced at the model layer. One more, compaction, moved to a server-side beta rather than vanishing. That ratio is the reassuring part of the release. It also tells you where to spend review time: the “Behaviour changes” rows deserve a test each, and so does the HTTP-layer row, because the changes that fail quietly give you nothing to grep for, while the renames and the removed-surface rows announce themselves at import or at the first call. The sections below take them in turn.

## 04 — Transporthttpx to httpx2: a fork with *careful* wording.

MIGRATION.md explains the transport move in one line: the SDK’s HTTP layer moved from httpx, “which is no longer actively maintained,” to httpx2. The [httpx2 project on PyPI](https://pypi.org/project/httpx2/) is stewarded by Pydantic Services Inc., whose [pydantic/httpx2 repository](https://github.com/pydantic/httpx2) hosts the fork, with original-author continuity from Tom Christie, httpx’s creator, and its current release at the time the SDK shipped was 2.12.0 from August 18 — two days earlier. The PyPI description is explicit about the motive: “With HTTPX itself seeing limited activity recently, Pydantic is picking up stewardship under the HTTPX2 name so that users have a reliably maintained path forward — including timely security updates.”

Notice what Anthropic does not say. Neither the release notes nor the SDK docs call httpx2 “the official successor” or claim an endorsement from the httpx maintainers. The release notes say “a maintained, API-compatible fork”; the SDK docs page, in its “Configuring the HTTP client” section, independently says “an API-compatible fork of httpx.” Neither phrase carries an endorsement, and that restraint is the accurate version — it is the one to repeat in your change ticket.

"The SDK sends requests with httpx2, an API-compatible fork of httpx."— Claude Platform docs, Python SDK page, “Configuring the HTTP client”

For most codebases the change is invisible, because the default client is built for you and the `DefaultHttpxClient`

helpers are unchanged. You have work to do in two situations: you construct your own `http_client`

, `Timeout`

or transport objects from httpx, or you run tracing or mocking libraries that patch httpx by module name.

``` python
# Before (0.x): custom client built from httpx
import httpx
from anthropic import Anthropic

client = Anthropic(
    http_client=httpx.Client(proxy="http://proxy.internal:3128"),
    timeout=httpx.Timeout(60.0),
)

# After (1.x), option A: build the same objects from httpx2
import httpx2 as httpx
from anthropic import Anthropic

client = Anthropic(
    http_client=httpx.Client(proxy="http://proxy.internal:3128"),
    timeout=httpx.Timeout(60.0),
)

# After (1.x), option B: make plain `import httpx` resolve to httpx2.
# Call this once at process startup, before any library imports httpx.
import httpx2

httpx2.alias_httpx()
```

Option B is the one that matters for observability and test suites. MIGRATION.md names the category — libraries that patch httpx directly — and the usual suspects are `respx`

, `pytest-httpx`

, OpenTelemetry’s `HTTPXClientInstrumentor`

and Sentry’s httpx integration. Without the alias, those tools keep instrumenting a module the SDK no longer uses, and the failure mode is silent: tests pass against a mock that never fires, traces stop showing Anthropic spans, and nobody gets an exception. Put `httpx2.alias_httpx()`

in the same bootstrap that configures tracing, and add one test that asserts an Anthropic call appears in your span exporter.

`aiohttp`

as an opt-in alternative via `DefaultAioHttpClient`

for higher async concurrency, and that path did not change in v1.0. If you already run on aiohttp, the httpx2 move touches you only where you import httpx types directly — *check your type hints and test fixtures, not your request path*.

## 05 — Removed SurfaceText Completions and the *3.10* floor.

The loudest removal is the legacy Text Completions client. `client.completions.create()`

— the SDK’s wrapper for the `/v1/complete`

endpoint — is gone, and so are the `anthropic.HUMAN_PROMPT`

and `anthropic.AI_PROMPT`

constants that built its prompt strings. Any module that still imports them fails at import time on 1.x, which at least makes this the easiest break to find. The fix is the port to Messages that has been the documented path for a long time.

``` python
# Before (0.x): legacy Text Completions
from anthropic import AI_PROMPT, HUMAN_PROMPT, Anthropic

client = Anthropic()
completion = client.completions.create(
    model=MODEL,
    max_tokens_to_sample=300,
    prompt=f"{HUMAN_PROMPT} Summarise this contract.{AI_PROMPT}",
)
text = completion.completion

# After (1.x): Messages
from anthropic import Anthropic

client = Anthropic()
message = client.messages.create(
    model=MODEL,
    max_tokens=300,
    messages=[{"role": "user", "content": "Summarise this contract."}],
)
text = message.content[0].text
```

The Python floor is the quieter removal, and the one with the longest lead time. MIGRATION.md states it plainly — “The minimum supported Python version has increased from 3.9 to 3.10” — and [PyPI’s metadata for anthropic 1.0.0](https://pypi.org/project/anthropic/1.0.0/) confirms it independently with `Requires-Python: >=3.10`

and classifiers for 3.10 through 3.14 only. A pip resolver on a 3.9 interpreter will simply refuse to select 1.0.0, which is polite, but it also means a service that pins `anthropic`

loosely on 3.9 will stay on 0.x forever without telling anyone. Add an explicit upper bound so the intention is visible in the lockfile.

##### Upgrade now

For services already on Python 3.10+, on Messages, with no custom httpx objects and no client-side compaction. Run the test suite, check tracing spans, ship.

##### Pin, then schedule

For services on Python 3.9, still calling completions.create(), or depending on client-side compaction_control. The pin is the last 0.x release and stays installable; give it an owner and a date.

##### Automated edit pass

MIGRATION.md notes that Claude Code users can run this command for automated edits. Treat the output as a first draft — it is a helper for the SDK migration, not part of the SDK, and the review burden stays with you.

## 06 — Tool RunnerCompaction moved *server-side*; it did not disappear.

This is the change most likely to break a running agent loop without raising anything. On 0.x, the tool runner accepted a client-side `compaction_control`

argument that compacted context locally once a token threshold was crossed. On 1.x that argument is removed, and the replacement is the server-side `context_management`

feature behind the `compact-2026-01-12`

beta. Same job, different layer, and one new constraint: MIGRATION.md notes the trigger threshold must be at least 50,000 tokens.

```
# Before (0.x): client-side compaction
runner = client.beta.messages.tool_runner(
    model=MODEL,
    max_tokens=4096,
    tools=TOOLS,
    messages=history,
    compaction_control={"enabled": True, "context_token_threshold": 100_000},
)

# After (1.x): server-side context management (beta)
runner = client.beta.messages.tool_runner(
    model=MODEL,
    max_tokens=4096,
    tools=TOOLS,
    messages=history,
    betas=["compact-2026-01-12"],
    context_management={
        "edits": [
            {
                "type": "compact_20260112",
                "trigger": {"type": "input_tokens", "value": 100_000},
            }
        ]
    },
)
```

Why it fails quietly: a loop that relied on local compaction and simply drops the argument keeps running, keeps accumulating context, and only surfaces a problem when it hits a context limit or a cost alarm many turns later. Two checks catch it. First, an integration test that drives a loop past the old threshold and asserts the compaction edit appears in the response. Second, a config lint that refuses any trigger value below 50,000 — the floor is documented, and a threshold copied over from an old client-side config can sit below it, which was fine locally and is rejected server-side now.

If your agent loop lives in the Claude Agent SDK rather than in the Python SDK’s tool runner, this section does not apply to you directly — [the Agent SDK has its own migration playbook](/blog/claude-agent-sdk-migration-playbook-from-claude-code-sdk-2026), and [our production-patterns guide](/blog/claude-agent-sdk-production-patterns-guide) covers context management on that side.

## 07 — BedrockAnthropicBedrock stops *guessing* your region.

On 0.x, constructing `AnthropicBedrock`

or `AsyncAnthropicBedrock`

with no region configured silently fell back to `us-east-1`

. On 1.x, MIGRATION.md documents that the same construction raises a `ValueError`

instead. The resolution order is explicit: an `aws_region=`

constructor argument first, then the `AWS_REGION`

or `AWS_DEFAULT_REGION`

environment variables, then the boto3 profile configuration. If none of those yields a region, the client refuses to start.

The SDK docs frame this class carefully: `AnthropicBedrock`

is retained for existing applications on the Bedrock `InvokeModel`

path, while `AnthropicBedrockMantle`

is the recommended class for new Bedrock projects. The region change is about the legacy class, which is precisely the one most likely to be sitting in an older service with a minimal constructor call.

##### Pass aws_region explicitly

AnthropicBedrock(aws_region="eu-central-1"). Highest precedence, visible in code review, and a harmless no-op on 0.x — so it is safe to land before the SDK upgrade.

##### AWS_REGION or AWS_DEFAULT_REGION

Second in the resolution order. Right when the same image runs in several regions and the deployment layer already owns the variable. Verify it reaches the process, not just the shell.

##### Lean on the shared AWS config

Lowest precedence. Works on developer machines with a configured profile and fails on a clean CI runner — which is the environment where the new ValueError will find you first.

##### Check who reads *raw events*

Unknown Bedrock stream events are now skipped rather than yielded; MIGRATION.md calls out amazon-bedrock-invocationMetrics specifically. Any dashboard fed from that event needs a new source.

The design call is the right one. A client that quietly routes production traffic to a region nobody chose is a data-residency incident waiting for an auditor, and the old default made that the path of least resistance. The cost is a one-time startup failure in any environment that relied on it — which is why the explicit constructor argument is worth landing this week even if the SDK upgrade itself waits.

## 08 — Smaller BreaksAsync raw responses, headers, and the *structured-output* rename.

The remaining changes are mechanical, but two of them hide in code that runs rarely. On the async client, `.with_raw_response`

results now require `await response.parse()`

where 0.x allowed a synchronous `.parse()`

. The `.text`

and `.content`

properties on raw responses became methods — `response.text()`

and `response.read()`

— and the response gains directly accessible `json()`

, `iter_bytes()`

, `iter_text()`

and `iter_lines()`

.

```
# Before (0.x): async raw response
response = await client.messages.with_raw_response.create(**params)
message = response.parse()
request_id = response.headers.get("request-id")
body = response.text

# After (1.x)
response = await client.messages.with_raw_response.create(**params)
message = await response.parse()
request_id = response.headers.get("Request-Id")  # names are case-insensitive now
body = response.text()
```

Headers are the second quiet one. Names are now case-insensitive, which is a loosening, but raw `bytes`

values now raise and must be decoded to `str`

first — a tightening that lands on whichever middleware stuffs a signed token into a header without decoding it. Structured output is the third: passing a raw schema dict as `output_format=`

is removed from message methods in favour of `output_config={"format": {...}}`

, and the `parse()`

, `stream()`

and `count_tokens()`

helpers accept only types for `output_format=`

. Finally, `messages.parse(stream=True)`

is gone, which MIGRATION.md notes “never worked” — use `messages.stream()`

with `output_format=`

and read `stream.get_final_message().parsed_output`

.

None of these justify delaying the migration on their own. They do justify running the migration on a branch with the full test suite, rather than bumping the version in a dependency-update bot and merging on green, because raw-response code and header middleware are exactly the paths most suites do not exercise.

## 09 — Hold-Back PinPin to 0.125.0 or migrate: a *decision*, not a default.

The hold-back pin is a real, currently installable version, not a guess: `anthropic==0.125.0`

, the last 0.x release, published on August 19 and still on PyPI. The looser form `anthropic>=0.125,<1`

does the same job while leaving room for any further 0.x uploads. Either way, a pin is a dated exception with an owner, and the table below is the decision behind it: the symptom that forces the pin, the pin itself, how much pressure sits behind the deadline, and what changes when you do migrate.

| Symptom | Recommended pin | Deadline pressure | What changes when you migrate |
|---|---|---|---|
| Service is still on Python 3.9 | anthropic==0.125.0 | High — the 0.x line is the only SDK path for 3.9, and it receives no 1.x features or fixes | Runtime moves to 3.10+ first; the SDK upgrade follows in the same change window |
| Still calling client.completions.create() | anthropic>=0.125,<1 | Highest — this surface was long-deprecated before v1.0 removed the client | Port to messages.create(); prompt strings built from HUMAN_PROMPT / AI_PROMPT become message arrays |
| Agent loop depends on client-side compaction_control | anthropic>=0.125,<1 | Medium — nothing breaks on 0.x, but the capability now lives server-side behind a beta | betas=["compact-2026-01-12"] plus context_management with a trigger of 50,000 input tokens or more |
| Relying on AnthropicBedrock’s old us-east-1 default | No pin needed | Low — set the region explicitly today; it is a no-op on 0.x and required on 1.x | Construction raises ValueError until aws_region, AWS_REGION / AWS_DEFAULT_REGION, or a boto3 profile supplies a region |
| Sending non-default temperature / top_p / top_k | No pin helps | Already failing on the seven current models; model-level, not SDK-level | Delete or default the values for current models; move older-model calls to extra_body with a comment naming the dependency |

The last row is the one to internalise. Pinning protects you from SDK-level changes; it does nothing for a behaviour the model enforces. That is the general lesson of a 1.0 like this one, and it maps onto the framework in [our API versioning decision matrix](/blog/api-versioning-strategies-2026-engineering-decision-matrix): a client library’s major version is a contract about the typed surface, and the typed surface can be narrower than the wire protocol or wider than what a given model honours. When the three disagree, the model wins, and your tests should be written against the model.

Looking forward, the direction of travel is not hard to read. Anthropic’s typed surface and the sampling restriction on its current models now agree, the Agent SDK and Codex CLI have both been through their own config migrations this summer — [Codex’s was a config-schema move](/blog/codex-cli-rust-migration-playbook-config-changes-2026) rather than a transport swap — and the pattern across vendors is that SDK majors are increasingly the place where deprecations get enforced rather than announced. The teams that cope best keep a single adapter module around each vendor client, so the next major touches one file. If you are building or operating agentic systems on Claude and want that adapter layer designed before the next migration rather than during it, our [AI transformation engagements](/services/ai-transformation) start with exactly that audit, and our [web development team](/services/web-development) handles the runtime and dependency upgrades that usually come bundled with it.

## 10 — ConclusionMigrate the behaviour changes *deliberately*; the rest is find-and-replace.

### The SDK’s typed surface and the models’ sampling rules now agree — the real work is in the behaviour changes, not the renames.

Anthropic Python SDK v1.0 is a deprecation gate. The HTTP layer moves to httpx2, “a maintained, API-compatible fork” in Anthropic’s own careful wording; the floor rises to Python 3.10; Text Completions, the sampling parameters and client-side compaction leave the typed surface; AnthropicBedrock refuses to guess a region. Fifteen documented changes, and *only one is enforced by the models themselves* — sampling, where seven current models already return a 400 on any non-default value regardless of how the request arrives.

The migration itself is an afternoon for a service that is on Python 3.10+, on Messages, and not building its own httpx objects. It is a planned change for anyone running a long agent loop on client-side compaction, instrumenting httpx by module name, or constructing `AnthropicBedrock`

without a region. The first two break with nothing raised at all; the third refuses to construct the client, which is loud but lands at startup in whichever environment relied on the old default. Land the region argument and the `alias_httpx()`

call first; both are safe on 0.x.

If you cannot move this week, `anthropic==0.125.0`

is a real pin with a real date, and it buys you time on everything except sampling. Give it an owner, and write the tests that matter against the model rather than the SDK — because that is the boundary this release just made visible.
