Skip to content

fix: async transform recursion + type introspection cache perf#1296

Open
giulio-leone wants to merge 4 commits intoanthropics:mainfrom
giulio-leone:anthropic-1195-work
Open

fix: async transform recursion + type introspection cache perf#1296
giulio-leone wants to merge 4 commits intoanthropics:mainfrom
giulio-leone:anthropic-1195-work

Conversation

@giulio-leone
Copy link
Copy Markdown

Summary

  • perf: cache type introspection in _transform_recursive to eliminate redundant dispatch overhead
  • fix: use async recursion in dict branch of _async_transform_recursive for correct async semantics
  • fix: increase wall-clock threshold to 30s for CI robustness
  • test: replace wall-clock assertion with relative comparison

These patches fix async transform correctness and improve performance in hot paths.

…edundant dispatch

The _transform_recursive function and its async variant performed type
introspection (strip_annotated_type, get_origin, is_typeddict,
is_list_type, is_union_type, etc.) on every recursive call, even though
the type annotation is the same for all values of a given field. On
large payloads (~90K messages), this consumed ~6.6% of total CPU time
with zero transformation output since Messages API types have no
PropertyInfo annotations.

Changes:
- Add _cached_transform_dispatch(): LRU-cached function that precomputes
  the dispatch path (typeddict/dict/sequence/union/other) and extracts
  type args once per annotation type. Subsequent calls are O(1) dict
  lookups instead of re-running type introspection.
- Add _get_field_key_map(): LRU-cached function that precomputes the
  key alias mapping for each TypedDict type, replacing per-field
  _maybe_transform_key calls with a single dict.get() lookup.
- Expand _no_transform_needed() to include str and bool, allowing
  lists of strings/bools to skip per-element recursion.
- Apply same optimizations to _async_transform_recursive and
  _async_transform_typeddict.

Fixes anthropics#1195
Address review feedback:
1. The dict branch in _async_transform_recursive called the synchronous
   _transform_recursive, defeating async benefits. Changed to
   await _async_transform_recursive.
2. Relaxed wall-clock assertion in performance test from 2s to 10s to
   avoid flakiness in CI environments with variable load.
Use sync-vs-async relative timing instead of a fixed threshold so
the test is resilient to CI environments with variable load while
still catching performance regressions.

Refs: anthropics#1195
@giulio-leone giulio-leone requested a review from a team as a code owner March 25, 2026 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant