---
title: "Python SDK changelog"
type: reference
tags: [python, sdk, changelog, versions, releases]
created: 2026-09-17
updated: 2026-09-21
confidence: high
sources:
  - raw/docs/sdk__python__changelog.md
  - raw/github/typesafe-sdk-python/docs/changelog.md
  - raw/github/typesafe-sdk-python/pyproject.toml
jev_version: "jev-1.13.0"
sdk_python: "0.7.1"
summary: "typesafe-sdk release history: 0.5.7 initial public release (2026-09-14), 0.6.0 Score.criteria breaking change, 0.7.0 msgspec to pydantic plus response_model, 0.7.1 API-key validation."
---

# Python SDK changelog

> **TL;DR** The current version is **`0.7.1`, released 2026-09-21**. Two breaking changes so far: `0.6.0` (2026-09-15) made `Score.criteria` an ordered sequence instead of an int-keyed dictionary, and `0.7.0` (2026-09-18) swapped the serialization library from `msgspec` to `pydantic` and added `system_one(..., response_model=...)`. Write new code against 0.7.1.

## Release table

| Version | Date | Kind | Headline |
|---|---|---|---|
| `0.7.1` | 2026-09-21 | patch | API key validated early and excluded from logged exceptions; AI-gateway usage examples |
| `0.7.0` | 2026-09-18 | minor, **breaking** | ser/de moves from `msgspec` to `pydantic`; new `response_model` argument on `system_one`; `str` subclasses serialize correctly |
| `0.6.0` | 2026-09-15 | minor, **breaking** | `Score.criteria` becomes an ordered sequence; abstract input types; richer errors; `RetryPolicy` validation; picklable exceptions and responses |
| `0.5.7` | 2026-09-14 | initial public release | First published SDK |
| `0.0.1a0` | — (date not captured) | pre-release placeholder | Reserves the `typesafe-sdk` name on PyPI; no documented content |

The upstream changelog (both the docs page and `docs/changelog.md` in the repo) covers `0.7.1`, `0.7.0`, `0.6.0` and `0.5.7`. `0.0.1a0` appears in the PyPI release listing collected 2026-09-17 and has no changelog entry; the PyPI listing has not been re-collected since, so `0.7.0` / `0.7.1` are confirmed from the changelog and `pyproject.toml` rather than from PyPI.

Repository state captured for this wiki: `https://github.com/typesafe-ai/typesafe-sdk-python` at commit **`0ffd094c72ed9445223060b24ffd7a56aa781fb4`**, captured 2026-09-21 (`raw/MANIFEST.json`). `pyproject.toml` at that commit declares `version = "0.7.1"`. The previous snapshot in this wiki was commit `420ef4ffb612d5a539a1e0f0fe883ff6770340af` ("Release v0.6.0", 2026-09-15).

## v0.7.1 (2026-09-21)

Verbatim from the upstream changelog:

**Bug fixes**

- validate the API key early and exclude the value from logged exceptions

**Documentation**

- add examples for usage with AI gateways

What that means in code: `TypeSafeClient(api_key=...)` now resolves *and validates* the key inside the constructor (`resolve_and_validate_api_key` in `_core/config.py`), so a missing, empty, non-ASCII, or whitespace-containing key raises `TypeSafeError` before any HTTP request — "Invalid API keys raise `TypeSafeError` during client creation, before any request or retry." Separately, `_core/logging.py:redact_exception` rewrites transport exceptions (message, `__cause__`/`__context__` chain, and `__notes__`) replacing every secret-header value with `***`, and detaches the unredacted original so it cannot resurface through implicit exception chaining.

The gateway examples are the OpenRouter and Vercel AI Gateway blocks now in the usage guide — reproduced in [[reference/python-sdk]].

## v0.7.0 (2026-09-18)

Verbatim from the upstream changelog:

**Breaking Changes**

- ser/de library has been changed from `msgspec` to `pydantic`

**Bug fixes**

- `str` subclasses are now correctly serialized as strings instead of lists of characters

**Features**

