For any async workflow that fans out (e.g., Promise.all over providers) or mutates shared session state, apply two rules: 1) Bound/cancel all external async work (timeouts must abort the underlying operation, not only the awaiting caller). 2) Centralize lifecycle transitions for shared mutable state (prefer a state enum + transition helper over ad-hoc “reset fields in parallel”).
How to apply
Example (client-side timeout with defense-in-depth)
const LIVE_MODELS_TIMEOUT_MS = 4000;
function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
promise.then(
(value) => { clearTimeout(timer); resolve(value); },
(err) => { clearTimeout(timer); reject(err); }
);
});
}
// In fan-out code, ensure each task is bounded so Promise.all can complete.
const liveIds = await withTimeout(
acpListProviderSupportedModels(providerId),
LIVE_MODELS_TIMEOUT_MS,
`live model discovery for ${providerId}`
);
Example (lifecycle state centralized)
enum PromptLifecycle { Idle, AwaitingRun, Running, Succeeded, Failed }
function transitionEntry(entry: Entry, next: PromptLifecycle) {
// Reset/updates happen in one place to keep concurrent transitions consistent.
switch (next) {
case PromptLifecycle.Idle:
entry.activePromptAttemptId = null;
entry.activeRunId = null;
return;
// other states...
}
}
This prevents: (a) UI workflows stalling indefinitely due to a single slow dependency, (b) leaked in-flight work when only the client await is timed out, and (c) inconsistent session state caused by partial or parallel field resets.
Enter the URL of a public GitHub repository