Skip to content

fix(anthropic): disable vendor SDK retries by default - #2198

Open
rosetta-livekit-bot[bot] wants to merge 4 commits into
mainfrom
artisans-council-kale
Open

fix(anthropic): disable vendor SDK retries by default#2198
rosetta-livekit-bot[bot] wants to merge 4 commits into
mainfrom
artisans-council-kale

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • disable Anthropic SDK retries by default so framework connection options own retries
  • add maxRetries for callers that explicitly want a vendor-client retry policy
  • preserve caller ownership when a custom client is injected
  • add a patch changeset for @livekit/agents-plugin-anthropic

Ports livekit/agents#6604.

Verification

  • pnpm exec vitest run plugins/anthropic (15 passed)
  • pnpm build
  • pnpm lint
  • pnpm format:check
Source diff coverage

Source diff coverage

Source file Classification Target coverage
livekit-plugins/livekit-plugins-anthropic/livekit/plugins/anthropic/llm.py Adapted plugins/anthropic/src/llm.ts: added camelCase maxRetries, defaults internally constructed SDK clients to 0, and leaves injected clients unchanged.
tests/test_plugin_anthropic.py Adapted plugins/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-anthropic was building anthropic.AsyncClient without max_retries, so the SDK default of 2 internal retries stacked on top of framework conn_options.max_retry. That made wall-clock time exceed conn_options.timeout (especially with FallbackAdapter).

OpenAI plugin already defaults vendor client retries to 0. This PR matches that for Anthropic.

Changes

  • Pass max_retries=0 by default when constructing anthropic.AsyncClient in the Anthropic LLM plugin.
  • Optional max_retries constructor arg for callers who want a different vendor-client policy.
  • Unit test that the default client has max_retries == 0.
  • Custom client= injection is unchanged (caller owns that client).

Verification

  • ruff format / ruff check on touched files
  • pytest 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 pass max_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: 0 so framework connOptions owns retries, while callers can opt out with an explicit maxRetries or an injected client. 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, provider resolves to api.anthropic.test from the injected client's baseURL, and the caller's maxRetries: 7 remains unmutated.
  • forwards an explicit maxRetries to the Anthropic SDK: an explicit maxRetries: 2 reaches 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 || fallback short-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 hardcodes maxRetries: 0, and also catches ignoring the option. pnpm exec vitest run plugins/anthropic passed: 15 passed (15).

Merge-conflict resolution

The conflict with the prewarm feature that landed on main was resolved as a strict union. The describe('Anthropic LLM prewarm', ...) block is byte-identical to origin/main, and the SDK mock subclasses the real Anthropic client via importOriginal rather than stubbing it. git merge-tree --write-tree --messages origin/main HEAD produced only a tree OID, no CONFLICT, and exit 0.

CI note

The Test check does not appear at head dd95c982ecc7de1295d01676bcb2789ce224beba because .github/workflows/test.yml has a paths filter that excludes plugins/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.yml restricts its pull_request trigger to these paths:

paths:
  - '.github/workflows/test.yml'
  - 'agents/**'
  - 'package.json'
  - 'plugins/test/**'
  - 'pnpm-lock.yaml'
  - 'pnpm-workspace.yaml'
  - 'turbo.json'

plugins/anthropic/** is not listed, and this PR touches only plugins/anthropic/ plus a changeset. The Test job is therefore never scheduled — even though the substance of this PR is test changes to plugins/anthropic/src/llm.test.ts. Any plugin-only PR has the same blind spot.

Verified locally instead. At head dd95c982ecc7de1295d01676bcb2789ce224beba:

npx vitest run plugins/anthropic/src/llm.test.ts
Test Files  1 passed (1)
     Tests  15 passed (15)

Note also that plugins/anthropic/package.json defines no test script, so pnpm --filter @livekit/agents-plugin-anthropic test silently 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 --silent plus three agents/src/inference files. The "Test all plugins" and "Test specific plugins" steps are commented out at .github/workflows/test.yml:69-93 under # 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.

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner July 31, 2026 21:15
@changeset-bot

changeset-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: dd95c98

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 39 packages
Name Type
@livekit/agents-plugin-anthropic Patch
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-azure Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-krisp Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-protoface Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch
@livekit/agents-plugins-test Patch

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

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

toubatbrian and others added 3 commits August 3, 2026 13:26
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>
/** Pre-configured Anthropic client instance. */
client?: Anthropic;
/** Vendor client retries. Defaults to 0 because the framework owns retries. */
maxRetries?: number;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think for OpenAI clients, we just have it 0 internally. We can skip this parameter here too to avoid confusion.

@toubatbrian
toubatbrian enabled auto-merge (squash) August 4, 2026 22:01
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.

2 participants