/** * Status line for the loading view's running sub-state. * * The backend does not stream agent progress, so the line is chosen from elapsed run time * only and never claims a specific activity. It starts neutral and gets more playful the * longer the run goes, in the same register as the Exit queue button (js/queue.js), so a * multi-minute wait reads as patience rather than a hang. */ /** How often the running view re-evaluates the status line. */ export const RUNNING_STATUS_TICK_MS = 5000; /** * Stages ordered by the elapsed time (ms) at which each line takes over. * @type {ReadonlyArray<{ fromMs: number, text: string }>} */ export const RUNNING_STATUS_STAGES = Object.freeze([ { fromMs: 0, text: 'Searching Confluence…' }, { fromMs: 20_000, text: 'Rummaging through the wiki…' }, { fromMs: 60_000, text: "Reading everything so you don't have to…" }, { fromMs: 120_000, text: 'Turning pages faster than a human could…' }, { fromMs: 240_000, text: 'Lost in Confluence, found three more tabs…' }, { fromMs: 420_000, text: 'Has anyone updated this page since 2019? Checking…' }, { fromMs: 660_000, text: 'Still at it. If time runs out, it answers with what it found…' }, ]); /** * Picks the running status line for the time elapsed since the query was sent. * Non-finite or negative input reads as "just started". * @param {number} elapsedMs * @returns {string} */ export function formatRunningStatus(elapsedMs) { const elapsed = Number.isFinite(elapsedMs) && elapsedMs > 0 ? elapsedMs : 0; let text = RUNNING_STATUS_STAGES[0].text; for (const stage of RUNNING_STATUS_STAGES) { if (elapsed >= stage.fromMs) text = stage.text; } return text; }