voice: retry missing run outputs - #1978
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: 129a15c The changes in this PR will be included in the next version bump. This PR includes changesets to release 36 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 |
- Surface a failed retry generateReply (e.g. session closing) as the UnexpectedModelBehavior rejection's cause instead of hiding it behind the schema-mismatch message - Fall back to the zod schema class name in the retry warning; .description is undefined for schemas without .describe() - Remove unreachable try/catch around the retry warning (a RunResult with a session always has an initialized logger) - Document that outputOptions: null disables retries, and the deliberate divergence from Python: a task completed with null is not retryable - Add tests covering retry-then-success, retry exhaustion, the null opt-out, and custom maxRetries/retryInstructions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
toubatbrian
approved these changes
Jul 7, 2026
Merged
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
AgentSession.run({ outputType })RunOutputOptionswithmaxRetriesandretryInstructionsUnexpectedModelBehaviorwhen structured output remains missing or invalidValidation
pnpm buildpnpm vitest run agents/src/voice/testing/run_result.test.tspnpm eslint agents/src/_exceptions.ts agents/src/voice/agent_session.ts agents/src/voice/index.ts agents/src/voice/testing/index.ts agents/src/voice/testing/run_result.ts(passes with one pre-existing warning inagent_session.ts:343)cue-clitext-mode smoke against a temporary JS worker: greeting and user turn resolved with assistantconversation_item_addedframework eventsNotes
pnpm api:checkis blocked by existing repo issues: missingapi-extractor.jsonin some plugin packages; focusedpnpm --filter @livekit/agents api:checkis blocked by the existing API Extractor limitation onexport * as ___indist/index.d.ts.Ported from livekit/agents#6080
Original PR description
A run with an
output_typeends withfinal_output=Nonewhenever the model finishes its turn in prose instead of calling the task's completion tool — common with chatty models, and currently surfaced as a genericRuntimeErrorthat callers can't distinguish or recover from.Following pydantic-ai's output-tool semantics:
New
output_optionsonrun()(an options TypedDict in the style ofkeyterm_options/expressiveness): when the run ends without itsoutput_type, the session re-prompts in the same context as a per-turn system message (max_retries, default 2) before raising;retry_instructionsoverrides the built-in retry prompt.A distinct
UnexpectedModelBehavior(exported fromlivekit.agents, same name as pydantic-ai's) replaces the generic RuntimeError once the budget is exhausted, so callers can catch the failure specifically.Defaults convert the dominant failure (model summarizes in prose) into a recovered run. Unit tests cover recovery, the prompt override, and exhaustion via FakeLLM.
🤖 Generated with Claude Code