Skip to content

fix(ai): delegate lazy stream watchdogs to transports and bound Responses/Azure setup - #3829

Merged
Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
innocarpe:fix/provider-stream-stall-progress-timeout
Aug 5, 2026
Merged

fix(ai): delegate lazy stream watchdogs to transports and bound Responses/Azure setup#3829
Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
innocarpe:fix/provider-stream-stall-progress-timeout

Conversation

@innocarpe

@innocarpe innocarpe commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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:

  1. Lets Anthropic, OpenAI, and Azure paths with raw transport watchdogs own timeout decisions (PROVIDER_OWNED_STREAM_WATCHDOG).
  2. Closes the review gap: Responses/Azure only armed iterateWithIdleTimeout after create() returned. Map streamFirstEventTimeoutMs into 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 typed stream_first_event_timeout.

Changes

  • Let Anthropic, OpenAI, and Azure paths with raw transport watchdogs own timeout decisions.
  • Retain the lazy wrapper watchdog for providers without a transport watchdog.
  • Keep toolChoiceIncapability inside the first-event window.
  • Honor caller-supplied OpenAI Completions idle timeout overrides.
  • Apply semantic Responses progress filtering and caller abort propagation to Azure Responses.
  • Shared resolveOpenAISdkRequestTimeoutMs() helper; Completions/Responses/Azure use it for setup bounds.
  • Lazy-path regression coverage for fetch that never resolves before headers (typed provider code + caller abort).

Test plan

  • bun --cwd=packages/ai run check — pass
  • bun 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 fail
  • Live hung Azure/Responses header outage recovery (not run)

Notes

  • Keeps transport-owned idle progress after the stream arms.
  • Does not re-enable a racing outer first-event clock on all provider-owned paths (review rejected that dual-clock approach).

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
@innocarpe innocarpe changed the title fix(ai): delegate lazy stream watchdogs to transports fix(ai): delegate lazy stream watchdogs to transports and bound Responses/Azure setup Aug 5, 2026
@Yeachan-Heo
Yeachan-Heo merged commit 0fdbb5e into Yeachan-Heo:dev Aug 5, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants