feat(worker): warn on near-duplicate titles in add_task/batch_add_tasks

add_task and batch_add_tasks now report up to 3 open (non-terminal)
tasks in the same list with a strongly overlapping title, so a
parallel agent can notice and mention a likely duplicate instead of
silently creating one. The task is always created regardless. Uses a
cheap normalized-word overlap heuristic (no embeddings/LLM call),
robust to German umlaut/digraph spelling variants. Breaking change:
AddTask now returns AddTaskResult { task, possibleDuplicates } instead
of a bare TaskRefDto; BatchAddTaskResult gained a PossibleDuplicates
field.
This commit is contained in:
mika kuns
2026-08-06 11:24:17 +02:00
parent 7cfe280a23
commit 3e07536ee9
5 changed files with 199 additions and 12 deletions
+10 -5
View File
@@ -7,7 +7,9 @@ public sealed record BatchAddTaskInput(string Title, string? Description = null,
public sealed record BatchSetMyDayInput(string TaskId, bool IsMyDay, int? SortOrder = null);
public sealed record BatchGetTaskResult(string Id, bool Found, TaskDto? Task, string? Error);
public sealed record BatchAddTaskResult(int Index, string Title, bool Ok, TaskRefDto? Task, string? Error);
public sealed record BatchAddTaskResult(
int Index, string Title, bool Ok, TaskRefDto? Task,
IReadOnlyList<PossibleDuplicateDto>? PossibleDuplicates, string? Error);
public sealed record BatchTaskResult(string TaskId, bool Ok, string? Error);
public sealed record BatchCancelResult(string TaskId, bool Ok, bool Cancelled, string? Error);
public sealed record BatchCleanupResult(string TaskId, bool Ok, bool Removed, bool BranchDeleted, string? Error);
@@ -62,8 +64,11 @@ public sealed class BatchMcpTools
"Create many tasks in one list at once. Each item: { title, description?, model? } " +
"(model: haiku|sonnet|opus, blank = inherit list/global default). " +
"queueImmediately enqueues every created task. " +
"Returns one result per item: { index, title, ok, task, error }; task is a lean reference " +
"(id, listId, title, status, sortOrder, isMyDay), not the description you just sent. Max 100 items.")]
"Returns one result per item: { index, title, ok, task, possibleDuplicates, error }; task is " +
"a lean reference (id, listId, title, status, sortOrder, isMyDay), not the description you just " +
"sent. Each item is always created — possibleDuplicates is a non-blocking heads-up (up to 3 open " +
"tasks in the same list with a strongly overlapping title, id/title/status only); check it and " +
"mention any hit to the caller, but do not treat it as an error. Max 100 items.")]
public async Task<IReadOnlyList<BatchAddTaskResult>> BatchAddTasks(
string listId,
BatchAddTaskInput[] tasks,
@@ -82,12 +87,12 @@ public sealed class BatchMcpTools
var created = await _svc.AddTask(
listId, item.Title, item.Description, createdBy,
queueImmediately, item.Model, cancellationToken);
results.Add(new BatchAddTaskResult(i, item.Title, true, created, null));
results.Add(new BatchAddTaskResult(i, item.Title, true, created.Task, created.PossibleDuplicates, null));
}
catch (OperationCanceledException) { throw; }
catch (Exception ex)
{
results.Add(new BatchAddTaskResult(i, item.Title, false, null, ex.Message));
results.Add(new BatchAddTaskResult(i, item.Title, false, null, null, ex.Message));
}
}
return results;