fix(anthropic): disable vendor SDK retries by default - #2198
Open
rosetta-livekit-bot[bot] wants to merge 4 commits into
Open
fix(anthropic): disable vendor SDK retries by default#2198rosetta-livekit-bot[bot] wants to merge 4 commits into
rosetta-livekit-bot[bot] wants to merge 4 commits into
Conversation
🦋 Changeset detectedLatest commit: dd95c98 The changes in this PR will be included in the next version bump. This PR includes changesets to release 39 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # plugins/anthropic/src/llm.test.ts
The PR claimed callers keep ownership of an injected `client` and that an explicit `maxRetries` is honored, but neither was covered. Add a test that an injected client skips SDK construction entirely and keeps its own retry policy, and one that an explicit `maxRetries` reaches the SDK client. Co-authored-by: Cursor <cursoragent@cursor.com>
Release notes need to state that the vendor SDK no longer retries by default and that `connOptions` now owns retries, plus the escape hatches. Co-authored-by: Cursor <cursoragent@cursor.com>
chenghao-mou
reviewed
Aug 4, 2026
| /** Pre-configured Anthropic client instance. */ | ||
| client?: Anthropic; | ||
| /** Vendor client retries. Defaults to 0 because the framework owns retries. */ | ||
| maxRetries?: number; |
Member
There was a problem hiding this comment.
I think for OpenAI clients, we just have it 0 internally. We can skip this parameter here too to avoid confusion.
toubatbrian
enabled auto-merge (squash)
August 4, 2026 22:01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
maxRetriesfor callers that explicitly want a vendor-client retry policyclientis injected@livekit/agents-plugin-anthropicPorts livekit/agents#6604.
Verification
pnpm exec vitest run plugins/anthropic(15 passed)pnpm buildpnpm lintpnpm format:checkSource diff coverage
Source diff coverage
livekit-plugins/livekit-plugins-anthropic/livekit/plugins/anthropic/llm.pyplugins/anthropic/src/llm.ts: added camelCasemaxRetries, defaults internally constructed SDK clients to0, and leaves injected clients unchanged.tests/test_plugin_anthropic.pyplugins/anthropic/src/llm.test.ts: ported the default-retries assertion by transparently recording JS SDK constructor options because the target client field is a true private field; follow-up review added injected-client and explicit-override coverage.No source files were omitted or not applicable.
Ported from livekit/agents#6604
Original PR description
Summary
Fixes #6603.
livekit-plugins-anthropicwas buildinganthropic.AsyncClientwithoutmax_retries, so the SDK default of 2 internal retries stacked on top of frameworkconn_options.max_retry. That made wall-clock time exceedconn_options.timeout(especially with FallbackAdapter).OpenAI plugin already defaults vendor client retries to 0. This PR matches that for Anthropic.
Changes
max_retries=0by default when constructinganthropic.AsyncClientin the Anthropic LLM plugin.max_retriesconstructor arg for callers who want a different vendor-client policy.max_retries == 0.client=injection is unchanged (caller owns that client).Verification
ruff format/ruff checkon touched filespytest tests/test_plugin_anthropic.py(8 passed)Backwards compatibility
Default behavior for the constructed client changes from SDK default (2) to 0 so retries are owned by the framework only. Callers who pass their own
client=are unaffected. Callers who want SDK retries can passmax_retries=....Verification
Cue applicability
Cue is not applicable to this PR. The change controls how the Anthropic SDK client is constructed: internally created clients default to
maxRetries: 0so frameworkconnOptionsowns retries, while callers can opt out with an explicitmaxRetriesor an injectedclient. This is request-construction behavior with no voice/runtime path that a Cue session could observe; no voice verification was performed.Behavior-level verification
The closest faithful verification is the plugin unit suite:
leaves an injected client and its retry policy untouched: the SDK constructor call count stays unchanged,providerresolves toapi.anthropic.testfrom the injected client'sbaseURL, and the caller'smaxRetries: 7remains unmutated.forwards an explicit maxRetries to the Anthropic SDK: an explicitmaxRetries: 2reaches the SDK constructor.The independent re-review confirmed both tests are non-vacuous. The injected-client test catches mutation A, which eagerly constructs a fallback client before applying the
client || fallbackshort-circuit; its provider and mutation assertions also catch assigning a different client or mutating the caller's object. The override test catches mutation B, which hardcodesmaxRetries: 0, and also catches ignoring the option.pnpm exec vitest run plugins/anthropicpassed: 15 passed (15).Merge-conflict resolution
The conflict with the prewarm feature that landed on
mainwas resolved as a strict union. Thedescribe('Anthropic LLM prewarm', ...)block is byte-identical toorigin/main, and the SDK mock subclasses the real Anthropic client viaimportOriginalrather than stubbing it.git merge-tree --write-tree --messages origin/main HEADproduced only a tree OID, noCONFLICT, and exit 0.CI note
The
Testcheck does not appear at headdd95c982ecc7de1295d01676bcb2789ce224bebabecause.github/workflows/test.ymlhas apathsfilter that excludesplugins/anthropic/**. This is a path filter, not a test failure and not a consequence of the resolved conflict.CI coverage gap — tests for this PR never ran in CI
The Test check is absent from this PR (Build, Formatting, REUSE-3.2, Devin Review, and CLA all pass). That is not a flake.
.github/workflows/test.ymlrestricts itspull_requesttrigger to these paths:plugins/anthropic/**is not listed, and this PR touches onlyplugins/anthropic/plus a changeset. The Test job is therefore never scheduled — even though the substance of this PR is test changes toplugins/anthropic/src/llm.test.ts. Any plugin-only PR has the same blind spot.Verified locally instead. At head
dd95c982ecc7de1295d01676bcb2789ce224beba:Note also that
plugins/anthropic/package.jsondefines notestscript, sopnpm --filter @livekit/agents-plugin-anthropic testsilently exits 0 without running anything — worth knowing before relying on that command as a check.Widening the path filter alone would not close this gap. The Test job's only active test steps are
pnpm test agents --silentplus threeagents/src/inferencefiles. The "Test all plugins" and "Test specific plugins" steps are commented out at.github/workflows/test.yml:69-93under# TODO (AJS-83) Re-enable once plugins are refactored with abort controllers. So even if the filter scheduled this PR's Test job, zero plugin tests would run. No plugin test has executed in this repo's CI for as long as AJS-83 has been open, which means no plugin-only PR can currently produce a CI test signal. Both the filter and AJS-83 are repo-level fixes outside this PR's scope; flagging them here so the missing check is not mistaken for a pass.