@posthog/agent
Version:
TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog
136 lines (133 loc) • 4.98 kB
JavaScript
import { Logger } from './utils/logger.js';
class TodoManager {
fileManager;
logger;
constructor(fileManager, logger) {
this.fileManager = fileManager;
this.logger =
logger || new Logger({ debug: false, prefix: "[TodoManager]" });
}
async readTodos(taskId) {
try {
const content = await this.fileManager.readTaskFile(taskId, "todos.json");
if (!content) {
return null;
}
const parsed = JSON.parse(content);
this.logger.debug("Loaded todos", {
taskId,
total: parsed.metadata.total,
pending: parsed.metadata.pending,
in_progress: parsed.metadata.in_progress,
completed: parsed.metadata.completed,
});
return parsed;
}
catch (error) {
this.logger.debug("Failed to read todos.json", {
taskId,
error: error instanceof Error ? error.message : String(error),
});
return null;
}
}
async writeTodos(taskId, todos) {
this.logger.debug("Writing todos", {
taskId,
total: todos.metadata.total,
pending: todos.metadata.pending,
in_progress: todos.metadata.in_progress,
completed: todos.metadata.completed,
});
await this.fileManager.writeTaskFile(taskId, {
name: "todos.json",
content: JSON.stringify(todos, null, 2),
type: "artifact",
});
this.logger.info("Todos saved", {
taskId,
total: todos.metadata.total,
completed: todos.metadata.completed,
});
}
parseTodoWriteInput(toolInput) {
const items = [];
if (toolInput.todos && Array.isArray(toolInput.todos)) {
for (const todo of toolInput.todos) {
items.push({
content: todo.content || "",
status: todo.status || "pending",
activeForm: todo.activeForm || todo.content || "",
});
}
}
const metadata = this.calculateMetadata(items);
return { items, metadata };
}
calculateMetadata(items) {
const total = items.length;
const pending = items.filter((t) => t.status === "pending").length;
const in_progress = items.filter((t) => t.status === "in_progress").length;
const completed = items.filter((t) => t.status === "completed").length;
return {
total,
pending,
in_progress,
completed,
last_updated: new Date().toISOString(),
};
}
async getTodoContext(taskId) {
const todos = await this.readTodos(taskId);
if (!todos || todos.items.length === 0) {
return "";
}
const lines = ["## Previous Todo List\n"];
lines.push("You previously created the following todo list:\n");
for (const item of todos.items) {
const statusIcon = item.status === "completed"
? "✓"
: item.status === "in_progress"
? "▶"
: "○";
lines.push(`${statusIcon} [${item.status}] ${item.content}`);
}
lines.push(`\nProgress: ${todos.metadata.completed}/${todos.metadata.total} completed\n`);
return lines.join("\n");
}
// check for TodoWrite tool call and persist if found
async checkAndPersistFromMessage(message, taskId) {
if (message.type !== "assistant" ||
typeof message.message !== "object" ||
!message.message ||
!("content" in message.message) ||
!Array.isArray(message.message.content)) {
return null;
}
for (const block of message.message.content) {
if (block.type === "tool_use" && block.name === "TodoWrite") {
try {
this.logger.info("TodoWrite detected, persisting todos", { taskId });
const todoList = this.parseTodoWriteInput(block.input);
await this.writeTodos(taskId, todoList);
this.logger.info("Persisted todos successfully", {
taskId,
total: todoList.metadata.total,
completed: todoList.metadata.completed,
});
return todoList;
}
catch (error) {
this.logger.error("Failed to persist todos", {
taskId,
error: error instanceof Error ? error.message : String(error),
});
return null;
}
}
}
return null;
}
}
export { TodoManager };
//# sourceMappingURL=todo-manager.js.map