@@ -6591,6 +6591,48 @@ describe("createAgentChatService", () => {
65916591 expect(sessionService.deleteSession).toHaveBeenCalledWith(session.id);
65926592 });
65936593
6594+ it("purges a running Codex chat even when app-server interrupt and archive requests hang", async () => {
6595+ const events: AgentChatEventEnvelope[] = [];
6596+ const { service, sessionService } = createService({
6597+ onEvent: (event: AgentChatEventEnvelope) => events.push(event),
6598+ });
6599+ const session = await service.createSession({
6600+ laneId: "lane-1",
6601+ provider: "codex",
6602+ model: "gpt-5.4",
6603+ });
6604+
6605+ await service.sendMessage({
6606+ sessionId: session.id,
6607+ text: "Start a Codex turn.",
6608+ }, { awaitDispatch: true });
6609+
6610+ await waitForEvent(
6611+ events,
6612+ (event): event is AgentChatEventEnvelope =>
6613+ event.event.type === "status"
6614+ && event.event.turnStatus === "started"
6615+ && event.event.turnId === "turn-1",
6616+ );
6617+
6618+ mockState.delayedCodexMethods.add("turn/interrupt");
6619+ mockState.delayedCodexMethods.add("thread/archive");
6620+ vi.useFakeTimers();
6621+ try {
6622+ const deleted = service.deleteSession({ sessionId: session.id });
6623+ await vi.advanceTimersByTimeAsync(10_000);
6624+ await expect(deleted).resolves.toBeUndefined();
6625+ } finally {
6626+ vi.useRealTimers();
6627+ }
6628+
6629+ expect(sessionService.end).toHaveBeenCalledWith(
6630+ expect.objectContaining({ sessionId: session.id, status: "disposed" }),
6631+ );
6632+ expect(sessionService.deleteSession).toHaveBeenCalledWith(session.id);
6633+ expect(sessionService.get(session.id)).toBeNull();
6634+ });
6635+
65946636 it("does not follow transcript symlinks outside ADE during purge", async () => {
65956637 const { service, sessionService } = createService();
65966638 const session = await service.createSession({
@@ -14700,6 +14742,7 @@ describe("createAgentChatService", () => {
1470014742 isCliWrapped: false,
1470114743 harnessProfile: "verified",
1470214744 } as any,
14745+ getDirtyFileTextForPath: () => "remember unsaved edits",
1470314746 logger: createLogger() as any,
1470414747 });
1470514748
@@ -14708,6 +14751,9 @@ describe("createAgentChatService", () => {
1470814751 expect.objectContaining({ type: "text" }),
1470914752 expect.objectContaining({ type: "file", filename: "note.txt" }),
1471014753 ]));
14754+ const persistedContent = streamMessages[0]?.content as Array<Record<string, unknown>>;
14755+ const filePart = persistedContent.find((part) => part.type === "file") as { data?: Buffer } | undefined;
14756+ expect(filePart?.data?.toString("utf8")).toBe("remember unsaved edits");
1471114757 expect(streamMessages[2]).toEqual({
1471214758 role: "user",
1471314759 content: "Continue from your last step.",
0 commit comments