feat(api): GET /api/tasks — operator visibility into A2A turns (#339) - #342
feat(api): GET /api/tasks — operator visibility into A2A turns (#339)#342mabry1985 wants to merge 1 commit into
Conversation
Scheduled jobs had `/api/scheduler/jobs` and subagent runs had `/api/agents`, but the turns themselves — what the agent is working on right now — had no operator surface. During the #337 runaway, `/api/agents` and `/api/delegations` both read empty while ~2,000 turns were executing, because they track subagent runs and delegations rather than A2A tasks; establishing what was actually running meant reading the sqlite store over ssh. Two choices taken from that incident: - Read the sqlite file the SDK writes rather than `DatabaseTaskStore.list`, whose owner filter (resolved from a ServerCallContext the operator API has no natural value for) could silently return an empty list — the exact failure this endpoint exists to prevent. - Always return `counts_by_state` for the whole store, not just the page. The runaway was legible in one number (2,030 tasks WORKING); a page of the newest 100 would have hidden it. Degrades to `available: False` on a missing or corrupt store instead of 500ing, since this is the surface you reach for when things are already broken, and reports unparseable rows as UNKNOWN rather than dropping them. Committed OpenAPI + API reference regenerated (CI-gated). Console panel is NOT included — this is the headless surface only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 46 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Fixes #339.
Why
Scheduled jobs have
/api/scheduler/jobs; subagent runs have/api/agents. The turns themselves had no operator surface. During the #337 runaway,/api/agentsand/api/delegationsboth returned empty while ~2,000 turns were executing — they track subagent runs and delegations, not A2A tasks. Working out what was actually running meant readinga2a-tasks.dbover ssh with sqlite3.What
GET /api/tasks?limit=&state=&context_id=→{tasks, count, counts_by_state, db, available}.Two design choices taken directly from the incident:
DatabaseTaskStore.list. The store's list filters by an owner resolved from aServerCallContextthe operator API has no natural value for; an owner mismatch would return an empty list — precisely the "everything looks idle while it isn't" failure this endpoint exists to prevent. A forensics surface must not be able to quietly return nothing.counts_by_statealways covers the whole store, not just the page. The runaway was legible in a single number (2,030 tasks inTASK_STATE_WORKING); a paginated list of the newest 100 would have concealed it.Robustness, on the principle that this is what you reach for when things are already broken:
available: false, never a 500UNKNOWN, not silently droppedstateacceptsworkingorTASK_STATE_WORKINGTests
tests/test_operator_tasks.py(8) covers ordering, the whole-store histogram under paging, both state spellings, context filtering, missing/corrupt store degradation, malformed-row reporting, and limit clamping. Plus 2 route tests for filter pass-through and the unwired default.Full suite: 1743 passed. ruff check + format clean. Committed OpenAPI + API reference regenerated (
check_openapi_spec.pyandgen_api_docs.py --checkboth green).Not included
The issue also suggests surfacing this in the console alongside scheduler jobs, and pairing it with a cancel affordance. This PR is the headless endpoint only — the console panel is a separate piece of work. Worth noting the cancel affordance is now straightforwardly buildable: cancel does genuinely stop a turn (verified under #338, regression test in #341), so a list + cancel button would have let the runaway be stopped through the API instead of by restarting the runtime.
🤖 Generated with Claude Code