feat: add 'blocked' status to tasks and todos (#22735)

This commit is contained in:
anj-s
2026-03-17 16:24:26 -07:00
committed by GitHub
parent e1eefffcf1
commit b8719bcd47
13 changed files with 64 additions and 9 deletions
+2 -1
View File
@@ -13,7 +13,8 @@ updates to the CLI interface.
- `todos` (array of objects, required): The complete list of tasks. Each object - `todos` (array of objects, required): The complete list of tasks. Each object
includes: includes:
- `description` (string): Technical description of the task. - `description` (string): Technical description of the task.
- `status` (enum): `pending`, `in_progress`, `completed`, or `cancelled`. - `status` (enum): `pending`, `in_progress`, `completed`, `cancelled`, or
`blocked`.
## Technical behavior ## Technical behavior
@@ -15,6 +15,7 @@ describe('<ChecklistItem />', () => {
{ status: 'in_progress', label: 'Doing this' }, { status: 'in_progress', label: 'Doing this' },
{ status: 'completed', label: 'Done this' }, { status: 'completed', label: 'Done this' },
{ status: 'cancelled', label: 'Skipped this' }, { status: 'cancelled', label: 'Skipped this' },
{ status: 'blocked', label: 'Blocked this' },
] as ChecklistItemData[])('renders %s item correctly', async (item) => { ] as ChecklistItemData[])('renders %s item correctly', async (item) => {
const { lastFrame, waitUntilReady } = render(<ChecklistItem item={item} />); const { lastFrame, waitUntilReady } = render(<ChecklistItem item={item} />);
await waitUntilReady(); await waitUntilReady();
@@ -13,7 +13,8 @@ export type ChecklistStatus =
| 'pending' | 'pending'
| 'in_progress' | 'in_progress'
| 'completed' | 'completed'
| 'cancelled'; | 'cancelled'
| 'blocked';
export interface ChecklistItemData { export interface ChecklistItemData {
status: ChecklistStatus; status: ChecklistStatus;
@@ -48,6 +49,12 @@ const ChecklistStatusDisplay: React.FC<{ status: ChecklistStatus }> = ({
</Text> </Text>
); );
case 'blocked':
return (
<Text color={theme.status.warning} aria-label="Blocked">
</Text>
);
default: default:
checkExhaustive(status); checkExhaustive(status);
} }
@@ -70,6 +77,7 @@ export const ChecklistItem: React.FC<ChecklistItemProps> = ({
return theme.text.accent; return theme.text.accent;
case 'completed': case 'completed':
case 'cancelled': case 'cancelled':
case 'blocked':
return theme.text.secondary; return theme.text.secondary;
case 'pending': case 'pending':
return theme.text.primary; return theme.text.primary;
@@ -1,5 +1,10 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`<ChecklistItem /> > renders { status: 'blocked', label: 'Blocked this' } item correctly 1`] = `
"⛔ Blocked this
"
`;
exports[`<ChecklistItem /> > renders { status: 'cancelled', label: 'Skipped this' } item correctly 1`] = ` exports[`<ChecklistItem /> > renders { status: 'cancelled', label: 'Skipped this' } item correctly 1`] = `
"✗ Skipped this "✗ Skipped this
" "
@@ -22,6 +22,7 @@ export const TASK_TYPE_LABELS: Record<TaskType, string> = {
export enum TaskStatus { export enum TaskStatus {
OPEN = 'open', OPEN = 'open',
IN_PROGRESS = 'in_progress', IN_PROGRESS = 'in_progress',
BLOCKED = 'blocked',
CLOSED = 'closed', CLOSED = 'closed',
} }
export const TaskStatusSchema = z.nativeEnum(TaskStatus); export const TaskStatusSchema = z.nativeEnum(TaskStatus);
@@ -697,6 +697,7 @@ DO NOT use this tool for simple tasks that can be completed in less than 2 steps
- in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time. - in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time.
- completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed. - completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed.
- cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled. - cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled.
- blocked: Subtask is blocked and cannot be completed at this time.
## Methodology for using this tool ## Methodology for using this tool
@@ -766,6 +767,7 @@ The agent did not use the todo list because this task could be completed by a ti
"in_progress", "in_progress",
"completed", "completed",
"cancelled", "cancelled",
"blocked",
], ],
"type": "string", "type": "string",
}, },
@@ -1451,6 +1453,7 @@ DO NOT use this tool for simple tasks that can be completed in less than 2 steps
- in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time. - in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time.
- completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed. - completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed.
- cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled. - cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled.
- blocked: Subtask is blocked and cannot be completed at this time.
## Methodology for using this tool ## Methodology for using this tool
@@ -1520,6 +1523,7 @@ The agent did not use the todo list because this task could be completed by a ti
"in_progress", "in_progress",
"completed", "completed",
"cancelled", "cancelled",
"blocked",
], ],
"type": "string", "type": "string",
}, },
@@ -543,6 +543,7 @@ DO NOT use this tool for simple tasks that can be completed in less than 2 steps
- in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time. - in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time.
- completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed. - completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed.
- cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled. - cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled.
- blocked: Subtask is blocked and cannot be completed at this time.
## Methodology for using this tool ## Methodology for using this tool
@@ -609,7 +610,13 @@ The agent did not use the todo list because this task could be completed by a ti
[TODOS_ITEM_PARAM_STATUS]: { [TODOS_ITEM_PARAM_STATUS]: {
type: 'string', type: 'string',
description: 'The current status of the task.', description: 'The current status of the task.',
enum: ['pending', 'in_progress', 'completed', 'cancelled'], enum: [
'pending',
'in_progress',
'completed',
'cancelled',
'blocked',
],
}, },
}, },
required: [TODOS_ITEM_PARAM_DESCRIPTION, TODOS_ITEM_PARAM_STATUS], required: [TODOS_ITEM_PARAM_DESCRIPTION, TODOS_ITEM_PARAM_STATUS],
@@ -518,6 +518,7 @@ DO NOT use this tool for simple tasks that can be completed in less than 2 steps
- in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time. - in_progress: Marked just prior to beginning work on a given subtask. You should only have one subtask as in_progress at a time.
- completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed. - completed: Subtask was successfully completed with no errors or issues. If the subtask required more steps to complete, update the todo list with the subtasks. All steps should be identified as completed only when they are completed.
- cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled. - cancelled: As you update the todo list, some tasks are not required anymore due to the dynamic nature of the task. In this case, mark the subtasks as cancelled.
- blocked: Subtask is blocked and cannot be completed at this time.
## Methodology for using this tool ## Methodology for using this tool
@@ -584,7 +585,13 @@ The agent did not use the todo list because this task could be completed by a ti
[TODOS_ITEM_PARAM_STATUS]: { [TODOS_ITEM_PARAM_STATUS]: {
type: 'string', type: 'string',
description: 'The current status of the task.', description: 'The current status of the task.',
enum: ['pending', 'in_progress', 'completed', 'cancelled'], enum: [
'pending',
'in_progress',
'completed',
'cancelled',
'blocked',
],
}, },
}, },
required: [TODOS_ITEM_PARAM_DESCRIPTION, TODOS_ITEM_PARAM_STATUS], required: [TODOS_ITEM_PARAM_DESCRIPTION, TODOS_ITEM_PARAM_STATUS],
+6 -1
View File
@@ -823,7 +823,12 @@ export type ToolResultDisplay =
| TodoList | TodoList
| SubagentProgress; | SubagentProgress;
export type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled'; export type TodoStatus =
| 'pending'
| 'in_progress'
| 'completed'
| 'cancelled'
| 'blocked';
export interface Todo { export interface Todo {
description: string; description: string;
+9 -1
View File
@@ -222,15 +222,23 @@ describe('Tracker Tools Integration', () => {
status: TaskStatus.IN_PROGRESS, status: TaskStatus.IN_PROGRESS,
dependencies: [], dependencies: [],
}; };
const t4 = {
id: 't4',
title: 'T4',
type: TaskType.TASK,
status: TaskStatus.BLOCKED,
dependencies: [],
};
const mockService = { const mockService = {
listTasks: async () => [t1, t2, t3], listTasks: async () => [t1, t2, t3, t4],
} as unknown as TrackerService; } as unknown as TrackerService;
const display = await buildTodosReturnDisplay(mockService); const display = await buildTodosReturnDisplay(mockService);
expect(display.todos).toEqual([ expect(display.todos).toEqual([
{ description: `task: T3 (t3)`, status: 'in_progress' }, { description: `task: T3 (t3)`, status: 'in_progress' },
{ description: `task: T2 (t2)`, status: 'pending' }, { description: `task: T2 (t2)`, status: 'pending' },
{ description: `task: T4 (t4)`, status: 'blocked' },
{ description: `task: T1 (t1)`, status: 'completed' }, { description: `task: T1 (t1)`, status: 'completed' },
]); ]);
}); });
+6 -2
View File
@@ -48,10 +48,11 @@ export async function buildTodosReturnDisplay(
} }
} }
const statusOrder = { const statusOrder: Record<TaskStatus, number> = {
[TaskStatus.IN_PROGRESS]: 0, [TaskStatus.IN_PROGRESS]: 0,
[TaskStatus.OPEN]: 1, [TaskStatus.OPEN]: 1,
[TaskStatus.CLOSED]: 2, [TaskStatus.BLOCKED]: 2,
[TaskStatus.CLOSED]: 3,
}; };
const sortTasks = (a: TrackerTask, b: TrackerTask) => { const sortTasks = (a: TrackerTask, b: TrackerTask) => {
@@ -80,6 +81,8 @@ export async function buildTodosReturnDisplay(
status = 'in_progress'; status = 'in_progress';
} else if (task.status === TaskStatus.CLOSED) { } else if (task.status === TaskStatus.CLOSED) {
status = 'completed'; status = 'completed';
} else if (task.status === TaskStatus.BLOCKED) {
status = 'blocked';
} }
const indent = ' '.repeat(depth); const indent = ' '.repeat(depth);
@@ -585,6 +588,7 @@ class TrackerVisualizeInvocation extends BaseToolInvocation<
const statusEmojis: Record<TaskStatus, string> = { const statusEmojis: Record<TaskStatus, string> = {
open: '⭕', open: '⭕',
in_progress: '🚧', in_progress: '🚧',
blocked: '⛔',
closed: '✅', closed: '✅',
}; };
+4 -1
View File
@@ -19,6 +19,7 @@ describe('WriteTodosTool', () => {
{ description: 'Task 1', status: 'pending' }, { description: 'Task 1', status: 'pending' },
{ description: 'Task 2', status: 'in_progress' }, { description: 'Task 2', status: 'in_progress' },
{ description: 'Task 3', status: 'completed' }, { description: 'Task 3', status: 'completed' },
{ description: 'Task 4', status: 'blocked' },
], ],
}; };
await expect(tool.buildAndExecute(params, signal)).resolves.toBeDefined(); await expect(tool.buildAndExecute(params, signal)).resolves.toBeDefined();
@@ -96,13 +97,15 @@ describe('WriteTodosTool', () => {
{ description: 'First task', status: 'completed' }, { description: 'First task', status: 'completed' },
{ description: 'Second task', status: 'in_progress' }, { description: 'Second task', status: 'in_progress' },
{ description: 'Third task', status: 'pending' }, { description: 'Third task', status: 'pending' },
{ description: 'Fourth task', status: 'blocked' },
], ],
}; };
const result = await tool.buildAndExecute(params, signal); const result = await tool.buildAndExecute(params, signal);
const expectedOutput = `Successfully updated the todo list. The current list is now: const expectedOutput = `Successfully updated the todo list. The current list is now:
1. [completed] First task 1. [completed] First task
2. [in_progress] Second task 2. [in_progress] Second task
3. [pending] Third task`; 3. [pending] Third task
4. [blocked] Fourth task`;
expect(result.llmContent).toBe(expectedOutput); expect(result.llmContent).toBe(expectedOutput);
expect(result.returnDisplay).toEqual(params); expect(result.returnDisplay).toEqual(params);
}); });
+1
View File
@@ -22,6 +22,7 @@ const TODO_STATUSES = [
'in_progress', 'in_progress',
'completed', 'completed',
'cancelled', 'cancelled',
'blocked',
] as const; ] as const;
export interface WriteTodosToolParams { export interface WriteTodosToolParams {