a2aproject / a2aproject/A2A

[Feat]: Method for blocking on Task updates

Aberta
#1,381 3 comentários 0 reações 0 responsáveis Ver no GitHub
triaged
Linguagem predominante
Shell
Estrelas
25.7k
Forks
2.6k
Merge médio
3d 6h
PRs com merge (30d)
16

Descrição

### Is your feature request related to a problem? Please describe.

There are two cases where clients receive non-terminal Tasks in a non-streaming context:

- When using non-blocking `SendMessage`
- When using blocking `SendMessage` and the Task enters an interrupted (`input-required`, `auth-required`) state

Clients must then poll the Task using `GetTask` to observe updates. If the agent and client both support it, clients may also subscribe to the Task and receive a stream of updates.

However, there is no means of performing a blocking `GetTask` that waits for a Task to reach another terminal or interrupted state. This is not an issue for tasks in `input-required` state, since the client must send a message with the requested input anyway. It can be awkward for `auth-required`; see below.

Viewed another way, we currently have 3 ways of getting updates on a Task when sending a message to an agent:
- Non-blocking (`SendMessage(blocking=False)`)
- Blocking (`SendMessage(blocking=True)`)
- Streaming (`SendStreamingMessage`)

But we only have two ways of getting updates on a Task _without_ sending a message:
- Non-blocking (`GetTask`)
- Streaming (`SubscribeToTask`)

Should we add a blocking case for receiving Task updates?

### Describe the solution you'd like

Two possible approaches to this:

1. Extend `GetTaskRequest` to include a `blocking` field. When a server receives a `GetTask` call with this field set to true, it does not return until the `Task` enters a terminal or interrupted state. The exact same semantics as `SendMessage(blocking=True)` has.
2. Introduce a new RPC: `WaitForTask`. Same semantics as above, just separated to a new protocol method.

I have slight preference for the first, but the benefit of the second is that it clearly separates out functionality that an agent may not implement.

### Describe alternatives you've considered

`SendMessage` with empty `parts` field. We could allow servers to interpret a SendMessage request that specifies a `task_id` but includes no content as the equivalent of a `GetTask` request. The same applies for SendStreamingMessage. We could even use this to completely eliminate `SubscribeToTask` and `GetTask` methods, but that would be very unintuitive.

### Additional context

The primary case where this becomes obvious is when a Task enters `auth-required` state. Authorization can be provided out-of-band, so from a client's perspective the point when a Task begins receiving updates again is not clear. The best thing for a client to do upon receiving a Task in `auth-required` state is to immediately begin polling the Task or subscribe to updates. This where the lack of a blocking get method shows: it feels incongruous to perform a blocking send, but then have to do non-blocking polling on the task.

Example pseudocode:

```python
task = await client.send_message("Please update my calendar to cancel all TSC meetings", blocking=True)
if task.status.state == 'auth-required':
print(f'Do the auth stuff please: {task.status.message}')
# This blocks until the task changes state. Without this, clients must perform
# a polling loop to watch for task state changes.
task = await client.get_task(task.id, blocking=True)
if task.status.state == 'complete':
print('I did it!')
else:
print('Something went terribly wrong')
```

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Guia de contribuição

Abrir o guia de contribuição

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.