Skip to content

feat: implement ListTasks across service, CLI, and MCP - #112

Merged
alDuncanson merged 2 commits into
mainfrom
feat/list-tasks
Sep 8, 2026
Merged

alDuncanson merged 2 commits into
mainfrom
feat/list-tasks

Conversation

@alDuncanson

Copy link
Copy Markdown
Owner

Closes #101

ListTasks is one of the eleven A2A v1.0 methods and Handler implemented it on no surface — there was no way to ask an agent what tasks exist.

Service layer

  • A2AService.list_tasks(...) wraps the SDK call and returns the raw ListTasksResponse for one page, with context_id, status, page_size, page_token, history_length, and include_artifacts pass-through
  • A2AService.list_all_tasks(...) follows next_page_token to the end, with a repeated-token guard so a misbehaving server cannot loop it forever
  • Requests always carry an explicit page size (default 50): an unset proto3 int is indistinguishable from zero, and servers reject a zero page size outright (found live)
  • task_state_from_label / TASK_STATE_LABELS translate compact labels like completed or input-required (hyphens or underscores) into TaskState values

CLI

handler task list with --context-id, --status (choice of real state labels), --page-size, --history-length, and --include-artifacts:

  • text output: one compact line per task (id state context=...)
  • --output json: full wire-format tasks wrapped with a count
  • --output ndjson: one task per line
  • All pages are always fetched rather than silently truncating at the first

MCP

A list_tasks tool with the same filters, returning {count, tasks} in wire format.

Verification

  • 472 tests pass; ruff/ty clean
  • Verified live against the streaming test agent: --output json task list returned all tasks, --status input_required and --context-id filters both narrowed correctly, and --page-size 2 over 6 tasks still returned all 6 across 3 pages

Follow-up

The TUI task browser this method unlocks is intentionally left out of scope; it's a separate feature this PR makes possible.

🤖 Generated with Claude Code

alDuncanson and others added 2 commits September 8, 2026 11:36
ListTasks is one of the eleven A2A v1.0 methods and Handler implemented
it on no surface; there was no way to ask an agent what tasks exist.

A2AService gains list_tasks (one page, raw ListTasksResponse) and
list_all_tasks (follows next_page_token to the end, with a repeated-
token guard so a misbehaving server cannot loop it forever). An unset
proto3 page size is indistinguishable from zero and servers reject
zero, so requests always carry an explicit page size (default 50).
task_state_from_label and TASK_STATE_LABELS translate compact labels
like "completed" or "input-required" into TaskState values for filters.

CLI: handler task list with --context-id, --status, --page-size,
--history-length, and --include-artifacts. Text output is a compact
one-line-per-task listing; --output json wraps the full wire-format
tasks with a count; ndjson emits one task per line. All pages are
always fetched rather than silently truncating at the first.

MCP: a list_tasks tool with the same filters, returning count + tasks.

Verified against the local streaming test agent: listing returns all
tasks across pages (page-size 2 over 6 tasks), and filtering by context
and by status both narrow correctly.

The TUI task browser this unlocks is left as a follow-up.

Closes #101

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- list_all_tasks deduplicates tasks by ID, stops when the server
  returns the token that was just sent (a guaranteed loop), and caps
  pagination at MAX_LIST_TASKS_PAGES so a server minting fresh tokens
  forever cannot spin the client; the old repeated-token guard appended
  the replayed page's tasks before breaking, double-counting them.
- page_size below 1 is rejected with a clear InputValidationError at
  the service, CLI, and MCP layers instead of silently becoming the
  default (0) or reaching the wire (negatives); the 50-task default is
  now stated in the CLI and MCP help.
- task_state_from_label only accepts the real states in
  TASK_STATE_LABELS: "unspecified" maps to the proto default and would
  silently drop the status filter, so it errors like any unknown label.
- The CLI --status option uses the tolerant parser instead of
  click.Choice, so the documented hyphenated spellings
  (input-required) and mixed case work, matching the MCP tool.
- The list_tasks log no longer reports "any" for a zero status value,
  and the test fake raises past its scripted pages instead of replaying
  the last one, so extra requests fail loudly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alDuncanson
alDuncanson marked this pull request as ready for review September 8, 2026 15:43
@alDuncanson
alDuncanson merged commit dd457dd into main Sep 8, 2026
4 checks passed
@alDuncanson
alDuncanson deleted the feat/list-tasks branch September 8, 2026 15:43
alDuncanson added a commit that referenced this pull request Sep 8, 2026
Follow-ups from #112.

list_all_tasks silently returned partial results. When a pagination
defense stopped the crawl early, callers got a short list with no way to
tell it apart from a complete one. It now returns a TaskListing carrying
the tasks plus a truncated flag, surfaced by the CLI in all three output
formats and by the MCP tool as a `truncated` field.

The loop also stops on any non-progressing page rather than only on an
immediately repeated token, so a server cycling two or more tokens is
caught on the first page that contributes nothing instead of spinning to
the page cap.

Drop the hardcoded 50-task default page size. page_size and
history_length are proto3 optional fields with real presence, so leaving
them unset genuinely omits them and the server applies its own default;
the comment claiming otherwise was wrong. Verified against a live agent.

Validation moves into shared validate_page_size and
validate_history_length helpers, used by the service, CLI, and MCP
instead of three copies. page_size now also rejects values above 100,
the spec maximum, which a server would only reject after a round trip.
history_length is validated on get_task as well, which had no check.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement ListTasks

1 participant