Skip to main content
Glama
blizzy78
by blizzy78
update_task.js6.49 kB
import { z } from 'zod'; import { zodToJsonSchema } from 'zod-to-json-schema'; import { DoneStatus, FailedStatus, TaskComplexitySchema, TaskCriticalPathSchema, TaskDefinitionsOfDoneSchema, TaskDescriptionSchema, TaskGoalSchema, TaskIDSchema, TaskStatusSchema, TaskTitleSchema, TaskUncertaintyAreasSchema, toBasicTaskInfo, TodoStatus, } from '../tasks.js'; const TaskUpdateSchema = z.object({ taskID: TaskIDSchema.describe('The identifier of the task to change status'), set: z .object({ status: TaskStatusSchema.optional().describe('The new status of this task'), title: TaskTitleSchema.optional(), description: TaskDescriptionSchema.optional(), goal: TaskGoalSchema.optional(), criticalPath: TaskCriticalPathSchema.optional(), estimatedComplexity: TaskComplexitySchema.optional(), }) .optional() .describe('Optional properties to update on this task'), add: z .object({ dependsOnTaskIDs: TaskIDSchema.array().min(1).optional().describe('New tasks that this task depends on'), definitionsOfDone: TaskDefinitionsOfDoneSchema.optional(), uncertaintyAreas: TaskUncertaintyAreasSchema.optional(), lessonsLearned: z .string() .min(1) .array() .min(1) .optional() .describe('Lessons learned while executing this task that may inform future tasks'), verificationEvidence: z .string() .min(1) .array() .min(1) .optional() .describe('Verification evidence that this task was executed as planned, and that the definitions of done were met'), }) .optional() .describe('Optional properties to add to this task'), remove: z .object({ dependsOnTaskIDs: TaskIDSchema.array().min(1).optional().describe('Tasks that this task no longer depends on'), }) .optional() .describe('Optional properties to remove from this task'), }); export const UpdateTaskArgsSchema = z.object({ tasks: TaskUpdateSchema.array().min(1).describe('The tasks to update'), }); export const UPDATE_TASK = 'update_task'; export const updateTaskTool = { name: UPDATE_TASK, title: 'Update tasks', description: `Updates the status and/or other properties of one or more tasks. Must use this tool before executing tasks, and when finished executing tasks. Should always include lessons learned to inform future tasks. Important: Always update multiple tasks in a single call if dependencies allow it.`, inputSchema: zodToJsonSchema(UpdateTaskArgsSchema, { $refStrategy: 'none' }), }; export async function handleUpdateTask({ tasks }, taskDB, singleAgent) { const updatedTasks = new Array(); for (const taskUpdate of tasks) { const task = handleUpdateSingleTask(taskUpdate, taskDB); updatedTasks.push(task); } const taskID = tasks.map((t) => t.taskID)[0]; const incompleteTaskIDs = taskDB.incompleteTasksInTree(taskID).map((t) => t.taskID); const res = { tasksUpdated: updatedTasks.map((t) => toBasicTaskInfo(t, false, t.status !== DoneStatus && t.status !== FailedStatus, t.status === TodoStatus)), incompleteTasksIdealOrder: singleAgent ? incompleteTaskIDs : undefined, }; return { content: [], structuredContent: res, }; } function handleUpdateSingleTask({ taskID, set, add, remove }, taskDB) { const task = taskDB.get(taskID); if (!task) { throw new Error(`Task not found: ${taskID}`); } if (set) { const { status: newStatus, title, description, goal, criticalPath, estimatedComplexity } = set; const oldStatus = task.status; const critPathDepsNotDone = task.dependsOnTaskIDs.filter((depTaskID) => { const depTask = taskDB.get(depTaskID); return depTask.criticalPath && depTask.status !== 'done'; }); const transitionValidations = [ { from: DoneStatus, to: FailedStatus, validate() { throw new Error(`Can't transition from ${oldStatus} to ${newStatus}`); }, }, { from: FailedStatus, to: DoneStatus, validate() { throw new Error(`Can't transition from ${oldStatus} to ${newStatus}`); }, }, { to: DoneStatus, validate() { if (critPathDepsNotDone.length > 0) { throw new Error(`Can't transition task ${taskID} to ${newStatus}: Critical path dependencies are not ${DoneStatus}: ${critPathDepsNotDone.join(', ')}`); } }, }, ]; transitionValidations .filter((tv) => !tv.from || tv.from === oldStatus) .filter((tv) => tv.to === newStatus) .forEach((tv) => tv.validate()); if (newStatus) { task.status = newStatus; } if (title) { task.title = title; } if (description) { task.description = description; } if (goal) { task.goal = goal; } if (typeof criticalPath !== 'undefined') { task.criticalPath = criticalPath; } if (estimatedComplexity) { task.estimatedComplexity = estimatedComplexity; } } if (add) { const { definitionsOfDone: addDefinitionsOfDone, uncertaintyAreas: addUncertaintyAreas, lessonsLearned: addLessonsLearned, verificationEvidence: addVerificationEvidence, } = add; if (addDefinitionsOfDone) { task.definitionsOfDone.push(...addDefinitionsOfDone); } if (addUncertaintyAreas) { task.uncertaintyAreas.push(...addUncertaintyAreas); } if (addLessonsLearned) { task.lessonsLearned.push(...addLessonsLearned); } if (addVerificationEvidence) { task.verificationEvidence.push(...addVerificationEvidence); } } if (remove) { const { dependsOnTaskIDs: removeDependsOnTaskIDs } = remove; if (removeDependsOnTaskIDs) { task.dependsOnTaskIDs = task.dependsOnTaskIDs.filter((depTaskID) => !removeDependsOnTaskIDs.includes(depTaskID)); } } return task; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/blizzy78/mcp-task-manager'

If you have feedback or need assistance with the MCP directory API, please join our Discord server