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:
mika kuns
2026-08-06 11:25:32 +02:00
parent 86f962ee7d
commit f8c48e2ed7
5 changed files with 151 additions and 22 deletions
+41 -3
View File
@@ -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);
}
}