feat(worker): wire list-handler phase parameter through handoff chain
Threads a nextPhase parameter (wait/merge/wait_final/merge_final, validated by the new MergeHelperPhase) from handoff_list_handler through HubBroadcaster/WorkerHub into InteractiveLaunchSpecService, which now picks the next session's system prompt (MergeHelperWait/MergeHelperMerge) and model (HandlerWaitAlias/HandlerMergeAlias) from it instead of hardcoding the old two-phase Execute prompt -- this also fixes a build break left by the prior prompt-split task, which removed PromptKind.MergeHelperExecute without updating its only caller. Also sets --model/--effort/--permission-mode explicitly for every list-handler session (Triage included) via PermissionModeResolver instead of inheriting the CLI's ambient model and hardcoding "auto", and adds Task to the merge-helper allowlist so the Merge phase can delegate diff reviews to subagents.
This commit is contained in:
@@ -53,15 +53,60 @@ public sealed class HandoffMcpToolsTests : IDisposable
|
||||
var survivor = await SeedTaskAsync(listId, TaskStatus.WaitingForReview, title: "Survivor");
|
||||
|
||||
var sut = BuildSut();
|
||||
var result = await sut.HandoffListHandler(handlerTask.Id, new[] { survivor.Id }, CancellationToken.None);
|
||||
var result = await sut.HandoffListHandler(handlerTask.Id, new[] { survivor.Id }, cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.True(result.Requested);
|
||||
Assert.Equal(handlerTask.Id, result.TaskId);
|
||||
Assert.Equal(1, result.SurvivingCount);
|
||||
Assert.Equal("wait", result.NextPhase);
|
||||
|
||||
var call = Assert.Single(_hubContext.Proxy.Calls);
|
||||
Assert.Equal("HandoffRequested", call.Method);
|
||||
Assert.Equal(handlerTask.Id, call.Args[0]);
|
||||
Assert.Equal("wait", call.Args[2]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandoffListHandler_NextPhaseDefaultsToWait()
|
||||
{
|
||||
var listId = await SeedListAsync();
|
||||
var handlerTask = await SeedTaskAsync(listId);
|
||||
var survivor = await SeedTaskAsync(listId, TaskStatus.WaitingForReview, title: "Survivor");
|
||||
|
||||
var sut = BuildSut();
|
||||
var result = await sut.HandoffListHandler(handlerTask.Id, new[] { survivor.Id }, cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.Equal("wait", result.NextPhase);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("wait")]
|
||||
[InlineData("merge")]
|
||||
[InlineData("wait_final")]
|
||||
[InlineData("merge_final")]
|
||||
public async Task HandoffListHandler_AcceptsEveryKnownPhase(string phase)
|
||||
{
|
||||
var listId = await SeedListAsync();
|
||||
var handlerTask = await SeedTaskAsync(listId);
|
||||
var survivor = await SeedTaskAsync(listId, TaskStatus.WaitingForReview, title: "Survivor");
|
||||
|
||||
var sut = BuildSut();
|
||||
var result = await sut.HandoffListHandler(handlerTask.Id, new[] { survivor.Id }, phase, CancellationToken.None);
|
||||
|
||||
Assert.Equal(phase, result.NextPhase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandoffListHandler_UnknownPhase_Throws()
|
||||
{
|
||||
var listId = await SeedListAsync();
|
||||
var handlerTask = await SeedTaskAsync(listId);
|
||||
var survivor = await SeedTaskAsync(listId, TaskStatus.WaitingForReview, title: "Survivor");
|
||||
|
||||
var sut = BuildSut();
|
||||
var ex = await Assert.ThrowsAsync<ArgumentException>(() =>
|
||||
sut.HandoffListHandler(handlerTask.Id, new[] { survivor.Id }, "phase-9", CancellationToken.None));
|
||||
Assert.Contains("phase-9", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -72,7 +117,7 @@ public sealed class HandoffMcpToolsTests : IDisposable
|
||||
|
||||
var sut = BuildSut();
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.HandoffListHandler(handlerTask.Id, Array.Empty<string>(), CancellationToken.None));
|
||||
sut.HandoffListHandler(handlerTask.Id, Array.Empty<string>(), cancellationToken: CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -80,7 +125,7 @@ public sealed class HandoffMcpToolsTests : IDisposable
|
||||
{
|
||||
var sut = BuildSut();
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.HandoffListHandler("missing", new[] { "x" }, CancellationToken.None));
|
||||
sut.HandoffListHandler("missing", new[] { "x" }, cancellationToken: CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -91,6 +136,6 @@ public sealed class HandoffMcpToolsTests : IDisposable
|
||||
|
||||
var sut = BuildSut();
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
sut.HandoffListHandler(handlerTask.Id, new[] { "missing" }, CancellationToken.None));
|
||||
sut.HandoffListHandler(handlerTask.Id, new[] { "missing" }, cancellationToken: CancellationToken.None));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user