From b6031a98e73e38b4ffd4e61699b4ff70f4f71a07 Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Tue, 24 Mar 2026 17:38:38 -0500 Subject: [PATCH] fix: ignore stale rows in subagent steer --- src/agents/subagent-control.test.ts | 85 +++++++++++++++++++++++++++++ src/agents/subagent-control.ts | 2 +- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/agents/subagent-control.test.ts b/src/agents/subagent-control.test.ts index f3ce0c33410..b0a1156bb0a 100644 --- a/src/agents/subagent-control.test.ts +++ b/src/agents/subagent-control.test.ts @@ -856,4 +856,89 @@ describe("steerControlledSubagentRun", () => { text: "stale task is already finished.", }); }); + + it("steers an ended current run that is still waiting on active descendants even when stale older rows exist", async () => { + const childSessionKey = "agent:main:subagent:stale-steer-worker"; + addSubagentRunForTests({ + runId: "run-stale-active-steer", + childSessionKey, + controllerSessionKey: "agent:main:main", + requesterSessionKey: "agent:main:main", + requesterDisplayKey: "main", + task: "stale active steer task", + cleanup: "keep", + createdAt: Date.now() - 9_000, + startedAt: Date.now() - 8_000, + }); + addSubagentRunForTests({ + runId: "run-current-ended-steer", + childSessionKey, + controllerSessionKey: "agent:main:main", + requesterSessionKey: "agent:main:main", + requesterDisplayKey: "main", + task: "current ended steer task", + cleanup: "keep", + createdAt: Date.now() - 5_000, + startedAt: Date.now() - 4_000, + endedAt: Date.now() - 1_000, + outcome: { status: "ok" }, + }); + addSubagentRunForTests({ + runId: "run-descendant-active-steer", + childSessionKey: `${childSessionKey}:subagent:leaf`, + controllerSessionKey: childSessionKey, + requesterSessionKey: childSessionKey, + requesterDisplayKey: childSessionKey, + task: "leaf task", + cleanup: "keep", + createdAt: Date.now() - 500, + startedAt: Date.now() - 500, + }); + + __testing.setDepsForTest({ + callGateway: async >(request: CallGatewayOptions) => { + if (request.method === "agent.wait") { + return {} as T; + } + if (request.method === "agent") { + return { runId: "run-followup-steer" } as T; + } + throw new Error(`unexpected method: ${request.method}`); + }, + }); + + const result = await steerControlledSubagentRun({ + cfg: {} as OpenClawConfig, + controller: { + controllerSessionKey: "agent:main:main", + callerSessionKey: "agent:main:main", + callerIsSubagent: false, + controlScope: "children", + }, + entry: { + runId: "run-current-ended-steer", + childSessionKey, + requesterSessionKey: "agent:main:main", + requesterDisplayKey: "main", + controllerSessionKey: "agent:main:main", + task: "current ended steer task", + cleanup: "keep", + createdAt: Date.now() - 5_000, + startedAt: Date.now() - 4_000, + endedAt: Date.now() - 1_000, + outcome: { status: "ok" }, + }, + message: "updated direction", + }); + + expect(result).toEqual({ + status: "accepted", + runId: "run-followup-steer", + sessionKey: childSessionKey, + sessionId: undefined, + mode: "restart", + label: "current ended steer task", + text: "steered current ended steer task.", + }); + }); }); diff --git a/src/agents/subagent-control.ts b/src/agents/subagent-control.ts index c3fb53e2554..b6fa3690ece 100644 --- a/src/agents/subagent-control.ts +++ b/src/agents/subagent-control.ts @@ -670,7 +670,7 @@ export async function steerControlledSubagentRun(params: { error: "Subagents cannot steer themselves.", }; } - const currentEntry = getSubagentRunByChildSessionKey(params.entry.childSessionKey); + const currentEntry = getLatestSubagentRunByChildSessionKey(params.entry.childSessionKey); const currentHasPendingDescendants = currentEntry && countPendingDescendantRuns(currentEntry.childSessionKey) > 0; if (