Skip to content

AbortSignal is unconditionally cleared when resumableStream is enabled, making stop/cancel non-functional #1239

@lzj960515

Description

@lzj960515

Bug Description

When resumableStream is enabled on a chat request, the server-core handler unconditionally sets options.abortSignal = undefined, making it impossible for clients to cancel an in-progress generation. Clicking "Stop" in the UI only stops the client-side stream display — the backend LLM continues running to completion.

Root Cause

In packages/server-core/src/handlers/agent.handlers.ts:

```typescript
if (resumableStreamEnabled) {
options.abortSignal = undefined; // <-- AbortSignal is discarded
}
```

The comment indicates this was intentional (to support reconnection), but it has the side effect of making cancellation completely non-functional when resumable streams are in use.

Expected Behavior

Clients should be able to cancel an in-progress LLM generation even when resumableStream: true is set. The two concerns (resumability and cancellability) should be independent.

Suggested Fix

Instead of discarding the AbortSignal, the handler could:

  1. Use a composite signal — create an internal AbortController for the LLM call, and abort it when either the client's signal fires or a new cancel API endpoint is called. The resumable stream adapter can then clean up independently.

  2. Expose a cancel endpoint — add DELETE /agents/:id/chat/:conversationId (similar to POST /workflows/:id/executions/:executionId/cancel for workflows) that aborts the active generation and calls clearActiveStream.

Either approach decouples cancellation from the stream transport layer.

Steps to Reproduce

  1. Enable resumable streams: send a chat request with options.resumableStream: true
  2. Start a long-running generation
  3. Call the stop/abort action (client-side AbortController.abort() or disconnect)
  4. Observe: the backend LLM generation continues until completion

Environment

  • VoltAgent server-core (checked against current main)
  • Reproduces with any LLM provider (OpenAI, Anthropic, etc.)

Related Code

  • packages/server-core/src/handlers/agent.handlers.ts — where abortSignal is cleared
  • packages/server-core/src/utils/options.ts — where the signal is initially set
  • packages/server-core/src/handlers/workflow.handlers.ts — workflows already have a proper cancel endpoint as a reference implementation

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