a2aproject / a2aproject/a2a-rs
a2acli: verify Agent Card capabilities before capability-gated operations
- Lenguaje dominante
- Rust
- Estrellas
- 75
- Forks
- 19
- Merge medio
- 11 h 27 min
- PR fusionados (30 d)
- 21
Descripción
Part of #181 (Tier 2).
## Summary
`A2ACLI_VER_003` (Tier 2) requires the tool to **verify a capability on the Agent Card before invoking a capability-gated operation** — streaming, push notifications, or the extended card (§13.3).
`a2acli` reads `AgentCapabilities` only to render it. The three references in `a2acli/src/lib.rs` are all inside `impl TextRender for AgentCard`:
```rust
.field("Streaming", self.capabilities.streaming.unwrap_or(false))
.field("Push Notifications", self.capabilities.push_notifications.unwrap_or(false))
.field("Extended Card", self.capabilities.extended_agent_card.unwrap_or(false))
```
Nothing gates an operation on them. `send --stream` against an agent whose card declares `streaming: false` still opens a stream and relies on the server refusing it; `card get --extended` and the `task push-config` commands likewise attempt the call regardless of what the card advertises.
## Why
The current behavior is *safe* — #173 made the streaming path fall back to polling on `UNSUPPORTED_OPERATION`, and protocol errors are reported cleanly — but it is a round-trip and an error the card already told us to expect. The spec's point is that the card is the contract: if it says the capability is absent, the tool knows before it asks.
It also produces a better failure. "the agent card does not declare streaming" names the cause; a bare `UNSUPPORTED_OPERATION` from the server does not say whether the capability is absent, disabled, or unavailable right now.
## Scope
- [ ] Before `--stream` (on `send`) and before `task subscribe`, check `capabilities.streaming`.
- [ ] Before `card get --extended`, check `capabilities.extended_agent_card`.
- [ ] Before any `task push-config` subcommand, check `capabilities.push_notifications`.
- [ ] When the capability is absent: for `send --stream`, keep #173's behavior and fall back to the blocking poll path, with the reason on stderr — the caller asked for a result, not specifically for a stream. For the others, where there is no equivalent path, fail with the reason rather than making the call.
- [ ] Treat an absent (`None`) capability field as not declared, consistent with the card renderer's `unwrap_or(false)`.
- [ ] Keep every message credential-free and on stderr.
- [ ] Tests: an agent card declaring each capability `false` produces the pre-flight outcome without the corresponding RPC ever reaching the fixture server — assert on the server-side call record, not just on the CLI's output.
## Requirements closed
| ID | Requirement |
| --- | --- |
| `A2ACLI_VER_003` | Verifies a capability on the Agent Card before invoking a capability-gated operation (streaming, push, extended card) (§13.3) |
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.