fix(ai): delegate lazy stream watchdogs to transports and bound Responses/Azure setup - #3829
Merged
Yeachan-Heo merged 2 commits intoAug 5, 2026
Conversation
The lazy provider wrapper watched normalized assistant events while several providers already watched richer raw transport events. That second clock could expire after transport-only progress, replace a live response with a blank generic stall error, and race provider-specific failure handling. Providers with raw watchdogs now own timeout decisions; the shared wrapper remains for providers that need it. OpenAI Completions now honors caller idle overrides internally, Azure shares the semantic Responses progress filter, and provider-owned paths preserve caller cancellation. Lore-id: e4a32f9c Constraint: providers without raw transport watchdogs retain the shared lazy watchdog Rejected: raise the global timeout | masks watchdog ownership and delays genuine stalls Confidence: high Scope-risk: medium Reversibility: code-only Tested: packages/ai check; 2153 package tests and 10224 assertions; 115 timeout and concurrency tests Not-tested: live provider outage recovery
Delegating lazy-stream watchdogs to transports removed the outer first-event clock, but Responses and Azure only armed their idle iterator after create() returned. A never-resolving pre-headers fetch could then wait the SDK default (10 minutes) before any provider watchdog existed. Map streamFirstEventTimeoutMs into the OpenAI/Azure SDK request timeout via a shared helper (Completions parity), and normalize pre-connect Azure SDK timeouts to typed stream_first_event_timeout. Keep transport-owned idle progress after the stream arms. Lore-id: b7c4e19a Constraint: keep provider-owned raw-event idle after create() returns Constraint: Completions-style explicit-vs-fallback SDK timeout rules Rejected: re-enable outer first-event for all provider-owned paths | dual clocks race transport progress Confidence: high Scope-risk: medium Reversibility: code-only Tested: packages/ai check; openai-first-event-timeout, register-builtins, stream-timeout-defaults Not-tested: live Azure/Responses hung-header outage recovery
9 tasks
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
Replaces closed PR #3708 (same branch/intent; force-push after close prevented reopen). Addresses the exact-head REQUEST_CHANGES feedback on setup/first-event parity.
The lazy provider wrapper measured idle time from normalized assistant events while OpenAI-family providers already watched richer raw transport events. Transport-only progress could refresh only the provider watchdog, so the outer wrapper aborted an active stream first and replaced a live response with a blank generic stall error.
This series:
PROVIDER_OWNED_STREAM_WATCHDOG).iterateWithIdleTimeoutaftercreate()returned. MapstreamFirstEventTimeoutMsinto the SDK request timeout (Completions parity) so a never-resolving pre-headers fetch cannot sit on the ~10m SDK default before any transport watchdog exists. Pre-connect Azure SDK timeouts normalize to typedstream_first_event_timeout.Changes
toolChoiceIncapabilityinside the first-event window.resolveOpenAISdkRequestTimeoutMs()helper; Completions/Responses/Azure use it for setup bounds.Test plan
bun --cwd=packages/ai run check— passbun test packages/ai/test/openai-first-event-timeout.test.ts packages/ai/test/register-builtins.test.ts packages/ai/test/stream-timeout-defaults.test.ts— 58 pass, 0 failNotes