fix: Keep stream open on interrupted state changes by kabir · Pull Request #756 · a2aproject/a2a-java · GitHub
Skip to content

fix: Keep stream open on interrupted state changes - #756

Merged
kabir merged 3 commits into
a2aproject:mainfrom
kabir:issue-754
Mar 23, 2026
Merged

kabir merged 3 commits into
a2aproject:mainfrom
kabir:issue-754

Conversation

@kabir

@kabir kabir commented Mar 17, 2026

Copy link
Copy Markdown
Collaborator

Fixes #754

@gemini-code-assist

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request correctly resolves an issue where event streams were prematurely closing for tasks in an interrupted state, such as INPUT_REQUIRED. The fix aligns the stream termination logic in EventConsumer with the A2A protocol specification, ensuring streams only terminate when a task reaches a final state. The refactoring of the TaskState enum to explicitly define and track isInterrupted states is a solid design improvement that enhances code clarity. Additionally, the new integration test, testSubscribeToTaskWithInterruptedStateKeepsStreamOpen, provides excellent coverage and validation for the corrected behavior. The changes are well-implemented and I have no further suggestions.

@jmesnil

jmesnil commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

@kabir The JSON-RPC reproducer still fails:

 # Step 1: Create a non-terminal task (input_required state)
   RESPONSE=$(curl -s -X POST http://localhost:9999 \
     -H "Content-Type: application/json" \
     -d '{
       "jsonrpc":"2.0","id":1,"method":"SendMessage",
       "params":{"message":{"role":"ROLE_USER","parts":[{"text":"test"}],"messageId":"tck-input-required-repro"}}
     }')
   TASK_ID=$(echo "$RESPONSE" | python3 -c "import sys,json; r=json.load(sys.stdin); print(r['result']['task']['id'])")
   echo "Task ID: $TASK_ID  State: TASK_STATE_INPUT_REQUIRED"

At this point, the task is in TASK_STATE_INPUT_REQUIRED.
But when I subscribe to the task, the HTTP POST request returns immediately:

$ curl -s -N -X POST http://localhost:9999 \
     -H "Content-Type: application/json" \
     -H "Accept: text/event-stream" \
     -d "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"SubscribeToTask\",\"params\":{\"id\":\"$TASK_ID\"}}"

data: {"jsonrpc":"2.0","id":2,"result":{"task":{"id":"938089f1-9ce5-4bff-8cc8-8d092f3e5c84","contextId":"ba5beadd-cd73-4188-ad1f-f011dec726a9","status":{"state":"TASK_STATE_INPUT_REQUIRED","timestamp":"2026-03-17T14:40:49.748656Z"},"artifacts":[],"history":[],"metadata":{}}}}
id: 0

BTW, the id: 0 looks very suspicious in the event stream...

At this point, I was expecting the request to stay open until I complete the task with another message such as:

 curl -s -X POST http://localhost:9999 \
     -H "Content-Type: application/json" \
     -d "{
       \"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"SendMessage\",
       \"params\":{\"message\":{\"role\":\"ROLE_USER\",\"parts\":[{\"text\":\"done\"}],\"messageId\":\"tck-complete-task-repro\",\"taskId\":\"$TASK_ID\"}}
     }"

kabir and others added 2 commits March 17, 2026 15:06
The EventConsumer grace period logic was incorrectly closing the queue
after agent completion, even when the task was in an interrupted state
(INPUT_REQUIRED or AUTH_REQUIRED).

Per A2A Protocol Specification 3.1.6, streams must remain open for
interrupted states to receive future state updates, regardless of
whether the agent has completed.

Changes:
- Track last seen task state in EventConsumer
- Prevent grace period queue close if task is in interrupted state
- Add logging for interrupted state detection

This fixes the issue where SubscribeToTask would close immediately
after delivering the initial Task snapshot for INPUT_REQUIRED tasks.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@kabir

kabir commented Mar 17, 2026

Copy link
Copy Markdown
Collaborator Author

@jmesnil I've tried to make the test do what the reproducer does

@kabir

kabir commented Mar 17, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request provides a critical fix to ensure that event streams remain open for tasks in an interrupted state (like INPUT_REQUIRED), adhering to the A2A specification. The changes are well-implemented across several files. In EventConsumer, the logic for closing the stream is corrected to check for interrupted states. The TaskState enum is refactored to explicitly include the concept of an "interrupted" state, which is a great design improvement that enhances clarity and maintainability. The isStreamTerminatingTask method is also corrected. The changes are supported by excellent tests, including an updated unit test and a new, comprehensive integration test that thoroughly validates the end-to-end behavior. The code quality is high, and the fix appears robust and correct.

@kabir

kabir commented Mar 23, 2026

Copy link
Copy Markdown
Collaborator Author

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.

[Bug]: SubscribeToTask stream closes immediately instead of staying open for state updates

2 participants