a2aproject / a2aproject/a2a-python

cancel() and producer-failure write a terminal state to the store but not to active subscriber streams

Đang mở
#1,175 5 bình luận 0 reaction 1 người được giao Được @rohityan nhận Xem trên GitHub
component: server status:awaiting response
Ngôn ngữ chính
Python
Star
2.1k
Fork
496
Merge trung bình
4 ngày 17 giờ
Pull request đã merge (30 ngày)
12

Mô tả

Follow-up from the review of #1172 (raised by @astrogilda).

### What happens

`ActiveTask.cancel()` now closes a task out to a terminal `CANCELED` state when
the executor's `cancel()` is cleanup-only or the task was parked in a
non-terminal state (e.g. `input-required`). That terminal state is written
directly to the task store via `save_task_event`, because by that point both
the agent and subscriber event queues are already closed.

The consequence is that the terminal state reaches the **store** but not an
**active subscriber stream**. A client that was streaming the task
(`SubscribeToTask` / `message/stream`) receives the initial `Task` in `WORKING`
and then the stream ends; it never sees a `CANCELED` event and has to re-read
the task to learn the outcome. The push path does not fire either, since
`_update_task_state` only notifies on `PushNotificationEvent`.

### Why it was left out of #1172

At the point of the direct store write, both queues are already closed, so a
store write is the only option left. The same pattern already exists for the
producer-failure path (`active_task.py`, the `FAILED` write in
`_run_producer`'s `except Exception` arm), under a comment that says so. #1172
kept scope to the authorization fix (#1159) and the "cancel leaves an actionable
terminal state" fix (#1170); this stream-visibility gap is orthogonal.

### Proposed follow-up

Give a streaming or push-subscribed client a way to observe the terminal state
without polling. Options to weigh:

- Emit a synthetic terminal `TaskStatusUpdateEvent` to `_event_queue_subscribers`
before the queues are torn down, so an active subscriber sees the transition.
- Route the terminal store write through the push path so `push_sender` fires.

Both the `cancel()` CANCELED write and the producer-failure `FAILED` write share
this gap and should get the same treatment.

### Repro

Subscribe to a live task whose executor's `cancel()` is cleanup-only, cancel it,
and collect the events the subscriber receives: the stream yields the initial
`WORKING` task and ends, while `task_store.get` afterwards returns `CANCELED`.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.