Spaces:
Running
Running
| import { DynamicStructuredTool } from "@langchain/core/tools"; | |
| import { z } from "zod"; | |
| interface Task { | |
| id: number; | |
| description: string; | |
| status: "pending" | "in_progress" | "completed"; | |
| createdAt: Date; | |
| completedAt?: Date; | |
| } | |
| class TaskTracker { | |
| private tasks: Task[] = []; | |
| private nextId = 1; | |
| addTask(description: string): Task { | |
| const task: Task = { | |
| id: this.nextId++, | |
| description, | |
| status: "pending", | |
| createdAt: new Date(), | |
| }; | |
| this.tasks.push(task); | |
| return task; | |
| } | |
| updateTaskStatus(id: number, status: Task["status"]): Task | null { | |
| const task = this.tasks.find((t) => t.id === id); | |
| if (task) { | |
| task.status = status; | |
| if (status === "completed") { | |
| task.completedAt = new Date(); | |
| } | |
| return task; | |
| } | |
| return null; | |
| } | |
| getTasks(): Task[] { | |
| return [...this.tasks]; | |
| } | |
| getActiveTasks(): Task[] { | |
| return this.tasks.filter((t) => t.status !== "completed"); | |
| } | |
| clear(): void { | |
| this.tasks = []; | |
| this.nextId = 1; | |
| } | |
| formatTaskList(): string { | |
| if (this.tasks.length === 0) { | |
| return "No tasks in the list."; | |
| } | |
| const statusEmoji = { | |
| pending: "β³", | |
| in_progress: "π", | |
| completed: "β ", | |
| }; | |
| return this.tasks | |
| .map( | |
| (t) => | |
| `${statusEmoji[t.status]} [${t.id}] ${t.description} (${t.status})`, | |
| ) | |
| .join("\n"); | |
| } | |
| } | |
| const taskTracker = new TaskTracker(); | |
| export const planTasksTool = new DynamicStructuredTool({ | |
| name: "plan_tasks", | |
| description: | |
| "Plan and break down a complex task into smaller steps. Use this BEFORE starting any multi-step work to organize your approach.", | |
| schema: z.object({ | |
| tasks: z | |
| .array(z.string()) | |
| .min(1) | |
| .describe( | |
| "List of task descriptions in order of execution. Keep each task focused and achievable with a single tool call.", | |
| ), | |
| }), | |
| func: async (input: { tasks: string[] }) => { | |
| taskTracker.clear(); | |
| const createdTasks = input.tasks.map((desc) => taskTracker.addTask(desc)); | |
| return `Task plan created with ${createdTasks.length} tasks:\n${taskTracker.formatTaskList()}\n\nStart with task 1 and mark it as in_progress when you begin.`; | |
| }, | |
| }); | |
| export const updateTaskTool = new DynamicStructuredTool({ | |
| name: "update_task", | |
| description: | |
| "Update the status of a task. Mark as 'in_progress' when starting, 'completed' when done.", | |
| schema: z.object({ | |
| taskId: z.number().min(1).describe("The task ID to update"), | |
| status: z | |
| .enum(["pending", "in_progress", "completed"]) | |
| .describe("The new status for the task"), | |
| }), | |
| func: async (input: { taskId: number; status: Task["status"] }) => { | |
| const task = taskTracker.updateTaskStatus(input.taskId, input.status); | |
| if (!task) { | |
| return `Error: Task ${input.taskId} not found.`; | |
| } | |
| const activeTasks = taskTracker.getActiveTasks(); | |
| const nextTask = activeTasks.find((t) => t.status === "pending"); | |
| let response = `Task ${task.id} marked as ${task.status}: "${task.description}"`; | |
| if (input.status === "completed" && nextTask) { | |
| response += `\n\nNext task: [${nextTask.id}] ${nextTask.description}`; | |
| } else if (input.status === "completed" && activeTasks.length === 0) { | |
| response += "\n\nAll tasks completed! π"; | |
| } | |
| response += `\n\nCurrent task list:\n${taskTracker.formatTaskList()}`; | |
| return response; | |
| }, | |
| }); | |
| export const viewTasksTool = new DynamicStructuredTool({ | |
| name: "view_tasks", | |
| description: "View the current task list and their statuses.", | |
| schema: z.object({}), | |
| func: async () => { | |
| return taskTracker.formatTaskList(); | |
| }, | |
| }); | |
| export const taskTrackerTools = [planTasksTool, updateTaskTool, viewTasksTool]; | |