Skip to content

chore(deps): weekly dependency update - #783

Merged
Abhijeet Prasad (AbhiPrasad) merged 3 commits into
mainfrom
deps/weekly-update-2026-09-21
Sep 22, 2026
Merged

Abhijeet Prasad (AbhiPrasad) merged 3 commits into
mainfrom
deps/weekly-update-2026-09-21

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Automated weekly dependency update via python scripts/update-matrix-latest.py && uv lock --upgrade.

⚠️ Provider SDK packages changed. A human needs to re-record cassettes locally before merging.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5cb0ae0ca6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "Codex (@codex) address that feedback".

Comment thread py/pyproject.toml
openai 3.16.1 converted its resource packages to PEP 562 lazy re-exports.
`_resolve_attr_path` walks with `inspect.getattr_static`, which never invokes a
module-level `__getattr__`, so `openai.resources.chat.completions.Completions`
looked absent and `ChatCompletionsPatcher` silently no-opped: after
`setup_openai()` / `auto_instrument()`, chat completions produced no spans at
all. Fall back to a plain getattr when the object being walked is a module —
modules carry no descriptors, so nothing is triggered that getattr_static was
protecting against.

Also refresh the `latest` cassettes for the provider SDKs this dependency
update bumped by a minor version: openai, anthropic, ai-sdk, litellm,
google-genai, openrouter, pydantic-ai, strands, typesafe, pipecat. dspy is
refreshed too — its session installs the litellm matrix pin, and litellm
1.102.0 fetches the model price map at runtime, which the old cassettes did
not carry.

huggingface-hub cassettes are left as-is: re-recording fails because the tests
pin `provider="cerebras"` / `provider="featherless-ai"` for models HF no longer
routes there. That is pre-existing test drift, not a 1.32.0 regression, and the
committed cassettes still play back green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-22T15:36:41.501590Z 316ed39 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

CI failed test_dspy(latest) on Windows across 3.11-3.14. Two separate
problems, both from the LiteLLM 1.100.1 -> 1.102.0 bump.

1.102.0 fetches model_prices_and_context_window.json from GitHub on import.
My earlier re-record captured it, which both bloated the cassette by ~3MB and
displaced the tiktoken cl100k_base download that CI needs and my machine
(warm tiktoken cache) never makes. Setting LITELLM_LOCAL_MODEL_COST_MAP keeps
the fetch off the wire entirely, so the cassette goes back to being about the
traffic under test -- it is now byte-identical to main again.

The env var is scoped to the DSPy session on purpose: an older LiteLLM's
bundled map does not know newer model names, and test_litellm(1.74.0) fails
provider resolution for gpt-image-1-mini under it.

Also make patcher module resolution consult sys.modules before importlib.
Separately, test_mistral(latest) failed on ubuntu/3.10 with
`KeyError: <thread id>` raised from importlib._bootstrap while resolve_root()
imported mistralai.client.chat -- CPython 3.10's re-entrancy bookkeeping
tripping over our own lock traffic. We call import_module for every patcher on
every setup(), almost always for a module that is already imported, so the
sys.modules fast path removes nearly all of it. That failure does not
reproduce locally (3/3 green on 3.10), so this is a mitigation rather than a
proven cure; it is a worthwhile change on its own merits either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 316ed395ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

Comment on lines +639 to +641
module = sys.modules.get(name)
if module is not None:
return module

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait for modules that are still initializing

When setup() races with a provider or provider-submodule import on another thread, the loader has already inserted a partially initialized module into sys.modules, so this fast path returns it before its patch targets exist. The previous importlib.import_module() call waited on the per-module import lock; now patchers can conclude that their targets are absent and leave subsequent provider calls uninstrumented unless setup() is invoked again. Keep the shortcut for fully initialized modules, but fall back to the import machinery when the module spec is still initializing.

Useful? React with 👍 / 👎.

Comment thread py/pyproject.toml

[tool.braintrust.matrix.claude-agent-sdk]
latest = "claude-agent-sdk==0.2.152"
latest = "claude-agent-sdk==0.2.157"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Re-record Claude transport cassettes for 0.2.157

The latest Claude Agent SDK session now installs 0.2.157, but py/src/braintrust/integrations/claude_agent_sdk/cassettes/latest/ is unchanged and therefore still replays the prior SDK's subprocess protocol. Fresh evidence after the earlier review is that this revision re-records the HTTP cassettes for several upgraded providers while leaving every Claude transport cassette untouched, so CI cannot detect request/event-shape changes introduced by this upgrade; record and validate the latest Claude cassettes with 0.2.157.

AGENTS.md reference: AGENTS.md:L219-L224

Useful? React with 👍 / 👎.

@AbhiPrasad
Abhijeet Prasad (AbhiPrasad) merged commit c851061 into main Sep 22, 2026
83 checks passed
@AbhiPrasad
Abhijeet Prasad (AbhiPrasad) deleted the deps/weekly-update-2026-09-21 branch September 22, 2026 15:42
Abhijeet Prasad (AbhiPrasad) added a commit that referenced this pull request Sep 22, 2026
…#793)

Follow-up to #783, which merged before this landed. Addresses the Codex
review finding on that PR.

## The problem

#783 added a `sys.modules` fast path to `_import_optional_module` so
patcher resolution stops reacquiring the import lock on every `setup()`.
It returned any module present in `sys.modules`.

The loader inserts a module into `sys.modules` **before** executing its
body. So when `setup()` races a provider import on another thread, the
shortcut hands back a half-built module: its patch targets do not exist
yet, `applies()` concludes they are absent, and the patcher is
**silently skipped**. `importlib.import_module` would have blocked on
the per-module lock until the other thread finished.

That is the same failure mode #783 set out to fix for openai's lazy
modules, reintroduced in a narrower window — worth closing rather than
leaving.

## The fix

Guard the shortcut with the spec's `_initializing` flag. This is not an
invented heuristic: it is the predicate CPython itself uses for the same
decision. From 3.11+ `importlib._bootstrap._find_and_load`:

```python
# Optimization: we avoid unneeded module locking if the module
# already exists in sys.modules and is fully initialized.
module = sys.modules.get(name, _NEEDS_LOADING)
if (module is _NEEDS_LOADING or
    getattr(getattr(module, "__spec__", None), "_initializing", False)):
    ...
```

## Why keep the shortcut at all

3.10's `_find_and_load` has no such optimization — it takes the module
lock unconditionally:

```python
def _find_and_load(name, import_):
    with _ModuleLockManager(name):
        ...
```

That unconditional lock is what produced the `KeyError: <thread id>`
from `importlib._bootstrap` on the ubuntu/3.10 shard of #783 (3.10's
`_blocking_on` is one slot per thread, so a re-entrant import deletes
the outer frame's entry). On 3.11+ this shortcut is effectively
redundant with CPython's own; on 3.10 it is doing real work.

## Testing

Added `test_import_optional_module_waits_for_initializing_module`, which
puts a module with `_initializing = True` in `sys.modules` and asserts
we fall through to the import machinery, then that the shortcut applies
again once initialization completes.

`test_core` green on 3.10 (859 passed) and 3.14 (861 passed).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant