Reference AAEP subscriber that prints event streams to the terminal in a readable format
Project description
CLI Debug Subscriber
A reference AAEP subscriber that connects to any producer's /events SSE endpoint and prints the event stream in a screen-reader-friendly terminal format. Useful for debugging, demos, and as a starting point for your own subscriber.
If you're new to AAEP and want to see what events look like in practice, this is the easiest way.
What this subscriber does
- Connects to any AAEP producer's
/eventsSSE endpoint - Parses each event and prints it in a clear human-readable format
- Handles all 12 core event types
- Replies to
awaiting.confirmationandawaiting.clarificationevents interactively - Color-codes critical-urgency events when the terminal supports it
- Validates each received event against the AAEP schemas (optional, via
--validate) - Saves the captured stream to a JSONL file (optional, via
--save)
This subscriber is the simplest possible AAEP consumer. It demonstrates the protocol's value without any AT integration — you can run it against any producer and observe how the protocol surfaces information to users.
Installation
cd examples/subscribers/cli-debug
pip install -e .
Requires Python 3.10 or newer.
Quick start
In one terminal, start any AAEP producer (e.g., the python-minimal example):
python -m aaep_minimal_producer.server --port 8080
In another terminal, run this subscriber:
aaep-listen --endpoint http://localhost:8080
In a third terminal, send a request to the producer:
curl -X POST http://localhost:8080/sessions \
-H "Content-Type: application/json" \
-d '{"user_message": "What is my balance?"}'
You should see events stream into the subscriber's terminal in real time, including state changes, tool invocations, streaming output, and the session completion event.
For the confirmation flow, try:
curl -X POST http://localhost:8080/sessions \
-H "Content-Type: application/json" \
-d '{"user_message": "Send an email to alice@example.com"}'
The subscriber will display the confirmation prompt and ask you (in the terminal) to accept or reject. Your decision is sent back to the producer via POST /messages.
Usage
aaep-listen --endpoint URL [OPTIONS]
Required:
--endpoint URL Producer base URL (e.g., http://localhost:8080)
Optional:
--save FILE Also save events to this JSONL file
--validate Validate each event against AAEP schemas
--filter-urgency LEVEL Only display events with this urgency (normal|critical)
--filter-type TYPE Only display events of this type (repeatable)
--auto-reject Auto-reject all confirmations (for unattended use)
--auto-accept Auto-accept all confirmations (DANGEROUS, debug only)
--no-color Disable terminal colors
--quiet Print events as compact one-line JSON only
--help Show this help
--version Show version
Sample output
[12:34:56.789] aaep:agent.session.started Processing: What is my balance?
[12:34:56.823] aaep:agent.state.changed Considering the request.
from_state: idle -> to_state: thinking
[12:34:57.105] aaep:agent.tool.invoked Calling fetch_balance.
tool: fetch_balance
risk_level: low
irreversible: false
[12:34:57.401] aaep:agent.tool.completed $3,247.18
tool: fetch_balance
status: success
[12:34:57.452] aaep:agent.state.changed Generating response.
from_state: calling_tool -> to_state: writing_output
[12:34:57.501] aaep:agent.output.streaming Your balance is $3,247.18.
position: 0 complete: false
[12:34:57.612] aaep:agent.output.streaming Anything else?
position: 27 complete: true
[12:34:57.701] aaep:agent.session.completed Response complete.
duration_ms: 912
tool_invocations_count: 1
Critical-urgency events appear in red (or with !! prefix if --no-color).
Confirmation flow
When the producer emits an awaiting.confirmation event, the subscriber pauses and prompts:
!! [12:34:57.300] aaep:agent.awaiting.confirmation Confirm: call send_email?
action: Call send_email with: to=alice@example.com, subject=Hello
consequence: This action cannot be easily undone.
risk_level: high
irreversible: true
default_decision: reject
timeout: 300 seconds
Accept this action? [y/N/?]:
yoryes→ accept (sendsdecision: "accept")nornoor just Enter → reject (sendsdecision: "reject")?→ show the full event JSON
The default is reject, matching the protocol's safe-by-default contract for irreversible high-risk actions.
Using as a debugging tool
Common debug recipes:
# Save everything from a session for later inspection
aaep-listen --endpoint http://localhost:8080 --save session.jsonl
# Only see critical events
aaep-listen --endpoint http://localhost:8080 --filter-urgency critical
# Validate every event against schemas (catches malformed producers)
aaep-listen --endpoint http://localhost:8080 --validate
# Capture without prompting in CI
aaep-listen --endpoint http://localhost:8080 --auto-reject --save run.jsonl
# Compact JSON output for piping into jq or other tools
aaep-listen --endpoint http://localhost:8080 --quiet | jq 'select(.urgency == "critical")'
Using as the basis for your own subscriber
This subscriber's source (aaep_cli_debug/listener.py) is structured as a starting point for real subscribers:
- The SSE consumer is in
aaep_cli_debug/listener.py:listen() - The event-to-text rendering is in
aaep_cli_debug/listener.py:format_event() - The reply mechanism is in
aaep_cli_debug/listener.py:send_reply()
To build an AT-integrated subscriber, replace format_event() with calls to your AT's speech engine, and send_reply() with your AT's user-input mechanism. The transport layer (SSE consumption, reply posting) doesn't change.
See ../nvda-addon-prototype/ for a worked example of replacing the rendering layer with an NVDA speech-engine integration.
Project layout
cli-debug/
├── README.md
├── pyproject.toml
├── aaep_cli_debug/
│ ├── __init__.py
│ └── listener.py # SSE consumer + event formatter + reply sender
└── tests/
└── test_listener.py
See also
- Subscribers Guide — full guide to building AAEP subscribers
../nvda-addon-prototype/— NVDA add-on subscriber example../web-subscriber-react/— browser-based subscriber exampleaaep-tools— capture and replay tools that complement this debugger
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aaep_cli_debug-1.0.0.tar.gz.
File metadata
- Download URL: aaep_cli_debug-1.0.0.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4b491a60aa1f2c8816553668df63fea90ddadd1b9198db2bc8ba48c7b87aa19
|
|
| MD5 |
6ed9aeeb9ea20a812858774d4e5d511a
|
|
| BLAKE2b-256 |
e93d1b0adec5b29074cf644265d9c8b8a10c23923c0d028f9d3a611e7241a37f
|
File details
Details for the file aaep_cli_debug-1.0.0-py3-none-any.whl.
File metadata
- Download URL: aaep_cli_debug-1.0.0-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01447e56268d6c654777c5e882c2fc5cca573a589fd947007a6d66b1a30c88e2
|
|
| MD5 |
0afe702281780c9e34e20262fbf7c81d
|
|
| BLAKE2b-256 |
115dc9f9be7a8a46438a95cea8cef27845053553c76d8f48659496107d54a84d
|