Add statuses filter argument to duoWorkflowWorkflows query
What does this MR do and why?
Adds a statuses argument to the duoWorkflowWorkflows GraphQL query, so callers can filter Duo Agent Platform sessions by exact status instead of only the coarser statusGroup. The new argument is also threaded through the list_duo_sessions MCP tool.
This matters because the AWAITING_INPUT status group lumps together input_required (session resting between chat turns, nothing needed) with plan_approval_required and tool_call_approval_required (session blocked on someone's approval). There was no way to ask for just "sessions waiting on my decision". statusGroup and statuses are mutually exclusive: passing both returns an error rather than silently combining filters. No UI changes — this is a GraphQL API and MCP tool change only.
This builds on a community contribution that did the original GraphQL work, much appreciated. On top of that, this MR:
- Fixes a bug where the finder mapped the status enum a second time, raising
NoMethodErroron any real query. - Moves test coverage from a resolver unit spec to the GraphQL request spec.
Database review — statuses filter
New scope Ai::DuoWorkflows::Workflow.in_statuses, used by
WorkflowsFinder#resolve_statuses. No migration, no new index, no bulk operation.
status IN (7, 8) is plan_approval_required and tool_call_approval_required.
LIMIT 20 is the default GraphQL connection page size.
1. Query.duoWorkflowWorkflows(statuses:)
SELECT "duo_workflows_workflows".* FROM "duo_workflows_workflows"
WHERE "duo_workflows_workflows"."user_id" = 11001664
AND "duo_workflows_workflows"."status" IN (7, 8)
ORDER BY "duo_workflows_workflows"."created_at" DESC
LIMIT 20 OFFSET 0Plan: https://postgres.ai/console/gitlab/gitlab-production-main/sessions/57763/commands/162383
2. Project.duoWorkflowWorkflows(statuses:)
SELECT "duo_workflows_workflows".* FROM "duo_workflows_workflows"
WHERE "duo_workflows_workflows"."user_id" = 11001664
AND "duo_workflows_workflows"."project_id" = 278964
AND "duo_workflows_workflows"."status" IN (7, 8)
ORDER BY "duo_workflows_workflows"."created_at" DESC
LIMIT 20 OFFSET 0Plan: https://postgres.ai/console/gitlab/gitlab-production-main/sessions/57763/commands/162391
3. Existing statusGroup: AWAITING_INPUT, for comparison
Same index, same plan node, same filter mechanism, so this change introduces no new
access pattern. Four of the six existing status groups (paused, completed, failed,
canceled) already map to a single status value, so status IN (<one value>) is not new
either.
SELECT "duo_workflows_workflows".* FROM "duo_workflows_workflows"
WHERE "duo_workflows_workflows"."user_id" = 11001664
AND "duo_workflows_workflows"."status" IN (6, 7, 8)
ORDER BY "duo_workflows_workflows"."created_at" DESC
LIMIT 20 OFFSET 0Plan: https://postgres.ai/console/gitlab/gitlab-production-main/sessions/57763/commands/162400
References
- Issue: #608884 (closed)
- Original community merge request: !254036 (closed)
Screenshots or screen recordings
No UI changes — this is a GraphQL API and MCP tool change.
| Before | After |
|---|---|
How to set up and validate locally
-
Open the GraphQL explorer at
http://gdk.test:3000/-/graphql-explorer. Any signed-in user works — the query returns your own sessions. In the GDK the seeded sessions belong toroot, so sign in as root to have data to look at. -
Compare the coarse filter with the exact one:
{ duoWorkflowWorkflows(statusGroup: AWAITING_INPUT, first: 100) { nodes { statusName } } }{ duoWorkflowWorkflows( statuses: [PLAN_APPROVAL_REQUIRED, TOOL_CALL_APPROVAL_REQUIRED] first: 100 ) { nodes { statusName } } }The first returns a mix of
input_required,plan_approval_required, andtool_call_approval_required; the second returns only the two approval states. That difference is the point of this MR. -
Pass both
statusGroupandstatusestogether and expect the errorOnly one of [statusGroup, statuses] arguments is allowed at the same time.
first: 100 is needed because the connection has no count field and the default page size is 20.
Validating the MCP tool path
A real MCP client needs a personal access token with the mcp scope. Quicker, in rails console:
svc = Mcp::Tools::DuoWorkflows::ListDuoSessionsService.new(name: 'list_duo_sessions')
svc.set_cred(current_user: User.find_by(username: 'root'))
svc.execute(request: nil, params: { arguments: { statuses: %w[plan_approval_required tool_call_approval_required] } })It rejects an unknown status name, and rejects status_group and statuses together.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.