fix(prompt-gate): scope reservation releases

This commit is contained in:
YeonGyu-Kim
2026-05-15 21:52:29 +09:00
parent 2eec0d96d9
commit 2bd4944bad
8 changed files with 156 additions and 8 deletions
+46 -2
View File
@@ -43,6 +43,11 @@ export type PromptAsyncGateResult =
| { status: "unavailable" }
| { status: "failed"; error: unknown }
type PromptAsyncReservationReleaseOptions = {
reservedBy?: string | readonly string[]
reservedByPrefix?: string | readonly string[]
}
const promptAsyncReservations = new Map<string, PromptAsyncReservation>()
function pruneExpiredReservations(now = Date.now()): void {
@@ -62,6 +67,30 @@ function getActiveReservation(sessionID: string): PromptAsyncReservation | undef
return promptAsyncReservations.get(sessionID)
}
function reservationSourceMatches(
reservationSource: string,
expectedSource: string | readonly string[],
expectedPrefix?: string | readonly string[],
): boolean {
if (typeof expectedSource === "string") {
if (reservationSource === expectedSource) {
return true
}
} else if (expectedSource.includes(reservationSource)) {
return true
}
if (expectedPrefix === undefined) {
return false
}
if (typeof expectedPrefix === "string") {
return reservationSource.startsWith(expectedPrefix)
}
return expectedPrefix.some((prefix) => reservationSource.startsWith(prefix))
}
export async function promptAsyncAfterSessionIdle<TInput = PromptAsyncInput>(args: {
client: PromptAsyncClient<TInput>
sessionID: string
@@ -216,10 +245,24 @@ export function releaseAllPromptAsyncReservationsForTesting(): void {
promptAsyncReservations.clear()
}
export function releasePromptAsyncReservation(sessionID: string, source: string): void {
export function releasePromptAsyncReservation(
sessionID: string,
source: string,
options?: PromptAsyncReservationReleaseOptions,
): boolean {
const existing = promptAsyncReservations.get(sessionID)
if (!existing) {
return
return false
}
const expectedSource = options?.reservedBy ?? source
if (!reservationSourceMatches(existing.source, expectedSource, options?.reservedByPrefix)) {
log("[prompt-async-gate] promptAsync reservation release skipped for different source", {
sessionID,
source,
reservedBy: existing.source,
})
return false
}
promptAsyncReservations.delete(sessionID)
@@ -228,4 +271,5 @@ export function releasePromptAsyncReservation(sessionID: string, source: string)
source,
reservedBy: existing.source,
})
return true
}