Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/agents/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ReadFile } from '../gadgets/ReadFile.js';
import { Sleep } from '../gadgets/Sleep.js';
import { CreatePR } from '../gadgets/github/index.js';
import { Tmux } from '../gadgets/tmux.js';
import { TodoDelete, TodoUpsert } from '../gadgets/todo/index.js';
import { TodoDelete, TodoUpdateStatus, TodoUpsert } from '../gadgets/todo/index.js';
import {
AddChecklistToCard,
CreateTrelloCard,
Expand Down Expand Up @@ -290,6 +290,7 @@ function createAgentBuilderWithGadgets(
new Sleep(),
// Task tracking gadgets
new TodoUpsert(),
new TodoUpdateStatus(),
new TodoDelete(),
// GitHub gadgets (no PR creation for planning)
...(isReadOnlyAgent ? [] : [new CreatePR()]),
Expand Down
15 changes: 6 additions & 9 deletions src/agents/prompts/templates/implementation.eta
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@ You are an expert software engineer implementing features and fixing issues base

## Task Tracking

Use TodoUpsert to create a todo list after reading the Trello card. This helps you:
- Plan your work upfront
- Track progress through implementation
- Stay focused and avoid getting lost in exploration

**Workflow:**
1. After reading the card, create todos for each major step (e.g., "Create feature branch", "Implement X", "Write tests", "Run lint/type checks", "Create PR")
2. Mark each todo as `in_progress` when you start it
3. Mark each todo as `done` when you complete it
Use the todo gadgets to plan and track your progress:

1. **Plan**: After reading the Trello card, use `TodoUpsert` to create todos for major steps
2. **Start**: Use `TodoUpdateStatus` to mark a todo as `in_progress` when you begin working on it
3. **Complete**: Use `TodoUpdateStatus` to mark it as `done` when finished
4. **One at a time**: Only have ONE todo in_progress at any time

## Understanding the Codebase

Expand Down
42 changes: 42 additions & 0 deletions src/agents/prompts/templates/partials/rules-efficiency.eta
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,45 @@ in a single batch. Avoid the 'fix-run-repeat' loop for known breaking changes.
When validating changes, always prioritize auto-fixing commands (e.g., format, lint --fix) before
running read-only checks. If a generated artifact (like a migration or lockfile) looks incorrect,
investigate the environment state rather than manually patching the output.

### Acting on EditFile/WriteFile Results (CRITICAL)

EditFile and WriteFile return structured output. You MUST read and act on it.

**Status Codes:**
- `status=success` - Edit worked, but CHECK THE DIAGNOSTICS SECTION
- `status=failed` - Search content not found, USE THE SUGGESTIONS
- `status=error` - Operation failed (permissions, path), read error message

**On status=failed (search not found):**

The output includes a SUGGESTIONS section with similar content found in the file:
```
SUGGESTIONS (similar content found):
Line 42 (85% similar):
```{what actually exists}```
```

1. READ this section - it shows what the file actually contains
2. Adjust your search pattern to match the actual content
3. Common issues: whitespace differences, indentation, content changed by previous edit
4. NEVER retry the exact same search - that's a loop

**On status=success (check diagnostics):**

Success responses include TypeScript and Biome diagnostics:
```
=== TypeScript Check ===
{any type errors from your edit}

=== Biome Lint ===
{any lint issues from your edit}
```

If diagnostics show issues, FIX THEM IMMEDIATELY before making more edits.
Don't proceed to other files until the current file is clean.

**Recovery Escalation:**
1. First failure: Use SUGGESTIONS to adjust search pattern
2. Second failure: Read entire file with ReadFile, understand actual structure
3. Third failure: Use WriteFile to replace the entire file content
15 changes: 6 additions & 9 deletions src/agents/prompts/templates/respond-to-review.eta
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ You are an expert software engineer addressing code review feedback on a pull re

## Task Tracking

Use TodoUpsert to create a todo list after reading the review comments. This helps you:
- Track each review comment that needs addressing
- Avoid missing any feedback
- Stay focused and organized

**Workflow:**
1. After reading comments, create a todo for each comment/issue to address
2. Mark each todo as `in_progress` when you start it
3. Mark each todo as `done` when you complete it AND reply to the comment
Use the todo gadgets to track review comments:

1. **Plan**: After reading comments, use `TodoUpsert` to create a todo for each comment to address
2. **Start**: Use `TodoUpdateStatus` to mark a todo as `in_progress` when you begin working on it
3. **Complete**: Use `TodoUpdateStatus` to mark it as `done` when finished AND reply to the comment
4. **One at a time**: Only have ONE todo in_progress at any time

## Understanding the Codebase

Expand Down
3 changes: 2 additions & 1 deletion src/agents/review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
formatCheckStatus,
} from '../gadgets/github/index.js';
import { Tmux } from '../gadgets/tmux.js';
import { TodoDelete, TodoUpsert } from '../gadgets/todo/index.js';
import { TodoDelete, TodoUpdateStatus, TodoUpsert } from '../gadgets/todo/index.js';
import { githubClient } from '../github/client.js';
import type { AgentInput, AgentResult, CascadeConfig, ProjectConfig } from '../types/index.js';
import { cleanupLogDirectory, cleanupLogFile, createFileLogger } from '../utils/fileLogger.js';
Expand Down Expand Up @@ -253,6 +253,7 @@ function createReviewAgentBuilder(
new Sleep(),
// Task tracking gadgets
new TodoUpsert(),
new TodoUpdateStatus(),
new TodoDelete(),
// GitHub gadgets (read + create review)
new GetPRDetails(),
Expand Down
6 changes: 5 additions & 1 deletion src/agents/utils/agentLoop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,13 @@ function addGadgetSpecificLogContext(

if (gadgetName === 'TodoUpsert') {
if (parameters.id) logContext.id = parameters.id;
if (parameters.status) logContext.status = parameters.status;
if (parameters.content) logContext.todo = truncateContent(String(parameters.content), 80);
}

if (gadgetName === 'TodoUpdateStatus') {
logContext.id = parameters.id;
logContext.status = parameters.status;
}
}

// ============================================================================
Expand Down
52 changes: 49 additions & 3 deletions src/config/hintConfig.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { execSync } from 'node:child_process';
import type { TrailingMessage } from 'llmist';
import { formatTodoList, loadTodos } from '../gadgets/todo/storage.js';

Expand Down Expand Up @@ -33,6 +34,31 @@ function getAgentHint(agentType?: string): string {
return AGENT_HINTS.default;
}

/**
* Run a shell command and return output, or null on error.
*/
function runCommand(command: string): string | null {
try {
return execSync(command, { encoding: 'utf-8', timeout: 5000 }).trim();
} catch {
return null;
}
}

/**
* Get git status output (short format for brevity).
*/
function getGitStatus(): string | null {
return runCommand('git status --short');
}

/**
* Get PR view output if a PR exists for current branch.
*/
function getPRView(): string | null {
return runCommand('gh pr view 2>/dev/null');
}

/**
* Format the iteration status line with appropriate urgency indicator.
*/
Expand Down Expand Up @@ -76,13 +102,33 @@ export function getIterationTrailingMessage(agentType?: string): TrailingMessage
return (ctx) => {
const iterationStatus = formatIterationStatus(ctx.iteration, ctx.maxIterations, batchHint);

// For implementation agent, include the current todo list
// For implementation agent, include progress info, git status, and PR status
if (agentType === 'implementation') {
const sections: string[] = [iterationStatus];

// Add todo list if there are todos
const todos = loadTodos();
if (todos.length > 0) {
const todoListFormatted = formatTodoList(todos);
return `${iterationStatus}\n\n## Current Progress\n\n${todoListFormatted}`;
sections.push(`## Current Progress\n\n${formatTodoList(todos)}`);
}

// Add git status
const gitStatus = getGitStatus();
if (gitStatus) {
sections.push(`## Git Status\n\n\`\`\`\n${gitStatus}\n\`\`\``);
} else {
sections.push('## Git Status\n\nNo uncommitted changes.');
}

// Add PR status if a PR exists
const prView = getPRView();
if (prView) {
sections.push(`## PR Status\n\n\`\`\`\n${prView}\n\`\`\``);
} else {
sections.push('## PR Status\n\nNo PR exists for current branch.');
}

return sections.join('\n\n');
}

return iterationStatus;
Expand Down
46 changes: 46 additions & 0 deletions src/gadgets/todo/TodoUpdateStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* TodoUpdateStatus gadget - Update the status of existing todo items.
* Helps agents track progress through implementation tasks.
*/
import { Gadget, z } from 'llmist';
import { type TodoStatus, formatTodoList, loadTodos, saveTodos } from './storage.js';

export class TodoUpdateStatus extends Gadget({
name: 'TodoUpdateStatus',
description: `Update the status of an existing todo item.
Use this to track progress: mark todos as in_progress when starting, done when complete.`,
schema: z.object({
id: z.string().describe('ID of the todo to update (required)'),
status: z.enum(['pending', 'in_progress', 'done']).describe('New status'),
comment: z.string().optional().describe('Brief explanation of why this change is needed'),
}),
examples: [
{
params: { id: '1', status: 'in_progress', comment: 'Starting work on first task' },
output:
'✏️ Updated todo #1 → in_progress.\n\n📋 Todo List\n Progress: 0/1 done, 1 in progress, 0 pending\n\n🔄 #1 [in_progress]: Read and understand requirements',
comment: 'Mark todo as in progress',
},
{
params: { id: '1', status: 'done', comment: 'Task completed successfully' },
output:
'✏️ Updated todo #1 → done.\n\n📋 Todo List\n Progress: 1/1 done, 0 in progress, 0 pending\n\n✅ #1 [done]: Read and understand requirements',
comment: 'Mark todo as done',
},
],
}) {
override execute(params: this['params']): string {
const { id, status } = params;
const todos = loadTodos();
const index = todos.findIndex((t) => t.id === id);

if (index === -1) {
throw new Error(`Todo #${id} not found. Use TodoUpsert to create todos first.`);
}

todos[index].status = status as TodoStatus;
todos[index].updatedAt = new Date().toISOString();
saveTodos(todos);
return `✏️ Updated todo #${id} → ${status}.\n\n${formatTodoList(todos)}`;
}
}
Loading