Skip to content

fix: isolate llm fallback errors and prevent output replay - #2480

Open
chenghao-mou wants to merge 3 commits into
mainfrom
chenghao/fix/AGT-3492-llm-fallback-stream-errors
Open

fix: isolate llm fallback errors and prevent output replay#2480
chenghao-mou wants to merge 3 commits into
mainfrom
chenghao/fix/AGT-3492-llm-fallback-stream-errors

Conversation

@chenghao-mou

Copy link
Copy Markdown
Member

Concurrent LLM requests could inherit another stream's failure and replay text or tool calls. Scope fallback failures to their child stream, stop outer retries after output when retryOnChunkSent is false, and cancel active children when the parent closes.

Fixes #2477. Adopts @dtran26's diagnosis and reproduction; local probes also confirmed child-retry and cancellation failures. Addresses AGT-3492.

Validated with 13 regression cases, the original reproducers, and 2,623 passing core tests.

Initial prompt and agent context

Model: GPT-6

can you investigate github 2477?

can you check for python parity?

okay, we need to fix both repos. Can you fix the node first? Then I will start another thread for the python issue

run a subagent for code review, then if it looks good, open a draft PR.

Read terminal errors from each child stream, stop outer retries after
forwarded output, and propagate cancellation to active children.

Fixes #2477
Addresses AGT-3492

Co-authored-by: Dan Tran <7690403+dtran26@users.noreply.github.com>
@chenghao-mou chenghao-mou added the review_effort:high Cross-cutting or subtle changes requiring broad context and substantial validation label Sep 11, 2026
@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e82da41

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 Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic 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-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-meta 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-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai 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

@chenghao-mou
chenghao-mou marked this pull request as ready for review September 11, 2026 09:19
@chenghao-mou
chenghao-mou requested a review from a team as a code owner September 11, 2026 09:19

@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.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Wrap retryable failures after output in a non-retryable APIError instead of
changing connection options. Keep the provider error as cause and preserve
errors that are already terminal.

Co-authored-by: Dan Tran <7690403+dtran26@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Make APIError.retryable writable so fallback can stop outer retries without
replacing the provider error. Preserve its class, identity, and metadata;
remove the wrapper and cause support added for it.

Co-authored-by: Dan Tran <7690403+dtran26@users.noreply.github.com>

@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 found 1 new potential issue.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

{ llm: llm.label(), ...extra },
'failed after sending chunk, skip retrying. Set `retryOnChunkSent` to `true` to enable.',
);
if (error instanceof APIError) error.retryable = false;

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.

🟡 Shared provider errors lose retries

When a provider reuses an APIError, FallbackAdapter permanently marks it terminal after one partial response. Later requests receiving that instance skip configured retries without emitting output.

Learn more

The provider creates and owns the error object. Marking that object non-retryable stores request-specific fallback state on an object that can outlive this stream. Any later stream that throws the same instance enters LLMStream, sees retryable === false, and terminates immediately.

Example: A provider caches one APITimeoutError and throws it for two requests. The first request emits text before failing, so fallback changes the cached error. The second request fails before output, but its configured outer retry never runs because the cached error remains non-retryable.

Recommended fix: Keep the terminal-after-output decision on this FallbackLLMStream or its parent retry state instead of mutating the provider error. Preserve the original error instance when emitting it, while explicitly telling the outer LLMStream not to retry this stream failure.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review_effort:high Cross-cutting or subtle changes requiring broad context and substantial validation

Projects

None yet

1 participant