- the `system_one` method now accepts a new `response_model` argument that can be set to a desired `pydantic` model for additional *type-safety*

### What the breaking change means in code

| Change | 0.6.0 | 0.7.0 |
|---|---|---|
| Runtime dependency | `msgspec>=0.21.1` | `pydantic>=2.12.0` + `pydantic-core>=2.41.1` |
| Serialize a response | `msgspec.json.encode(response)` | `response.model_dump_json()` |
| Response/question base | `msgspec.Struct` | `pydantic.BaseModel` |
| Decode failure type inside the SDK | `msgspec.DecodeError` / `msgspec.ValidationError` | `pydantic.ValidationError` |
| Question objects with unknown kwargs | tolerated by the wire struct | `ConfigDict(extra="forbid")` → `pydantic.ValidationError` |
| Question `TypedDict`s | `extra_items=JSONValue \| None` | `closed=True` |
| `JSONValue` / `JSONContent` | `TypeAlias` | `TypeAliasType` |

```python
from typesafe_sdk import Noul, NoulAnswer, SystemOneResponse, TypeSafeClient


class BillingResponse(SystemOneResponse):
    billing: NoulAnswer


with TypeSafeClient() as client:
    result = client.system_one(
        "I was charged twice.",
        {"billing": Noul(instructions="Is this about billing?")},
        response_model=BillingResponse,
    )
    assert result.billing == result.nouls["billing"]
```

The full migration checklist is in [[reference/python-sdk]] under "Migrating from 0.6.0". The 0.6.0 `Score.criteria` sequence rule is unaffected and still applies.

## v0.6.0 (2026-09-15)

Verbatim from the upstream changelog:

**Breaking Changes**

- accept `Score.criteria` as an ordered sequence instead of a dictionary keyed by integers

**Features**

- improve type annotations on SDK inputs to accept abstract types like `Mapping` and `Sequence`
- improve error messages to include http details and metadata

**Bug fixes**

- handle invalid values in `RetryPolicy`
- make exceptions and responses picklable

**Documentation**

- link more concepts from main [docs](https://docs.typesafe.ai/)

### What the breaking change means in code

```python
from typesafe_sdk import Score

# 0.6.0 and later
Score(instructions="How urgent is this ticket?", criteria=["can wait", "this week", "today"])

# pre-0.6.0 shape — an int-keyed dict; no longer the documented form
# Score(instructions="How urgent is this ticket?",
#       criteria={0: "can wait", 1: "this week", 2: "today"})
```

Migration steps when upgrading from 0.5.7 (still required on 0.7.x — the sequence form is unchanged):

1. Find every `Score(...)` construction and every `{"type": "score", ...}` dictionary.
2. Replace the int-keyed dict with a list (or tuple) ordered from score `0` upward. `sorted(old.items())` then `[value for _, value in ...]` reproduces the order.
3. Leave answer-reading code alone: `ScoreAnswer.legend` and `ScoreAnswer.probabilities` are still keyed by **integer** score. Only the question side changed.
4. Re-check `RetryPolicy(...)` arguments — invalid values now raise `TypeSafeError` at construction instead of being accepted silently.

See [[reference/python-sdk-questions]] for the current question contract and [[reference/python-sdk-responses]] for the answer side.

### Where each change is visible in the API

| Change | Observable effect | Page |
|---|---|---|
| `Score.criteria` sequence | `Score(criteria=Sequence[JSONContent])`; empty sequence raises `TypeSafeError` | [[reference/python-sdk-questions]] |
| Abstract input types | `state`, `questions`, `criteria`, `headers` accept `Mapping`/`Sequence`, not just `dict`/`list` | [[reference/python-sdk]] |
| Richer error messages | `TypeSafeAPIError.endpoint`, and `__str__` renders `endpoint: status message (request_id=…)` | [[reference/python-sdk-retries-errors]] |
| `RetryPolicy` validation | `__post_init__` raises `TypeSafeError` for bad `max_retries`, backoff values, jitter, or timeout | [[reference/python-sdk-retries-errors]] |
| Picklable exceptions and responses | In 0.6.0 via `Response.__copy__` / `__reduce__` carrying `request_id` and the raw HTTP response; `TypeSafeAPIResponseValidationError.args` is set explicitly. 0.7.0 deleted both dunders when `Response` became a `BaseModel` — Pydantic's own copy/pickle support took over, and the transport metadata still lives in the instance `__dict__` | [[reference/python-sdk-responses]] |

## v0.5.7 (2026-09-14)

Verbatim: "This is the initial public release of TypeSafe Python SDK. Learn more in the [documentation](https://docs.typesafe.ai/sdk/python)."

No itemized changes are published for this release. The version number starting at `0.5.7` rather than `0.1.0` is not explained upstream; the Python and JavaScript SDKs share the `0.5.7` → `0.6.0` sequence, which suggests a shared internal release train (inferred).

## v0.0.1a0

Listed on PyPI among the `typesafe-sdk` releases (`0.0.1a0`, `0.5.7`, `0.6.0`) as collected on 2026-09-17. No changelog entry, no release date captured, and no documentation references it. Treat it as a name-reservation pre-release; do not install it.

## Related packages

| Package | Version | Note |
|---|---|---|
| `typesafe-sdk` | 0.7.1 (2026-09-21) | The SDK. Import as `typesafe_sdk`. |
| `typesafe-ai` | 0.1.0 | Redirect shim that simply depends on `typesafe-sdk`. |
| `typesafe` | 0.9.1 | Unrelated third-party package — **not** TypeSafe AI. |
| `@typesafe-ai/sdk` (npm) | 0.6.0 (2026-09-15); 0.5.7 on 2026-09-12 | The JavaScript SDK. The two SDKs moved in lockstep through 0.6.0, but the JS SDK has **not** followed Python to 0.7.x — see [[reference/javascript-sdk-changelog]]. |
| `system-one-adapter` | 0.2.0 (2026-09-18) | Requires `typesafe-sdk>=0.7.0`; 0.1.5 pinned `>=0.6.0,<0.7.0`. See [[reference/system-one-adapter]]. |

## Version pinning

The SDK is pre-1.0 and has shipped a breaking change in each of its last two minor bumps (0.6.0, 0.7.0), so pin conservatively:

```toml
# pyproject.toml
dependencies = ["typesafe-sdk>=0.7.1,<0.8"]
```

```sh
uv add "typesafe-sdk>=0.7.1,<0.8"
```

Check the installed version at runtime:

```python
from typesafe_sdk import __version__

print(__version__)  # resolved via importlib.metadata.version("typesafe-sdk")
```

## Related

- [[reference/python-sdk]] — install, clients, `system_one()`, and the 0.6.0 → 0.7.x migration
- [[reference/python-sdk-questions]] — the current `Score.criteria` contract
- [[reference/python-sdk-responses]] — answers, usage, models
- [[reference/python-sdk-retries-errors]] — `RetryPolicy` validation and richer errors
- [[reference/javascript-sdk-changelog]] — the JS SDK's parallel release line
- [[syntheses/version-timeline]] — models, SDKs, API and company timeline
- [[entities/github-repos]] — the `typesafe-ai` GitHub organisation

## Sources

- raw/docs/sdk__python__changelog.md (https://docs.typesafe.ai/sdk/python/changelog.md)
- raw/github/typesafe-sdk-python/docs/changelog.md, pyproject.toml (https://github.com/typesafe-ai/typesafe-sdk-python @ 0ffd094c72ed9445223060b24ffd7a56aa781fb4, captured 2026-09-21)
- raw/github/typesafe-sdk-python/src/typesafe_sdk/_core/{config,logging,json,schemas/base}.py — the 0.7.x mechanisms described above
- raw/github/system-one-adapter-python/docs/changelog.md, pyproject.toml — the adapter's matching 0.2.0 release
- PyPI release listing for `typesafe-sdk` (0.0.1a0, 0.5.7, 0.6.0) and the `typesafe-ai` shim, collected 2026-09-17 and recorded in CLAUDE.md
