This commit is contained in:
Agnik Paul 2026-08-26 09:36:31 -07:00 committed by GitHub
commit 02e25f2efb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 3 deletions

View file

@ -33,7 +33,11 @@ export async function forgetMemoryRequest(
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify(params),
signal: options?.signal ?? AbortSignal.timeout(FETCH_TIMEOUT_MS),
// Compose rather than choose: a caller-supplied signal must add cancellation
// on top of the timeout, not replace it, or the request becomes unbounded.
signal: options?.signal
? AbortSignal.any([options.signal, AbortSignal.timeout(FETCH_TIMEOUT_MS)])
: AbortSignal.timeout(FETCH_TIMEOUT_MS),
})
if (!response.ok) {

View file

@ -112,7 +112,7 @@ describe("memoryForget", () => {
expect(init.signal).toBeInstanceOf(AbortSignal)
})
it("uses a caller-provided signal instead of creating a timeout", async () => {
it("cancels through a caller-provided signal", async () => {
const fetchMock = stubFetch()
const controller = new AbortController()
@ -124,7 +124,39 @@ describe("memoryForget", () => {
)
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit]
expect(init.signal).toBe(controller.signal)
// The request signal is a composite, not the caller's own, but aborting
// the caller still aborts the request.
expect(init.signal).not.toBe(controller.signal)
controller.abort()
expect(init.signal?.aborted).toBe(true)
})
it("keeps the timeout when a caller-provided signal is present", async () => {
const timeoutController = new AbortController()
const timeoutSpy = vi
.spyOn(AbortSignal, "timeout")
.mockReturnValue(timeoutController.signal)
const fetchMock = stubFetch()
const controller = new AbortController()
try {
await forgetMemoryRequest(
API_KEY,
{ containerTag: "user_1", id: "mem_1" },
undefined,
{ signal: controller.signal },
)
expect(timeoutSpy).toHaveBeenCalledWith(30_000)
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit]
// Firing only the timeout leg aborts the request: a caller signal adds
// cancellation, it does not remove the 30s bound.
timeoutController.abort()
expect(init.signal?.aborted).toBe(true)
} finally {
timeoutSpy.mockRestore()
}
})
it("throws a descriptive error on non-2xx responses", async () => {