mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 09:07:46 +02:00
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>
This commit is contained in:
1 parent
35fdc0c66b
commit
cd4c4ed205
32 files changed
+1286
-179
No files matched your search
@@ -0,0 +1,35 @@
|
||||
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));
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user