Skip to content

Commit a19bacb

Browse files
committed
Resolve turn interruption only on close cancellation
1 parent f4163f0 commit a19bacb

2 files changed

Lines changed: 28 additions & 9 deletions

File tree

src/CodexAcpServer.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,9 +1223,7 @@ export class CodexAcpServer {
12231223
if (!turn) {
12241224
return;
12251225
}
1226-
void this.interruptPromptTurn(turn, "Cancel").catch((err) => {
1227-
logger.error("Prompt request cancellation failed to interrupt turn", err);
1228-
});
1226+
void this.requestTurnInterrupt(turn, "Cancel");
12291227
};
12301228

12311229
if (signal.aborted) {
@@ -1253,6 +1251,20 @@ export class CodexAcpServer {
12531251
threadId: turn.threadId,
12541252
turnId: turn.turnId,
12551253
});
1254+
try {
1255+
await this.requestTurnInterrupt(turn, requestName);
1256+
} finally {
1257+
this.codexAcpClient.resolveTurnInterrupted({
1258+
threadId: turn.threadId,
1259+
turnId: turn.turnId,
1260+
});
1261+
}
1262+
}
1263+
1264+
private async requestTurnInterrupt(
1265+
turn: { threadId: string, turnId: string },
1266+
requestName: "Cancel" | "Close",
1267+
): Promise<void> {
12561268
try {
12571269
await this.runWithProcessCheck(() => this.codexAcpClient.turnInterrupt({
12581270
threadId: turn.threadId,
@@ -1264,11 +1276,6 @@ export class CodexAcpServer {
12641276
});
12651277
} catch (err) {
12661278
logger.error(`${requestName} - turnInterrupt failed`, err);
1267-
} finally {
1268-
this.codexAcpClient.resolveTurnInterrupted({
1269-
threadId: turn.threadId,
1270-
turnId: turn.turnId,
1271-
});
12721279
}
12731280
}
12741281

src/__tests__/CodexACPAgent/CodexAcpClient.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,8 +899,9 @@ describe('ACP server test', { timeout: 40_000 }, () => {
899899
const turnCompleted = deferred<TurnCompletedNotification>();
900900
vi.spyOn(mockFixture.getCodexAppServerClient(), "awaitTurnCompleted")
901901
.mockReturnValue(turnCompleted.promise);
902+
const turnInterrupt = deferred<void>();
902903
const turnInterruptSpy = vi.spyOn(mockFixture.getCodexAcpClient(), "turnInterrupt")
903-
.mockResolvedValue();
904+
.mockReturnValue(turnInterrupt.promise);
904905
const controller = new AbortController();
905906

906907
const promptPromise = mockFixture.getCodexAcpAgent().prompt({
@@ -920,11 +921,22 @@ describe('ACP server test', { timeout: 40_000 }, () => {
920921
});
921922
});
922923

924+
mockFixture.sendServerNotification({
925+
method: "item/agentMessage/delta",
926+
params: {
927+
threadId: "session-id",
928+
turnId: "turn-id",
929+
itemId: "tail-item",
930+
delta: "tail output",
931+
},
932+
});
923933
turnCompleted.resolve({
924934
threadId: "session-id",
925935
turn: createTurn("turn-id", "completed"),
926936
});
927937
await expect(promptPromise).resolves.toMatchObject({stopReason: "end_turn"});
938+
expect(mockFixture.getAcpConnectionDump([])).toContain("tail output");
939+
turnInterrupt.resolve(undefined);
928940
});
929941

930942
it('interrupts a late-started turn after the ACP prompt request is cancelled', async () => {

0 commit comments

Comments
 (0)