feat(agent): cancellation, timeouts, typed errors, and lifecycle helpers#13
Merged
Merged
Conversation
Hardens CoderAgent based on external integration feedback (durable deep-research fan-out on Vercel Workflow), then a quality + correctness pass. - abortSignal now interrupts the *server* run (not just the local socket); a stream cancel() interrupts too, so wedged turns stop holding their workspace. - requestTimeoutMs: per-segment time budget that interrupts and rejects with a retryable CoderChatError (kind: "timeout") instead of hanging. - A stream that ends before the turn settles now rejects with a retryable CoderChatError (kind: "stream_closed") rather than reporting a truncated result as a clean stop; transport errors and server error events are classified into typed, retryable errors too. - CoderAgent.listModels() to discover model hints. - await using support via Symbol.asyncDispose (interrupt + archive on scope exit). - Warn when responseFormat/JSON-schema output is requested (unsupported server-side; use @coder/ai-sdk-provider + generateObject instead). - Docs: Agent-vs-provider decision guide, error handling, workspaces/quota, durable-workflow recipe, and timeout semantics. Change-Id: I19e900ea5a4e8d7c8ff34813ae5f47399dc5d28d Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
This was referenced Jun 24, 2026
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.
Why
An external team integrated
@coder/ai-sdk-agentinto a durable deep-researchfan-out (Vercel Workflow) and reported that the friction was concentrated in
cancellation, timeouts, quota visibility, error typing, and lifecycle. This PR
hardens those paths, then adds a quality + correctness pass on top.
What changed
Cancellation & timeouts
abortSignalnow interrupts the server-side run, not just the localWebSocket — a wedged turn stops generating and releases its workspace instead
of running on, orphaned. Tearing down a
stream()(cancel) interrupts too.requestTimeoutMs: a per-segment time budget. On expiry the run isinterrupted and the call rejects with a retryable
CoderChatError(
kind: "timeout") instead of hanging. Documented as per-segment, withabortSignal: AbortSignal.timeout(ms)for total wall-clock.Typed, retryable errors
CoderChatError(
kind: "stream_closed", retryable) rather than reporting a truncated resultas a clean
stop.errorevents are classified into typed,retryable errors (no more bare
DOMException/non-retryable transport errorsbypassing the documented retry contract).
API & lifecycle
CoderAgent.listModels()to discover validmodelhints.await usingsupport viaSymbol.asyncDispose(interrupt + archive on scopeexit), so cleanup rides scope exit instead of a forgotten
finally.responseFormat/JSON-schema output is requested — chatd doesnot constrain output server-side; use
@coder/ai-sdk-provider+generateObjectinstead.Docs
workspaces & quota, a durable-workflow recipe, and timeout/cleanup semantics.
Process
Built from the integration feedback, then refined with a
/simplifypass and amax-effort
/code-reviewpass. The review caught a real regression the simplifypass had introduced (a caller's own
AbortSignal.timeoutbeing misclassified asthe agent's timeout) plus several edge cases in the new error/interrupt paths —
all fixed here, each with a regression test.
Testing
@coder/ai-sdk-agent(8 new, covering abort→interrupt,timeout, stream-close, transport error, caller-timeout classification, cancel,
and the responseFormat warning); 178 across the repo. All green.
pnpm check(format + lint + typecheck) andpnpm buildpass.Known follow-ups (out of scope)
createChatleaves a chat whose id we never received, so itcan't be interrupted — needs client-generated ids or a reconcile sweep.
requires_actionsafety-counter (pre-existing) can finish a turn astool-callswith no tool calls ifaction_requirednever arrives.🤖 Generated with Claude Code