Files
PaperClipAI/ui/src/components/transcript/read-transcript-request.ts
T
DottaandPaperclip cd4c4ed205 fix(ui): stabilize task loading and live feeds (#13095)
Coordinate initial conversation reveal, preserve message identity and reading anchors during live updates, and bound transcript reads with recoverable retries. Cover desktop/mobile navigation and rich task loading with actual-route browser tests.

Verified all Linux CI gates, 5,575 local UI tests, eight layout browser scenarios, and recorded native Codex walkthroughs. Greptile: 5/5; all review findings resolved.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-09 10:00:37 -05:00

36 lines
1.4 KiB
TypeScript

export const TRANSCRIPT_REQUEST_TIMEOUT_MS = 15_000;
/** Bound history reads, including body consumption, and release coalesced GETs
* on timeout so Retry starts a fresh request. Late responses cannot commit. */
export function readTranscriptRequest<T>(request: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T> {
if (signal.aborted) return Promise.reject(new DOMException("History read cancelled", "AbortError"));
return new Promise<T>((resolve, reject) => {
const controller = new AbortController();
let settled = false;
const finish = (complete: () => void) => {
if (settled) return;
settled = true;
window.clearTimeout(timer);
signal.removeEventListener("abort", onAbort);
complete();
};
const onAbort = () => {
finish(() => reject(new DOMException("History read cancelled", "AbortError")));
controller.abort();
};
const timer = window.setTimeout(() => {
finish(() => reject(new Error("Run history took too long to load. Retry to load it.")));
controller.abort();
}, TRANSCRIPT_REQUEST_TIMEOUT_MS);
signal.addEventListener("abort", onAbort, { once: true });
try {
request(controller.signal).then(
(value) => finish(() => resolve(value)),
(error) => finish(() => reject(error)),
);
} catch (error) {
finish(() => reject(error));
}
});
}