Skip to content

Commit 96f1edc

Browse files
committed
test(api): fix abort signal propagation test timing
1 parent d46cb9e commit 96f1edc

3 files changed

Lines changed: 25 additions & 31 deletions

File tree

src/api/providers/__tests__/openai-codex-native-tool-calls.spec.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -546,23 +546,12 @@ describe("OpenAiCodexHandler native tool calls", () => {
546546
global.fetch = mockFetch as any
547547

548548
const controller = new AbortController()
549-
await handler.completePrompt("Test prompt", { abortSignal: controller.signal })
549+
const promise = handler.completePrompt("Test prompt", { abortSignal: controller.signal })
550+
controller.abort()
551+
await promise
550552

551553
const fetchCallArgs = mockFetch.mock.calls[0]
552-
// The implementation merges signals using AbortSignal.any(),
553-
// which creates a new merged signal when both primary and secondary are provided.
554-
// The merged signal should abort when the user's signal aborts.
555-
let signalAborted = false
556-
fetchCallArgs[1]?.signal.addEventListener(
557-
"abort",
558-
() => {
559-
signalAborted = true
560-
},
561-
{ once: true },
562-
)
563-
controller.abort()
564-
await new Promise((resolve) => setTimeout(resolve, 10))
565-
expect(signalAborted).toBe(true)
554+
expect(fetchCallArgs[1]?.signal.aborted).toBe(true)
566555
})
567556

568557
it("completePrompt should work without options (backward compatible)", async () => {

src/api/providers/bedrock.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -841,21 +841,19 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
841841

842842
// Build request options with abortSignal and/or timeoutMs
843843
let mergeTimeoutId: ReturnType<typeof setTimeout> | undefined
844+
let upstreamAbortListener: (() => void) | undefined
844845
const sendOptions: { abortSignal?: AbortSignal } | undefined = (() => {
845846
let signal: AbortSignal | undefined = options?.abortSignal
846847
if (options?.timeoutMs !== undefined && options.timeoutMs > 0) {
847848
if (signal && !signal.aborted) {
848849
// When both are provided, create a merged signal that aborts when either fires
849850
const controller = new AbortController()
850851
mergeTimeoutId = setTimeout(() => controller.abort(), options.timeoutMs)
851-
signal.addEventListener(
852-
"abort",
853-
() => {
854-
clearTimeout(mergeTimeoutId)
855-
controller.abort()
856-
},
857-
{ once: true },
858-
)
852+
upstreamAbortListener = () => {
853+
clearTimeout(mergeTimeoutId)
854+
controller.abort()
855+
}
856+
signal.addEventListener("abort", upstreamAbortListener, { once: true })
859857
signal = controller.signal
860858
} else if (!signal) {
861859
signal = AbortSignal.timeout(options.timeoutMs)
@@ -870,6 +868,9 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
870868
response = await this.client.send(command, sendOptions)
871869
} finally {
872870
if (mergeTimeoutId) clearTimeout(mergeTimeoutId)
871+
if (upstreamAbortListener && options?.abortSignal) {
872+
options.abortSignal.removeEventListener("abort", upstreamAbortListener)
873+
}
873874
}
874875
if (
875876
response?.output?.message?.content &&

src/api/providers/openai-codex.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,8 @@ export class OpenAiCodexHandler extends BaseProvider implements SingleCompletion
11581158
// Build a request-local abort controller with timeout support (don't mutate this.abortController)
11591159
let localAbortController: AbortController | undefined
11601160
let timeoutId: ReturnType<typeof setTimeout> | undefined
1161+
let upstreamAbortSignal: AbortSignal | undefined
1162+
let upstreamAbortListener: (() => void) | undefined
11611163

11621164
if (options?.timeoutMs !== undefined || options?.abortSignal) {
11631165
localAbortController = new AbortController()
@@ -1174,18 +1176,16 @@ export class OpenAiCodexHandler extends BaseProvider implements SingleCompletion
11741176

11751177
// Propagate abort from the caller-supplied signal into the local controller.
11761178
if (options.abortSignal) {
1179+
upstreamAbortSignal = options.abortSignal
11771180
if (options.abortSignal.aborted) {
11781181
localAbortController.abort()
11791182
clearTimeout(timeoutId)
11801183
} else {
1181-
options.abortSignal.addEventListener(
1182-
"abort",
1183-
() => {
1184-
localAbortController?.abort()
1185-
clearTimeout(timeoutId)
1186-
},
1187-
{ once: true },
1188-
)
1184+
upstreamAbortListener = () => {
1185+
localAbortController?.abort()
1186+
clearTimeout(timeoutId)
1187+
}
1188+
options.abortSignal.addEventListener("abort", upstreamAbortListener, { once: true })
11891189
}
11901190
}
11911191
}
@@ -1292,6 +1292,10 @@ export class OpenAiCodexHandler extends BaseProvider implements SingleCompletion
12921292
}
12931293
throw error
12941294
} finally {
1295+
clearTimeout(timeoutId)
1296+
if (upstreamAbortSignal && upstreamAbortListener) {
1297+
upstreamAbortSignal.removeEventListener("abort", upstreamAbortListener)
1298+
}
12951299
this.abortController = undefined
12961300
}
12971301
}

0 commit comments

Comments
 (0)