Skip to content

Think: expose the turn's AbortSignal to beforeTurn #2309

Closed

Description

@banchichen

Problem

Think.beforeTurn(ctx) may await I/O or a model call before streamText starts. If the user stops the turn during that wait, the hook has no way to observe the cancellation: TurnContext does not expose an AbortSignal. The turn can therefore remain in preparation until the awaited work finishes or times out.

The signal already exists in _prepareInferenceInvocation(input): the hook context is built without it, while the same input.signal is passed to streamText later. The public TurnContext type has no corresponding field.

Requested API

Expose the turn's signal to subclass beforeTurn hooks:

interface TurnContext {
  // existing fields...
  abortSignal?: AbortSignal;
}

const ctx: TurnContext = {
  // existing fields...
  abortSignal: input.signal,
};

Optional matches TurnInput.signal? and preserves callers without a signal. A subclass can pass it to abortable I/O, stop waiting promptly, and return from beforeTurn at a safe boundary. Some preparation writes should finish atomically, so exposing the signal is more useful than automatically racing and abandoning the entire hook. This request is for the in-process subclass hook; it does not require sending an AbortSignal through extension RPC snapshots.

Use case

We currently carry this one-field patch on @cloudflare/think@0.17.0. Our beforeTurn may wait for image-history previews (up to 8 seconds) or a history-summary model call (up to 30 seconds). Before the patch, Stop could not interrupt those waits. With the signal threaded through the waits, a local full-stack test using the real WebSocket cancel frame ended the two stopped turns in 7 ms and 29 ms, and both conversations handled a subsequent turn normally.

Related: #2240 also requests a field on TurnContext, but for request correlation rather than cancellation.

Activity

  1. banchichen commented on Sep 21, 2026

    @banchichen
    Author

    I implemented this as a small patch on my fork: compare the branch against main (commit). It exposes input.signal as optional TurnContext.abortSignal, documents its use in beforeTurn, and adds a Workers regression test that cancels during the hook and verifies a later turn still succeeds.

    Validation passed: Think build, all 229 tests in think-session.test.ts, Think typecheck, repository formatting, and lint. The full pnpm run check stops at check:exports because my filtered install has no build outputs for three unrelated packages.

    I tried to open a PR, but GitHub says this repository limits PR creation to collaborators. If a maintainer can open a PR from this branch or enable PR creation for my account, I'm happy to follow through with review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions