fix(worker): make list_tasks/batch_get_tasks lean by default
list_tasks on a list of ~100 verbosely-described tasks could return 390k+ characters in one call, blowing past the caller's token limit. Both tools now default to lean TaskRefDto references (no Description/Result) and take an includeDescription flag to opt back into the full TaskDto payload — same flag-alongside-nullable-payload idiom already used by BatchGetTaskResult/TaskConfigResult. get_task is unchanged.
This commit is contained in:
+41
-3
@@ -149,17 +149,55 @@ public sealed class BatchMcpToolsTests : IDisposable
|
||||
var task = await SeedTaskAsync(listId);
|
||||
var sut = BuildSut();
|
||||
|
||||
var results = await sut.BatchGetTasks(new[] { task.Id, "nope" }, CancellationToken.None);
|
||||
var results = await sut.BatchGetTasks(new[] { task.Id, "nope" }, cancellationToken: CancellationToken.None);
|
||||
|
||||
var found = results.Single(r => r.Id == task.Id);
|
||||
var missing = results.Single(r => r.Id == "nope");
|
||||
Assert.True(found.Found);
|
||||
Assert.NotNull(found.Task);
|
||||
Assert.Null(found.TaskFull);
|
||||
Assert.False(missing.Found);
|
||||
Assert.Null(missing.Task);
|
||||
Assert.Null(missing.TaskFull);
|
||||
Assert.Null(missing.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BatchGetTasks_Default_ReturnsLeanTask_NoTaskFull()
|
||||
{
|
||||
var listId = await SeedListAsync();
|
||||
var task = await SeedTaskAsync(listId);
|
||||
task.Description = "a description that should not come back by default";
|
||||
await _tasks.UpdateAsync(task);
|
||||
var sut = BuildSut();
|
||||
|
||||
var results = await sut.BatchGetTasks(new[] { task.Id }, cancellationToken: CancellationToken.None);
|
||||
|
||||
var found = results.Single(r => r.Id == task.Id);
|
||||
Assert.True(found.Found);
|
||||
Assert.NotNull(found.Task);
|
||||
Assert.Equal(task.Id, found.Task!.Id);
|
||||
Assert.Null(found.TaskFull);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BatchGetTasks_IncludeDescriptionTrue_ReturnsTaskFull()
|
||||
{
|
||||
var listId = await SeedListAsync();
|
||||
var task = await SeedTaskAsync(listId);
|
||||
task.Description = "the full description";
|
||||
await _tasks.UpdateAsync(task);
|
||||
var sut = BuildSut();
|
||||
|
||||
var results = await sut.BatchGetTasks(new[] { task.Id }, includeDescription: true, cancellationToken: CancellationToken.None);
|
||||
|
||||
var found = results.Single(r => r.Id == task.Id);
|
||||
Assert.True(found.Found);
|
||||
Assert.Null(found.Task);
|
||||
Assert.NotNull(found.TaskFull);
|
||||
Assert.Equal("the full description", found.TaskFull!.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BatchDeleteTasks_RunningTask_ReportedNotOk_OthersDeleted()
|
||||
{
|
||||
@@ -212,7 +250,7 @@ public sealed class BatchMcpToolsTests : IDisposable
|
||||
{
|
||||
var sut = BuildSut();
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => sut.BatchGetTasks(Array.Empty<string>(), CancellationToken.None));
|
||||
() => sut.BatchGetTasks(Array.Empty<string>(), cancellationToken: CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -222,7 +260,7 @@ public sealed class BatchMcpToolsTests : IDisposable
|
||||
var ids = Enumerable.Range(0, 101).Select(i => i.ToString()).ToArray();
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => sut.BatchGetTasks(ids, CancellationToken.None));
|
||||
() => sut.BatchGetTasks(ids, cancellationToken: CancellationToken.None));
|
||||
Assert.Contains("max", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,10 +947,11 @@ public sealed class ExternalMcpServiceTests : IDisposable
|
||||
await SeedTaskAsync(listId, "idle", TaskStatus.Idle);
|
||||
var sut = NewService();
|
||||
|
||||
var result = await sut.ListTasks(listId, null, "WaitingForReview", CancellationToken.None);
|
||||
var result = await sut.ListTasks(listId, null, "WaitingForReview", cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("WaitingForReview", result[0].Status);
|
||||
Assert.NotNull(result.Tasks);
|
||||
Assert.Single(result.Tasks!);
|
||||
Assert.Equal("WaitingForReview", result.Tasks![0].Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -961,10 +962,47 @@ public sealed class ExternalMcpServiceTests : IDisposable
|
||||
await SeedTaskAsync(listId, "done", TaskStatus.Done);
|
||||
var sut = NewService();
|
||||
|
||||
var result = await sut.ListTasks(listId, null, "WaitingForChildren", CancellationToken.None);
|
||||
var result = await sut.ListTasks(listId, null, "WaitingForChildren", cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("WaitingForChildren", result[0].Status);
|
||||
Assert.NotNull(result.Tasks);
|
||||
Assert.Single(result.Tasks!);
|
||||
Assert.Equal("WaitingForChildren", result.Tasks![0].Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListTasks_Default_ReturnsLeanReferences_NoDescriptionOrTasksFull()
|
||||
{
|
||||
var listId = await SeedListAsync();
|
||||
var task = await SeedTaskAsync(listId, "with desc");
|
||||
task.Description = "a long description that should not come back by default";
|
||||
await _tasks.UpdateAsync(task);
|
||||
var sut = NewService();
|
||||
|
||||
var result = await sut.ListTasks(listId, cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.False(result.IncludeDescription);
|
||||
Assert.NotNull(result.Tasks);
|
||||
Assert.Null(result.TasksFull);
|
||||
Assert.Single(result.Tasks!);
|
||||
Assert.Equal(task.Id, result.Tasks![0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListTasks_IncludeDescriptionTrue_ReturnsFullTasks()
|
||||
{
|
||||
var listId = await SeedListAsync();
|
||||
var task = await SeedTaskAsync(listId, "with desc");
|
||||
task.Description = "the full description";
|
||||
await _tasks.UpdateAsync(task);
|
||||
var sut = NewService();
|
||||
|
||||
var result = await sut.ListTasks(listId, includeDescription: true, cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.True(result.IncludeDescription);
|
||||
Assert.Null(result.Tasks);
|
||||
Assert.NotNull(result.TasksFull);
|
||||
Assert.Single(result.TasksFull!);
|
||||
Assert.Equal("the full description", result.TasksFull![0].Description);
|
||||
}
|
||||
|
||||
// ── MergeTask allowWaitingForReview ───────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user