feat(FN-024): Add dependencies parameter to fn_task_update tool
- Added optional dependencies parameter to taskUpdateParams schema - Implemented validation for self-dependency and non-existent task IDs - Updates task dependencies via store.updateTask() when parameter is provided - Preserves existing dependencies when parameter is omitted - Updated tool description to document the new parameter
This commit is contained in:
@@ -544,6 +544,9 @@ const taskUpdateParams = Type.Object({
|
|||||||
STEP_STATUSES.map((s) => Type.Literal(s)),
|
STEP_STATUSES.map((s) => Type.Literal(s)),
|
||||||
{ description: "New status: pending, in-progress, done, or skipped" },
|
{ description: "New status: pending, in-progress, done, or skipped" },
|
||||||
),
|
),
|
||||||
|
dependencies: Type.Optional(Type.Array(Type.String(), {
|
||||||
|
description: "Optional task dependency array. Replaces existing dependencies. Pass ['FN-001', 'FN-002'] to set dependencies. Pass [] to clear all dependencies. Omit parameter to preserve existing dependencies.",
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
// taskLogParams and taskCreateParams are imported from agent-tools.ts
|
// taskLogParams and taskCreateParams are imported from agent-tools.ts
|
||||||
@@ -5071,10 +5074,11 @@ export class TaskExecutor {
|
|||||||
description:
|
description:
|
||||||
"Update a step's status. Call before starting a step (in-progress), " +
|
"Update a step's status. Call before starting a step (in-progress), " +
|
||||||
"after completing it (done), or to skip it (skipped). " +
|
"after completing it (done), or to skip it (skipped). " +
|
||||||
|
"Optionally update task dependencies by passing a dependencies array. " +
|
||||||
"The board updates in real-time.",
|
"The board updates in real-time.",
|
||||||
parameters: taskUpdateParams,
|
parameters: taskUpdateParams,
|
||||||
execute: async (_id: string, params: Static<typeof taskUpdateParams>) => {
|
execute: async (_id: string, params: Static<typeof taskUpdateParams>) => {
|
||||||
const { step, status } = params;
|
const { step, status, dependencies } = params;
|
||||||
|
|
||||||
// Record step progress for stuck task detection.
|
// Record step progress for stuck task detection.
|
||||||
// Step transitions (in-progress, done, skipped) indicate real progress
|
// Step transitions (in-progress, done, skipped) indicate real progress
|
||||||
@@ -5129,6 +5133,43 @@ export class TaskExecutor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle dependencies parameter if provided
|
||||||
|
if (dependencies !== undefined) {
|
||||||
|
// Validate: prevent self-dependency
|
||||||
|
if (dependencies.includes(taskId)) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text" as const,
|
||||||
|
text: `Cannot add self-dependency: ${taskId} cannot depend on itself.`,
|
||||||
|
}],
|
||||||
|
details: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate: all dependency task IDs must exist
|
||||||
|
const invalidIds: string[] = [];
|
||||||
|
for (const depId of dependencies) {
|
||||||
|
try {
|
||||||
|
await store.getTask(depId);
|
||||||
|
} catch {
|
||||||
|
invalidIds.push(depId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidIds.length > 0) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text" as const,
|
||||||
|
text: `Cannot set dependencies — the following task(s) do not exist: ${invalidIds.join(", ")}`,
|
||||||
|
}],
|
||||||
|
details: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update dependencies
|
||||||
|
await store.updateTask(taskId, { dependencies });
|
||||||
|
}
|
||||||
|
|
||||||
const task = await store.updateStep(taskId, stepIndex, status as StepStatus);
|
const task = await store.updateStep(taskId, stepIndex, status as StepStatus);
|
||||||
const stepInfo = task.steps[stepIndex];
|
const stepInfo = task.steps[stepIndex];
|
||||||
if (!stepInfo) {
|
if (!stepInfo) {
|
||||||
|
|||||||
Reference in New Issue
Block a user