Skip to content

Commit b2f24bd

Browse files
committed
Stamp interrupted stop reason on send_input interrupt
send_input with interrupt:true already unblocked wait_agents as interrupted, but only the overlay flipped. Stamp session.stopReason after the follow-up queues so that wait JSON includes stop_reason interrupted, matching interrupt_agent.
1 parent c707aa4 commit b2f24bd

3 files changed

Lines changed: 26 additions & 2 deletions

File tree

src/subagent/agent-fleet.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,8 +1103,13 @@ describe("interrupt_agent unblocks wait_agents", () => {
11031103
await callTool(sendInput, { target: id, message: "stop that", interrupt: true });
11041104
const waited = await waiting;
11051105
expect(waited.timed_out).toBe(false);
1106-
const results = waited.results as { status: string }[];
1107-
expect(results[0]!.status).toBe("interrupted");
1106+
const results = waited.results as {
1107+
agent_id: string;
1108+
status: string;
1109+
stop_reason?: string;
1110+
}[];
1111+
expect(results).toEqual([{ agent_id: id, status: "interrupted", stop_reason: "interrupted" }]);
1112+
expect(deps.sessions.get(id)?.stopReason).toBe("interrupted");
11081113
followupGate.resolve("later");
11091114
});
11101115

src/subagent/session-store.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,19 @@ describe("terminal stop reasons", () => {
308308
expect(store.interruptOne(session.id).ok).toBe(true);
309309
expect(store.get(session.id)?.stopReason).toBe("interrupted");
310310
});
311+
312+
test("sendInputOne interrupt records stopReason interrupted", () => {
313+
const store = createSubAgentSessionStore();
314+
const session = store.start({ description: "d", agentId: "a", brief: "b", retained: true });
315+
store.markRunning(session.id);
316+
store.registerInterrupt(session.id, () => {});
317+
store.registerFollowup(session.id, () => new Promise(() => {}));
318+
expect(store.sendInputOne(session.id, "stop that", { interrupt: true })).toEqual({
319+
ok: true,
320+
status: "interrupted",
321+
});
322+
expect(store.get(session.id)?.stopReason).toBe("interrupted");
323+
});
311324
});
312325

313326
describe("CL-6943 reusable worker sessions", () => {

src/subagent/session-store.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,12 @@ export function createSubAgentSessionStore(
13031303
queueFollowupTurn(id, message, "interrupted", {
13041304
...(opts.onFollowupReply !== undefined ? { onReply: opts.onFollowupReply } : {}),
13051305
});
1306+
// After beginFollowupTurn, which clears leftover stopReason. Stamp
1307+
// here so an in-flight wait_agents overlay can project interrupted
1308+
// without flipping lifecycle off the live follow-up.
1309+
mutate(id, (s) => {
1310+
s.stopReason = "interrupted";
1311+
});
13061312
pruneRetained();
13071313
return { ok: true, status: "interrupted" };
13081314
}

0 commit comments

Comments
 (0)