[Feat]: Method for blocking on Task updates
- 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
Avaliação
Esta issue ainda não foi avaliada.