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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions