070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
270 lines
8.8 KiB
TypeScript
270 lines
8.8 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
latestTodosFromEvents,
|
|
latestTodoWriteInputForPinnedCard,
|
|
parseTodoWriteInput,
|
|
unfinishedTodosFromEvents,
|
|
} from '../../src/runtime/todos';
|
|
import type { AgentEvent } from '../../src/types';
|
|
|
|
const firstTodoInput = {
|
|
todos: [
|
|
{ content: 'Draft layout', status: 'completed' },
|
|
{ content: 'Build components', status: 'in_progress', activeForm: 'Building components' },
|
|
{ content: 'Run QA', status: 'pending' },
|
|
{ content: '', status: 'pending' },
|
|
{ content: 'Unknown status defaults pending', status: 'blocked' },
|
|
null,
|
|
],
|
|
};
|
|
|
|
describe('todo event helpers', () => {
|
|
it('normalizes TodoWrite input and ignores malformed items', () => {
|
|
expect(parseTodoWriteInput(firstTodoInput)).toEqual([
|
|
{ content: 'Draft layout', status: 'completed', activeForm: undefined },
|
|
{
|
|
content: 'Build components',
|
|
status: 'in_progress',
|
|
activeForm: 'Building components',
|
|
},
|
|
{ content: 'Run QA', status: 'pending', activeForm: undefined },
|
|
{
|
|
content: 'Unknown status defaults pending',
|
|
status: 'pending',
|
|
activeForm: undefined,
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('uses the latest TodoWrite event as the current todo truth', () => {
|
|
const events: AgentEvent[] = [
|
|
{ kind: 'tool_use', id: 'todo-1', name: 'TodoWrite', input: firstTodoInput },
|
|
{ kind: 'text', text: 'Working...' },
|
|
{ kind: 'tool_use', id: 'todo-empty', name: 'TodoWrite', input: { todos: [] } },
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'todo-2',
|
|
name: 'TodoWrite',
|
|
input: { todos: [{ content: 'Final polish', status: 'pending' }] },
|
|
},
|
|
];
|
|
|
|
expect(latestTodosFromEvents(events)).toEqual([
|
|
{ content: 'Final polish', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('recognizes lowercase OpenCode todowrite events', () => {
|
|
const events: AgentEvent[] = [
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'todo-1',
|
|
name: 'todowrite',
|
|
input: {
|
|
todos: [
|
|
{ content: 'Self-check template', status: 'completed' },
|
|
{ content: 'Emit single artifact', status: 'pending' },
|
|
],
|
|
},
|
|
},
|
|
];
|
|
|
|
expect(unfinishedTodosFromEvents(events)).toEqual([
|
|
{ content: 'Emit single artifact', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('normalizes Codex update_plan input as the current task queue', () => {
|
|
const events: AgentEvent[] = [
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'plan-1',
|
|
name: 'update_plan',
|
|
input: {
|
|
plan: [
|
|
{ step: 'Inspect chat rendering', status: 'completed' },
|
|
{ step: 'Add annotation card', status: 'in_progress' },
|
|
{ step: 'Run focused tests', status: 'pending' },
|
|
],
|
|
},
|
|
},
|
|
];
|
|
|
|
expect(latestTodosFromEvents(events)).toEqual([
|
|
{ content: 'Inspect chat rendering', status: 'completed', activeForm: undefined },
|
|
{ content: 'Add annotation card', status: 'in_progress', activeForm: undefined },
|
|
{ content: 'Run focused tests', status: 'pending', activeForm: undefined },
|
|
]);
|
|
expect(unfinishedTodosFromEvents(events)).toEqual([
|
|
{ content: 'Add annotation card', status: 'in_progress', activeForm: undefined },
|
|
{ content: 'Run focused tests', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('recognizes snake_case todo_write events', () => {
|
|
const input = latestTodoWriteInputForPinnedCard([
|
|
{
|
|
runStatus: 'running',
|
|
events: [
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'todo-1',
|
|
name: 'todo_write',
|
|
input: { todos: [{ content: 'Port task queue card', status: 'pending' }] },
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
expect(parseTodoWriteInput(input)).toEqual([
|
|
{ content: 'Port task queue card', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('accepts native task item text aliases used by different agents', () => {
|
|
expect(parseTodoWriteInput({
|
|
todos: [
|
|
{ description: 'Inspect plan mode output', status: 'completed' },
|
|
{ label: 'Render todo card', status: 'in_progress' },
|
|
{ text: 'Run focused tests', status: 'pending' },
|
|
],
|
|
})).toEqual([
|
|
{ content: 'Inspect plan mode output', status: 'completed', activeForm: undefined },
|
|
{ content: 'Render todo card', status: 'in_progress', activeForm: undefined },
|
|
{ content: 'Run focused tests', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('uses lowercase todowrite as the latest todo truth over older TodoWrite events', () => {
|
|
const events: AgentEvent[] = [
|
|
{ kind: 'tool_use', id: 'todo-1', name: 'TodoWrite', input: firstTodoInput },
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'todo-2',
|
|
name: 'todowrite',
|
|
input: { todos: [{ content: 'Emit single artifact', status: 'pending' }] },
|
|
},
|
|
];
|
|
|
|
expect(latestTodosFromEvents(events)).toEqual([
|
|
{ content: 'Emit single artifact', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('treats an empty latest TodoWrite event as authoritative', () => {
|
|
const events: AgentEvent[] = [
|
|
{ kind: 'tool_use', id: 'todo-1', name: 'TodoWrite', input: firstTodoInput },
|
|
{ kind: 'text', text: 'All done.' },
|
|
{ kind: 'tool_use', id: 'todo-empty', name: 'TodoWrite', input: { todos: [] } },
|
|
];
|
|
|
|
expect(latestTodosFromEvents(events)).toEqual([]);
|
|
expect(unfinishedTodosFromEvents(events)).toEqual([]);
|
|
});
|
|
|
|
it('returns only pending and in-progress todos as unfinished', () => {
|
|
expect(unfinishedTodosFromEvents([
|
|
{ kind: 'tool_use', id: 'todo-1', name: 'TodoWrite', input: firstTodoInput },
|
|
])).toEqual([
|
|
{
|
|
content: 'Build components',
|
|
status: 'in_progress',
|
|
activeForm: 'Building components',
|
|
},
|
|
{ content: 'Run QA', status: 'pending', activeForm: undefined },
|
|
{
|
|
content: 'Unknown status defaults pending',
|
|
status: 'pending',
|
|
activeForm: undefined,
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('marks the active todo as stopped when a failed run ended without a final TodoWrite', () => {
|
|
const input = latestTodoWriteInputForPinnedCard([
|
|
{
|
|
id: 'assistant-1',
|
|
role: 'assistant',
|
|
content: '',
|
|
runStatus: 'failed',
|
|
events: [
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'todo-1',
|
|
name: 'TodoWrite',
|
|
input: {
|
|
todos: [
|
|
{ content: 'Draft layout', status: 'completed' },
|
|
{ content: 'Build components', status: 'in_progress', activeForm: 'Building components' },
|
|
{ content: 'Run QA', status: 'pending' },
|
|
],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
expect(parseTodoWriteInput(input)).toEqual([
|
|
{ content: 'Draft layout', status: 'completed', activeForm: undefined },
|
|
{ content: 'Build components', status: 'stopped', activeForm: 'Building components' },
|
|
{ content: 'Run QA', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('marks the active todo as stopped when a nominally successful run ended with stale progress', () => {
|
|
const input = latestTodoWriteInputForPinnedCard([
|
|
{
|
|
runStatus: 'succeeded',
|
|
endedAt: 3_000,
|
|
events: [
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'todo-1',
|
|
name: 'TodoWrite',
|
|
input: {
|
|
todos: [
|
|
{ content: 'Generate HTML', status: 'in_progress' },
|
|
{ content: 'Self-check', status: 'pending' },
|
|
],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
expect(parseTodoWriteInput(input)).toEqual([
|
|
{ content: 'Generate HTML', status: 'stopped', activeForm: undefined },
|
|
{ content: 'Self-check', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
|
|
it('marks update_plan items as stopped when a terminal run ends with stale progress', () => {
|
|
const input = latestTodoWriteInputForPinnedCard([
|
|
{
|
|
runStatus: 'succeeded',
|
|
endedAt: 3_000,
|
|
events: [
|
|
{
|
|
kind: 'tool_use',
|
|
id: 'plan-1',
|
|
name: 'update_plan',
|
|
input: {
|
|
plan: [
|
|
{ step: 'Inspect chat rendering', status: 'completed' },
|
|
{ step: 'Add annotation card', status: 'in_progress' },
|
|
{ step: 'Run focused tests', status: 'pending' },
|
|
],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
expect(parseTodoWriteInput(input)).toEqual([
|
|
{ content: 'Inspect chat rendering', status: 'completed', activeForm: undefined },
|
|
{ content: 'Add annotation card', status: 'stopped', activeForm: undefined },
|
|
{ content: 'Run focused tests', status: 'pending', activeForm: undefined },
|
|
]);
|
|
});
|
|
});
|