Skip to content

fix: rename Blocking to ReturnImmediately and implement return-immediately behavior#339

Open
rokonec wants to merge 2 commits intoa2aproject:mainfrom
rokonec:fix/329-return-immediately
Open

fix: rename Blocking to ReturnImmediately and implement return-immediately behavior#339
rokonec wants to merge 2 commits intoa2aproject:mainfrom
rokonec:fix/329-return-immediately

Conversation

@rokonec
Copy link
Collaborator

@rokonec rokonec commented Mar 25, 2026

Summary

Addresses two issues from #329:

  1. Property rename: SendMessageConfiguration.BlockingReturnImmediately to match the A2A v1 spec wire format "returnImmediately" (proto field return_immediately).
  2. Server behavior: Implement return-immediately execution mode in A2AServer.SendMessageAsync — when ReturnImmediately = true, the server returns the first Task event immediately and continues processing in the background.

Also fixes agent card discovery and sample bugs discovered during validation.

Changes

Core SDK

  • SendMessageConfiguration.ReturnImmediately — Renamed from Blocking with inverted semantics. Default false = blocking (wait for completion), matching spec Section 3.2.2.
  • A2AServer.SendMessageAsync — Checks ReturnImmediately, returns first Task event immediately via new MaterializeReturnImmediatelyResponseAsync method. Background drain continues applying events to the task store.
  • A2AServer : IAsyncDisposable — Background tasks tracked in ConcurrentDictionary for cancellation via tasks/cancel and graceful shutdown via DisposeAsync().
  • RequestContext.Configuration — Propagated from SendMessageRequest so agents can inspect ReturnImmediately and adapt behavior.
  • Log.BackgroundEventProcessingFailed — Source-generated log method (event ID 3) for background drain errors.

Agent Card Discovery

  • MapA2A() — Now registers /.well-known/agent-card.json at both the domain root (spec Section 8.2) and the path prefix (backward compat).

Samples

  • EchoAgentWithTasks — Simulates slow work when ReturnImmediately = true; added Working case for task-target-state metadata.
  • TaskBasedCommunicationSample — Added DemoReturnImmediatelyAsync showing send → immediate response → poll for completion.
  • Program.csbaseUrl derived from --urls arg so agent cards match actual listening port. Removed speccompliance-only MapWellKnownAgentCard special case.
  • Metadata fixtask-target-state serialized as "Working" string instead of "TASK_STATE_WORKING" enum value.

Tests (6 new)

  • Return-immediately with slow handler returns non-terminal state
  • Message response unaffected by returnImmediately
  • Background processing completes with artifacts
  • Explicit blocking mode waits for completion
  • CancelTaskAsync cancels background return-immediately handler
  • DisposeAsync cancels background work on shutdown

Validation

  • Build: 0 errors, 0 warnings
  • Tests: 1328/1328 passed (net8.0 + net10.0)
  • Samples: All 5 demos run end-to-end (GetAgentDetails, MessageBased non-streaming + streaming, TaskBased short-lived + long-running + cancel, ReturnImmediately)

Closes #329

…ately behavior

- rename SendMessageConfiguration.Blocking to ReturnImmediately matching A2A v1 spec
- add MaterializeReturnImmediatelyResponseAsync with background event drain
- track background tasks for cancellation via tasks/cancel and graceful shutdown
- add 6 server unit tests covering return-immediately, cancel, and dispose

🐛 - Generated by Copilot
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant enhancement to the A2A server's message handling by implementing a "return-immediately" execution mode, which aligns the SDK with the A2A v1 specification for non-blocking operations. This allows clients to receive an initial task response quickly while the server efficiently manages and completes the remaining work in the background. The changes also include robust mechanisms for managing and gracefully shutting down these background tasks, alongside improvements to agent card discovery and comprehensive updates to samples and tests to demonstrate and validate the new behavior.

Highlights

  • Configuration Property Rename: The SendMessageConfiguration.Blocking property was renamed to ReturnImmediately with inverted semantics to align with the A2A v1 spec's "returnImmediately" wire format.
  • Return-Immediately Execution Mode: Implemented a new execution mode in A2AServer.SendMessageAsync where, if ReturnImmediately is true, the server returns the first Task event immediately and continues processing the remaining events in the background.
  • Graceful Background Task Management: A2AServer now implements IAsyncDisposable to track and manage background tasks using ConcurrentDictionary, allowing for cancellation via tasks/cancel and graceful shutdown during disposal.
  • Agent Card Discovery Enhancement: Agent card discovery was improved by registering /.well-known/agent-card.json at both the domain root (per spec) and the path prefix (for backward compatibility).
  • Sample Updates: The EchoAgentWithTasks sample was updated to simulate slow work for ReturnImmediately requests and correct task-target-state metadata. A new DemoReturnImmediatelyAsync was added to TaskBasedCommunicationSample to illustrate the new workflow.
  • New Logging and Context Propagation: A new source-generated log method Log.BackgroundEventProcessingFailed was added for background errors, and RequestContext.Configuration is now propagated to agents.
  • Comprehensive Testing: Six new unit tests were added to thoroughly validate the ReturnImmediately functionality, covering scenarios like slow handlers, message responses, background processing completion, explicit blocking, task cancellation, and server disposal.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a "return-immediately" (non-blocking) communication pattern for agents, allowing clients to receive an immediate response with an in-progress task while the agent continues processing in the background. The changes involve updating the SendMessageConfiguration to use ReturnImmediately, adding a new sample demonstration, and significantly refactoring the A2AServer to manage background tasks and their cancellation. The A2AServer now implements IAsyncDisposable and uses ConcurrentDictionary to track background operations. The review comments highlight several critical issues related to the use of ConcurrentDictionary in A2AServer, specifically that using indexers to add items to _backgroundCancellations and _backgroundTasks can lead to overwriting existing entries, causing resource leaks and making background tasks un-cancellable. It is recommended to use TryAdd for safer and more explicit handling. Additionally, the iteration and removal of items from _backgroundCancellations during disposal is identified as unreliable due to potential issues with ConcurrentDictionary enumeration while modifying the collection; a safer pattern involving taking a snapshot of keys before iteration is suggested.

}
}, CancellationToken.None);

_backgroundTasks[context.TaskId] = drainTask;
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Similar to the issue with _backgroundCancellations, using an indexer on _backgroundTasks can overwrite an existing entry. This could lead to an old background task being orphaned if a new one is added for the same task ID before the old one completes. Using TryAdd would be safer and would make the intention of adding a new, unique background task explicit. If TryAdd fails, it would indicate a logic error that should be investigated, as there should not be an existing background task if the CancellationTokenSource was successfully added.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. The drain task is now tracked in _backgroundTasks and shares the same CTS token as the original handler (via CTS reuse for continuations). The _backgroundTasks overwrite for the same taskId is acceptable here — the prior drain is either still running (sharing the same CTS, so cancel reaches both) or already completed (removed itself in finally).

@rokonec rokonec force-pushed the fix/329-return-immediately branch 3 times, most recently from ba13faa to a1f0c1a Compare March 25, 2026 23:07
- register /.well-known/agent-card.json at root in MapA2A() framework method
- remove speccompliance-only special case from sample Program.cs

🔧 - Generated by Copilot
@rokonec rokonec force-pushed the fix/329-return-immediately branch from a1f0c1a to b5c1f98 Compare March 25, 2026 23:14
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.

SendMessageConfiguration uses 'Blocking' instead of spec's 'returnImmediately', and non-blocking behavior is not implemented

2 participants