feat(ai): add a timeout option to chat(), matching the media activities
Maintainer thường phản hồi trong vòng 1 ngày
@AlemTuzlak đang làm issue này rồi.
Từ ngày 26/9/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Problem
#981 / #1047 gave the media activities and summarize a shared timeout contract: timeout + abortSignal, composed by createActivityAbortControls. chat() never got one.
packages/ai/src/utilities/activity-abort.ts provides createActivityAbortControls({ abortSignal, timeout }), combineAbortSignals, raceWithAbort and isActivityAbortError. Together they compose the timeout with the caller signal into one effective signal and race the adapter call, so a hung provider still rejects. They also clear the timer on settle and route the abort to middleware onAbort rather than onError. Every generate* activity and summarize uses them.
chat() takes only abortController (activities/chat/index.ts L1019-L1022), keeps its own private copy of combineAbortSignals, and has no timeout option. The abortController doc in types.ts suggests building a timeout by hand with setTimeout(() => abortController.abort(), 5000). So a chat stream that never sends headers, or starts and then goes silent, is bounded only by whatever the caller aborts with.
Provider SDK timeouts don't reliably fill the gap either. Some of them drop their own timeout once a signal is passed, and adapters pass the chat signal down. For example, @openrouter/sdk applies timeoutMs only when no signal is present (OpenRouterTeam/typescript-sdk#1123). A core-level timeout composed into the signal avoids that for every adapter.
Verified in @tanstack/ai 0.58.0 and on main at 3e30cde.
Proposal
await chat({
adapter,
messages,
timeout: 30_000,
abortController,
})
timeout?: number: the maximum duration in ms of onechat()invocation, with no default. It would be built oncreateActivityAbortControls, and the effective signal passed to the adapter the same way the media activities do it.chat()would also use the sharedcombineAbortSignals.- Because adapters may ignore the signal, the stream's reads should also be raced against it (the
raceWithAbortidea applied pernext()), so a stalled iterator still rejects. - A timeout is an abort for middleware (
onAbort, notonError), with a distinguishable reason: the existingTimeoutErrorfromcreateTimeoutReason. Callers can then tell "timed out" from "caller aborted" and fall back to another model or retry. - The timer is cleared when the run settles.
Follow-up (or an option in the same change): streaming deadlines
For long reasoning or streaming outputs, a total cap has to be set high enough not to cut off legitimate slow answers, and then it catches stalls late. Two opt-in deadlines would complement timeout:
- a first-chunk timeout: from request start to the first parsed stream chunk;
- an idle timeout: the maximum gap between parsed chunks.
"Chunk" here means a parsed StreamChunk reaching core. SSE keep-alive comments may be dropped by the adapter or SDK before core sees them, so they neither count as progress nor mask a stall. For tool loops, these deadlines would re-arm for each model call.
Motivation
In a production app running many parallel structured chat() calls per request, a rare provider hang held one call until the whole request's deadline (80-118s observed) instead of failing fast and falling back to another model. The workaround today is an app-level AbortController + setTimeout at every call site. That doesn't get onAbort timeout classification, and it duplicates what createActivityAbortControls already does.
Tests (mirroring #1047)
- A timeout aborts a hung
chatStream, including one that ignores the signal. - The first of caller abort or timeout wins and keeps its reason.
- A timeout triggers
onAbortexactly once, notonError. - Completion clears the timer.
- Ngôn ngữ chính
- TypeScript
- Star
- 3.1k
- Fork
- 340
- Merge trung bình
- 2 ngày 11 giờ
- Pull request đã merge (30 ngày)
- 170
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của TanStack/ai
-
otelMiddleware: media generation spans never capture prompt, input media or output, even with captureContentCó thể đã có người làm @AlemTuzlak đã nhận 1 ngày trước. Đang mởwaiting-on: maintainer
TanStack/ai#1526 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
otelMiddleware: captureContent drops image/audio/video/document parts, recording only '[image]' placeholdersCó thể đã có người làm @AlemTuzlak đã nhận 1 ngày trước. Đang mởhas-pr waiting-on: maintainer
TanStack/ai#1525 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Does a hosted provider package have to carry a key?Có thể đã có người làm @AlemTuzlak đã nhận 2 ngày trước. Đang mởwaiting-on: author
TanStack/ai#1506 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Client tools never execute against spec-compliant AG-UI servers (plain `success` RUN_FINISHED)Có thể đã có người làm @jherr đã nhận 4 ngày trước. Đang mởwaiting-on: maintainer
TanStack/ai#1464 · 1 reaction · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Add ai to awesome-ai-plugins?Có thể đã có người làm @tombeckenham đã nhận 10 ngày trước. Đang mởwaiting-on: maintainer
TanStack/ai#1382 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Issue tương tự
-
bug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
StabilityNexus/Fate-EVM-Frontend#153 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
code-yeongyu/oh-my-openagent#9039 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Tencent/teamai-cli#862 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug good first issue hacktoberfest redis
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
libredb/libredb-studio#1164 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
flake
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
coder/xum#4920 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày