fix(ui): keep explicit ended steer targets

This commit is contained in:
Ayaan Zaidi 2026-03-29 10:26:05 +05:30
parent 83808fe494
commit 3a43401924
No known key found for this signature in database
2 changed files with 42 additions and 15 deletions

View File

@ -764,7 +764,7 @@ describe("executeSlashCommand /steer (soft inject)", () => {
);
});
it("ignores ended subagent sessions when resolving target", async () => {
it("keeps ended subagent targets so steer does not fall back to the current session", async () => {
const request = vi.fn(async (method: string, _payload?: unknown) => {
if (method === "sessions.list") {
return {
@ -790,16 +790,9 @@ describe("executeSlashCommand /steer (soft inject)", () => {
"researcher try again",
);
// "researcher" is ended, so the full string is sent to current session
expect(result.content).toBe("Steered.");
expect(request).toHaveBeenCalledWith(
"chat.send",
expect.objectContaining({
sessionKey: "agent:main:main",
message: "researcher try again",
deliver: false,
}),
);
expect(result.content).toBe("No active run matched `researcher`. Use `/redirect` instead.");
expect(request).toHaveBeenCalledWith("sessions.list", {});
expect(request).not.toHaveBeenCalledWith("chat.send", expect.anything());
});
it("returns a no-op summary when the current session has no active run", async () => {
@ -915,6 +908,40 @@ describe("executeSlashCommand /redirect (hard kill-and-restart)", () => {
});
});
it("redirects an ended subagent instead of falling back to the current session", async () => {
const request = vi.fn(async (method: string, _payload?: unknown) => {
if (method === "sessions.list") {
return {
sessions: [
row("agent:main:main"),
row("agent:main:subagent:researcher", {
spawnedBy: "agent:main:main",
endedAt: Date.now() - 60_000,
}),
],
};
}
if (method === "sessions.steer") {
return { status: "started", runId: "run-3", messageSeq: 1 };
}
throw new Error(`unexpected method: ${method}`);
});
const result = await executeSlashCommand(
{ request } as unknown as GatewayBrowserClient,
"agent:main:main",
"redirect",
"researcher start over completely",
);
expect(result.content).toBe("Redirected `researcher`.");
expect(result.trackRunId).toBeUndefined();
expect(request).toHaveBeenCalledWith("sessions.steer", {
key: "agent:main:subagent:researcher",
message: "start over completely",
});
});
it("returns usage when no message is provided", async () => {
const request = vi.fn();

View File

@ -642,10 +642,6 @@ function resolveSteerSubagent(
if (!key || !isSubagentSessionKey(key)) {
continue;
}
// P1: skip ended sessions so stale subagents are not targeted
if (session.endedAt) {
continue;
}
const normalizedKey = key.toLowerCase();
const parsed = parseAgentSessionKey(normalizedKey);
const belongsToCurrentSession = isWithinCurrentSessionSubtree(
@ -675,6 +671,10 @@ function resolveSteerSubagent(
* Resolve an optional subagent target from the first word of args.
* Returns the resolved session key and the remaining message, or
* falls back to the current session key with the full args as message.
*
* Ended subagents are still resolved here so explicit `/steer <id> ...`
* can surface the correct "No active run matched" message and `/redirect <id> ...`
* can restart that specific session instead of silently steering the current one.
*/
async function resolveSteerTarget(
client: GatewayBrowserClient,