From 8c13173dc576684a0cbee2e545088a59e21e49a6 Mon Sep 17 00:00:00 2001 From: Lauren ten Hoor <32955832+laurentenhoor@users.noreply.github.com> Date: Tue, 10 Feb 2026 08:34:30 +0800 Subject: [PATCH] fix: add explicit worker state update in task_pickup after dispatch (#23) (#31) Adds defense-in-depth by explicitly calling activateWorker() in task_pickup.ts after dispatchTask() returns. This ensures the worker state (active, issueId, model, sessionKey, startTime) is properly set in projects.json even if dispatchTask's internal state update encounters issues. The redundant update: - Sets active=true, issueId, and model for both spawn and reuse cases - Sets sessionKey and startTime only on new spawns (not on session reuse) - Provides fallback if race conditions or I/O errors affect dispatch.ts Fixes #23 --- lib/tools/task-pickup.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/tools/task-pickup.ts b/lib/tools/task-pickup.ts index 02468e7..7143e17 100644 --- a/lib/tools/task-pickup.ts +++ b/lib/tools/task-pickup.ts @@ -17,7 +17,7 @@ import { dispatchTask } from "../dispatch.js"; import { type Issue, type StateLabel } from "../task-managers/task-manager.js"; import { createProvider } from "../task-managers/index.js"; import { selectModel } from "../model-selector.js"; -import { getProject, getWorker, readProjects } from "../projects.js"; +import { activateWorker, getProject, getWorker, readProjects } from "../projects.js"; import type { ToolContext } from "../types.js"; import { detectContext, generateGuardrails } from "../context-guard.js"; import { isDevTier, isTier, type Tier } from "../tiers.js"; @@ -313,6 +313,27 @@ export function createTaskPickupTool(api: OpenClawPluginApi) { pluginConfig, }); + // 8b. Explicitly update worker state in projects.json + // Defense in depth: ensure state is set even if dispatchTask had issues + const now = new Date().toISOString(); + const stateUpdateParams: { + issueId: string; + model: string; + sessionKey?: string; + startTime?: string; + } = { + issueId: String(issue.iid), + model: modelAlias, + }; + + // Only set sessionKey and startTime on new spawn (not on reuse) + if (dispatchResult.sessionAction === "spawn") { + stateUpdateParams.sessionKey = dispatchResult.sessionKey; + stateUpdateParams.startTime = now; + } + + await activateWorker(workspaceDir, groupId, role, stateUpdateParams); + // 9. Send notification to project group const notifyConfig = getNotificationConfig(pluginConfig); await notify(