fix: eagerly cancel stream when user presses ESC (#388)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2025-12-24 18:12:31 -08:00
committed by GitHub
parent afbe253de2
commit 6410bdece7

View File

@@ -53,6 +53,26 @@ export async function drainStream(
let hasCalledFirstMessage = false;
let fallbackError: string | null = null;
// Track if we triggered abort via our listener (for eager cancellation)
let abortedViaListener = false;
// Set up abort listener to propagate our signal to SDK's stream controller
// This immediately cancels the HTTP request instead of waiting for next chunk
const abortHandler = () => {
abortedViaListener = true;
// Abort the SDK's stream controller to cancel the underlying HTTP request
if (stream.controller && !stream.controller.signal.aborted) {
stream.controller.abort();
}
};
if (abortSignal && !abortSignal.aborted) {
abortSignal.addEventListener("abort", abortHandler, { once: true });
} else if (abortSignal?.aborted) {
// Already aborted before we started
abortedViaListener = true;
}
try {
for await (const chunk of stream) {
// console.log("chunk", chunk);
@@ -184,6 +204,19 @@ export async function drainStream(
stopReason = "error";
markIncompleteToolsAsCancelled(buffers);
queueMicrotask(refresh);
} finally {
// Clean up abort listener
if (abortSignal) {
abortSignal.removeEventListener("abort", abortHandler);
}
}
// If we aborted via listener but loop exited without setting stopReason
// (SDK returns gracefully on abort), mark as cancelled
if (abortedViaListener && !stopReason) {
stopReason = "cancelled";
markIncompleteToolsAsCancelled(buffers);
queueMicrotask(refresh);
}
// Stream has ended, check if we captured a stop reason