























@@ -602,6 +602,56 @@ describe("subagent registry seam flow", () => {
602602expect(run?.outcome?.status).toBe("error");
603603});
604604605+it("announces aborted agent.wait snapshots as killed subagent failures", async () => {
606+mocks.callGateway.mockImplementation(async (request: { method?: string }) => {
607+if (request.method === "agent.wait") {
608+return {
609+status: "ok",
610+startedAt: 100,
611+endedAt: 250,
612+stopReason: "aborted",
613+};
614+}
615+return {};
616+});
617+618+mod.registerSubagentRun({
619+runId: "run-aborted-wait",
620+childSessionKey: "agent:main:subagent:child",
621+requesterSessionKey: "agent:main:main",
622+requesterDisplayKey: "main",
623+task: "aborted wait",
624+cleanup: "keep",
625+expectsCompletionMessage: true,
626+});
627+628+await waitForFast(() => {
629+expect(mocks.runSubagentAnnounceFlow).toHaveBeenCalledTimes(1);
630+});
631+const announceParams = expectRecordFields(
632+getMockCallArg(mocks.runSubagentAnnounceFlow, 0, 0, "aborted wait announce"),
633+{ childRunId: "run-aborted-wait" },
634+"aborted wait announce params",
635+);
636+expectRecordFields(
637+announceParams.outcome,
638+{
639+status: "error",
640+error: "subagent run terminated",
641+startedAt: 100,
642+endedAt: 250,
643+elapsedMs: 150,
644+},
645+"aborted wait announce outcome",
646+);
647+648+const run = mod
649+.listSubagentRunsForRequester("agent:main:main")
650+.find((entry) => entry.runId === "run-aborted-wait");
651+expect(run?.endedReason).toBe("subagent-killed");
652+expect(run?.outcome?.status).toBe("error");
653+});
654+605655it("reconciles stale active runs from persisted terminal session state during sweep", async () => {
606656mocks.callGateway.mockImplementation(async (request: { method?: string }) => {
607657if (request.method === "agent.wait") {
@@ -917,6 +967,78 @@ describe("subagent registry seam flow", () => {
917967expect(run?.outcome?.status).toBe("error");
918968});
919969970+it("announces aborted lifecycle end events as killed subagent failures", async () => {
971+mocks.callGateway.mockImplementation(async (request: { method?: string }) => {
972+if (request.method === "agent.wait") {
973+return { status: "pending" };
974+}
975+return {};
976+});
977+978+mod.registerSubagentRun({
979+runId: "run-aborted-end",
980+childSessionKey: "agent:main:subagent:child",
981+requesterSessionKey: "agent:main:main",
982+requesterDisplayKey: "main",
983+task: "aborted task",
984+cleanup: "keep",
985+expectsCompletionMessage: true,
986+});
987+988+const lastOnAgentEventCall = mocks.onAgentEvent.mock.calls[
989+mocks.onAgentEvent.mock.calls.length - 1
990+] as unknown as
991+| [(evt: { runId: string; stream: string; data: Record<string, unknown> }) => void]
992+| undefined;
993+const lifecycleHandler = lastOnAgentEventCall?.[0];
994+expect(lifecycleHandler).toBeTypeOf("function");
995+996+lifecycleHandler?.({
997+runId: "run-aborted-end",
998+stream: "lifecycle",
999+data: {
1000+phase: "start",
1001+startedAt: 10,
1002+},
1003+});
1004+lifecycleHandler?.({
1005+runId: "run-aborted-end",
1006+stream: "lifecycle",
1007+data: {
1008+phase: "end",
1009+startedAt: 10,
1010+endedAt: 20,
1011+stopReason: "aborted",
1012+},
1013+});
1014+1015+await waitForFast(() => {
1016+expect(mocks.runSubagentAnnounceFlow).toHaveBeenCalledTimes(1);
1017+});
1018+const announceParams = expectRecordFields(
1019+getMockCallArg(mocks.runSubagentAnnounceFlow, 0, 0, "aborted announce"),
1020+{ childRunId: "run-aborted-end" },
1021+"aborted announce params",
1022+);
1023+expectRecordFields(
1024+announceParams.outcome,
1025+{
1026+status: "error",
1027+error: "subagent run terminated",
1028+startedAt: 10,
1029+endedAt: 20,
1030+elapsedMs: 10,
1031+},
1032+"aborted announce outcome",
1033+);
1034+1035+const run = mod
1036+.listSubagentRunsForRequester("agent:main:main")
1037+.find((entry) => entry.runId === "run-aborted-end");
1038+expect(run?.endedReason).toBe("subagent-killed");
1039+expect(run?.outcome?.status).toBe("error");
1040+});
1041+9201042it("preserves run-mode keep entries past SESSION_RUN_TTL_MS sweep", async () => {
9211043mod.registerSubagentRun({
9221044runId: "run-keep-survives-ttl",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。