Support long-running agent work with unified invocation lifecycle commands
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
### Summary
Expose orthogonal primitives for creating and managing agent work while keeping a single lifecycle command group across protocols.
- `azd ai agent invoke` creates work.
- `azd ai agent invocations show|follow|cancel` manages existing work.
- `--long-running` requests continued service-side execution after client disconnection.
- `--no-wait` controls when the CLI returns.
“Invocations” in the command group is the noun form of `invoke`, not a restriction to the wire protocol named `invocations`. Each supported operation maps to the selected protocol's service API. This avoids adding a new resource noun for every future protocol.
### CLI contract
```bash
# Create work and wait for completion; infer the protocol from the agent
azd ai agent invoke "message"
# Responses: continue service-side execution after disconnection, remain attached
azd ai agent invoke "message" --long-running
# Responses: return after receiving the service-assigned ID
azd ai agent invoke "message" --long-running --no-wait
# Manage current work using the selected agent's protocol
azd ai agent invocations show
azd ai agent invocations follow
azd ai agent invocations cancel
# Select protocol and service-assigned ID explicitly
azd ai agent invocations show --protocol responses --id
azd ai agent invocations follow --protocol responses --id
azd ai agent invocations cancel --protocol responses --id
azd ai agent invoke "message" --protocol invocations
azd ai agent invocations show --protocol invocations --id
azd ai agent invocations cancel --protocol invocations --id
```
`--id` is optional: omission selects the current ID for the selected agent and protocol. Explicit targeting does not change current selection. There is no separate `responses` command group, and no compatibility aliases for `--background`, `--resumable`, `--response-id`, or `--invocation-id`.
### Protocol selection
Use the same selection model as `invoke`:
1. With `--agent-endpoint`, derive the protocol and agent from the URL. Do not also supply `--protocol`, `--agent-name`, or `--version` to lifecycle commands.
2. Otherwise use explicit `--protocol` when supplied.
3. Otherwise infer the protocol from the selected agent when unambiguous. Multi-protocol agents require explicit selection.
`--agent-name` selects an agent in multi-agent projects, following the existing `sessions` command convention. Do not infer protocols from ID prefixes. Resolve the protocol before reading its current ID.
Explicit `--id` with `--agent-endpoint` works without project-backed local state. Authentication and any required `--user-identity` must still be provided by the caller.
### Supported operations
| Operation | Responses protocol | Invocations protocol |
| --- | --- | --- |
| `invoke` | Responses create | Existing synchronous, SSE, raw, and 202/poll behavior |
| `invoke --long-running` | Supported | Unsupported for now |
| `invocations show` | Response snapshot GET | One-shot Invocation GET |
| `invocations follow` | One streaming GET, replay from the beginning | Unsupported for now |
| `invocations cancel` | Response cancel POST | Invocation cancel POST, if the agent implements it |
An unsupported operation fails clearly before issuing a lifecycle request. A CLI-supported operation can still fail if the deployed agent does not implement the corresponding endpoint.
The service team may add long-running support to protocols such as A2A later. Future protocol implementations can support appropriate operations under this same group. This change does not add or promise lifecycle support for A2A, Activity, WebSocket, or voice, and does not invent semantics where no service contract exists.
### Execution and waiting
`--long-running` means: continue service-side execution after this client disconnects. It is not a minimum-duration setting and does not promise crash recovery, checkpointing, or automatic reconnect.
For Responses, it sends `store=true` and `background=true`. The API field is still called `background`; only the CLI flag is renamed.
`--no-wait` requires `--long-running`. It reads through the first complete SSE event that identifies the Response, saves the current ID when local state is available, prints the ID, and detaches without waiting for completion. A save failure is surfaced rather than silently claiming the current ID was saved.
Without `--no-wait`, remain attached until completion or disconnection. After disconnection, users can run `invocations follow` again. Never retry the creating POST automatically.
For now, `--long-running` is remote Responses-only and rejects an explicitly supplied total `--timeout` or `--output raw`. Ordinary foreground/raw and existing Invocations create/poll behavior remain unchanged.
### Service behavior and steering
#### Responses
- `POST /responses` creates a Response from supplied input.
- `background` controls whether service-side work continues after disconnection.
- Reusing `conversation.id` preserves history. If work is active and the agent supports steering, another Response can steer it. Otherwise concurrency behavior belongs to the service and agent.
- Repeated steering inputs are valid; later input supersedes earlier input.
- Steering works across foreground and background execution modes.
- `GET /responses/{id}` returns a snapshot.
- `GET /responses/{id}?stream=true` replays buffered events and follows new events. The tested service requires creation with `background=true` for replay/follow, including completed Responses. Foreground snapshots can still be shown.
- `POST /responses/{id}/cancel` requests cancellation without stopping the hosted session.
#### Invocations
- `POST /invocations` creates an Invocation.
- `GET /invocations/{id}` retrieves it.
- `POST /invocations/{id}/cancel` requests cancellation, subject to agent support.
azd does not block a new invoke because another Response is active, and performs no previous-Response status preflight. Existing session/conversation reuse remains unchanged. There is no separate `--steer`, `--resume`, `--continue`, or invoke-level `--cancel` operation.
### Current selection
Keep one current service-assigned ID per agent context and protocol. Responses and Invocation IDs remain in separate internal maps even though the public command group is shared.
- An identified foreground or long-running Responses create replaces the current Response ID.
- An identified successful remote Invocations create replaces the current Invocation ID.
- A create that fails before providing an ID leaves the previous current selection unchanged.
- Normal attached execution may continue with a warning if current-ID persistence fails. Foreground raw output does not guarantee ID extraction.
- Explicit show/follow/cancel never changes current selection.
- Concurrent creates may overwrite current selection; use explicit IDs to manage concurrent work.
Only IDs are saved as lifecycle state—no status, event sequence, session, or conversation metadata. Existing session/conversation stores remain independent create-time context. No backward-compatibility migration is required.
### Show, follow, and cancel
**Show:** perform one GET. Return JSON by default, with `--output table` for a summary following `sessions show`. Do not poll or use cached status.
**Follow:** for Responses, perform one `GET /responses/{id}?stream=true` and replay from the beginning every time. Do not send `starting_after`, track event cursors, suppress events by sequence, reconnect automatically, or silently fall back to show. A disconnect reports the ID and follow guidance. Completed work replays and exits successfully; failed/incomplete/cancelled outcomes retain their existing error behavior.
**Cancel:** POST to the selected protocol's cancel endpoint. If a rejected cancel is followed by a GET confirming terminal service state, report that state and succeed. Otherwise retain the cancel failure. Do not clear current selection or stop/delete the session.
### Delivery
- #9900: shared `invocations show|follow|cancel` commands with Responses support, `--long-running`, and simplification of the merged #9703 implementation.
- #9901: Invocations-protocol show/cancel and current-ID storage in the shared dispatcher, without changing existing create/poll behavior.
The superseded #9704–#9706 stack remains closed. No event cursor, periodic persistence, automatic reconnect, active-response guard, or dedicated steering command is retained.
Contributor guide
Assessment
This issue has not been assessed yet.