镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix(a2a-server): preserve canceled streaming task status - #1447

Open
Hugo-DDT wants to merge 1 commit into
VoltAgent:mainfrom
Hugo-DDT:fix/a2a-stream-cancellation
Open

Hugo-DDT wants to merge 1 commit into
VoltAgent:mainfrom
Hugo-DDT:fix/a2a-stream-cancellation

Conversation

@Hugo-DDT

@Hugo-DDT Hugo-DDT commented Oct 11, 2026 •

Copy link
Copy Markdown

PR Checklist

Bugs / Features

  • Related issue(s) linked — independently reproduced; no issue has been opened.
  • Tests for the changes have been added.
  • Docs have been added / updated — no public API change.
  • Changesets have been added.

What is the current behavior?

After tasks/cancel returns a canceled task, message/stream can overwrite that task with completed if the agent's iterator ends normally on abort. A buffered chunk arriving after cancellation is also appended. Cancellation before the agent call or while awaiting completion metadata can similarly be ignored.

The existing cancellation test covers an iterator that throws on abort, which reaches the cancellation handler. Normal iterator completion bypasses that handler.

What is the new behavior?

Check the AbortSignal before starting the agent, after stream initialization, before accepting chunks, after iteration, and before saving the completed result. An aborted operation uses the existing cancellation handler and cleanup path.

Extend the cancellation test to cover throwing, normal completion, and a late chunk. Add cases for cancellation before the agent call and while awaiting completion metadata. Check both final stream events and persisted task status.

Notes for reviewers

On baseline 72a46c76b4507e1f98b41d5050a92bd30587eb70, the new regression cases produced four failures. With this fix, all 13 A2A package tests pass. Local type checking, CJS/ESM/declaration builds, Biome checks for the two changed TypeScript files, and git diff --check also pass.

Validation used a separate pinned npm toolchain because the workspace's frozen pnpm installation failed with connection resets from the configured npm mirror. Core/internal dependencies were published packages at the same versions as the workspace manifests. The complete workspace dependency installation and CI were not validated. Tests use a stub agent and the in-memory task store; no live provider was exercised.

This patch preserves cancellation at the covered stream boundaries. It does not add transactional concurrency guarantees for custom asynchronous task stores. Preparation and local validation were AI-assisted.


Summary by cubic

Fixes @voltagent/a2a-server overwriting a canceled task with completed when the agent stream ends normally on abort, and prevents a buffered chunk from being appended after cancellation.

  • Checks the AbortSignal before starting the agent, after stream initialization, before accepting chunks, after iteration, and before saving the completed result; an aborted operation reuses the existing cancellation handler and cleanup path.
  • Extends cancellation tests to cover throwing iterators, normal completion, late chunks, cancellation before the agent call, and cancellation while awaiting completion metadata, asserting both final stream events and persisted task status.

Written for commit 2fac930. Summary will update on new commits.

View guided diff

Summary by CodeRabbit

  • Bug Fixes
    • Canceled tasks now remain canceled if a stream ends normally or produces a late update.
    • Canceling before streaming begins prevents the stream from starting.
    • Cancellation remains effective while completion details are being retrieved.

Copilot AI balanced review requested due to automatic review settings October 11, 2026 06:47
@changeset-bot

changeset-bot Bot commented Oct 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2fac930

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/a2a-server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7ae978ad-a010-4a24-86cf-6bdf3a8c4fb5

📥 Commits

Reviewing files that changed from the base of the PR and between 72a46c7 and 2fac930.


📒 Files selected for processing (3)
  • .changeset/a2a-stream-cancellation.md
  • packages/a2a-server/src/server.spec.ts
  • packages/a2a-server/src/server.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.



📝 Walkthrough

Walkthrough

The A2A stream generator now checks for cancellation before and during agent streaming, after chunk consumption, and before saving the completed task. Tests cover cancellation at these points and across several stream outcomes.

Changes

A2A stream cancellation

Layer / File(s) Summary
Cancellation checks during stream generation
packages/a2a-server/src/server.ts, packages/a2a-server/src/server.spec.ts, .changeset/a2a-stream-cancellation.md
The generator checks for cancellation before agent generation, after stream creation, before processing chunks, and after chunk consumption. Tests cover rejected, normally ended, and late-chunk streams, plus cancellation before consumption. The changeset records the patch.
Cancellation checks during task completion
packages/a2a-server/src/server.ts, packages/a2a-server/src/server.spec.ts
The generator checks for cancellation before saving and yielding the completed task. A test checks that cancellation remains the final stream event and stored task state after completion metadata resolves.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix


Merge Risk: ⚪ Minimal · up to 2fac9

This change keeps a canceled streaming task canceled instead of overwriting it with completed or appending a late chunk. No actionable merge-blocking risk was found. Custom asynchronous task stores can still race on the final save, which the PR states is out of scope.

Pre-merge checks | Passed 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check Passed The title is concise and clearly describes the primary change: preserving canceled streaming task status in the A2A server.
Description check Passed The description includes the required checklist, current behavior, new behavior, and reviewer notes. It also explains why issue linking and documentation updates do not apply, and it reports tests and…
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/a2a-server/src/server.ts">

<violation number="1" location="packages/a2a-server/src/server.ts:405">
P2: A custom asynchronous `TaskStore.save` can pause after this check; cancellation during the save still reaches the unconditional completed `yield`. Recheck after each stream save so the abort path emits the canceled record instead of a stale event.</violation>
</file>

Reply to a comment to ask cubic a question or push back. It learns from your replies.

View guided diff | Re-trigger cubic

let aggregatedText = "";

try {
abortController.signal.throwIfAborted();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: A custom asynchronous TaskStore.save can pause after this check; cancellation during the save still reaches the unconditional completed yield. Recheck after each stream save so the abort path emits the canceled record instead of a stale event.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/a2a-server/src/server.ts, line 405:

<comment>A custom asynchronous `TaskStore.save` can pause after this check; cancellation during the save still reaches the unconditional completed `yield`. Recheck after each stream save so the abort path emits the canceled record instead of a stale event.</comment>

<file context>
@@ -402,6 +402,7 @@ export class A2AServer {
       let aggregatedText = "";
 
       try {
+        abortController.signal.throwIfAborted();
         const voltMessage = toVoltAgentMessage(normalizedMessage);
         const agentOptions = server.buildAgentCallOptions({
</file context>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants