Skip to content

Port timeout.firstChunkMs for streamText - #712

Merged
kblok merged 2 commits into
mainfrom
port-first-chunk-timeout
Oct 21, 2026
Merged

kblok merged 2 commits into
mainfrom
port-first-chunk-timeout

Conversation

@kblok

@kblok kblok commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

streamText now honors TimeoutConfiguration.FirstChunkMs. It aborts a step with a TimeoutError ("First chunk timeout of Nms exceeded") when the provider returns its response stream but no content arrives in time. Chunks without output (response metadata, raw chunks, empty deltas) do not stop the timer. The first text, reasoning, tool input, or tool call chunk disarms it, and each step starts a fresh budget. The end of the model response, a provider stream error, and the end of the step also clear it. GenerateTextAsync has no stream, so it logs the upstream "only supported by streaming functions" warning, together with the chunkMs one when both are set.

Part of #702.

.NET-only symbols: none. TimeoutConfiguration.FirstChunkMs mirrors firstChunkMs.

Not ported

Tracked in #702.

  • streamText first chunk timeout::should clear firstChunkMs when the registered step stream is cancelled (stream-text-timeout.test.ts; the port has no experimental_transform / stopStream)
  • packages/ai/src/prompt/prepare-language-model-call-options.test.ts::timeout helpers (from request-options) > getStepTimeoutMs::should return stepMs from an object (the port has no getStepTimeoutMs; callers read TimeoutConfiguration.StepMs)
  • packages/ai/src/prompt/prepare-language-model-call-options.test.ts::timeout helpers (from request-options) > getFirstChunkTimeoutMs::should return undefined when timeout is undefined (no getFirstChunkTimeoutMs; callers read FirstChunkMs)
  • packages/ai/src/prompt/prepare-language-model-call-options.test.ts::timeout helpers (from request-options) > getFirstChunkTimeoutMs::should return undefined when timeout is a number (same reason; a TimeSpan converts to TotalMs only)
  • packages/ai/src/prompt/prepare-language-model-call-options.test.ts::timeout helpers (from request-options) > getFirstChunkTimeoutMs::should return firstChunkMs from an object (same reason)
  • The file and reasoning file cases of "should disarm firstChunkMs before forwarding the first ${name}" (the port has no file stream part).

Still open in #702: toolMs, per-tool timeouts, the stream retry tests, and AgentOptions.Timeout.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TQmtUKfZTs497KkiGSfYk9

Summary by CodeRabbit

  • New Features

    • Added FirstChunkMs to configure a streaming timeout for receiving the first content chunk from each generation step.
    • First-chunk timeouts ignore metadata and empty chunks, reset for each step, and stop when content arrives or the stream ends.
  • Bug Fixes

    • Improved timeout handling when streaming completes or encounters provider errors.
    • Added clearer warnings when streaming-only timeout settings are used with non-streaming generation.
  • Documentation

    • Updated timeout configuration and quickstart documentation to describe FirstChunkMs and its streaming-only behavior.

kblok and others added 2 commits October 21, 2026 17:06
…its start

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQmtUKfZTs497KkiGSfYk9
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: hardkoded/vercel-ai-sdk-dotnet/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a66961d3-0fac-4dee-9fab-00de81598339
📥 Commits

Reviewing files that changed from the base of the PR and between 4144b33 and 2d6fbf5.

📒 Files selected for processing: 7
  • docs/articles/quickstart.md
  • src/Vercel.AI/Generation.cs
  • src/Vercel.AI/Prompt/TimeoutConfiguration.cs
  • src/Vercel.AI/PublicTypes.cs
  • src/Vercel.AI/Util/CallTimeouts.cs
  • tests/Vercel.AI.Tests/Upstream/GenerateText/OptionsTimeoutTests.cs
  • tests/Vercel.AI.Tests/Upstream/GenerateText/StreamTextTimeout/StreamTextFirstChunkTimeoutTests.cs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

📝 Walkthrough

Streaming generation now supports a per-step timeout that runs until the first content chunk arrives. Non-output chunks do not end the timeout. Non-streaming generation warns when either streaming-only timeout is configured.

Changes: First-chunk timeout

Layer / File(s) Summary
Timeout configuration and setup
src/Vercel.AI/Prompt/TimeoutConfiguration.cs, src/Vercel.AI/Util/CallTimeouts.cs, src/Vercel.AI/PublicTypes.cs
TimeoutConfiguration adds FirstChunkMs. CallTimeouts creates its controller for streaming calls and includes it in merged abort signals.
Streaming timeout lifecycle
src/Vercel.AI/Generation.cs, src/Vercel.AI/Util/CallTimeouts.cs, tests/Vercel.AI.Tests/Upstream/GenerateText/StreamTextTimeout/StreamTextFirstChunkTimeoutTests.cs
Streaming starts the timeout before consuming model output. It clears on first output, step completion, cleanup, or error, and re-arms for each step. Tests cover non-output chunks, output types, multiple steps, and provider errors.
Unsupported-timeout warnings and documentation
src/Vercel.AI/Generation.cs, tests/Vercel.AI.Tests/Upstream/GenerateText/OptionsTimeoutTests.cs, docs/articles/quickstart.md
Non-streaming generation warns separately for FirstChunkMs and ChunkMs. Tests cover each warning and their combined order. The quickstart describes the timeout behavior.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant StreamTextAsync
  participant Provider
  participant ResponseStream
  participant CallTimeouts
  StreamTextAsync->>Provider: Request model response stream
  Provider-->>StreamTextAsync: Return response stream
  StreamTextAsync->>CallTimeouts: StartFirstChunk()
  StreamTextAsync->>ResponseStream: Read stream parts
  ResponseStream-->>StreamTextAsync: Emit first content chunk
  StreamTextAsync->>CallTimeouts: OnOutputChunk()
Loading

Possibly related issues

  • Issue 702 requests firstChunkMs for streamText; this change implements that timeout and its warning behavior.
  • Issue 697 covers streamText timeout options and unported timeout tests; this change implements the firstChunkMs portion.
Merge Risk: ⚪ Minimal · up to 2d6fb

The first-output deadline interrupts a stalled stream as intended. No identified issue blocks merging after normal checks.

Security architecture risk: 🔵 Low · up to 2d6fb

The timeout is opt-in and confined to one generation call. Normal cleanup and cancellation paths are wired, but concurrent timer expiry and provider-specific cancellation behavior remain unverified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The new abort authority is scoped to one generation call and inherited by its later steps through a shared signal. Expiry faults that call's result tasks and cancels its token; the inspected change does not introduce a cross-call controller or additional tool authority.

Trust Boundaries and Controls

  • observed — A provider cannot keep the first-output deadline alive indefinitely using only metadata or empty deltas. A qualifying output part intentionally ends this deadline, so FirstChunkMs alone is not a whole-response execution budget.

Resilience and Maintainability Implications

  • observed — Each provider read is raced against the call's abort signal, allowing timeout handling to proceed without waiting for a noncooperative read. Stopping the provider's underlying work still requires cancellation cooperation. An atomic completion guard prevents a later abort from replacing an already selected successful outcome.

Hardening Proposals

  • proposed — If strict step-local expiry arbitration is required, use one atomic ownership decision for timer expiry and retirement. The existing scheduler checks cancellation outside the lifecycle lock and does not join an executing callback; strengthening that behavior would make boundary-time cleanup guarantees explicit rather than scheduling-dependent.
Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely identifies the main change: adding timeout.firstChunkMs support to streamText.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Upstream Parity Passed PASS. The PR names upstream tests and behavior, so the check applies. TimeoutConfiguration.FirstChunkMs maps to upstream firstChunkMs; the timeout lifecycle and generate warning match `vercel/ai@d…
Full details: Upstream Parity

Explanation

PASS. The PR names upstream tests and behavior, so the check applies. TimeoutConfiguration.FirstChunkMs maps to upstream firstChunkMs; the timeout lifecycle and generate warning match vercel/ai@dfcace2a3e7f3016ccb0e3c7e3a5b8103c8967b4 (packages/ai/src/prompt/request-options.ts, generate-text.ts, and stream-text.ts). The port includes the warning tests and the four supported first-chunk tests. It marks the upstream file and reasoning-file cases as Partial and lists both omissions with the reason that the .NET port has no file stream part. The changed user-visible API and behavior are documented in docs/articles/quickstart.md; COMPATIBILITY.md is unchanged, so the pin-move condition does not apply. No unapproved .NET-only behavior or unmapped source symbol is introduced.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@kblok
kblok merged commit 393afe7 into main Oct 21, 2026
2 checks passed
@kblok
kblok deleted the port-first-chunk-timeout branch October 21, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-tag Ready to tag a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant