Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/anthropic/_utils/_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
is_annotated_type,
strip_annotated_type,
)
from ..lib._compaction import omit_compaction_encrypted_content

_T = TypeVar("_T")

Expand Down Expand Up @@ -109,7 +110,7 @@ class Params(TypedDict, total=False):
It should be noted that the transformations that this function does are not represented in the type system.
"""
transformed = _transform_recursive(data, annotation=cast(type, expected_type))
return cast(_T, transformed)
return cast(_T, omit_compaction_encrypted_content(transformed))


@lru_cache(maxsize=8096)
Expand Down Expand Up @@ -316,7 +317,7 @@ class Params(TypedDict, total=False):
It should be noted that the transformations that this function does are not represented in the type system.
"""
transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type))
return cast(_T, transformed)
return cast(_T, omit_compaction_encrypted_content(transformed))


async def _async_transform_recursive(
Expand Down
56 changes: 56 additions & 0 deletions src/anthropic/lib/_compaction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Request-side handling of compaction content blocks.

Response compaction blocks include ``encrypted_content``, but the Messages API
rejects that field on request blocks (``Extra inputs are not permitted``). The
documented round-trip is ``messages.append(response.content)``, so the SDK
omits ``encrypted_content`` from compaction blocks while serializing requests.

This module is not Stainless-generated; keep request-only behavior here so it
survives OpenAPI regenerations of the TypedDicts.
"""

from __future__ import annotations

from typing import Any, TypeVar, cast

_T = TypeVar("_T")


def omit_compaction_encrypted_content(data: _T) -> _T:
"""Drop ``encrypted_content`` from compaction blocks in a request payload.

Other block types that legitimately send ``encrypted_content`` (web search
results, advisor redacted results) are left unchanged. Objects that do not
contain a compaction block are returned unchanged so request transform
identity optimizations keep working.
"""
return cast(_T, _omit_compaction_encrypted_content(data))


def _omit_compaction_encrypted_content(data: object) -> Any:
if isinstance(data, list):
items = cast("list[object]", data)
new_items: list[object] = [_omit_compaction_encrypted_content(item) for item in items]
if all(new is old for new, old in zip(new_items, items)):
return cast(Any, data)
return cast(Any, new_items)
if isinstance(data, tuple):
tuple_items = cast("tuple[object, ...]", data)
new_tuple = tuple(_omit_compaction_encrypted_content(item) for item in tuple_items)
if all(new is old for new, old in zip(new_tuple, tuple_items)):
return cast(Any, data)
return cast(Any, new_tuple)
if not isinstance(data, dict):
return data

mapping = cast("dict[str, object]", data)
nested: dict[str, object] = {key: _omit_compaction_encrypted_content(value) for key, value in mapping.items()}
changed = any(nested[key] is not value for key, value in mapping.items())
if mapping.get("type") == "compaction" and "encrypted_content" in mapping:
if not changed:
nested = dict(mapping)
nested.pop("encrypted_content", None)
return cast(Any, nested)
if changed:
return cast(Any, nested)
return cast(Any, data)
7 changes: 6 additions & 1 deletion src/anthropic/types/beta/beta_compaction_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ class BetaCompactionBlock(BaseModel):
"""Summary of compacted content, or null if compaction failed"""

encrypted_content: Optional[str] = None
"""Opaque metadata from prior compaction, to be round-tripped verbatim"""
"""Opaque metadata returned on compaction response blocks.

The Messages API rejects this field on request compaction blocks, so the SDK
omits it when serializing requests. Clients can still append ``response.content``
verbatim; the field is dropped on the wire, not on the response object.
"""

type: Literal["compaction"]
7 changes: 6 additions & 1 deletion src/anthropic/types/beta/beta_compaction_block_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ class BetaCompactionBlockParam(TypedDict, total=False):
"""Summary of previously compacted content, or null if compaction failed"""

encrypted_content: Optional[str]
"""Opaque metadata from prior compaction, to be round-tripped verbatim"""
"""Opaque metadata returned on compaction response blocks.

The Messages API rejects this field on request compaction blocks, so the SDK
omits it when serializing requests. Prefer appending ``response.content``
unmodified; do not rely on this field being sent.
"""
Loading