a2aproject / a2aproject/a2a-rs
a2acli: task download — save task artifacts to disk
- Dominant language
- Rust
- Stars
- 75
- Forks
- 19
- Avg merge
- 11h 27m
- Merged PRs (30d)
- 21
Description
Part of #181 (Tier 2). **Phase 2 — surface not yet defined upstream.**
## Summary
`A2ACLI_DOWNLOAD_001` (Tier 2) requires `task download` — save task artifacts to disk (§7.1).
This is the other half of a Tier 1 requirement already met. `A2ACLI_SEND_004`/§10.2 says a file part has *"its name, media type and size reported, and its content written to disk only when the caller asked for it (`task download`, Tier 2)"*. #173 implemented the reporting side:
```
File: report.bin (application/octet-stream, 3 bytes)
```
There is currently no way to ask for the content.
## Why
Artifact bytes are presently unreachable: `-o json` carries them base64-encoded inside the protocol object, so the only way to get a file out of a task today is to pipe JSON through a decoder. For an agent that produces documents, that is the primary output.
## Surface to agree first
The Go CLI has no `task download` (no such file in `internal/cli/`), so **there is nothing to conform to** — this issue would define the surface. Open questions worth settling in `a2a-cli` before implementing:
- positional target: `task download ` with `--output-dir`, or ` `?
- selecting a subset: by artifact id, by name, by index, or all?
- filename derivation when an artifact part has no `filename`, and collision handling.
- URL-referenced file parts: §10.2 is explicit that the CLI never fetches a `--file-part` URL when *sending*. Whether `task download` fetches a URL-referenced artifact on the way *out* is a real decision, not an obvious one — it turns the tool into an HTTP client for arbitrary agent-supplied URLs.
- what goes on stdout: a manifest of written paths, so a script can consume it, versus nothing.
## Scope (pending the above)
- [ ] Agree the surface upstream in `a2a-cli`; record the outcome on this issue.
- [ ] `task download ` writing artifact file parts to disk.
- [ ] Never write outside the caller-specified directory: reject a `filename` containing a path separator or `..` rather than sanitizing it silently — an agent-supplied filename is untrusted input.
- [ ] Refuse to overwrite by default; require an explicit flag.
- [ ] Report each written path on stdout (`text`: one `Label: value` per file; `-o json`: a manifest), diagnostics on stderr.
- [ ] A task with no file artifacts is a clean exit 0 saying so, not an error.
- [ ] Tests: inline `Raw` parts written with correct bytes; a traversal-shaped filename rejected; an existing file not clobbered absent the flag.
## Requirements closed
| ID | Requirement |
| --- | --- |
| `A2ACLI_DOWNLOAD_001` | `task download` — save task artifacts to disk (§7.1) |
Contributor guide
Assessment
This issue has not been assessed yet.