From b05ab49d425f53a5fe780d4abfe56004d8dd503e Mon Sep 17 00:00:00 2001 From: Sampath Kumar Date: Tue, 1 Sep 2026 20:24:47 +0000 Subject: [PATCH 1/4] docs: add --exec server example --- examples/exec-demo/README.md | 59 +++++++++++++++++++++++++ examples/exec-demo/a2a_unaware_agent.py | 31 +++++++++++++ examples/exec-demo/content-generator.sh | 17 +++++++ 3 files changed, 107 insertions(+) create mode 100644 examples/exec-demo/README.md create mode 100755 examples/exec-demo/a2a_unaware_agent.py create mode 100755 examples/exec-demo/content-generator.sh diff --git a/examples/exec-demo/README.md b/examples/exec-demo/README.md new file mode 100644 index 0000000..69a99cd --- /dev/null +++ b/examples/exec-demo/README.md @@ -0,0 +1,59 @@ +# `--exec` demo — turn a script into an A2A server + +Two simple, runnable scripts for demonstration. Each builds a working A2A server from an ordinary program. You write no A2A-specific code; the `a2a` CLI does the work through its `--exec` mode. + +With `--exec`, the CLI hands your script the message on **stdin** and turns whatever the script prints on **stdout** into the response. The exit code sets the result: `0` succeeds, non-zero fails, and anything on **stderr** is logged (and shown in the failure message). + +| File | What it does | +|---|---| +| `content-generator.sh` | Uppercases the message and adds a word count. Returns one response. | +| `a2a_unaware_agent.py` | Prints one numbered line per word, with a short delay — handy for streaming. | + +## Try the scripts on their own + +Run either script directly and pipe in a message: + +```bash +echo "1 2 3 4 5 helloworld" | bash content-generator.sh +echo "5 4 3 2 1 helloworld" | python3 a2a_unaware_agent.py +``` + +## Run them as an A2A server + +Install the CLI (see the [repo README](../../README.md)): + +```bash +go install github.com/a2aproject/a2a-cli@latest +``` + +### Server Instance + +Start a server that wraps one of the scripts (**terminal A**): + +```bash +# Bash script — returns the whole output as one response +a2a server --exec "bash content-generator.sh" --port 8080 + +# Python script — stream one piece per line. +# -u keeps output unbuffered so pieces arrive promptly; --chunk splits on newline. +a2a server --exec "python3 -u a2a_unaware_agent.py" --chunk=$'\n' --port 8080 +``` + +### Client Instance + +Send a message with the client (**terminal B**): + +```bash +# Know your agent +a2a card get -a http://localhost:8080 -o json + +# One-shot response +a2a send -a http://localhost:8080 "hello world from A2A" + +# Watch pieces arrive live (pair with the --chunk server above) +a2a send -a http://localhost:8080 --stream "one two three four" +``` + +## Learn more + +These scripts scratch the surface. The `a2a` CLI does much more: agent-card discovery, direct-endpoint connections, and multi-part messages with text, file, and data parts. It also handles async and streaming sends, task management, and echo and proxy server modes. Read the [a2a-cli specification](../../specification/SPEC.md) to explore everything the tool offers. diff --git a/examples/exec-demo/a2a_unaware_agent.py b/examples/exec-demo/a2a_unaware_agent.py new file mode 100755 index 0000000..575a029 --- /dev/null +++ b/examples/exec-demo/a2a_unaware_agent.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +"""An A2A-unaware agent. + +`a2a server --exec` pipes the incoming message text to stdin and turns +stdout into the response artifact. Exit 0 => completed, non-zero => failed. +stderr is logged by the CLI (and attached to the failure status on error). + +Run streaming chunks with: a2a server --exec "python3 -u a2a_unaware_agent.py" --chunk=$'\n' +Use `python3 -u` so stdout is unbuffered and chunks stream promptly. +""" + +import sys +import time + + +def main() -> int: + message = sys.stdin.read().strip() + if not message: + print("error: empty message", file=sys.stderr) + return 1 + + # Do the "work". Here: stream one line per word so --chunk can split on \n. + for i, word in enumerate(message.split(), start=1): + print(f"{i}. {word}") + sys.stdout.flush() + time.sleep(0.3) # visible streaming when run with --chunk=$'\n' + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/examples/exec-demo/content-generator.sh b/examples/exec-demo/content-generator.sh new file mode 100755 index 0000000..db74536 --- /dev/null +++ b/examples/exec-demo/content-generator.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# An A2A-unaware agent. The a2a CLI (server --exec) feeds the incoming +# message text on stdin and turns whatever we print on stdout into the +# response artifact. Exit 0 => completed, non-zero => failed. +set -euo pipefail + +# Read the whole message from stdin. +message="$(cat)" + +if [[ -z "${message// }" ]]; then + echo "error: empty message" >&2 # stderr is logged; shows up in the failure status + exit 1 +fi + +# Do the "work". Here: shout it back with a word count. +words=$(echo "$message" | wc -w | tr -d ' ') +echo "You said (${words} words): ${message^^}" From c9d2c919a577de3174170cead1da83b49b5f7d23 Mon Sep 17 00:00:00 2001 From: Sampath Kumar Date: Tue, 1 Sep 2026 20:36:18 +0000 Subject: [PATCH 2/4] test: add smoke test and lessons index for examples --- examples/README.md | 25 ++++++++++++++++++++++++ examples/exec-demo/README.md | 8 ++++++++ examples/exec-demo/test.sh | 38 ++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 examples/README.md create mode 100755 examples/exec-demo/test.sh diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..67f73ce --- /dev/null +++ b/examples/README.md @@ -0,0 +1,25 @@ +# a2a-cli examples + +A short, hands-on course in the `a2a` CLI. Each lesson builds on the last. Start at lesson 1. + +## Lessons + +### 1. Run a simple A2A server — [`exec-demo/`](exec-demo/) + +Turn an ordinary script into a working A2A server with `--exec`. Send it a message and read the response. No A2A-specific code required. + +### 2. Discover and talk to an agent + +Using the Python script from lesson 1, learn the client side: + +- `card get` — fetch an agent card, plain and with `-o json` +- set the agent card through config so you can drop the `-a` flag, and export the card +- `send` a simple text message + +### 3. Messages and tasks + +Go deeper into the `message` and `task` features: multi-part messages, streaming and async sends, and managing tasks (`task get`, `task list`, `task cancel`, `task subscribe`). + +## Learn more + +Read the [a2a-cli specification](../specification/SPEC.md) for everything the tool offers. diff --git a/examples/exec-demo/README.md b/examples/exec-demo/README.md index 69a99cd..0d41872 100644 --- a/examples/exec-demo/README.md +++ b/examples/exec-demo/README.md @@ -54,6 +54,14 @@ a2a send -a http://localhost:8080 "hello world from A2A" a2a send -a http://localhost:8080 --stream "one two three four" ``` +## Test + +`test.sh` checks both scripts on a plain pipe — no server needed. Because `--exec` only pipes the message to stdin and reads stdout, this exercises the same path the server runs. + +```bash +bash test.sh +``` + ## Learn more These scripts scratch the surface. The `a2a` CLI does much more: agent-card discovery, direct-endpoint connections, and multi-part messages with text, file, and data parts. It also handles async and streaming sends, task management, and echo and proxy server modes. Read the [a2a-cli specification](../../specification/SPEC.md) to explore everything the tool offers. diff --git a/examples/exec-demo/test.sh b/examples/exec-demo/test.sh new file mode 100755 index 0000000..5a48d0f --- /dev/null +++ b/examples/exec-demo/test.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Smoke-test the demo scripts without starting a server. +# --exec just pipes stdin -> stdout and checks the exit code, so testing the +# scripts on a plain pipe tests exactly what the server would run. +set -uo pipefail +cd "$(dirname "$0")" + +fails=0 +check() { # check -- output actual-exit + local name=$1 want_code=$2 want_text=$3 got_code=$5 out=$4 + if [[ "$got_code" != "$want_code" ]]; then + echo "FAIL: $name — exit $got_code, want $want_code"; ((fails++)); return + fi + if [[ -n "$want_text" && "$out" != *"$want_text"* ]]; then + echo "FAIL: $name — output missing '$want_text'"; ((fails++)); return + fi + echo "ok: $name" +} + +# content-generator.sh: uppercases and counts words, exit 0. +out=$(echo "hello world" | bash content-generator.sh); code=$? +check "bash: happy path" 0 "HELLO WORLD" "$out" "$code" + +# content-generator.sh: empty input fails with exit 1. +out=$(echo "" | bash content-generator.sh 2>/dev/null); code=$? +check "bash: empty input fails" 1 "" "$out" "$code" + +# a2a_unaware_agent.py: one numbered line per word, exit 0. +out=$(echo "one two" | python3 a2a_unaware_agent.py); code=$? +check "python: happy path" 0 "1. one" "$out" "$code" + +# a2a_unaware_agent.py: empty input fails with exit 1. +out=$(echo "" | python3 a2a_unaware_agent.py 2>/dev/null); code=$? +check "python: empty input fails" 1 "" "$out" "$code" + +echo +if ((fails)); then echo "$fails test(s) failed"; exit 1; fi +echo "all tests passed" From d9332776700715d3409e4d38f541ee8ceb381dd5 Mon Sep 17 00:00:00 2001 From: Sampath Kumar Date: Fri, 4 Sep 2026 17:07:07 +0000 Subject: [PATCH 3/4] docs: add config and messages/tasks lessons, refine example READMEs Add lesson 3 (config: flag, env var, .env, config show, settings table) and lesson 4 (messages and tasks). Switch lesson 2 to the echo server and show sample responses. Tighten lesson prose and objectives. --- examples/README.md | 32 ++++-- examples/card-and-send/.env.example | 3 + examples/card-and-send/README.md | 107 +++++++++++++++++++ examples/card-and-send/run.sh | 40 +++++++ examples/config/.env.example | 8 ++ examples/config/README.md | 123 ++++++++++++++++++++++ examples/config/run.sh | 38 +++++++ examples/exec-demo/README.md | 71 +++++++++---- examples/messages-and-tasks/README.md | 91 ++++++++++++++++ examples/messages-and-tasks/note.txt | 1 + examples/messages-and-tasks/priority.json | 1 + examples/messages-and-tasks/run.sh | 41 ++++++++ 12 files changed, 527 insertions(+), 29 deletions(-) create mode 100644 examples/card-and-send/.env.example create mode 100644 examples/card-and-send/README.md create mode 100755 examples/card-and-send/run.sh create mode 100644 examples/config/.env.example create mode 100644 examples/config/README.md create mode 100755 examples/config/run.sh create mode 100644 examples/messages-and-tasks/README.md create mode 100644 examples/messages-and-tasks/note.txt create mode 100644 examples/messages-and-tasks/priority.json create mode 100755 examples/messages-and-tasks/run.sh diff --git a/examples/README.md b/examples/README.md index 67f73ce..dc4bfba 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,24 +1,34 @@ -# a2a-cli examples +# Cookbook: Learn the a2a CLI by example -A short, hands-on course in the `a2a` CLI. Each lesson builds on the last. Start at lesson 1. +> New to the `a2a` CLI? Start with the [repo README](../README.md), then keep the [command reference](../internal/) handy. + +👋 Welcome to the A2A CLI Cookbook. + +This is a short, hands-on course. Each lesson is a small folder you can run on its own, and each one builds on the last. As you progress you will see how capable the `a2a` CLI is and get to know its richer features. + +To get started you need only the `a2a` CLI installed. Every lesson starts its own example agent, so you can jump straight to any one of them. ## Lessons -### 1. Run a simple A2A server — [`exec-demo/`](exec-demo/) +### 1. Build a quick A2A server — [`exec-demo/`](exec-demo/) + +The `a2a` CLI is a client for A2A servers. It sends messages, tracks task progress, and fetches results. So first you need a server to talk to. + +Learn how to stand up a simple demo server. You will turn an ordinary script into a working A2A server with `--exec`, then send it a message and read the reply. No A2A-specific code required. + +### 2. Discover and talk to an agent — [`card-and-send/`](card-and-send/) -Turn an ordinary script into a working A2A server with `--exec`. Send it a message and read the response. No A2A-specific code required. +Before you can use an agent, you need to know what it can do. Every A2A agent answers that with an **agent card**. -### 2. Discover and talk to an agent +Learn the client side: read an agent's card, save it, set it once through config, and send a text message. -Using the Python script from lesson 1, learn the client side: +### 3. Configure the CLI — [`config/`](config/) -- `card get` — fetch an agent card, plain and with `-o json` -- set the agent card through config so you can drop the `-a` flag, and export the card -- `send` a simple text message +Learn the three ways to pass a setting: a CLI flag, a session environment variable, and a `.env` file. See how `a2a config show` tells you which one won, plus a table of every setting you can configure. -### 3. Messages and tasks +### 4. Messages and tasks — [`messages-and-tasks/`](messages-and-tasks/) -Go deeper into the `message` and `task` features: multi-part messages, streaming and async sends, and managing tasks (`task get`, `task list`, `task cancel`, `task subscribe`). +Go deeper: build messages from text, file, and data parts; stream and send async; and manage the tasks an agent creates with `task get`, `task list`, `task subscribe`, and `task cancel`. ## Learn more diff --git a/examples/card-and-send/.env.example b/examples/card-and-send/.env.example new file mode 100644 index 0000000..2a4ebb0 --- /dev/null +++ b/examples/card-and-send/.env.example @@ -0,0 +1,3 @@ +# Copy to .env so the a2a CLI picks it up automatically. +# With the agent card set here, you can drop the -a flag on every command. +A2ACLI_AGENT_CARD=http://localhost:8090 diff --git a/examples/card-and-send/README.md b/examples/card-and-send/README.md new file mode 100644 index 0000000..8214e59 --- /dev/null +++ b/examples/card-and-send/README.md @@ -0,0 +1,107 @@ +# Lesson 2 — discover and talk to an agent + +In lesson 1 you started a server. Now learn the client side: read an agent's card, save it, set it once through config, and send a message. + +## What you'll learn + +- What an **agent card** is and how to fetch it, plain and as JSON +- How to export a card to a file +- How to set the agent through a `.env` file so you can drop the `-a` flag +- How to send a simple text message + +## Prerequisites + +The `a2a` CLI installed (see the [repo README](../../README.md)). This lesson uses the built-in **echo** server, so there is nothing to write and you do not need to have finished lesson 1 first. + +## Start the agent (terminal A) + +The echo server sends your message straight back — a simple partner for learning the client: + +```bash +a2a server --echo --port 8090 --name "Echo Agent" +``` + +Leave it running. Do everything below in **terminal B**. + +## Step 1 — get the agent card + +Every A2A agent publishes an **agent card** that describes who it is and how to reach it. Fetch it: + +```bash +a2a card get http://localhost:8090 +``` + +```text +Echo Agent + URL: http://localhost:8090 + Version: 1.0.0 +``` + +Add `-o json` for the raw card — useful for scripts and for saving it: + +```bash +a2a card get http://localhost:8090 -o json +``` + +## Step 2 — export the card + +Save the card to a file so you can inspect it or serve it later: + +```bash +a2a card get http://localhost:8090 -o json > agent-card.json +``` + +## Step 3 — set the card through config + +Typing `-a http://localhost:8090` on every command gets old. Put it in a `.env` file instead: + +```bash +cp .env.example .env +``` + +This `.env` contains the following: + +```dotenv +A2ACLI_AGENT_CARD=http://localhost:8090 +``` + +The CLI reads `.env` from the working directory automatically, so you can now drop `-a`: + +```bash +a2a card get # uses A2ACLI_AGENT_CARD from .env +a2a config show # confirm the value and where it resolved from +``` + +```text +SETTING VALUE SOURCE +agent-card http://localhost:8090 local +... +``` + +## Step 4 — send a message + +The echo agent sends your text right back: + +```bash +a2a send "hello world from A2A" +``` + +```text +hello world from A2A +``` + +## Run the whole lesson + +`run.sh` does every step above — start the agent, read and export the card, set config, and send a message — then stops the agent: + +```bash +bash run.sh +``` + +## Next + +Lesson 3 shows the three ways to [configure the CLI](../config/) and lists every setting you can change. + +## Learn more + +Read the [a2a-cli specification](../../specification/SPEC.md) for the full set of commands and flags. diff --git a/examples/card-and-send/run.sh b/examples/card-and-send/run.sh new file mode 100755 index 0000000..89fc61b --- /dev/null +++ b/examples/card-and-send/run.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Lesson 2, end to end: start the agent, read its card, set config, send a message. +# Requires the `a2a` CLI on your PATH (go install github.com/a2aproject/a2a-cli@latest). +set -uo pipefail +cd "$(dirname "$0")" + +# Use the a2a CLI; if it is installed as a2a-cli, alias it. +shopt -s expand_aliases +type a2a >/dev/null 2>&1 || alias a2a=a2a-cli + +PORT=8090 +URL="http://localhost:$PORT" + +# Start the built-in echo server in the background; stop it on exit. +a2a server --echo --name "Echo Agent" --port "$PORT" --quiet & +SERVER_PID=$! +trap 'kill "$SERVER_PID" 2>/dev/null' EXIT + +# Wait for it to accept requests. +for _ in $(seq 1 20); do + a2a card get "$URL" >/dev/null 2>&1 && break + sleep 0.25 +done + +echo "== card get ==" +a2a card get "$URL" + +echo; echo "== card get -o json ==" +a2a card get "$URL" -o json + +echo; echo "== export the card to agent-card.json ==" +a2a card get "$URL" -o json > agent-card.json +echo "wrote agent-card.json" + +echo; echo "== set the card via .env, then drop -a ==" +echo "A2ACLI_AGENT_CARD=$URL" > .env +a2a config show + +echo; echo "== send a text message ==" +a2a send "hello world from A2A" diff --git a/examples/config/.env.example b/examples/config/.env.example new file mode 100644 index 0000000..dd54672 --- /dev/null +++ b/examples/config/.env.example @@ -0,0 +1,8 @@ +# Copy to .env so the a2a CLI picks it up automatically from this folder. +# Every A2ACLI_* variable maps to a flag; see the README for the full list. +A2ACLI_AGENT_CARD=http://localhost:8090 + +# A few more you might set: +# A2ACLI_OUTPUT=json +# A2ACLI_TIMEOUT=60s +# A2ACLI_TRANSPORT=rest,jsonrpc diff --git a/examples/config/README.md b/examples/config/README.md new file mode 100644 index 0000000..937d10e --- /dev/null +++ b/examples/config/README.md @@ -0,0 +1,123 @@ +# Lesson 3 — configure the CLI + +In lesson 2 you set the agent card in a `.env` file. That is one of three ways to give the `a2a` CLI a setting. This lesson covers all three. It also shows how `a2a config show` reveals which one won, and lists every setting you can configure. + +## What you'll learn + +- The three ways to pass a setting: a CLI flag, a session environment variable, and a `.env` file +- Which one to reach for, and why flags are best for agentic tools +- How `a2a config show` reports the effective value and where it came from +- Every setting you can configure, with its environment variable and default + +## Prerequisites + +The `a2a` CLI installed (see the [repo README](../../README.md)). For the `send` step, start a throwaway echo server in **terminal A**: + +```bash +a2a server --echo --port 8090 +``` + +An echo server sends your message straight back, so you can see requests land. Do everything below in **terminal B**. + +## The three ways to set a value + +### (a) Pass it on the command line + +Set the value right where you run the command: + +```bash +a2a card get -a http://localhost:8090 +a2a send -a http://localhost:8090 -o json "hello" +``` + +**Recommended for agentic tools and scripts.** The command carries its own settings, so anyone reading it sees exactly which agent the request goes to. Nothing is hidden in the environment or a file. + +### (b) Set a session environment variable + +Export a setting once and every command in that shell session picks it up. It lasts until you close the session: + +```bash +export A2ACLI_AGENT_CARD=http://localhost:8090 + +a2a card get # no -a needed +a2a send "hello" # response: hello +``` + +Good for a focused session against one agent, without editing any file. + +### (c) Put it in a `.env` file + +For a setting you want every time you work in a folder, write it to `.env`: + +```bash +echo "A2ACLI_AGENT_CARD=http://localhost:8090" > .env + +a2a card get # reads .env from the working directory +``` + +The CLI reads `.env` from the working directory automatically. Point at a different file with `--config ./other.env`. + +## See what won: `a2a config show` + +Settings can come from several places at once. `config show` prints the effective value and the source it resolved from: + +```bash +a2a config show +``` + +```text +SETTING VALUE SOURCE +agent-card http://localhost:8090 env +output text default +timeout 30s default +... +``` + +Add `-o json` for a machine-readable version. Credential settings such as `auth` are shown as ``. + +## Precedence + +When the same setting is given in more than one place, the CLI uses the first match in this order: + +1. a command-line flag +2. a session environment variable +3. the local `.env` (the file named by `--config`, or the nearest `.env` above the working directory) +4. the global `.env` at `~/.config/a2a-cli/.env` +5. the built-in default + +## All settings you can configure + +Set any of these as a flag, an environment variable, or a `.env` entry. The table lists each one with its variable name and default. The variable name is always the flag name in capitals, with a `A2ACLI_` prefix. + +| Setting | Short | Environment variable | Default | Purpose | +|---|---|---|---|---| +| `--agent-card` | `-a` | `A2ACLI_AGENT_CARD` | (unset) | Agent Card reference: host, card URL, or file path | +| `--endpoint` | `-e` | `A2ACLI_ENDPOINT` | (unset) | Direct interface URL; skips card resolution | +| `--transport` | | `A2ACLI_TRANSPORT` | (card order) | Transport preference: `rest`, `jsonrpc`, `grpc` | +| `--output` | `-o` | `A2ACLI_OUTPUT` | `text` | Output format: `text` or `json` | +| `--svc-param` | | `A2ACLI_SVC_PARAM` | (unset) | Service parameter, `key=value` | +| `--auth` | | `A2ACLI_AUTH` | (unset) | Authorization credentials (redacted in `config show`) | +| `--tenant` | | `A2ACLI_TENANT` | (unset) | Tenant identifier, sent on every request | +| `--timeout` | | `A2ACLI_TIMEOUT` | `30s` | Request timeout | +| `--verbose` | `-v` | `A2ACLI_VERBOSE` | `false` | Verbose output to stderr | +| `--insecure` | | `A2ACLI_INSECURE` | `false` | Use plaintext gRPC credentials | + +`--stream`, `--config`, `--help`, and `--version` must be passed as flags; they are never read from the environment or a `.env` file. + +> Store secrets such as `--auth` only in files you keep private. + +## Run the whole lesson + +`run.sh` starts an echo server, then walks through the three methods and `config show`: + +```bash +bash run.sh +``` + +## Next + +Lesson 4 goes deeper into [messages and tasks](../messages-and-tasks/). You will build multi-part messages, stream replies, and manage tasks. + +## Learn more + +Read the [a2a-cli specification](../../specification/SPEC.md) for the full set of commands and flags. diff --git a/examples/config/run.sh b/examples/config/run.sh new file mode 100755 index 0000000..0f46bc5 --- /dev/null +++ b/examples/config/run.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Lesson 3, end to end: the three ways to set a value, and `config show`. +# Requires the `a2a` CLI on your PATH (go install github.com/a2aproject/a2a-cli@latest). +set -uo pipefail +cd "$(dirname "$0")" + +# Use the a2a CLI; if it is installed as a2a-cli, alias it. +shopt -s expand_aliases +type a2a >/dev/null 2>&1 || alias a2a=a2a-cli + +PORT=8090 +URL="http://localhost:$PORT" + +# Start a throwaway echo server in the background; stop it on exit. +a2a server --echo --port "$PORT" --quiet & +SERVER_PID=$! +trap 'kill "$SERVER_PID" 2>/dev/null; rm -f .env' EXIT + +# Wait for it to accept requests. +for _ in $(seq 1 20); do + a2a card get "$URL" >/dev/null 2>&1 && break + sleep 0.25 +done + +echo "== (a) pass it on the command line ==" +a2a send -a "$URL" "hello from a flag" + +echo; echo "== (b) session environment variable ==" +export A2ACLI_AGENT_CARD="$URL" +a2a send "hello from an env var" + +echo; echo "== (c) .env file (unset the env var first so the file is used) ==" +unset A2ACLI_AGENT_CARD +echo "A2ACLI_AGENT_CARD=$URL" > .env +a2a send "hello from .env" + +echo; echo "== config show: effective values and their sources ==" +a2a config show diff --git a/examples/exec-demo/README.md b/examples/exec-demo/README.md index 0d41872..acf04b5 100644 --- a/examples/exec-demo/README.md +++ b/examples/exec-demo/README.md @@ -1,50 +1,81 @@ -# `--exec` demo — turn a script into an A2A server +# Lesson 1 — build an A2A server from a script -Two simple, runnable scripts for demonstration. Each builds a working A2A server from an ordinary program. You write no A2A-specific code; the `a2a` CLI does the work through its `--exec` mode. +The first step in learning the `a2a` CLI is to stand up a server you can send messages to and get replies from. The CLI gives you two ready-made server modes, no A2A-specific code required. -With `--exec`, the CLI hands your script the message on **stdin** and turns whatever the script prints on **stdout** into the response. The exit code sets the result: `0` succeeds, non-zero fails, and anything on **stderr** is logged (and shown in the failure message). +The simplest is `--echo`, which sends your message straight back. It is a "ping" for A2A: perfect for a first connection test. The more advanced is `--exec`: point it at any script that reads input and prints output, and it becomes a working A2A server. `--exec` is where the fun is — it turns any program into an agent for demos, testing, and small jobs. + +> `--echo` and `--exec` are built for learning, demos, and testing, not for production use. + +## What you'll learn + +- How to start the simplest server with `--echo` +- How `--exec` wraps an ordinary script as an A2A server +- How to send a one-shot message and read the reply +- How to stream a reply piece by piece + +## How `--exec` works + +The CLI hands your script the message on **stdin** and turns whatever the script prints on **stdout** into the response. The exit code sets the result: `0` succeeds, non-zero fails. Anything on **stderr** is logged and shown in the failure message. + +This example ships two small scripts: | File | What it does | |---|---| | `content-generator.sh` | Uppercases the message and adds a word count. Returns one response. | | `a2a_unaware_agent.py` | Prints one numbered line per word, with a short delay — handy for streaming. | -## Try the scripts on their own +## Prerequisites -Run either script directly and pipe in a message: +Install the CLI (see the [repo README](../../README.md)): ```bash -echo "1 2 3 4 5 helloworld" | bash content-generator.sh -echo "5 4 3 2 1 helloworld" | python3 a2a_unaware_agent.py +go install github.com/a2aproject/a2a-cli@latest ``` -## Run them as an A2A server +## Step 1 — warm up with the echo server -Install the CLI (see the [repo README](../../README.md)): +Start the simplest possible server in **terminal A**: ```bash -go install github.com/a2aproject/a2a-cli@latest +a2a server --echo --port 8080 ``` -### Server Instance +Send it a message from **terminal B** and get the same text back: -Start a server that wraps one of the scripts (**terminal A**): +```bash +a2a send -a http://localhost:8080 "hello world from A2A" +``` + +That is a full A2A round trip. Stop the echo server (Ctrl-C) and move on to `--exec` for something more useful. + +## Step 2 — run the scripts on their own + +Before the CLI is involved, confirm each script works on a plain pipe: + +```bash +echo "1 2 3 4 5 helloworld" | bash content-generator.sh +echo "5 4 3 2 1 helloworld" | python3 a2a_unaware_agent.py +``` + +## Step 3 — start a server from a script (terminal A) + +Wrap one of the scripts in a server: ```bash # Bash script — returns the whole output as one response a2a server --exec "bash content-generator.sh" --port 8080 -# Python script — stream one piece per line. +# Python script — streams one piece per line. # -u keeps output unbuffered so pieces arrive promptly; --chunk splits on newline. a2a server --exec "python3 -u a2a_unaware_agent.py" --chunk=$'\n' --port 8080 ``` -### Client Instance +Leave the server running. -Send a message with the client (**terminal B**): +## Step 4 — send a message (terminal B) ```bash -# Know your agent +# Fetch the agent card to confirm the server is up a2a card get -a http://localhost:8080 -o json # One-shot response @@ -56,12 +87,16 @@ a2a send -a http://localhost:8080 --stream "one two three four" ## Test -`test.sh` checks both scripts on a plain pipe — no server needed. Because `--exec` only pipes the message to stdin and reads stdout, this exercises the same path the server runs. +`test.sh` checks both scripts on a plain pipe — no server needed. Because `--exec` only pipes the message to stdin and reads stdout, this exercises the same path the server runs: ```bash bash test.sh ``` +## Next + +You have a running agent. In [lesson 2](../card-and-send/) you learn the client side properly: reading the agent card, saving it, and setting it once through config so you can drop the `-a` flag from every command. + ## Learn more -These scripts scratch the surface. The `a2a` CLI does much more: agent-card discovery, direct-endpoint connections, and multi-part messages with text, file, and data parts. It also handles async and streaming sends, task management, and echo and proxy server modes. Read the [a2a-cli specification](../../specification/SPEC.md) to explore everything the tool offers. +These scripts scratch the surface. The `a2a` CLI also does agent-card discovery, multi-part messages, async and streaming sends, task management, and echo and proxy server modes. Read the [a2a-cli specification](../../specification/SPEC.md) to explore everything the tool offers. diff --git a/examples/messages-and-tasks/README.md b/examples/messages-and-tasks/README.md new file mode 100644 index 0000000..2279898 --- /dev/null +++ b/examples/messages-and-tasks/README.md @@ -0,0 +1,91 @@ +# Lesson 4 — messages and tasks + +You can already talk to an agent. This lesson explores two richer areas. First, building a message from several **parts**. Second, managing the **tasks** an agent creates. + +## What you'll learn + +- The three kinds of message part: text, file, and data +- How to combine parts in one message +- How to stream a reply and how to send async +- How to inspect and manage tasks with `task get`, `task list`, `task subscribe`, and `task cancel` + +## Prerequisites + +The `a2a` CLI installed (see the [repo README](../../README.md)). This lesson reuses the Python script from lesson 1, whose short per-word delay makes long-running tasks easy to watch. You do not need to have finished the earlier lessons first. + +## Start the agent + +Run the agent in **terminal A**: + +```bash +a2a server --exec "python3 -u ../exec-demo/a2a_unaware_agent.py" --name "Word Numberer" --port 8080 +``` + +Set the card once in **terminal B** so the commands below stay short: + +```bash +echo "A2ACLI_AGENT_CARD=http://localhost:8080" > .env +``` + +## Messages + +A message is one or more **parts**, sent in the order you list them. There are three kinds: + +```bash +# Text part (a trailing string is shorthand for a single text part) +a2a send --text-part "number these words" + +# File part — a local path is inlined; a URL is sent by reference +a2a send --file-part note.txt --media-type text/plain + +# Data part — structured JSON, from a file or inline +a2a send --data-part priority.json +a2a send --data-part '{"priority":"high"}' + +# Combine parts in order +a2a send --text-part "with an attachment" --file-part note.txt --media-type text/plain +``` + +> This demo agent reads only the first text part. The other parts are still sent — add `-o json` or `--verbose` to see the full message the CLI builds. + +### Streaming and async + +```bash +# Stream the response as it is produced +a2a send --stream "one two three four five" + +# Fire-and-forget — returns a task id immediately +a2a send --async "one two three four five" +``` + +## Tasks + +Every `send` creates a **task**. The async send above prints its id; use it below: + +```bash +# Inspect one task +a2a task get +a2a task get --history 10 -o json + +# List recent tasks, optionally filtered +a2a task list +a2a task list --status completed --limit 20 + +# Follow a running task until it finishes +a2a task subscribe + +# Cancel a task +a2a task cancel +``` + +## Run the whole lesson + +`run.sh` starts the agent and walks through the message and task commands, then stops the agent: + +```bash +bash run.sh +``` + +## Learn more + +Read the [a2a-cli specification](../../specification/SPEC.md) for the full set of commands and flags. diff --git a/examples/messages-and-tasks/note.txt b/examples/messages-and-tasks/note.txt new file mode 100644 index 0000000..c496f52 --- /dev/null +++ b/examples/messages-and-tasks/note.txt @@ -0,0 +1 @@ +A small local file to attach as a file part. diff --git a/examples/messages-and-tasks/priority.json b/examples/messages-and-tasks/priority.json new file mode 100644 index 0000000..3ab1c5e --- /dev/null +++ b/examples/messages-and-tasks/priority.json @@ -0,0 +1 @@ +{"priority": "high", "topic": "demo"} diff --git a/examples/messages-and-tasks/run.sh b/examples/messages-and-tasks/run.sh new file mode 100755 index 0000000..baa6ddb --- /dev/null +++ b/examples/messages-and-tasks/run.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Lesson 3, end to end: multi-part messages, streaming, async, and task commands. +# Requires the `a2a` CLI on your PATH (go install github.com/a2aproject/a2a-cli@latest). +set -uo pipefail +cd "$(dirname "$0")" + +# Use the a2a CLI; if it is installed as a2a-cli, alias it. +shopt -s expand_aliases +type a2a >/dev/null 2>&1 || alias a2a=a2a-cli + +PORT=8080 +URL="http://localhost:$PORT" +export A2ACLI_AGENT_CARD="$URL" # so the client commands can skip -a + +# Start the lesson 1 script as a server in the background; stop it on exit. +a2a server --exec "python3 -u ../exec-demo/a2a_unaware_agent.py" --name "Word Numberer" --port "$PORT" --quiet & +SERVER_PID=$! +trap 'kill "$SERVER_PID" 2>/dev/null' EXIT + +for _ in $(seq 1 20); do + a2a card get >/dev/null 2>&1 && break + sleep 0.25 +done + +echo "== text part (shorthand) ==" +a2a send "number these words" + +echo; echo "== file part ==" +a2a send --file-part note.txt --media-type text/plain "with an attachment" + +echo; echo "== data part (inline) ==" +a2a send --data-part '{"priority":"high"}' "with data" + +echo; echo "== streaming ==" +a2a send --stream "one two three four five" + +echo; echo "== async: returns a task id ==" +a2a send --async "one two three four five" + +echo; echo "== list recent tasks ==" +a2a task list --limit 5 From 4c7cada914d4aad58d6ce5a99b422a58b3a82efe Mon Sep 17 00:00:00 2001 From: Sampath Kumar Date: Tue, 8 Sep 2026 14:51:24 +0000 Subject: [PATCH 4/4] docs: number example lessons and fix task/output drift --- .../{exec-demo => 01-exec-demo}/README.md | 2 +- .../a2a_unaware_agent.py | 0 .../content-generator.sh | 0 examples/{exec-demo => 01-exec-demo}/test.sh | 0 .../.env.example | 0 .../README.md | 18 +++++--- .../run.sh | 0 examples/{config => 03-config}/.env.example | 0 examples/{config => 03-config}/README.md | 7 ++-- examples/{config => 03-config}/run.sh | 0 .../README.md | 42 ++++++++++--------- .../note.txt | 0 .../priority.json | 0 .../run.sh | 9 ++-- examples/README.md | 10 ++--- 15 files changed, 51 insertions(+), 37 deletions(-) rename examples/{exec-demo => 01-exec-demo}/README.md (94%) rename examples/{exec-demo => 01-exec-demo}/a2a_unaware_agent.py (100%) rename examples/{exec-demo => 01-exec-demo}/content-generator.sh (100%) rename examples/{exec-demo => 01-exec-demo}/test.sh (100%) rename examples/{card-and-send => 02-card-and-send}/.env.example (100%) rename examples/{card-and-send => 02-card-and-send}/README.md (77%) rename examples/{card-and-send => 02-card-and-send}/run.sh (100%) rename examples/{config => 03-config}/.env.example (100%) rename examples/{config => 03-config}/README.md (92%) rename examples/{config => 03-config}/run.sh (100%) rename examples/{messages-and-tasks => 04-messages-and-tasks}/README.md (50%) rename examples/{messages-and-tasks => 04-messages-and-tasks}/note.txt (100%) rename examples/{messages-and-tasks => 04-messages-and-tasks}/priority.json (100%) rename examples/{messages-and-tasks => 04-messages-and-tasks}/run.sh (71%) diff --git a/examples/exec-demo/README.md b/examples/01-exec-demo/README.md similarity index 94% rename from examples/exec-demo/README.md rename to examples/01-exec-demo/README.md index acf04b5..b6f1fbc 100644 --- a/examples/exec-demo/README.md +++ b/examples/01-exec-demo/README.md @@ -95,7 +95,7 @@ bash test.sh ## Next -You have a running agent. In [lesson 2](../card-and-send/) you learn the client side properly: reading the agent card, saving it, and setting it once through config so you can drop the `-a` flag from every command. +You have a running agent. In [lesson 2](../02-card-and-send/) you learn the client side properly: reading the agent card, saving it, and setting it once through config so you can drop the `-a` flag from every command. ## Learn more diff --git a/examples/exec-demo/a2a_unaware_agent.py b/examples/01-exec-demo/a2a_unaware_agent.py similarity index 100% rename from examples/exec-demo/a2a_unaware_agent.py rename to examples/01-exec-demo/a2a_unaware_agent.py diff --git a/examples/exec-demo/content-generator.sh b/examples/01-exec-demo/content-generator.sh similarity index 100% rename from examples/exec-demo/content-generator.sh rename to examples/01-exec-demo/content-generator.sh diff --git a/examples/exec-demo/test.sh b/examples/01-exec-demo/test.sh similarity index 100% rename from examples/exec-demo/test.sh rename to examples/01-exec-demo/test.sh diff --git a/examples/card-and-send/.env.example b/examples/02-card-and-send/.env.example similarity index 100% rename from examples/card-and-send/.env.example rename to examples/02-card-and-send/.env.example diff --git a/examples/card-and-send/README.md b/examples/02-card-and-send/README.md similarity index 77% rename from examples/card-and-send/README.md rename to examples/02-card-and-send/README.md index 8214e59..d9f4115 100644 --- a/examples/card-and-send/README.md +++ b/examples/02-card-and-send/README.md @@ -73,21 +73,29 @@ a2a config show # confirm the value and where it resolved from ``` ```text -SETTING VALUE SOURCE -agent-card http://localhost:8090 local +SETTING VALUE SOURCE +agent-card http://localhost:8090 local-file ... ``` +The `local-file` source means the value came from a `.env` file in the working directory. + ## Step 4 — send a message -The echo agent sends your text right back: +The echo agent sends your text right back. Every `send` runs as a task, so the CLI prints the task, its status, and the reply in the artifacts: ```bash a2a send "hello world from A2A" ``` ```text -hello world from A2A +Task: 01a08152-ae99-73ae-98a3-58b82e14bde0 +Context: 01a08152-ae99-74bc-bfc7-d6ce8b2c74d2 +Status: completed (2026-09-08T14:01:14Z) +Artifacts: + [01a08152-ae99-75cd-891b-cceb14223d58] hello world from A2A +History: + [user] hello world from A2A ``` ## Run the whole lesson @@ -100,7 +108,7 @@ bash run.sh ## Next -Lesson 3 shows the three ways to [configure the CLI](../config/) and lists every setting you can change. +Lesson 3 shows the three ways to [configure the CLI](../03-config/) and lists every setting you can change. ## Learn more diff --git a/examples/card-and-send/run.sh b/examples/02-card-and-send/run.sh similarity index 100% rename from examples/card-and-send/run.sh rename to examples/02-card-and-send/run.sh diff --git a/examples/config/.env.example b/examples/03-config/.env.example similarity index 100% rename from examples/config/.env.example rename to examples/03-config/.env.example diff --git a/examples/config/README.md b/examples/03-config/README.md similarity index 92% rename from examples/config/README.md rename to examples/03-config/README.md index 937d10e..7cb7990 100644 --- a/examples/config/README.md +++ b/examples/03-config/README.md @@ -40,7 +40,7 @@ Export a setting once and every command in that shell session picks it up. It la export A2ACLI_AGENT_CARD=http://localhost:8090 a2a card get # no -a needed -a2a send "hello" # response: hello +a2a send "hello" # runs as a task; the reply is in the artifacts ``` Good for a focused session against one agent, without editing any file. @@ -94,7 +94,8 @@ Set any of these as a flag, an environment variable, or a `.env` entry. The tabl | `--agent-card` | `-a` | `A2ACLI_AGENT_CARD` | (unset) | Agent Card reference: host, card URL, or file path | | `--endpoint` | `-e` | `A2ACLI_ENDPOINT` | (unset) | Direct interface URL; skips card resolution | | `--transport` | | `A2ACLI_TRANSPORT` | (card order) | Transport preference: `rest`, `jsonrpc`, `grpc` | -| `--output` | `-o` | `A2ACLI_OUTPUT` | `text` | Output format: `text` or `json` | +| `--a2a-version` | | `A2ACLI_A2A_VERSION` | (unset) | A2A protocol version to advertise to the server | +| `--output` | `-o` | `A2ACLI_OUTPUT` | `text` | Output format: `text`, `json`, or `jsonl` | | `--svc-param` | | `A2ACLI_SVC_PARAM` | (unset) | Service parameter, `key=value` | | `--auth` | | `A2ACLI_AUTH` | (unset) | Authorization credentials (redacted in `config show`) | | `--tenant` | | `A2ACLI_TENANT` | (unset) | Tenant identifier, sent on every request | @@ -116,7 +117,7 @@ bash run.sh ## Next -Lesson 4 goes deeper into [messages and tasks](../messages-and-tasks/). You will build multi-part messages, stream replies, and manage tasks. +Lesson 4 goes deeper into [messages and tasks](../04-messages-and-tasks/). You will build multi-part messages, stream replies, and send async. ## Learn more diff --git a/examples/config/run.sh b/examples/03-config/run.sh similarity index 100% rename from examples/config/run.sh rename to examples/03-config/run.sh diff --git a/examples/messages-and-tasks/README.md b/examples/04-messages-and-tasks/README.md similarity index 50% rename from examples/messages-and-tasks/README.md rename to examples/04-messages-and-tasks/README.md index 2279898..75a4f28 100644 --- a/examples/messages-and-tasks/README.md +++ b/examples/04-messages-and-tasks/README.md @@ -1,24 +1,24 @@ # Lesson 4 — messages and tasks -You can already talk to an agent. This lesson explores two richer areas. First, building a message from several **parts**. Second, managing the **tasks** an agent creates. +You can already talk to an agent. This lesson explores two richer areas. First, building a message from several **parts**. Second, the **task** every send creates. ## What you'll learn - The three kinds of message part: text, file, and data - How to combine parts in one message - How to stream a reply and how to send async -- How to inspect and manage tasks with `task get`, `task list`, `task subscribe`, and `task cancel` +- How a send maps to a task, and the `task` commands for servers that keep tasks ## Prerequisites -The `a2a` CLI installed (see the [repo README](../../README.md)). This lesson reuses the Python script from lesson 1, whose short per-word delay makes long-running tasks easy to watch. You do not need to have finished the earlier lessons first. +The `a2a` CLI installed (see the [repo README](../../README.md)). This lesson reuses the Python script from [lesson 1](../01-exec-demo/), whose short per-word delay makes streaming easy to watch. You do not need to have finished the earlier lessons first. ## Start the agent Run the agent in **terminal A**: ```bash -a2a server --exec "python3 -u ../exec-demo/a2a_unaware_agent.py" --name "Word Numberer" --port 8080 +a2a server --exec "python3 -u ../01-exec-demo/a2a_unaware_agent.py" --name "Word Numberer" --port 8080 ``` Set the card once in **terminal B** so the commands below stay short: @@ -46,7 +46,7 @@ a2a send --data-part '{"priority":"high"}' a2a send --text-part "with an attachment" --file-part note.txt --media-type text/plain ``` -> This demo agent reads only the first text part. The other parts are still sent — add `-o json` or `--verbose` to see the full message the CLI builds. +> The CLI flattens every part into text on the script's stdin, so this demo agent numbers all of them — including the file's name and metadata. Add `-o json` or `--verbose` to see the full message the CLI builds. ### Streaming and async @@ -60,27 +60,31 @@ a2a send --async "one two three four five" ## Tasks -Every `send` creates a **task**. The async send above prints its id; use it below: +Every `send` creates a **task**. The `--async` send prints its id and state right away: -```bash -# Inspect one task -a2a task get -a2a task get --history 10 -o json - -# List recent tasks, optionally filtered -a2a task list -a2a task list --status completed --limit 20 +```text +Task: 01a08153-324e-7683-8551-320a70453e60 +Context: 01a08153-324e-7729-9632-7ecc52f71689 +Status: submitted +History: + [user] one two three four five +``` -# Follow a running task until it finishes -a2a task subscribe +Once you have a task id, the `task` commands inspect and manage it: -# Cancel a task -a2a task cancel +```bash +a2a task get # inspect one task +a2a task get --history 10 -o json +a2a task list --status completed --limit 20 # list recent tasks +a2a task subscribe # follow it until it finishes +a2a task cancel # cancel it ``` +> These commands need a server that **keeps** its tasks. The demo `--exec` server runs each request synchronously and does not store them, so against it the send commands above work but `task get`/`list`/`subscribe`/`cancel` return an error. Point them at a task-backed A2A server to see them in action. + ## Run the whole lesson -`run.sh` starts the agent and walks through the message and task commands, then stops the agent: +`run.sh` starts the agent and walks through the message, streaming, and async commands, then stops the agent: ```bash bash run.sh diff --git a/examples/messages-and-tasks/note.txt b/examples/04-messages-and-tasks/note.txt similarity index 100% rename from examples/messages-and-tasks/note.txt rename to examples/04-messages-and-tasks/note.txt diff --git a/examples/messages-and-tasks/priority.json b/examples/04-messages-and-tasks/priority.json similarity index 100% rename from examples/messages-and-tasks/priority.json rename to examples/04-messages-and-tasks/priority.json diff --git a/examples/messages-and-tasks/run.sh b/examples/04-messages-and-tasks/run.sh similarity index 71% rename from examples/messages-and-tasks/run.sh rename to examples/04-messages-and-tasks/run.sh index baa6ddb..78f1dfb 100755 --- a/examples/messages-and-tasks/run.sh +++ b/examples/04-messages-and-tasks/run.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Lesson 3, end to end: multi-part messages, streaming, async, and task commands. +# Lesson 4, end to end: multi-part messages, streaming, and async. # Requires the `a2a` CLI on your PATH (go install github.com/a2aproject/a2a-cli@latest). set -uo pipefail cd "$(dirname "$0")" @@ -13,7 +13,7 @@ URL="http://localhost:$PORT" export A2ACLI_AGENT_CARD="$URL" # so the client commands can skip -a # Start the lesson 1 script as a server in the background; stop it on exit. -a2a server --exec "python3 -u ../exec-demo/a2a_unaware_agent.py" --name "Word Numberer" --port "$PORT" --quiet & +a2a server --exec "python3 -u ../01-exec-demo/a2a_unaware_agent.py" --name "Word Numberer" --port "$PORT" --quiet & SERVER_PID=$! trap 'kill "$SERVER_PID" 2>/dev/null' EXIT @@ -37,5 +37,6 @@ a2a send --stream "one two three four five" echo; echo "== async: returns a task id ==" a2a send --async "one two three four five" -echo; echo "== list recent tasks ==" -a2a task list --limit 5 +# The `task get`/`list`/`subscribe`/`cancel` commands need a server that keeps +# its tasks. This demo `--exec` server runs synchronously and does not store +# them, so those commands are covered in the README rather than run here. diff --git a/examples/README.md b/examples/README.md index dc4bfba..61e0606 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,25 +10,25 @@ To get started you need only the `a2a` CLI installed. Every lesson starts its ow ## Lessons -### 1. Build a quick A2A server — [`exec-demo/`](exec-demo/) +### 1. Build a quick A2A server — [`01-exec-demo/`](01-exec-demo/) The `a2a` CLI is a client for A2A servers. It sends messages, tracks task progress, and fetches results. So first you need a server to talk to. Learn how to stand up a simple demo server. You will turn an ordinary script into a working A2A server with `--exec`, then send it a message and read the reply. No A2A-specific code required. -### 2. Discover and talk to an agent — [`card-and-send/`](card-and-send/) +### 2. Discover and talk to an agent — [`02-card-and-send/`](02-card-and-send/) Before you can use an agent, you need to know what it can do. Every A2A agent answers that with an **agent card**. Learn the client side: read an agent's card, save it, set it once through config, and send a text message. -### 3. Configure the CLI — [`config/`](config/) +### 3. Configure the CLI — [`03-config/`](03-config/) Learn the three ways to pass a setting: a CLI flag, a session environment variable, and a `.env` file. See how `a2a config show` tells you which one won, plus a table of every setting you can configure. -### 4. Messages and tasks — [`messages-and-tasks/`](messages-and-tasks/) +### 4. Messages and tasks — [`04-messages-and-tasks/`](04-messages-and-tasks/) -Go deeper: build messages from text, file, and data parts; stream and send async; and manage the tasks an agent creates with `task get`, `task list`, `task subscribe`, and `task cancel`. +Go deeper: build messages from text, file, and data parts; stream a reply; and send async to get back a task id and watch its lifecycle. Includes a reference for the `task` commands. ## Learn more