feat(worker): add PlanningChainCoordinator for sequential subtask execution

Coordinates Waiting -> Queued transitions between sibling subtasks: when a child finishes Done, the next Waiting sibling is promoted to Queued. WorkerHub.QueuePlanningSubtasksAsync exposes this to the UI; TaskRunner advances the chain on completion. Also tightens the planning-session prompt: planner must use MCP tools, not direct edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-04-25 09:36:01 +02:00
parent 288d2ece8b
commit 16e1ddd129
6 changed files with 283 additions and 4 deletions

View File

@@ -48,6 +48,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
private readonly IPlanningTerminalLauncher _launcher;
private readonly PlanningAggregator _planningAggregator;
private readonly PlanningMergeOrchestrator _planningMergeOrchestrator;
private readonly PlanningChainCoordinator _planningChain;
public WorkerHub(
QueueService queue,
@@ -61,7 +62,8 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
PlanningSessionManager planning,
IPlanningTerminalLauncher launcher,
PlanningAggregator planningAggregator,
PlanningMergeOrchestrator planningMergeOrchestrator)
PlanningMergeOrchestrator planningMergeOrchestrator,
PlanningChainCoordinator planningChain)
{
_queue = queue;
_agentService = agentService;
@@ -75,6 +77,30 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
_launcher = launcher;
_planningAggregator = planningAggregator;
_planningMergeOrchestrator = planningMergeOrchestrator;
_planningChain = planningChain;
}
public async Task QueuePlanningSubtasksAsync(string parentTaskId)
{
try
{
await _planningChain.QueueSubtasksSequentiallyAsync(parentTaskId, Context.ConnectionAborted);
}
catch (InvalidOperationException ex)
{
throw new HubException(ex.Message);
}
await using var ctx = await _dbFactory.CreateDbContextAsync();
var childIds = await ctx.Tasks
.Where(t => t.ParentTaskId == parentTaskId)
.Select(t => t.Id)
.ToListAsync();
await _broadcaster.TaskUpdated(parentTaskId);
foreach (var id in childIds)
await _broadcaster.TaskUpdated(id);
_queue.WakeQueue();
}
public string Ping() => $"pong v{Version}";