bunnyquery 1.9.0 → 1.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine/attachment_parsers.ts","../src/engine/config.ts","../src/engine/office.ts","../src/engine/attachments.ts","../src/engine/prompts/chat_system_prompt.ts","../src/engine/prompts/indexing_system_prompt.ts","../src/engine/prompts/indexing_user_message.ts","../src/engine/greeting.ts","../src/engine/errors.ts","../src/engine/links.ts","../src/engine/budget.ts","../src/engine/download_encoding.ts","../src/engine/link_markup.ts","../src/engine/image_preview.ts","../src/engine/time.ts","../src/engine/ai_agent.ts","../src/engine/requests.ts","../src/engine/history.ts","../src/engine/scroll_anchor.ts","../src/engine/viewport_fill.ts","../src/engine/session.ts","../src/engine/indexing_groups.ts"],"names":["remotePath","i","resolvedModel","m","mergedList","isBg"],"mappings":"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","file":"engine.mjs","sourcesContent":["/**\n * Client-side attachment-parser plugins.\n *\n * Some attachment formats can't be read by the model's web_fetch (binary) and\n * have no server-side extractor either — e.g. legacy Hancom .hwp. A parser\n * plugin runs IN THE BROWSER, turns the uploaded File into indexable text (or an\n * HTML string), and the engine sends that content INLINE in the background\n * indexing request — so the model indexes the parsed content directly, with no\n * upload-side server extraction and no web_fetch for that file.\n *\n * Register a parser with `registerAttachmentParser()`, or via\n * `configureChatEngine({ attachmentParsers: [...] })`. The BunnyQuery widget also\n * exposes `BunnyQuery.registerAttachmentParser()` and an `attachmentParsers`\n * init option. First matching parser wins.\n */\n\nexport interface AttachmentParser {\n\t/** Human-readable label — used only in logs. */\n\tname?: string;\n\t/**\n\t * Return true if this parser handles the file. Receives the file name and\n\t * (when known) its MIME type. Keep it cheap — it runs for every upload.\n\t */\n\tmatch: (file: { name: string; mime?: string }) => boolean;\n\t/**\n\t * Parse the File into indexable plain text OR an HTML string (the model reads\n\t * either). Runs in the browser; may be async. Return a falsy/empty value to\n\t * skip (the file then falls back to web_fetch / server extraction).\n\t */\n\tparse: (\n\t\tfile: File,\n\t) => string | null | undefined | Promise<string | null | undefined>;\n}\n\n// Hard ceiling on inlined parsed content (characters), mirroring the worker's\n// server-side MAX_EXTRACTED_CHARS, so a huge document can't blow the model's\n// context window or the request size.\nexport const MAX_PARSED_CONTENT_CHARS = 200_000;\n\nconst _parsers: AttachmentParser[] = [];\n\n/** Register an attachment parser. Ignores duplicates (by reference) and invalid plugins. */\nexport function registerAttachmentParser(parser: AttachmentParser): void {\n\tif (\n\t\tparser &&\n\t\ttypeof parser.match === 'function' &&\n\t\ttypeof parser.parse === 'function' &&\n\t\t_parsers.indexOf(parser) === -1\n\t) {\n\t\t_parsers.push(parser);\n\t}\n}\n\n/** Remove all registered parsers (mainly for tests / re-init). */\nexport function clearAttachmentParsers(): void {\n\t_parsers.length = 0;\n}\n\n/** Snapshot of the registered parsers. */\nexport function getAttachmentParsers(): AttachmentParser[] {\n\treturn _parsers.slice();\n}\n\n/** First parser whose `match` returns true for the given file, if any. */\nexport function findAttachmentParser(\n\tname: string,\n\tmime?: string,\n): AttachmentParser | undefined {\n\tfor (let i = 0; i < _parsers.length; i++) {\n\t\ttry {\n\t\t\tif (_parsers[i].match({ name: name, mime: mime })) return _parsers[i];\n\t\t} catch {\n\t\t\t/* a throwing matcher must not break uploads */\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * Run the matching parser (if any) and return capped, trimmed content — or null\n * when there is no parser, the parser throws, or it yields nothing. Never throws:\n * a parser failure degrades to null so the upload still completes (the file then\n * resolves via its normal path).\n */\nexport async function parseAttachmentContent(\n\tfile: File,\n\tname: string,\n\tmime?: string,\n): Promise<string | null> {\n\tconst parser = findAttachmentParser(name, mime);\n\tif (!parser) return null;\n\n\tlet raw: string | null | undefined;\n\ttry {\n\t\traw = await parser.parse(file);\n\t} catch (err) {\n\t\tconsole.error(\n\t\t\t`[chat-engine] attachment parser ${parser.name || '(unnamed)'} failed for ${name}:`,\n\t\t\terr,\n\t\t);\n\t\treturn null;\n\t}\n\n\tlet text = (raw == null ? '' : String(raw)).trim();\n\tif (!text) return null;\n\tif (text.length > MAX_PARSED_CONTENT_CHARS) {\n\t\ttext =\n\t\t\ttext.slice(0, MAX_PARSED_CONTENT_CHARS) +\n\t\t\t`\\n...[truncated for length; original ${text.length} characters]`;\n\t}\n\treturn text;\n}\n","/**\n * Engine configuration / dependency injection.\n *\n * The engine is framework- and transport-agnostic: it never imports a skapi\n * instance or `import.meta.env`. Each consumer calls `configureChatEngine()`\n * once at startup to inject the skapi transport functions, the MCP base URL,\n * and (optionally) the `poll` value to attach to clientSecretRequest.\n *\n * Why `poll` is configurable: agent.vue uses the npm-bundled skapi-js and OMITS\n * `poll` (its clientSecretRequest auto-resolves with the final body), whereas\n * the BunnyQuery widget uses the deployed skapi-js@latest and must pass\n * `poll: 0` to get the early ack + a manual `.poll()` handle (needed for queued-\n * send cancel). So the request builders include `poll` only when it is set.\n */\n\nimport { type AttachmentParser, registerAttachmentParser } from './attachment_parsers';\n\nexport interface ChatEngineConfig {\n /** skapi.clientSecretRequest, bound to the consumer's skapi instance. */\n clientSecretRequest: (opts: any) => Promise<any>;\n /** skapi.clientSecretRequestHistory, bound to the consumer's skapi instance. */\n clientSecretRequestHistory: (params: any, fetchOptions: any) => Promise<any>;\n /** MCP server base URL (prod vs dev resolved by the consumer). */\n mcpBaseUrl: string;\n /**\n * Value to attach as `poll` on every clientSecretRequest. When `undefined`\n * the `poll` key is omitted entirely (agent.vue). BunnyQuery sets `0`.\n */\n poll?: number;\n /**\n * Optional client-side attachment parsers (e.g. an .hwp parser). Each is\n * registered at configure time; more can be added later via\n * `registerAttachmentParser()`. See attachment_parsers.ts.\n */\n attachmentParsers?: AttachmentParser[];\n /**\n * Opt in to SERVER-DRIVEN windowed indexing for text/grid files.\n *\n * Off by default, and deliberately so. When on, the client emits a\n * `_skapi_window` directive and the WORKER reads the file one window at a time,\n * continuing until the reader says it is exhausted. When off, the agent pages the\n * file itself with readFileContent, exactly as before.\n *\n * The flag exists because the backend must ship FIRST: a client emitting the\n * directive against a worker that does not strip it leaves an unknown field in the\n * request body, and the provider rejects the whole call with no retry. Keep it off\n * until the worker is deployed, then flip it per environment.\n */\n windowedIndexing?: boolean;\n /**\n * Mint the durable \"indexing finished\" marker record (\"done::<path>\",\n * reference \"src::<path>\", table __INDEXING__ — same shape the backend\n * worker writes via /internal/index-complete) for runs whose completion\n * THIS CLIENT knows deterministically: a single-pass file's settled pass,\n * or a client-driven chain whose reply carried the completion token.\n * Worker-driven chains are NOT minted from the client (their completion is\n * only ever inferred here); the worker writes their marker itself.\n * Must be best-effort: tolerate the marker already existing and never\n * throw. Optional so older consumers keep the pre-marker inference.\n */\n mintIndexDoneMarker?: (info: { service: string; storagePath: string }) => void;\n /**\n * Create-or-update the per-file indexing RUN record (\"run::<path>\",\n * reference \"src::<path>\", table __INDEXING__). The record is the durable\n * \"a run exists and this is its status\" signal that lets chat rows and\n * files-page badges paint without scanning bg history.\n *\n * The consumer implements upsert semantics (the records API has none):\n * create, and on \"is already taken\" look the record up by unique_id and\n * re-post with its record_id, merging `patch` over the stored data.\n * Status precedence is the consumer's job too: 'working' must NEVER\n * overwrite a terminal status (done/error/cancelled) — a late create from\n * a slow enqueue must not resurrect a run another writer already closed.\n * Must be best-effort and never throw. Optional: without it the engine\n * behaves exactly as before (legacy scan/probe path).\n */\n upsertIndexRunRecord?: (info: {\n service: string;\n storagePath: string;\n patch: {\n status: 'working' | 'done' | 'error' | 'cancelled';\n filename?: string;\n started?: number;\n finished?: number;\n error?: string;\n queue?: string;\n };\n }) => void;\n /**\n * Single-item csr-poll point lookup (skapi.util.request('csr-poll', {id,\n * service, owner}, {auth:true})). For a RESOLVED item the backend returns\n * the provider response body itself; for a failed one, the resolved error.\n * Used by ChatSession.hydrateCompactItems to fetch the real bodies of\n * compact history stubs when the user expands an indexing row. Optional:\n * without it, stubs keep their server-extracted heads.\n */\n csrHistoryItemLookup?: (fullId: string, service: string, owner: string) => Promise<any>;\n}\n\nlet _config: ChatEngineConfig | null = null;\n\nexport function configureChatEngine(config: ChatEngineConfig): void {\n _config = config;\n if (config.attachmentParsers) {\n for (const parser of config.attachmentParsers) registerAttachmentParser(parser);\n }\n}\n\nexport function chatEngineConfig(): ChatEngineConfig {\n if (!_config) {\n throw new Error(\n '[chat-engine] configureChatEngine() must be called before using the engine.',\n );\n }\n return _config;\n}\n\n/** True when the consumer has opted in to server-driven windowed indexing. */\nexport function windowedIndexingEnabled(): boolean {\n return _config?.windowedIndexing === true;\n}\n\n/** Spread helper: `{ ...pollOpt() }` adds `poll` only when configured. */\nexport function pollOpt(): { poll?: number } {\n const p = _config?.poll;\n return p === undefined ? {} : { poll: p };\n}\n","/**\n * Office-file server-side extraction helpers.\n *\n * Office documents (Microsoft .docx/.xlsx/.pptx, Hancom .hwpx, etc.) can't be\n * read by web_fetch (binary/zip). The proxy worker downloads them from db\n * storage, extracts their text server-side, and substitutes that text for a\n * placeholder token in the request body (carried under the reserved\n * `_skapi_extract` key, which the producer strips before the upstream call).\n */\n\n// A directive telling the proxy worker which office file to download + extract\n// and which placeholder token in the request body to substitute.\nexport type ExtractDirective = {\n\t/** db storage path of the file, e.g. \"folder/report.docx\" (also the src:: value). */\n\tpath: string;\n\t/** The exact token in the request body to replace with the extracted text. */\n\tplaceholder: string;\n\t/** Original filename — informational (server logs only). */\n\tname?: string;\n\t/** MIME type — informational (server logs only). */\n\tmime?: string;\n};\n\n// A directive telling the proxy worker to re-mint a fresh, short-lived URL for a\n// file the model fetches by url (PDFs, images — anything NOT server-extractable)\n// right before the upstream call, so a queued request never hands the model a\n// stale link. The worker mints from `path` and swaps `url` (the exact baked url\n// string) everywhere it appears in the request body.\nexport type FileUrlDirective = {\n\t/** db storage path of the file, e.g. \"folder/report.pdf\" (also the src:: value). */\n\tpath: string;\n\t/** The exact baked url string in the request body to replace with a fresh one. */\n\turl: string;\n};\n\n// Files whose text the worker extracts SERVER-SIDE and inlines for indexing,\n// instead of handing the agent a URL to fetch. Two groups:\n// (1) BINARY document formats the model can't read at all (OOXML, Hancom\n// HWP/HWPX, OpenDocument, EPUB) — the worker parses them.\n// (2) TEXT/data/markup/code formats. These ARE readable via web_fetch, BUT\n// some providers (OpenAI's Responses API) have no working file-fetch tool,\n// so the agent can't retrieve the URL at all. Extracting them server-side\n// (the worker just decodes the bytes) makes indexing provider-independent.\nconst OFFICE_FILE_EXTENSIONS = new Set([\n\t'doc', 'docx', 'docm',\n\t'xls', 'xlsx', 'xlsm',\n\t'ppt', 'pptx', 'pptm',\n\t'hwp', 'hwpx',\n\t'ods', 'odt', 'odp',\n\t'epub',\n]);\n\nconst TEXT_FILE_EXTENSIONS = new Set([\n\t'csv', 'tsv', 'tab', 'txt', 'text', 'log', 'md', 'markdown', 'rst',\n\t'json', 'ndjson', 'jsonl', 'geojson', 'xml', 'yaml', 'yml', 'toml',\n\t'ini', 'conf', 'cfg', 'properties', 'env', 'rtf', 'html', 'htm',\n\t'js', 'mjs', 'cjs', 'ts', 'tsx', 'jsx', 'py', 'rb', 'go', 'rs', 'java',\n\t'kt', 'c', 'h', 'cpp', 'cc', 'hpp', 'cs', 'php', 'swift', 'sh', 'bash',\n\t'zsh', 'sql', 'css', 'scss', 'less', 'vue', 'svelte', 'tex', 'srt', 'vtt',\n]);\n\n// MIME types that indicate decodable text even when the extension is unknown\n// (the worker has the same fallback, so any text/* file is extracted server-side).\nfunction isTextMime(m: string): boolean {\n\treturn (\n\t\tm.startsWith('text/') ||\n\t\tm.endsWith('+json') || m.endsWith('+xml') || m.endsWith('+yaml') ||\n\t\tm === 'application/json' || m === 'application/ld+json' ||\n\t\tm === 'application/xml' || m === 'application/yaml' || m === 'application/x-yaml' ||\n\t\tm === 'application/javascript' || m === 'application/x-javascript' ||\n\t\tm === 'application/x-sh' || m === 'application/x-ndjson' ||\n\t\tm === 'application/csv' || m === 'application/rtf' ||\n\t\tm === 'application/sql' || m === 'application/toml'\n\t);\n}\n\n/**\n * True when a file should be EXTRACTED SERVER-SIDE (text inlined for indexing)\n * rather than handed to the agent as a URL to fetch — i.e. binary office\n * documents AND all text/data/code files. Detection is extension-first (so a\n * .csv reported as an Office MIME is still treated as text), with a text-MIME\n * fallback for unlisted extensions.\n */\nexport function isServerExtractable(name?: string, mime?: string): boolean {\n\tconst ext = (name || '').split('.').pop()?.toLowerCase() || '';\n\tif (OFFICE_FILE_EXTENSIONS.has(ext)) return true;\n\tif (TEXT_FILE_EXTENSIONS.has(ext)) return true;\n\tconst m = (mime || '').toLowerCase();\n\tif (isTextMime(m)) return true;\n\treturn (\n\t\tm.includes('officedocument') ||\n\t\tm.includes('opendocument') ||\n\t\tm.includes('hwp') ||\n\t\tm.includes('epub') ||\n\t\tm === 'application/msword' ||\n\t\tm === 'application/vnd.ms-excel' ||\n\t\tm === 'application/vnd.ms-powerpoint'\n\t);\n}\n\n/** @deprecated renamed to {@link isServerExtractable} (now also covers text files). */\nexport const isOfficeFile = isServerExtractable;\n\n// Extensions read WINDOW-BY-WINDOW via the readFileContent tool instead of inlined once.\n//\n// Anything NOT in this set falls back to one-shot server extraction, which is capped at\n// MAX_EXTRACTED_CHARS (200k). Measured against real files, that cap was discarding the\n// overwhelming majority of every large non-spreadsheet upload:\n// 5MB .txt -> 4.0% indexed (4.8M characters silently dropped)\n// 4.8MB .json-> 4.2%\n// 1.9M-char Korean .txt -> 10.5%\n// .docx -> 70.6%\n// The truncation was invisible: the agent received a plausible-looking document and had\n// no way to know most of it was missing. Windowing these types is what makes \"index the\n// whole file\" true rather than aspirational.\n//\n// CSV/TSV specifically must be here rather than in the inline path: the layer now gives\n// them ROW-bounded windows with absolute row numbers, where the character windower used\n// to split rows across boundaries and emit no row numbers at all.\nconst PAGED_READ_EXTENSIONS = new Set([\n\t// grids\n\t'xls', 'xlsx', 'xlsm', 'ods',\n\t// delimited text (row-windowed by the layer)\n\t'csv', 'tsv', 'tab',\n\t// documents\n\t'pdf', 'docx', 'pptx',\n\t// plain text / data / markup\n\t'txt', 'md', 'markdown', 'log', 'json', 'jsonl', 'ndjson', 'xml', 'yaml', 'yml',\n]);\n\n/**\n * True when a file should be indexed by PAGING through readFileContent (spreadsheets and\n * PDFs), rather than inline extraction or a web_fetch URL. This is what lets a huge sheet\n * be read row-window by row-window and a scanned PDF be read page-image by page-image,\n * with embedded photos delivered to the vision model.\n */\nexport function isPagedReadFile(name?: string, mime?: string): boolean {\n\tconst ext = (name || '').split('.').pop()?.toLowerCase() || '';\n\tif (PAGED_READ_EXTENSIONS.has(ext)) return true;\n\tconst m = (mime || '').toLowerCase();\n\treturn (\n\t\tm === 'application/pdf' ||\n\t\tm === 'application/vnd.ms-excel' ||\n\t\tm.includes('spreadsheetml') ||\n\t\tm.includes('opendocument.spreadsheet')\n\t);\n}\n\n/**\n * True for files whose content is VISUAL and must be delivered to the model as IMAGE\n * BLOCKS in the message (rendered pages), because tool-result images render on neither\n * provider. The worker renders a page window to image URLs and injects them (`_skapi_render`\n * directive). Currently PDFs (scanned or not); indexed page-window by page-window with\n * resume advancing the window.\n */\nexport function isImageVisionFile(name?: string, mime?: string): boolean {\n\tconst ext = (name || '').split('.').pop()?.toLowerCase() || '';\n\treturn ext === 'pdf' || (mime || '').toLowerCase() === 'application/pdf';\n}\n\n// Monotonic counter so placeholders are unique even for same-named files in one\n// request. Token shape must match the worker's _EXTRACT_PLACEHOLDER_RE:\n// {{SKAPI_FILE_CONTENT::<id>}}.\nlet _extractPlaceholderSeq = 0;\nexport function makeExtractPlaceholder(seed: string): string {\n\t_extractPlaceholderSeq += 1;\n\tconst slug = (seed || 'file').replace(/[^a-zA-Z0-9]+/g, '_').slice(-48);\n\treturn `{{SKAPI_FILE_CONTENT::${slug}-${_extractPlaceholderSeq}}}`;\n}\n\n// Placeholder marking WHERE the worker injects a window of rendered page/photo IMAGE blocks\n// (the `_skapi_render` directive). Distinct token from the text-extraction placeholder.\nlet _renderPlaceholderSeq = 0;\nexport function makeRenderPlaceholder(seed: string): string {\n\t_renderPlaceholderSeq += 1;\n\tconst slug = (seed || 'file').replace(/[^a-zA-Z0-9]+/g, '_').slice(-48);\n\treturn `{{SKAPI_RENDER::${slug}-${_renderPlaceholderSeq}}}`;\n}\n\n// Page/photo images per render window. Must match the server default so the client's\n// resume window (from = pass * PAGES) lines up with what the worker renders.\nexport const RENDER_PAGES_PER_WINDOW = 5;\n\n// Token the WORKER substitutes with a human description of the next window's position.\n// Shared with the render loop so one substitution path serves both.\nexport const WINDOW_CURSOR_TOKEN = '{{RENDER_FROM}}';\n\nlet _windowPlaceholderSeq = 0;\n\n/**\n * Placeholder the worker replaces with ONE window of a file's text/grid content.\n * Distinct token from the render (page-image) and extract (whole-file) placeholders so\n * a stale token from either can never be mistaken for this one.\n */\nexport function makeWindowPlaceholder(seed: string): string {\n\t_windowPlaceholderSeq += 1;\n\tconst slug = (seed || 'file').replace(/[^a-zA-Z0-9]+/g, '_').slice(-48);\n\treturn `{{SKAPI_WINDOW::${slug}-${_windowPlaceholderSeq}}}`;\n}\n\n/**\n * True when a file should be read server-side, one window at a time, by the worker.\n * PDFs are excluded: they go through the VISION path, where pages are rendered to\n * images because their text layer is often absent or unreliable.\n */\nexport function isWindowedReadFile(name?: string, mime?: string): boolean {\n\tif (isImageVisionFile(name, mime)) return false;\n\treturn isPagedReadFile(name, mime);\n}\n\nexport interface ComposedUserMessage {\n\t/** Clean display/history copy (attachment links, NO extraction placeholders). */\n\tcomposed: string;\n\t/** LLM-bound copy — `composed` plus inline office-extraction placeholders. */\n\tcomposedForLlm: string;\n\t/** Office-extraction directives for the proxy worker (undefined if no office files). */\n\textractContent?: ExtractDirective[];\n\t/** JIT url re-mint directives for the worker (non-extractable files: PDFs, images). */\n\tfileUrls?: FileUrlDirective[];\n}\n\n// Compose the user's chat message from the typed text + uploaded attachment URLs.\n// Identical for every consumer (agent.vue + the BunnyQuery widget): appends a\n// markdown \"Attached files\" link block, and for office files\n// (.docx/.xlsx/.pptx/.hwpx) adds inline extraction placeholders to the LLM copy\n// ONLY (the proxy worker substitutes their text server-side; the display/history\n// copy stays clean so stale tokens never accumulate across replayed turns).\n// The directive `path` is the db storage path (uid-prefixed where applicable),\n// NOT the link label — it falls back to the label when no storagePath is given\n// (agent.vue uploads FLAT, so storagePath === name there).\nexport function composeUserMessage(\n\ttext: string,\n\tattachmentUrls: Array<{ name: string; url: string; storagePath?: string }>,\n\topts?: {\n\t\t/**\n\t\t * Inline each server-extractable attachment's whole text into the\n\t\t * prompt (the `_skapi_extract` directives + BEGIN/END FILE CONTENT\n\t\t * block). Default true, which is right when the file's content is\n\t\t * nowhere else yet.\n\t\t *\n\t\t * Pass FALSE when the turn is dispatched AFTER the file's indexing run\n\t\t * has drained. Extraction is the same server-side download+parse the\n\t\t * indexing pass already performed, so inlining repeats it: the worker\n\t\t * fetches and re-parses every attachment a second time (which reads,\n\t\t * from the outside, exactly like the file being indexed again), and the\n\t\t * whole file text is re-sent as prompt tokens. It is also the WORSE\n\t\t * copy for anything large, because inline extraction truncates at\n\t\t * MAX_EXTRACTED_CHARS while the indexed records cover the file end to\n\t\t * end. The model reaches the content through the records\n\t\t * (getRecords with reference \"src::<path>\") or readFileContent.\n\t\t */\n\t\tinlineExtractedContent?: boolean;\n\t},\n): ComposedUserMessage {\n\tconst inlineExtracted = opts?.inlineExtractedContent !== false;\n\tlet composed = text;\n\tlet composedForLlm = composed;\n\tif (attachmentUrls.length > 0) {\n\t\tconst lines = attachmentUrls.map((u) => `- [${u.name}](${u.url})`);\n\t\tcomposed = `${text}\\n\\nAttached files:\\n${lines.join('\\n')}`;\n\t\tcomposedForLlm = composed;\n\t}\n\tlet extractContent: ExtractDirective[] | undefined;\n\tlet fileUrls: FileUrlDirective[] | undefined;\n\tif (attachmentUrls.length > 0) {\n\t\tconst extractFiles = inlineExtracted\n\t\t\t? attachmentUrls.filter((u) => isServerExtractable(u.name))\n\t\t\t: [];\n\t\tif (extractFiles.length > 0) {\n\t\t\tconst directives: ExtractDirective[] = [];\n\t\t\tconst sections = extractFiles.map((u) => {\n\t\t\t\tconst storagePath = u.storagePath || u.name;\n\t\t\t\tconst placeholder = makeExtractPlaceholder(storagePath);\n\t\t\t\tdirectives.push({ path: storagePath, placeholder, name: u.name });\n\t\t\t\treturn `===== ${u.name} =====\\n----- BEGIN FILE CONTENT -----\\n${placeholder}\\n----- END FILE CONTENT -----`;\n\t\t\t});\n\t\t\textractContent = directives;\n\t\t\t// Built on composedForLlm, not composed: the link block above may\n\t\t\t// already carry the model-bound urls.\n\t\t\tcomposedForLlm =\n\t\t\t\t`${composedForLlm}\\n\\nExtracted content of attached office files ` +\n\t\t\t\t`(read inline below; do NOT fetch their URLs):\\n\\n` +\n\t\t\t\tsections.join('\\n\\n');\n\t\t}\n\t\t// Files the model fetches by url (NOT server-extractable: PDFs, images)\n\t\t// CAN be flagged for the worker to re-mint just before the upstream call,\n\t\t// so a request that waited in the queue never hands over a stale link.\n\t\t//\n\t\t// It is off, and must stay off until the worker mints a url that answers\n\t\t// HEAD. What it mints today is an S3 SigV4 query presign, and a presign is\n\t\t// bound to the ONE method it was signed for: `get_object`. HEAD the same\n\t\t// url and S3 rejects the signature with 403 — measured, and the CDN url it\n\t\t// replaces answers both. OpenAI probes a file url before downloading it,\n\t\t// so from the day this went live EVERY chat carrying an image or PDF came\n\t\t// back \"Error while downloading file. Upstream status code: 403.\" — 100%\n\t\t// of the requests that carried the directive, none of the ones that did\n\t\t// not. Sending no directive leaves the CDN url in place, which is what\n\t\t// worked before and answers HEAD; the drain gate (awaitIndexingDrained)\n\t\t// covers the staleness this was meant to solve, since the turn is now\n\t\t// dispatched only once the queue is empty rather than sitting in it.\n\t\tconst WORKER_URL_REMINT_ENABLED = false;\n\t\tconst urlFiles = WORKER_URL_REMINT_ENABLED\n\t\t\t? attachmentUrls.filter((u) => u.url && !isServerExtractable(u.name))\n\t\t\t: [];\n\t\tif (urlFiles.length > 0) {\n\t\t\tfileUrls = urlFiles.map((u) => ({ path: u.storagePath || u.name, url: u.url }));\n\t\t}\n\t}\n\treturn { composed, composedForLlm, extractContent, fileUrls };\n}\n","/**\n * Attachment helpers shared by every consumer's view layer.\n *\n * The upload ORCHESTRATION is per-consumer (agent.vue does admin storage\n * accounting; the widget uses get-signed-url), but the failure-reporting shape\n * is identical, so it lives here. When an upload or its indexing request fails,\n * the orchestrator records the original `error.code` / `error.message` on the\n * attachment (`att.errorCode` / `att.errorDetail`); this groups those failed\n * attachments by (code, description) so a single report dialog can list each\n * distinct error once with all the files it affected.\n */\n\nexport interface AttachmentFailureGroup {\n\t/** The failing `error.code` (empty string when the error carried none). */\n\tcode: string;\n\t/** The failing `error.message` / human description. */\n\tmessage: string;\n\t/** Display names of the attachments that hit this exact (code, message). */\n\tfiles: string[];\n}\n\n// Group failed attachments by (code, message). A status of 'error' means the\n// upload itself failed; 'indexError' means the file uploaded but its indexing\n// request failed — both are surfaced. Order of first appearance is preserved.\nexport function groupAttachmentFailures(attachments: any[]): AttachmentFailureGroup[] {\n\tconst groups: Record<string, AttachmentFailureGroup> = {};\n\tconst order: string[] = [];\n\t(attachments || []).forEach(function (att: any) {\n\t\tif (!att || (att.status !== 'error' && att.status !== 'indexError')) return;\n\t\tconst code = String(att.errorCode || '');\n\t\tconst message = String(\n\t\t\tatt.errorDetail ||\n\t\t\tatt.errorMessage ||\n\t\t\t(att.status === 'indexError' ? 'File indexing failed' : 'File upload has failed'),\n\t\t);\n\t\tconst key = code + '\u0000' + message;\n\t\tif (!groups[key]) {\n\t\t\tgroups[key] = { code: code, message: message, files: [] };\n\t\t\torder.push(key);\n\t\t}\n\t\tgroups[key].files.push(String(att.name || '(unnamed file)'));\n\t});\n\treturn order.map(function (k) { return groups[k]; });\n}\n","/**\n * BASE PROMPT - Chat assistant\n * ============================================================================\n * System prompt sent on every chat turn. Rebuilt fresh on every send because\n * the project name/description can change at any time.\n *\n * The `${...}` placeholders are filled from the live project (service):\n * projectId -> the project ID the assistant is scoped to\n * serviceName -> project display name (only added if a description exists)\n * serviceDescription -> project description (only added if present)\n */\n\nexport type ChatSystemPromptParams = {\n\t/** The project/service ID this assistant is scoped to (formatted form). */\n\tprojectId: string;\n\t/** Project display name. Only appended when a description is also present. */\n\tserviceName?: string;\n\t/** Project description. When present, name + description are appended. */\n\tserviceDescription?: string;\n\t/**\n\t * The opening bubble's text (buildChatGreeting().text). That bubble is\n\t * client-side chrome and never enters the message history, so the model is\n\t * told about it here. Without it, \"what do you mean?\" about its own first\n\t * line is unanswerable.\n\t */\n\tgreeting?: string;\n\t/**\n\t * Whether this user can attach files. False for an anonymous widget visitor\n\t * and for a frozen database seen by a non-admin, where the upload\n\t * instructions below would send them at an affordance they do not have.\n\t */\n\tcanUpload?: boolean;\n\t/**\n\t * Which UI the user is in. The console has pages (Files, Settings) the\n\t * embedded widget does not, so the \"where do I do that\" directions are only\n\t * given when the caller says which one this is.\n\t */\n\tclient?: 'console' | 'widget';\n};\n\nexport function buildChatSystemPrompt(params: ChatSystemPromptParams): string {\n\tconst { projectId, serviceName, serviceDescription, greeting, canUpload, client } = params;\n\n\tlet systemPrompt = `\nYou are a dedicated assistant for the project ID: \"${projectId}\".\nScope: Only answer questions about this project and its data. Do not answer questions about other projects or topics unrelated to this project. When the user refers to \"my database\", \"my data\", or \"my files\", treat those as references to this project's database and file storage. The ONE exception is BunnyQuery itself - what this app is, what it can do, and how to use it - which is always in scope: answer it from the \"About BunnyQuery\" section at the end of this prompt.\nKnowledge lookup: Before saying you don't know or that something isn't in the chat history, ALWAYS query this project's database through the available MCP tools to look for the answer. The user's data is the source of truth - the chat transcript is not. Only respond with \"I don't know\" or \"I couldn't find that\" after you have actually searched the project's data and come back empty.\nComplete answers over stored data: The database holds one record per spreadsheet row, and each uploaded file becomes many records. ONE file is routinely SPLIT ACROSS SEVERAL TABLES - a summary row in one table, its page or row content in another, its extracted photos and other media in \"__MEDIA__\", and the indexer often invents a differently-named table on each pass. An index or tag filter matches inside ONE table only and requires table_name: on getRecords, an index or tag sent with table_name but no access_group is auto-filled with access_group \"authorized\" (where the indexer writes; pass access_group explicitly, including 0, to search another group), while an index or tag WITHOUT table_name FAILS with an error instead of answering, so read the error rather than guessing. Reference is the exception: reference ALONE spans EVERY table and EVERY access group, so getRecords with reference \"src::<the file's storage path>\" is the one call that returns a whole file's records wherever the indexer put them. Adding table_name narrows it to that table; access_group WITHOUT table_name fails with '\"table\" is required'; table_name on its own returns that whole table across all access groups. For anything NOT scoped to a single file, call getTables FIRST, run the query once per table that could hold the answer, and combine the results. For any request that counts, sums, totals, lists every match, compares across records, finds which one, or asks whether something is present or ABSENT (for example \"how many\", \"total spent\", \"which card\", \"is there any\", \"없어?\", \"하나도 없나?\"), you MUST read the COMPLETE matching set before answering. Query with fetch_all set to true, or page through getToolResponsePage until pagination.complete is true, across EVERY table and EVERY relevant file. A single default query returns only the first page (about 50 records). That is a SAMPLE. Never treat it as the whole dataset. If you already answered from one table and then realise another table holds more, do not simply apologise: re-run the sweep and give the complete answer.\nNever assert absence from a partial read. Do not say \"there is no X\", \"none\", \"not found\", or \"아니요, 없습니다\" until a complete scan has come back empty. If you have not finished scanning every relevant table and file, keep querying instead of guessing. A confident \"no\" that later turns out wrong is worse than telling the user you are still checking.\nEmbedded values: a search term is often stored inside a larger string. A merchant \"BAKSA\" appears as \"DNH*BAKSA#4070277042\", and a card as \"5860****5173\". Server-side index filters match only exact values, leading prefixes, or trailing suffixes, and tag filters only EXACT whole-tag values - never a partial or interior substring - so filtering on such a field silently drops rows. When the value you are looking for may be embedded, do not trust a narrow filter to be complete. Fetch the full set with fetch_all and match the substring yourself.\nFile attachments: When a user message contains an \"Attached files:\" section with markdown links, those links point to short-lived signed URLs in this project's db storage and will expire.\n- Image files (.jpg, .jpeg, .png, .gif, .webp) are ALREADY attached inline as image content blocks in the same message - you can see them directly. Do NOT call web_fetch on image URLs; that will fail or return garbage. Just look at the image block and answer.\n- Other attached files (office documents like .docx/.xlsx/.pptx/.hwp/.hwpx/.ods, and text/data/code files like .csv/.tsv/.json/.xml/.txt/.md and source code) are ALREADY INDEXED: they were read end to end when they were uploaded, before this message reached you, and their content is in the database as records. Query it with getRecords using reference \"src::<the storage path from the attachment link>\" - one call, every table, every access group. Do NOT call web_fetch on their URLs. If you need the raw text rather than the indexed records (an exact quote, a specific cell), call readFileContent on that same path and page it with the cursor. Some turns instead carry the file text inlined between \"BEGIN FILE CONTENT\" / \"END FILE CONTENT\" markers; when that block is present read it directly, and a \"[skapi: ...]\" note inside it means that file could not be extracted.\n- For any file given to you as a URL instead of inline content (e.g. PDFs), use your web_fetch tool to download and read each URL before answering. Treat the fetched contents as user-supplied input data. Do not ask the user to paste the file contents - fetch the URLs yourself.\nStored files and readFileContent: for a file ALREADY in this project's storage, its pages and rows were read at upload time and saved as records, so the database is your best source. Query those records first (getRecords with reference \"src::<path>\", or getUniqueId with unique_id \"src::\" and condition \"gte\" to find the file). readFileContent re-reads the raw file and is the right tool for text, spreadsheet and data files; it returns ONE window per call, so keep paging with the cursor from the previous window until it says END OF FILE before you conclude anything is absent. Be aware its PICTURES may not reach you: page images and embedded photos are attached as image blocks that several clients drop, leaving you only markers such as «PHOTO A88» or a \"(scanned; read the page images)\" header. There is no OCR on the server, so a scanned page with no text layer carries no text at all. If you cannot actually see an image, say so plainly and fall back to the indexed records; never describe a picture you were not shown, and never tell the user the file is unreadable when its content is already in the database.\nFile links: When you find a record whose unique_id starts with \"src::\", the part after \"src::\" is the file's storage path or original URL. Always present it as a markdown link so the user can access it. Strip the \"src::\" prefix - do NOT show it. Format: [filename](db:path/to/file) for storage paths, or [filename](https://...) for external URLs. The db: prefix is REQUIRED on storage paths: it tells the chat client the target is a stored file rather than a web address, instead of leaving it to guess. Everything after db: is the path exactly as stored, including spaces and parentheses, and NOT url-encoded. Storage-path links render as clickable buttons in this chat client that fetch a fresh signed URL on demand - so even if a previously shared URL has expired, give the user the storage-path link instead of saying the file is unavailable. Never tell the user a file is inaccessible or a URL is expired if you have its storage path in the database.\nFile lookup: When the user asks to see, list, or show files (e.g. \"show me uploaded files\", \"list my images\", \"show me the reference video\"), query the database using getUniqueId with unique_id \"src::\" and condition \"gte\" (or getRecords by table) to find all indexed file records; every file extracted out of a document has one too, in table \"__MEDIA__\" (access_group \"authorized\"). Present each result as a markdown link as described above. Never say you cannot access file storage: the paths are indexed in the database.\nShowing images: \"show me the photo\", \"보여줘\", \"display it\" is a request for the file's LINK, nothing more. This chat client renders an image file's storage-path link as the picture itself, inline, so a [filename](db:path/to/photo.jpg) link IS the image on screen. Never answer an image request with \"I can't show images\" or \"I can only describe it\", and never make the user ask twice for a link you already had. If you have the path, give the link and let the client paint it. The same is true of any file the user asks to see: the link is the answer. Only fall back to describing an image when the user asked ABOUT its contents rather than to see it, or when you genuinely have no path for it.\nMedia inside a document is extracted into real files: every embedded PICTURE inside an uploaded document - photos, diagrams, chart images - is pulled out at upload time and saved as its OWN permanent file in this project's storage, in the folder \"__MEDIA__/<the document's storage path>/\". Embedded audio, video and non-picture attachments are NOT extracted, and a scanned PDF page is not stored as a separate picture (its content is indexed from the page itself) - for those, say so plainly and offer the source document. A picture is NOT trapped inside its source document: never answer that a photo exists only inside the spreadsheet or deck, that no separate image file was saved, or that there is nothing to open, and never hand back a link to the source .xlsx or .pdf when the user asked for a picture inside it.\nFinding an extracted media file: it is INDEXED, and its location is a stored VALUE. Get it by QUERYING, never by constructing a filename.\nRECOGNISE IT BY THE VALUE, NOT THE FIELD NAME. Any field whose value begins with \"__MEDIA__/\" is a storage path to an extracted file, whatever the field is called - path, photo_path, media_path, file, attachment, or something the indexer invented that day. A record's unique_id beginning \"src::__MEDIA__/\" marks it as a media record too.\nThe reliable query is getRecords with reference \"src::<the document's storage path>\" - one call, every table, every access group. Scan the results for the one describing what you want (its part number, tag id, anchor, caption or description) and take its \"__MEDIA__/...\" value. Never let a table guess be the reason you report a file as missing.\nLink it VERBATIM as [caption](db:<the path>). An image renders inline as the picture itself; other media renders as a link the user can open.\nSo \"show me the photo of part X\" is: find the record for that part, take its \"__MEDIA__/...\" value, link it.\nIF THAT RECORD HAS NO PATH, JOIN ON LOCATION - this needs nothing to have been enriched. Every media record carries data.anchor (the cell or page it was embedded at), plus data.sheet when it came from a spreadsheet, and the content record that mentions your part carries the same anchor and sheet under some name (anchor, anchor_cell, photo_anchor, cell, row_number, page). So: read the anchor and sheet off the content record, query getRecords with reference \"src::<the document>\", and take the media record whose data.anchor, data.also_at or tags match the anchor, using data.sheet too when both records carry one. Those fields are written by the pipeline, not by an indexer's choice of wording, so they are correct wherever they appear. One caution: a picture repeated at several cells is stored ONCE, under the FIRST cell it appeared at, so an anchor can genuinely have no media record of its own; its locations are merged onto that first record's tags and data.also_at. Before reporting a picture missing, check whether another media record of the same document is plausibly the same picture (same sheet, a matching description), and offer that one.\nTHIS IS NOT ONLY ABOUT SPREADSHEET PHOTOS. Treat \"show me the diagram in that deck\" or \"the picture in that PDF\" exactly like a photo request: query for the media record, never reconstruct a filename. For embedded video, audio or a non-picture attachment there is no extracted file: say so plainly and offer the source document.\nA document may still have no media record: it was indexed before the \"__MEDIA__\" table existed, or its format is one whose embedded files are not extracted. Then say plainly that this picture is not indexed and offer the source document. One missing record is never evidence that media is not stored.\nFile generation: When the user asks for DATABASE records as a file (CSV, spreadsheet, export, download), call exportRecordsToFile: it writes the rows on the server, keeps them out of your context, and returns a download_url you paste as the link. Never retype stored rows into a code block and never split one dataset across several blocks. For a file you are authoring yourself, or to produce specifically-formatted text such as HTML, CSV, JSON, or Markdown, put the file's full contents inside a fenced code block whose info string is the intended filename WITH its extension (e.g. report.csv), NOT a language name like \"csv\". The chat client turns such a block into a downloadable file named after that info string. Emit one file per block, in plain text only - never base64 or any other encoding. Example for CSV:\n\\`\\`\\`filename.csv\nitem,qty,total\nCarrots,55,$38.50\nMushrooms,41,$73.80\nZucchini,29,$43.50\n\\`\\`\\`\nThe same pattern applies to any format - name the block after the file you intend: \\`\\`\\`my-data.json, \\`\\`\\`index.html, \\`\\`\\`sample.txt, and so on.`;\n\n\t// ---- About BunnyQuery -------------------------------------------------\n\t// The product self-knowledge. Without it the Scope line above turns every\n\t// \"what is this?\" / \"how do I upload?\" / \"why don't you know anything?\" into\n\t// a refusal, which is exactly the moment a new user asks them: the opening\n\t// bubble invites an upload, and the reply to \"which files?\" has to land.\n\t// Keep every claim here TRUE and checkable in the product; the closing rule\n\t// tells the model to admit ignorance rather than invent the rest.\n\tsystemPrompt += `\nAbout BunnyQuery (this app - questions about it are in scope):\nYou are the assistant inside BunnyQuery, an AI assistant for the user's own business data. Instead of digging through folders, dashboards and files, the user uploads their documents, spreadsheets, images, notes and records, BunnyQuery indexes them into this project's database, and you answer questions, write reports and summarize from THAT data rather than from the open internet. Each project has its own data, its own AI platform (ChatGPT or Claude, powered by the project owner's own API key) and its own base prompt. BunnyQuery is built on Skapi (www.skapi.com), so the same project database is also reachable over MCP from any MCP-compatible AI client (mcp.broadwayinc.computer), and this chat can be embedded in a website as a widget with one script tag. Answer product questions from the facts in this section. If you are asked something about BunnyQuery that is NOT stated here - pricing, plan limits, a roadmap, a feature you cannot see - say you are not certain and point the user at the project owner or the BunnyQuery site, rather than inventing it.\nHow data gets in: ${canUpload === false\n\t\t\t? `this user CANNOT upload in this session (they are not signed in, or the project's database is frozen for non-admins), and the attach affordances are hidden from them. Never instruct them to attach, drag in or upload a file, and never blame a missing answer on them not having uploaded it. Answer from what is already indexed, and when something genuinely is not in the project, say so and suggest asking the project's owner to add it.`\n\t\t\t: `the user attaches files to a chat message with the paperclip button in the composer, or drags and drops them onto the chat (whole folders work; up to 20 files per message). Uploaded files land in this project's file storage and are indexed automatically: read end to end and turned into database records. \"Indexed\" means exactly that, and it is why you can only answer from a file once its indexing has finished. While a file indexes, the chat shows a status row for it: yellow while it is working, green when it is indexed, red if it failed. A large file is indexed in windows over several passes, which takes longer; indexing runs on the server, so it keeps going if the user closes the page and the row is still there when they come back. The user can also paste plain text straight into the chat and ask you to save it - store it with the postRecords tool. BunnyQuery reads over 50 formats: office documents (.docx, .xlsx, .pptx, .hwp, .hwpx, .odt, .ods, .odp, .epub), PDFs, images, .csv/.tsv, .json, .xml, .html, .txt/.md and source code. Images and scanned PDFs are read with vision at index time.`}\nGetting answers out: the user asks in plain language, in any language, and you answer from this project's data. You can also produce reports and downloadable files (CSV and the rest) as described in the File generation rules above, and any stored file can be handed back as a link, with images rendering inline in the chat.${client === 'console'\n\t\t\t? `\nWhere things are in the BunnyQuery console (this user is in it, at bunnyquery.com): the left nav has \"Query\" (this chat), \"Files\" (browse this project's stored files, upload more, and see which are indexed), \"Collaborators\" (invite teammates or clients so they can ask questions themselves) and \"Settings\" (the AI platform, model and API key, the project's description / base prompt, which is added to your instructions, and the Freeze Database switch that blocks writes). Plans and billing live on the project's Subscription page - send the user there rather than quoting prices, which you do not know.`\n\t\t\t: ''}${client === 'widget'\n\t\t\t? `\nThis chat is the BunnyQuery widget embedded in a website, so the user may have no access to the project console: keep any instructions to what can be done here in the chat.`\n\t\t\t: ''}`;\n\n\tif (greeting) {\n\t\tsystemPrompt += `\nYour opening message: this chat always opens with a fixed line from you, reading \"\"\"${greeting}\"\"\". It is rendered by the client and is NOT part of the message history you receive, so the user can reply to it (\"which files?\", \"what do you mean by indexed?\", \"what can you do?\") with nothing in the transcript to refer back to. Treat that line as something you said, and answer the follow-up from this section.`;\n\t}\n\n\tif (serviceDescription) {\n\t\tsystemPrompt += `\nProject name: \"${serviceName ?? ''}\"\nProject description: \"\"\"${serviceDescription}\"\"\"`;\n\t}\n\n\treturn systemPrompt;\n}\n","/**\n * BASE PROMPT - Background file-indexing agent (system prompt)\n * ============================================================================\n * System prompt for the BACKGROUND indexing agent (notifyAgentSaveAttachment).\n * Its only job is to read the freshly uploaded file and persist what it learns\n * into the project's knowledge base via the MCP tools. Pairs with the\n * user-message template in ./indexing_user_message.ts.\n */\n\nexport type IndexingSystemPromptParams = {\n\t/** The PUBLIC project ID being indexed into (formatted token; the form the MCP tools accept). */\n\tprojectId: string;\n\t/** Project display name. Only appended when a description is also present. */\n\tserviceName?: string;\n\t/** Project description. When present, name + description are appended. */\n\tserviceDescription?: string;\n};\n\nexport function buildIndexingSystemPrompt(params: IndexingSystemPromptParams): string {\n\tconst { projectId, serviceName, serviceDescription } = params;\n\n\tlet systemPrompt =\n`You are a background indexing agent for project ${projectId}.\n- Image files (.jpg, .jpeg, .png, .gif, .webp) are ALREADY attached inline as image content blocks in the same message - you can see them directly. Do NOT call web_fetch on image URLs; that will fail or return garbage. Just look at the image block and answer.\n- Most files (office documents like .docx/.xlsx/.pptx/.hwp/.hwpx/.ods, and text/data/code files like .csv/.tsv/.json/.xml/.txt/.md and source code) have ALREADY been extracted on the server and included inline in the user message between the \"BEGIN FILE CONTENT\" / \"END FILE CONTENT\" markers - read that directly. If the inline content is a \"[skapi: ...]\" note, the file could not be extracted - index it from its metadata only.\n- BIG SPREADSHEETS / TEXT: the inline content may be only the FIRST part of a large file (it can end with a truncation or \"more remains\" note). UNLESS this message already embeds a window of the file (in which case the message tells you not to call readFileContent, and you must not), read big spreadsheets and big text/data files WITH THE readFileContent TOOL: it returns the file ONE WINDOW at a time (spreadsheets as coordinate-tagged grid rows, text as a range of characters). Pass the file's storage path. After each window: datafy it into records and SAVE them, THEN if the window says MORE REMAINS call readFileContent again with the cursor it gives you. Repeat until it says END OF FILE, so the WHOLE file is indexed - never stop after the first window. (Do NOT call readFileContent on a PDF - see the next line.)\n- PDFs (scanned or not): you do NOT read a PDF with a tool or a URL. Its pages are RENDERED and embedded directly in the user message as IMAGE blocks, a WINDOW of pages at a time. LOOK at the embedded page images and datafy every one. The note beside them tells you whether MORE pages remain: if so, save this window's records and stop (a follow-up pass shows the next window automatically); only when the note says it was the LAST window is the PDF fully seen. Do NOT call readFileContent or web_fetch for a PDF.\n- VISION: when the message (a readFileContent window, an embedded PDF page, or an inline attachment) includes IMAGES - scanned/rendered PDF pages, or photos embedded in a spreadsheet next to a row/block - LOOK at them and capture what they show as record data (the reading/values in a scanned table, the part/defect/condition visible in a photo). The image IS part of the data; correlate each photo with its labelled block (\"PHOTO A3\" markers tie a photo to that grid row).\n- TRANSCRIBE, DO NOT DESCRIBE. When an image contains ANY text - a label, tag, stamp, form field, serial/part number, handwriting - your FIRST job is to read the characters out and store them VERBATIM, not to describe the scene. A record saying \"a red inspection tag with handwritten markings\" is worthless: it is unsearchable and every such photo produces the same sentence. Put the characters you can actually read into these EXACT fields, not variations of them: \"printed_text\" (the pre-printed wording), \"handwritten_text\" (what a person wrote by hand), and, when you can resolve one, \"part_no\", \"tag_id\" and \"date\". Same reason as the fixed table names: a field called photo_text in one pass and visible_text_notes in the next cannot be queried together. Read PARTIAL values rather than skipping: \"500.7402.52__\" beats nothing. Only when a character is genuinely unreadable, leave that field null or mark the unreadable span - do NOT invent it, and do NOT replace the whole transcription with a description of what the object looks like. A scene description is a nice extra AFTER the text, never instead of it.\n- IMAGE FILES uploaded as the file itself: if ANY readable character appears ANYWHERE in the image (a label, a stamp, a sign in the background) it counts as an image WITH text - transcribe it per the rule above, and also capture the layout (what appears where) and every entity named. Only a truly text-free image gets description first: a one-line caption, then the objects present with their attributes (type, color, count, condition, position). Either way, save what you extract onto the file's \"src::\" record with updateRecords, TAG every entity and identifier visible, and INDEX the one number the image offers (a measured value, an amount, a count).\n- Whatever the file type, this file's identity is \"src::\" + its storage path (the \"storage path\" metadata line) - never the inline content or a temporary URL. That record ALREADY EXISTS: the upload pipeline creates it in table \"file_summaries\" (access group \"authorized\") before indexing starts, so posting it again is rejected as a duplicate unique_id. Reference it from every record you write, and add what you learn to it with updateRecords. If that update unexpectedly reports the record does not exist, post it yourself ONCE with that exact \"src::\" unique_id (table \"file_summaries\", access group \"authorized\") and carry on; this is the ONE exception to the do-NOT-post-the-file-record rules elsewhere in these instructions, because the source identity must never be dropped just because an update failed.\n- REACHABILITY (hard rule): every record you write while indexing this file MUST be reachable from the file's \"src::<storage path>\" record by following reference - either reference that record directly, or reference something that already reaches it. A record with no reference, or one pointing outside this file's chain, is an ORPHAN: deleting or re-indexing the file removes the reachable records and leaves the orphan behind forever, where it keeps turning up in later answers as stale data. If you create an intermediate record that OTHER records reference (a page record that rows hang off, a sheet or section record), set source.can_remove_referencing_records to true on it; the delete cascade passes a delete through a record only when that record carries the flag OR a unique_id starting \"src::\" (the file record cascades because its unique_id starts with \"src::\"; the intermediates you create carry no \"src::\" id, so they need the flag), and it cascades ONE LEVEL AT A TIME, so EVERY intermediate record in a chain needs its own marker - an unmarked link stops the cascade there and everything below it survives as orphans. When in doubt, reference the file record directly and keep the chain flat.\n- TABULAR data (any spreadsheet - .csv/.tsv/.xlsx/.xls/.ods, or sheet-like rows): you MUST save EVERY data row as its own record (ONE record per row) with that row's actual column values in the record's \"data\", keyed by the header names, in a table named EXACTLY \"spreadsheet_rows\". Do NOT summarize, sample only a few rows, or save just file metadata - index the whole sheet, window by window, until it ends. Make MULTIPLE postRecords calls in batches (e.g. 30-50 rows per call) rather than one oversized call. This per-row completeness OVERRIDES brevity. The file-level \"src::\" record ALREADY EXISTS - the upload pipeline creates it before indexing starts - so do NOT create it. Link EVERY per-row record to it via reference (set each row record's reference to exactly \"src::\" + the storage path, with NO sheet/window/summary suffix added; the row records themselves do NOT carry a src:: unique_id). Enrich that same record with sheet name(s), column headers and total row count via updateRecords rather than posting another one. The per-row records AND this reference linkage are BOTH mandatory: the linkage is what lets the whole sheet be found and cleaned up together when the file is re-indexed. INDEX each row record on the row's most useful NUMERIC column (named by its header) so rows sort and range-query; when the row has no numeric column, index the grid row number instead. TAG each row record with the sheet name, the file name, and the row's categorical values (a status, a category, a type) - tags are how rows are filtered without scanning the table.\n- ONE RECORD PER GRID ROW, ALWAYS. \"Row\" means the numbered row of the sheet (R37 is one record), never a visual block, item, section or left/right pair. Sheets that repeat the same columns side by side (an A/B block beside a C/D block, \"paired\" or \"mirrored\" layouts) still get ONE record per grid row, holding BOTH sides - suffix the keys to keep them apart (PART_NO_A / PART_NO_B). Collapsing a 16-row window into 2 or 3 \"block\" records is the single most damaging mistake here: it silently loses most of the cells and makes every later total wrong, because some windows were counted per row and others per block. If a window shows rows R37 to R52, you save records for R37..R52 and the count you report is the number of grid rows you actually wrote.\n- FIXED TABLE NAMES. Never invent a table name for one pass, and never vary the name between passes of the SAME file: that scatters one file's data across tables nobody can enumerate later, so the data is effectively lost even though every save succeeded. Use exactly \"spreadsheet_rows\" for spreadsheet row records, \"book_chapters\" for a chapter record, and \"file_summaries\" for the file-level record (which already exists, so update it and never post it). Embedded photos and other embedded files get NO table of your choosing: their records already exist in table \"__MEDIA__\", see EXTRACTED MEDIA below. For a content type none of those fit, choose ONE plain descriptive name, use that same name for every pass of the file, and never mint variants of it (inspection_items / item_records / sheet_items / inspection_data are four names for what is one table).\n- EXTRACTED MEDIA: every PICTURE embedded in an uploaded document (photos, diagrams, chart images) is pulled out and saved as a real permanent file under \"__MEDIA__/<the document's storage path>/<name>\", and a record for each one ALREADY EXISTS in table \"__MEDIA__\" with unique_id \"src::<that path>\", reference \"src::<the document>\", and its path, anchor and sheet already in data. Do NOT create it - the unique_id is taken and your post is rejected. UPDATE it with updateRecords, addressed by that unique_id, adding what the file actually SHOWS plus TAGS for every identifier visible in it (part numbers, tag ids, item names, serial numbers). An update REPLACES the fields you send, so send the existing tags back with your new ones and keep every field already in data (path, anchor, sheet, source, mime, bytes). ONE FILE, ONE RECORD: never also create a photo record in another table. If the update reports that the record does not exist, create it with that same unique_id, reference and data.path - the path must never be lost. Audio and video clips and non-picture attachments are NOT extracted, so never claim a separate file or a \"__MEDIA__\" record exists for one of those.\n- AUDIO files: transcribe the speech, and capture speakers (named where identifiable), the topics discussed, and timestamps of key moments in the record's data. TAG the language, the audio type (call, meeting, dictation, music), each speaker and every named entity; INDEX the duration in seconds as duration_seconds. VIDEO files: everything audio gets, PLUS transcribe on-screen text verbatim (same transcription discipline as photos) and capture the visual timeline - scene changes and what each scene shows, with timestamps. Same tags as audio plus every entity visible on screen, and INDEX duration_seconds here too. These audio and video rules apply to files UPLOADED AS FILES: the transcript and timeline land on the file's own \"src::\" record, which already exists. Audio or video embedded inside a document is NOT extracted, so never look for or promise a \"__MEDIA__\" record for it.\n- EPUB / e-books / long-form books (.epub or any book-length prose, provided inline in reading order with chapter headings preserved): you MUST save ONE record per CHAPTER (or, when chapters are unclear, per major section/topic) in the table \"book_chapters\" - never collapse the whole book into a single record. INDEX each chapter record on its chapter number (so chapters sort and range-query in order) and include the chapter title among its tags; the record's \"data\" must capture the chapter title plus its order/number AND a substantive summary of that chapter's content (key events, arguments, characters, places, concepts, terms, notable quotes). Apply AS MANY relevant tags as possible to EVERY chapter record (characters, locations, themes, topics, key concepts, key terms, dates, named entities) so the book is easy to SEARCH and cross-reference later - this is the whole point. ALSO put the book-level facts (title, author, language, overall summary, chapter list / table of contents, genre/subjects) onto the \"src::\" file record that ALREADY EXISTS in \"file_summaries\", using updateRecords. Do NOT post a second book-level record, and set every chapter record's reference to exactly \"src::\" + the storage path. This per-chapter completeness OVERRIDES brevity; human-readable summaries only, never raw/binary bytes.\n- URL SOURCES: when the source being indexed is a URL rather than an uploaded file (a temporary or signed URL that merely DELIVERS an uploaded file's bytes is not a URL source; that file keeps its storage-path identity), its identity is \"src::\" + the FULL URL INCLUDING the query string (the query string often selects the content, so dropping it collapses different pages into one identity). If no record with that unique_id exists, create it; if the slot is already taken, update that record or reference it - never mint a variant id. For a WEB PAGE: extract everything on it, infer the page's primary entity type when it is not obvious (product, listing, article, profile), TAG that entity type plus the entities on the page, and INDEX the ONE number every entity of that type can be compared by (a price for a product, a date for an article). Any OTHER URL (a file behind a link) is downloaded and indexed under whichever per-type rule above matches its content. When the URL's content offers more index points than one record carries, add reference-linked records reachable from its \"src::\" record.\n- This is a background indexing task: do ALL the MCP saving FIRST, never reply mid-task, and never ask the user questions. Be exhaustive about meaning (and, for tabular data, about every row). SAVE AS YOU GO: persist each window's records before reading the next, so progress is never lost. If the file is so large you cannot finish in one turn, still save everything you have read so far; a follow-up pass will automatically continue from where you stopped. NEVER store raw or encoded file bytes in ANY field: no base64, no data: URIs, no hex or blob dumps. A long opaque non-human-readable string is not data - replace it with a structured description of what it encodes. If base64 or a data: URI is all you have for something, describe it conceptually and never paste it; if nothing human-readable can be extracted at all, OMIT that record rather than saving noise.\n- COMPLETION SIGNAL: only when YOU paged the file yourself with readFileContent and it reported \"END OF FILE\", with every row/item saved, end your final message with the token INDEXING_COMPLETE on its own line. If more rows remain, do NOT write that token - leaving it out is how the system knows to run another pass to continue. When the file arrives INSIDE this message one window at a time (an embedded window of rows/text, or rendered PDF page images), you are NOT the one who decides it is finished: the system advances the window off the real page/row count and sends the next pass automatically, so save this window, report what you saved, and never imply you have seen the whole file.\n- Only AFTER every save is done, send exactly ONE final message summarizing what you indexed - never just \"Indexing complete\", and never a raw/base64/binary value or a large pasted dump. Keep it to a few factual sentences or a short markdown bullet list covering: the file name, its content type, each table you wrote to with its record/row count and the key columns/fields or topics captured, and anything that could not be extracted. Follow this shape - Indexed <file name> (<content type>): saved <N> records to <table(s)> capturing <key columns/fields or topics>; could not extract: <gaps, or none>.`;\n\n\tif (serviceDescription) {\n\t\tsystemPrompt += `\nProject name: \"${serviceName ?? ''}\"\nProject description: \"\"\"${serviceDescription}\"\"\"`;\n\t}\n\n\treturn systemPrompt;\n}\n","/**\n * BASE PROMPT - Background file-indexing agent (user message)\n * ============================================================================\n * USER-role message paired with the indexing system prompt. Sent by\n * notifyAgentSaveAttachment() each time a file is uploaded or re-indexed.\n *\n * NOTE: the leading line \"A new file has just been uploaded. Index it now.\" and\n * the \"- name: ...\" line are also what the chat client parses to build the\n * \"Indexing: <name>\" history bubble - keep those fields on their own lines.\n */\n\nexport type IndexingAttachmentInfo = {\n\t/** Original file name. */\n\tname: string;\n\t/** Storage path within the project's db storage. */\n\tstoragePath: string;\n\t/** MIME type, if detected. Omitted from the message when unknown. */\n\tmime?: string;\n\t/** File size in bytes, if known. Omitted from the message when unknown. */\n\tsize?: number;\n\t/** Temporary signed URL the agent/MCP fetches to read the file contents. */\n\turl: string;\n};\n\nexport type BuildIndexingUserMessageOptions = {\n\t/**\n\t * For files with no paged reader (.epub/.hwp/.doc/.rtf, source code) the model can't read the binary via\n\t * web_fetch, so the proxy worker extracts the text server-side and replaces\n\t * this exact token with it. When provided, the message embeds the token (and\n\t * drops the temporary-URL line - there is nothing for the model to fetch).\n\t */\n\tinlineContentPlaceholder?: string;\n\t/**\n\t * Actual file content parsed CLIENT-SIDE by an attachment-parser plugin (e.g.\n\t * an .hwp parser). Embedded inline verbatim - no server extraction and no\n\t * web_fetch for this file. Takes precedence over `inlineContentPlaceholder`.\n\t */\n\tinlineContent?: string;\n\t/**\n\t * Spreadsheet or PDF: read by PAGING through the readFileContent tool (grid rows +\n\t * embedded photos / rendered scanned pages), not inline and not by web_fetch. The\n\t * message instructs the agent to page through EVERY window and datafy each.\n\t */\n\tpagedRead?: boolean;\n};\n\nexport function buildIndexingUserMessage(\n\tattachment: IndexingAttachmentInfo,\n\toptions?: BuildIndexingUserMessageOptions,\n): string {\n\tconst head =\n\t\t`A new file has just been uploaded. Index it now.\\n\\n` +\n\t\t`File metadata:\\n` +\n\t\t`- name: ${attachment.name}\\n` +\n\t\t`- storage path: ${attachment.storagePath}\\n` +\n\t\t(attachment.mime ? `- mime type: ${attachment.mime}\\n` : '') +\n\t\t(typeof attachment.size === 'number' ? `- size (bytes): ${attachment.size}\\n` : '');\n\n\tif (options?.inlineContent) {\n\t\t// Parsed client-side (an attachment-parser plugin). The content is already\n\t\t// inlined below - no server extraction, no URL to fetch.\n\t\treturn (\n\t\t\thead +\n\t\t\t`\\nThe file's content was parsed by the client and is provided inline below. ` +\n\t\t\t`Read it directly - do NOT fetch any URL for this file. ` +\n\t\t\t`Set every record's reference to exactly \"src::\" + the storage path above (not this content). That file record already exists, so enrich it with updateRecords rather than posting it.\\n\\n` +\n\t\t\t`----- BEGIN FILE CONTENT -----\\n` +\n\t\t\t`${options.inlineContent}\\n` +\n\t\t\t`----- END FILE CONTENT -----`\n\t\t);\n\t}\n\n\tif (options?.inlineContentPlaceholder) {\n\t\t// Office file: text was extracted on the server and is inlined below\n\t\t// between the markers. Do NOT fetch any URL for this file.\n\t\treturn (\n\t\t\thead +\n\t\t\t`\\nThe file's text content was extracted on the server and is provided inline below. ` +\n\t\t\t`Read it directly - do NOT fetch any URL for this file. ` +\n\t\t\t`Set every record's reference to exactly \"src::\" + the storage path above (not this content). That file record already exists, so enrich it with updateRecords rather than posting it.\\n\\n` +\n\t\t\t`----- BEGIN FILE CONTENT -----\\n` +\n\t\t\t`${options.inlineContentPlaceholder}\\n` +\n\t\t\t`----- END FILE CONTENT -----`\n\t\t);\n\t}\n\n\tif (options?.pagedRead) {\n\t\t// Spreadsheet / PDF: force the paging path. The agent MUST read this with the\n\t\t// readFileContent tool (which returns the file window by window, with grid rows,\n\t\t// embedded photos, and rendered scanned pages), NOT by fetching the URL.\n\t\treturn (\n\t\t\thead +\n\t\t\t`\\nRead this file with the readFileContent tool, using the storage path above - do NOT fetch a URL and do NOT rely on a single sample. ` +\n\t\t\t`readFileContent returns the file ONE WINDOW at a time: spreadsheets as coordinate-tagged grid rows (e.g. 'R4 A:E&I NUMBER | B:E1007'), scanned/large PDFs as rendered PAGE IMAGES, and windows may include embedded photos - LOOK at any images and datafy what they show. ` +\n\t\t\t`Page through EVERY window: for each window SAVE records for its rows/items/pages (postRecords, one record per row/item), THEN if the window says MORE REMAINS call readFileContent again with the cursor it gives you. Repeat until it says END OF FILE, so the WHOLE file is indexed. ` +\n\t\t\t`Do NOT stop after the first window and do NOT just write a summary. Set every record's reference to exactly \"src::\" + the storage path above; that file record already exists, so enrich it with updateRecords instead of posting it again.` +\n\t\t\t(attachment.url ? `\\n(A temporary URL is provided ONLY as a fallback if readFileContent fails: ${attachment.url})` : '')\n\t\t);\n\t}\n\n\treturn head + `- temporary URL (fetch this to read the file contents): ${attachment.url}`;\n}\n\n/**\n * Token the WORKER substitutes with the 1-based first page of the window it is about to\n * render, when it builds the next pass of a document from `RENDER_CONTINUE_TEMPLATE`.\n * Must match the worker's RENDER_FROM_TOKEN.\n */\nexport const RENDER_FROM_TOKEN = '{{RENDER_FROM}}';\nconst WINDOW_CURSOR_TOKEN = RENDER_FROM_TOKEN;\n\n/**\n * User message for a VISION file (PDF): its pages are delivered as RENDERED PAGE IMAGES that\n * the proxy worker injects into THIS message at the `placeholder` token (tool-result images\n * render on neither provider, so the pages must be image blocks in the message itself). Each\n * pass shows one WINDOW of pages starting at `renderFrom` (0-based).\n *\n * The WORKER advances the window: when its renderer reports pages remaining it enqueues the\n * next pass itself, off the true page count, so a document indexes end-to-end with no browser\n * involved. This message therefore only ever describes ONE window, and the model is never\n * asked to decide whether the document is finished.\n *\n * renderFrom === 0 is the FIRST pass (leads with \"A new file has just been uploaded.\" so the\n * client builds the \"Indexing: <name>\" bubble); a continue pass (built by the worker from\n * buildIndexingRenderContinueTemplate) leads with \"CONTINUE indexing\" so it is not a duplicate\n * primary bubble.\n */\nexport function buildIndexingRenderMessage(\n\tattachment: IndexingAttachmentInfo,\n\tplaceholder: string,\n\trenderFrom: number,\n): string {\n\tconst from = Math.max(0, renderFrom || 0);\n\tif (from > 0) return buildIndexingRenderContinueTemplate(attachment, placeholder, String(from + 1));\n\n\treturn (\n\t\t`A new file has just been uploaded. Index it now.\\n\\n` +\n\t\tbuildRenderMeta(attachment) +\n\t\t`\\nThis is a PDF. Its pages are delivered to you as RENDERED PAGE IMAGES embedded directly in this ` +\n\t\t`message (you do NOT need any tool, URL, or web_fetch to see them). You are shown a WINDOW of pages ` +\n\t\t`at a time, starting at page ${from + 1}.\\n` +\n\t\tbuildRenderDatafy(placeholder)\n\t);\n}\n\n/**\n * The CONTINUE pass, as a template the worker fills in. `pageLabel` defaults to the\n * RENDER_FROM_TOKEN placeholder, which the worker replaces with the real 1-based start page\n * of the window it is rendering; passing an explicit label produces a ready-to-send message.\n */\nexport function buildIndexingRenderContinueTemplate(\n\tattachment: IndexingAttachmentInfo,\n\tplaceholder: string,\n\tpageLabel: string = RENDER_FROM_TOKEN,\n): string {\n\tconst src = `src::${attachment.storagePath}`;\n\treturn (\n\t\t`CONTINUE indexing a PDF whose previous pass did not finish.\\n\\n` +\n\t\tbuildRenderMeta(attachment) +\n\t\t`\\nRecords for the earlier pages are ALREADY saved (they reference \"${src}\"). The NEXT window of ` +\n\t\t`rendered page images (starting at page ${pageLabel}) is embedded in this message. Datafy each page as ` +\n\t\t`before and do NOT re-save pages that are already saved.\\n` +\n\t\tbuildRenderDatafy(placeholder)\n\t);\n}\n\nfunction buildRenderMeta(attachment: IndexingAttachmentInfo): string {\n\treturn (\n\t\t`File metadata:\\n` +\n\t\t`- name: ${attachment.name}\\n` +\n\t\t`- storage path: ${attachment.storagePath}\\n` +\n\t\t(attachment.mime ? `- mime type: ${attachment.mime}\\n` : '')\n\t);\n}\n\n// Shared datafy guidance. The placeholder is where the worker splices the note + rendered\n// page images; instructions reference \"the page images in this message\" so they read\n// correctly whether the images land before or after this text.\n//\n// Deliberately says nothing about INDEXING_COMPLETE or about whether the document is\n// finished: the worker decides that from the renderer's page count. Asking the model was\n// what used to end an 88-page file at page 15.\nfunction buildRenderDatafy(placeholder: string): string {\n\treturn (\n\t\t`\\n${placeholder}\\n\\n` +\n\t\t`LOOK at each rendered page image in this message and DATAFY what it shows: for EVERY page ` +\n\t\t`call postRecords and save records - one record per row / table entry / line item visible on the page ` +\n\t\t`(or one record for the page if it is prose), capturing every value you can read (OCR the text, read tables ` +\n\t\t`cell by cell, describe any photos/diagrams). Set EVERY record's reference to exactly \"src::\" + the storage path above. That file record ALREADY EXISTS, so do NOT post it, and do NOT give your page records a \"src::\" unique_id of their own. A record with no reference back to it is an ORPHAN: re-indexing the file deletes the linked records and leaves the orphan behind forever as stale data.\\n\\n` +\n\t\t`Each image is preceded by a label giving its DOCUMENT PAGE number. That label is the page's identity - ` +\n\t\t`use it, and ignore any page number PRINTED on the document itself (a scan often restarts its own ` +\n\t\t`numbering per section, so a footer reading \"PAGE 4 OF 8\" routinely disagrees with the real position). ` +\n\t\t`Whether a page is one you have already saved is stated in the note above the images - decide from that, ` +\n\t\t`never from a printed page number.\\n\\n` +\n\t\t`Transcribe COMPLETELY, not representatively. A table with twenty rows gets twenty records, not a sample ` +\n\t\t`of the first few - if a page has more rows than you can save comfortably, still save them all rather than ` +\n\t\t`summarising. Where a page carries an embedded text layer it is quoted above that page's image: it is the ` +\n\t\t`exact text and should be preferred over reading the pixels, with the image used for layout, tables, ` +\n\t\t`stamps and handwriting.\\n\\n` +\n\t\t`Save records for THIS window of pages only, then stop and report what you saved. Do NOT try to read ` +\n\t\t`the rest of the file and do NOT worry about the pages after this window: if any remain, the next window ` +\n\t\t`is rendered and sent to you automatically. Report only the pages you were actually shown - never imply ` +\n\t\t`you have seen the whole document.`\n\t);\n}\n\n/**\n * User message for a WINDOWED file: the worker splices ONE window of the file's rows or\n * text into this message at `placeholder`, then continues from the reader's own cursor\n * until the file is exhausted.\n *\n * The agent is deliberately NOT asked to page the file itself, and is NOT asked to judge\n * whether it is finished. Both used to be its job, and both failed the same way: the\n * traversal lived inside a single turn's budget, so a large file simply stopped partway\n * with a confident summary of the part it had seen.\n */\nexport function buildIndexingWindowMessage(\n\tattachment: IndexingAttachmentInfo,\n\tplaceholder: string,\n\tisContinuation: boolean,\n\tpositionLabel?: string,\n): string {\n\tconst src = `src::${attachment.storagePath}`;\n\tconst head = isContinuation\n\t\t? `CONTINUE indexing a file whose previous pass did not finish.\\n\\n`\n\t\t: `A new file has just been uploaded. Index it now.\\n\\n`;\n\tconst where = isContinuation\n\t\t? `\\nRecords for the earlier windows are ALREADY saved (they reference \"${src}\"). The NEXT window ` +\n\t\t `(starting at ${positionLabel || WINDOW_CURSOR_TOKEN}) is embedded below. Do NOT re-save windows that are already saved.\\n`\n\t\t: `\\nThis file is delivered to you ONE WINDOW at a time, embedded directly in this message. ` +\n\t\t `You do NOT need any tool, URL, or web_fetch to read it.\\n`;\n\n\treturn (\n\t\thead +\n\t\tbuildRenderMeta(attachment) +\n\t\twhere +\n\t\t`\\n${placeholder}\\n\\n` +\n\t\t`DATAFY this window: call postRecords and save records for everything in it - ONE RECORD PER ROW ` +\n\t\t`for tabular data (keyed by the column headers), or one record per section for prose. Capture every ` +\n\t\t`value you can read. The file-level record ALREADY EXISTS with unique_id \"src::\" + the storage path above: do NOT post it (a duplicate unique_id is rejected), enrich it with updateRecords, ` +\n\t\t`and link every row/section record to it by reference.\\n\\n` +\n\t\t`If this window has PHOTOS attached as images, LOOK at each one and datafy what it actually shows. ` +\n\t\t`A «PHOTO ...» marker in the grid text ties a picture to its row and comes in two forms. ` +\n\t\t`«PHOTO A88 -> __MEDIA__/...» means the picture at cell A88 is saved as a permanent file at exactly that storage path, and its record in table \"__MEDIA__\" has unique_id \"src::\" + that path: UPDATE that record with updateRecords, adding what the picture SHOWS and TAGS for every identifier visible in it (part numbers, tag ids, item names, serial numbers). Do NOT create a duplicate and do NOT add a second photo record in another table: one file, one record. If that update reports the record does not exist, create it ONCE with that same unique_id, reference \"src::\" + the storage path above, table \"__MEDIA__\", access group \"authorized\", and data carrying the path - the path must never be lost. ` +\n\t\t`A bare «PHOTO A88» marker with no arrow is a picture with no stored path of its own in this window: usually a repeat stored under an earlier anchor, or one too small to keep. NEVER construct a storage path or unique_id for it: find its record, if any, with getRecords reference \"src::\" + the storage path above, matching the cell against data.anchor or tags, and enrich what you find. The row record stays about its row's cells. Never report that photo contents could not be extracted when images are attached here.\\n\\n` +\n\t\t`Save records for THIS window only, then stop and report what you saved. Do NOT try to read the rest ` +\n\t\t`of the file, and do NOT call readFileContent - if more remains, the next window is read and sent to ` +\n\t\t`you automatically. Report only what you were actually shown, and never imply you have seen the whole ` +\n\t\t`file when the note beside the window says more remains.`\n\t);\n}\n\n/**\n * User message for a RESUME pass: a previous indexing pass could not finish this large\n * file, so continue it from where the already-saved records leave off (never restart).\n */\nexport function buildIndexingContinueMessage(attachment: IndexingAttachmentInfo): string {\n\tconst src = `src::${attachment.storagePath}`;\n\treturn (\n\t\t`CONTINUE indexing a file whose previous pass did not finish.\\n\\n` +\n\t\t`File metadata:\\n` +\n\t\t`- name: ${attachment.name}\\n` +\n\t\t`- storage path: ${attachment.storagePath}\\n` +\n\t\t(attachment.mime ? `- mime type: ${attachment.mime}\\n` : '') +\n\t\t`\\nRecords for the earlier windows/pages of this file are ALREADY saved (they reference \"${src}\"). ` +\n\t\t`First call getRecords with reference \"${src}\" to see how far the previous pass got (the furthest row/window already saved). The reference ALONE is the whole query: it returns every record written from this file across ALL tables and ALL access groups, so do NOT add table_name or access_group to narrow it. The response is PAGED, so keep fetching pages until it reports there are no more, and take the furthest point from the WHOLE set, never from the first page. ` +\n\t\t`Then call readFileContent with the storage path above and a CURSOR that RESUMES just after that point - do NOT start at the beginning. The cursor is derivable from what you already saved:\\n` +\n\t\t` - Spreadsheet: the cursor is \"<sheetIndex>:<nextRow>\" (0-based sheet index, 1-based row). If you saved up to row R of sheet S, use cursor=\"S:R+1\".\\n` +\n\t\t` - Text: the cursor is the character offset already read.\\n` +\n\t\t`Index the REMAINING windows - one record per row/item, looking at any page images or embedded photos - saving as you go until readFileContent reports END OF FILE. ` +\n\t\t`A «PHOTO <cell>» marker in a window marks an embedded picture whose extracted file already has a record in table \"__MEDIA__\": find it with getRecords reference \"src::\" + the storage path above and match the cell against data.anchor or tags (a repeated picture is stored under its first anchor only), then enrich it with updateRecords. Never create a photo record of your own and never construct a path for one. ` +\n\t\t`Do NOT re-save windows that are already saved. ` +\n\t\t`Set every record's reference to exactly \"src::\" + the storage path above (no sheet, window or summary suffix added). That file record already exists, so do NOT post it; enrich it with updateRecords. When the ENTIRE file is finally indexed, end your message with the token INDEXING_COMPLETE.`\n\t);\n}\n","/**\n * The chat's opening line, in ONE place.\n *\n * Both clients paint this bubble themselves (the widget builds DOM nodes,\n * agent.vue renders template markup) because the project name sits inside its\n * own translate=\"no\" element. Forking the sentence between them is how the two\n * copies drifted before, so the sentence lives here and each client only\n * decides how to draw the three pieces.\n *\n * It is ALSO what the assistant is told it opened with (buildChatSystemPrompt's\n * `greeting`): the bubble is pure client-side chrome and never enters the\n * message history, so without this the model cannot answer \"what do you mean,\n * indexed?\" or \"which files should I upload?\" about its own first line.\n */\n\nexport type ChatGreetingParams = {\n\t/** Project display name. Rendered by the client inside translate=\"no\". */\n\tprojectName?: string;\n\t/**\n\t * Whether this session can attach files at all. False for an anonymous\n\t * widget visitor and for a frozen database seen by a non-admin: telling\n\t * those users to upload is a dead end, so they get the ask-first line.\n\t */\n\tcanUpload?: boolean;\n};\n\nexport type ChatGreetingParts = {\n\t/** Text before the project name. */\n\tlead: string;\n\t/** The quoted project name, or \"\" when the project has no name. */\n\tname: string;\n\t/** Text after the project name. */\n\ttail: string;\n\t/** The whole line as plain text: what the assistant is told it said. */\n\ttext: string;\n};\n\nexport function buildChatGreeting(params: ChatGreetingParams): ChatGreetingParts {\n\tconst name = params.projectName ? '\"' + params.projectName + '\"' : '';\n\t// canUpload is opt-out: a caller that does not know defaults to the\n\t// upload-first line, which is the right lead for every ordinary session.\n\tconst lead = params.canUpload === false\n\t\t? 'Hi! Ask me anything about the data in your project'\n\t\t: 'Hi! Start by attaching the files related to your project';\n\tconst tail = params.canUpload === false\n\t\t? '.'\n\t\t: ', or pasting plain text into the chat. Once they are indexed, ask me anything about that data.';\n\treturn { lead, name, tail, text: lead + (name ? ' ' + name : '') + tail };\n}\n","/**\n * Error detection + message extraction (pure). Moved verbatim from the\n * agent.vue / bunnyquery chatbox so both consumers share one implementation.\n */\n\n// Plain-language text per upstream status, for the case below where the provider\n// gave us no readable message of its own.\nvar STATUS_MESSAGE: { [code: string]: string } = {\n\t'408': 'The AI provider timed out before it started.',\n\t'409': 'The AI provider rejected the request as conflicting.',\n\t'413': 'The request was too large for the AI provider.',\n\t'429': 'The AI provider is rate limiting requests right now.',\n\t'500': 'The AI provider hit an internal error.',\n\t'502': 'The AI provider is temporarily unreachable.',\n\t'503': 'The AI provider is temporarily unavailable.',\n\t'504': 'The AI provider timed out.',\n};\n\nfunction isTransientStatus(status: number): boolean {\n\treturn status === 408 || status === 425 || status === 429 || status >= 500;\n}\n\nexport function getErrorMessage(input: any): string {\n\tif (!input) return 'Something went wrong.';\n\tif (typeof input === 'string') return input;\n\tif (input.error && input.error.message) return input.error.message;\n\tif (input.body && input.body.error && input.body.error.message) return input.body.error.message;\n\tif (input.body && typeof input.body.message === 'string') return input.body.message;\n\tif (input.message) return input.message;\n\n\t// Every branch above assumes the provider answered with JSON. It does not\n\t// always: a gateway failure in front of the model API (Cloudflare's \"502 Bad\n\t// gateway\" page, an ALB error page) arrives as an HTML STRING in `body`, so\n\t// `body.error` / `body.message` are undefined on it and the user used to get a\n\t// bare 'Something went wrong.' with no way to tell a provider outage from a\n\t// bug in their own data. The status code is the one thing we always have, so\n\t// say what it means and whether retrying is worth it.\n\tvar status = typeof input.status_code === 'number' ? input.status_code\n\t\t: typeof input.status === 'number' ? input.status : 0;\n\tif (status) {\n\t\tvar text = STATUS_MESSAGE[String(status)]\n\t\t\t|| (status >= 500 ? 'The AI provider returned a server error.'\n\t\t\t\t: 'The AI provider rejected the request.');\n\t\treturn text + ' (error ' + status + ')'\n\t\t\t+ (isTransientStatus(status) ? ' This is usually temporary, please try again.' : '');\n\t}\n\treturn 'Something went wrong.';\n}\n\nexport function isErrorResponseBody(response: any): boolean {\n\tif (!response || typeof response !== 'object') return false;\n\tif (typeof response.status_code === 'number' && response.status_code >= 400) return true;\n\tif (response.type === 'error') return true;\n\tif (response.error && (response.error.message || response.error.type)) return true;\n\tvar body = response.body;\n\tif (body && typeof body === 'object') {\n\t\tif (body.type === 'error') return true;\n\t\tif (body.error && (body.error.message || body.error.type)) return true;\n\t}\n\tif (typeof response.message === 'string' && response.message.length) {\n\t\tvar hasClaude = Array.isArray(response.content);\n\t\tvar hasOpenAI =\n\t\t\ttypeof response.output_text === 'string' ||\n\t\t\tArray.isArray(response.output) ||\n\t\t\tArray.isArray(response.choices);\n\t\tif (!hasClaude && !hasOpenAI) return true;\n\t}\n\treturn false;\n}\n\n// A request that failed because the REQUEST ITSELF is malformed — an unknown or\n// rejected parameter on a 400/422 — will deterministically re-fail if resent\n// unchanged; no session refresh or retry can fix it. Detecting it lets the retry\n// gates refuse to auto-resend (otherwise a 400 whose param name merely contains\n// \"token\", e.g. `max_output_tokens`, trips the `invalid_request + token` branch\n// of isAuthExpiredError below and loops refresh->resend forever, burning tokens).\n// This is the `_skapi_extract` 400 class. Distinct from auth-expiry, which IS\n// retryable after a token refresh — so 401 (auth) and 429/5xx (transient) are\n// intentionally NOT treated as non-retryable here.\nexport function isNonRetryableRequestError(input: any): boolean {\n\tif (!input || typeof input !== 'object') return false;\n\n\tvar status = typeof input.status_code === 'number' ? input.status_code\n\t\t: typeof input.status === 'number' ? input.status : undefined;\n\n\t// Collect the error envelope wherever it lives (response, response.body, or a\n\t// thrown error), mirroring isErrorResponseBody / isAuthExpiredError.\n\tvar param: any = undefined;\n\tvar blobs: string[] = [];\n\tvar sources = [input.error, input.body && input.body.error, input.body, input];\n\tfor (var i = 0; i < sources.length; i++) {\n\t\tvar e = sources[i];\n\t\tif (!e) continue;\n\t\tif (typeof e === 'string') { blobs.push(e); continue; }\n\t\tif (typeof e !== 'object') continue;\n\t\tif (param === undefined && e.param != null) param = e.param;\n\t\tif (typeof e.code === 'string') blobs.push(e.code);\n\t\tif (typeof e.type === 'string') blobs.push(e.type);\n\t\tif (typeof e.message === 'string') blobs.push(e.message);\n\t}\n\tvar hay = blobs.join(' | ').toLowerCase();\n\n\t// Explicit \"unknown / unsupported parameter\" is always a malformed request.\n\tif (hay.indexOf('unknown_parameter') !== -1 || hay.indexOf('unknown parameter') !== -1 ||\n\t\thay.indexOf('unsupported_parameter') !== -1 || hay.indexOf('unsupported parameter') !== -1) {\n\t\treturn true;\n\t}\n\n\t// A 400/422 invalid_request that points at a specific rejected field: resending\n\t// the identical body re-fails. (401 -> isAuthExpiredError; 429/5xx -> transient.)\n\tvar isClientReqStatus = status === 400 || status === 422;\n\tif (isClientReqStatus && param != null && param !== '') return true;\n\tif (isClientReqStatus && hay.indexOf('invalid_request') !== -1 &&\n\t\t(hay.indexOf('parameter') !== -1 || hay.indexOf('param') !== -1)) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport function isAuthExpiredError(input: any): boolean {\n\tif (!input) return false;\n\tvar blobs: string[] = [];\n\tvar push = function (v: any) { if (typeof v === 'string' && v) blobs.push(v); };\n\tif (typeof input === 'string') push(input);\n\telse {\n\t\tpush(input.message); push(input.code);\n\t\tif (input.error) { push(input.error.message); push(input.error.code); push(input.error.type); }\n\t\tif (input.body) {\n\t\t\tpush(input.body.message);\n\t\t\tif (input.body.error) { push(input.body.error.message); push(input.body.error.code); push(input.body.error.type); }\n\t\t}\n\t\tif (typeof input.status === 'number' && input.status === 401) return true;\n\t\tif (typeof input.status_code === 'number' && input.status_code === 401) return true;\n\t}\n\tvar hay = blobs.join(' | ').toLowerCase();\n\tif (!hay) return false;\n\treturn hay.indexOf('token has expired') !== -1 || hay.indexOf('token is expired') !== -1 ||\n\t\thay.indexOf('expired_token') !== -1 || hay.indexOf('invalid_token') !== -1 ||\n\t\thay.indexOf('unauthorized') !== -1 || hay.indexOf('not authorized') !== -1 ||\n\t\t(hay.indexOf('invalid_request') !== -1 && hay.indexOf('token') !== -1);\n}\n\n/**\n * True when the AI PROVIDER rejected the project's own API key.\n *\n * Deliberately narrow, and deliberately NOT the same question as\n * isAuthExpiredError: that one is about OUR session/MCP bearer going stale,\n * which the client fixes by refreshing and resending. This one means the key\n * the project owner pasted is wrong or revoked, which only a human can fix.\n *\n * A bare 401 is NOT enough to conclude it (the MCP bearer expiring is also a\n * 401), so this matches only the provider's key-specific markers:\n * Anthropic -> `authentication_error`, \"invalid x-api-key\"\n * OpenAI -> `invalid_api_key`, \"Incorrect API key provided\"\n * Accepts a response object, a thrown error, or the message string those get\n * reduced to by getErrorMessage, because the view usually only keeps the text.\n */\nexport function isProviderApiKeyError(input: any): boolean {\n\tif (!input) return false;\n\tvar blobs: string[] = [];\n\tvar push = function (v: any) { if (typeof v === 'string' && v) blobs.push(v); };\n\tif (typeof input === 'string') push(input);\n\telse {\n\t\tpush(input.message); push(input.code); push(input.type);\n\t\tif (input.error) { push(input.error.message); push(input.error.code); push(input.error.type); }\n\t\tif (input.body) {\n\t\t\tpush(input.body.message); push(input.body.type);\n\t\t\tif (input.body.error) { push(input.body.error.message); push(input.body.error.code); push(input.body.error.type); }\n\t\t}\n\t}\n\tvar hay = blobs.join(' | ').toLowerCase();\n\tif (!hay) return false;\n\treturn hay.indexOf('authentication_error') !== -1 ||\n\t\thay.indexOf('invalid_api_key') !== -1 ||\n\t\thay.indexOf('invalid x-api-key') !== -1 ||\n\t\thay.indexOf('incorrect api key') !== -1 ||\n\t\thay.indexOf('invalid api key') !== -1 ||\n\t\thay.indexOf('no api key provided') !== -1;\n}\n","/**\n * Pure link/path helpers (no DOM, no marked). Moved verbatim from the chatbox.\n * `projectId` is passed as a PARAMETER (the original read it from a global) so\n * the engine stays consumer-agnostic. The HTML-emitting helpers\n * (buildLinkPartFromGroups, linkToAnchorHtml, fileToAnchorHtml, parseMsgParts*)\n * stay in each VIEW — only these pure pieces move here.\n */\n\nexport var EXPIRED_ATTACHMENT_URL_HOST = '_expired_.url';\nexport var EXPIRED_ATTACHMENT_URL_ORIGIN = 'https://' + EXPIRED_ATTACHMENT_URL_HOST;\nexport var LINK_LABEL_MAX_DISPLAY_CHARS = 32;\n\n/**\n * Lifetime of the url minted when a user clicks an expired attachment chip.\n *\n * Mint it as a PLAIN get-db presign, never with generate_temporary_cdn_url: the\n * cdn branch ignores `expires` entirely and hands back a url good for the rest of\n * the current UTC day plus the next one, so a \"20 minute\" link would in fact live\n * 24 to 48 hours. The dashboard has always done this correctly and the widget did\n * not, which is precisely the kind of divergence a shared constant exists to stop.\n */\nexport var EXPIRED_LINK_REFRESH_EXPIRES_SECONDS = 20 * 60;\n\n/**\n * Lifetime of the url minted for an inline image PREVIEW.\n *\n * Longer than the click url above, and for a different reason. A click hands the\n * user a url they may keep, so it stays short. A preview url is consumed by the\n * page itself and never leaves it, and it is the ONE lever on how long the\n * downloaded picture stays reusable: get_signed_url will not cache a mint for\n * longer than the credential inside it survives, so `browser_cache` cannot buy\n * local availability that `expires` has not paid for. Twenty minutes meant every\n * image re-downloaded three times an hour of ordinary reading.\n *\n * An hour, giving 55 minutes of cache once the server's five minute headroom is\n * taken off. Short enough that a leaked preview url is not a standing grant, long\n * enough that a conversation does not re-fetch its own pictures while the user is\n * still reading it.\n */\nexport var PREVIEW_URL_EXPIRES_SECONDS = 60 * 60;\n\n/**\n * Seconds the browser may reuse a minted preview url (`browser_cache`).\n *\n * A presigned url is a fresh SigV4 query string on every mint, so it can never\n * be a browser cache key on its own and every reload re-downloads every image.\n * Asking for the MINT with a cacheable GET fixes it from the other end: the same\n * url comes back out of the browser cache, so the body already on disk stays\n * addressable.\n *\n * A CEILING, not a promise. get_signed_url caps what it grants at the lifetime of\n * the url inside the response (expires minus headroom, so 15 minutes for the\n * platform's 20 minute url), because a mint cached for longer than its own\n * credential is a guaranteed 403 that the browser keeps serving from its own\n * store. Asking for the week is still right: it says what this client would\n * reuse if the url were stable by construction, and the server decides.\n *\n * What keeps an image painting is the cached BODY, not a live url. Once the\n * browser evicts that body it refetches with a url that has since expired, gets a\n * 403, and the error path re-mints with `refresh` and mintCacheBustStamp. That\n * path is load-bearing, not a rare fallback.\n *\n * A week is the platform default for reading a private file, not a number chosen\n * here: skapi-js reads every private record file with\n * PRIVATE_FILE_BROWSER_CACHE_SECONDS = 7 days against the same 20-minute url, and\n * get_signed_url caps the header at BROWSER_CACHE_MAX_SECONDS = 7 days. A chat\n * that asked for a day was re-downloading images the rest of the product would\n * have served from disk.\n *\n * Applies to previews only. A CLICK must open a live url, so the chip refresh\n * stays on an uncached POST mint.\n */\nexport var PREVIEW_BROWSER_CACHE_SECONDS = 7 * 24 * 60 * 60;\n\n/**\n * How long a client may keep serving an href it already minted before dropping\n * back to the placeholder and re-minting.\n *\n * DERIVED from the TTL above, with five minutes of headroom, because the\n * invariant \"the cache must expire before the url does\" used to be a comment\n * next to two independent literals. If it is ever violated a client serves a\n * dead url with no way to notice; deriving it makes that unrepresentable.\n */\nexport var LINK_REFRESH_WINDOW_MS = (EXPIRED_LINK_REFRESH_EXPIRES_SECONDS - 5 * 60) * 1000;\n\n/**\n * Cache generation for the mint request url. BUMP THIS to abandon every mint\n * response browsers are currently holding.\n *\n * Generation 2 retires the entries written before 2026-08-11. Those were stored\n * with `max-age=604800` around a presign that dies in twenty minutes, so from\n * minute 21 each one is a guaranteed 403 that the browser keeps serving from its\n * own store for the rest of the week. The server no longer grants a lifetime a\n * url cannot back (get_signed_url resolve_browser_cache), but that fixes what is\n * written from now on and cannot reach what is already stored on a user's\n * device. Changing the url is the only thing that can: an entry nobody requests\n * again is an entry that cannot answer again.\n */\nexport var MINT_CACHE_GENERATION = 2;\n\n/**\n * Window stamp for a REFRESH mint.\n *\n * WINDOWED, not Date.now(): a per-call stamp is a new cache key per image per\n * retry, which is what made the original `nocache` parameter worse than the\n * disease. One stamp per refresh window means every repair inside those minutes\n * shares a single entry, and it rotates before the url it carries can die.\n */\nexport function mintCacheBustStamp(now?: number): number {\n\treturn Math.floor((now == null ? Date.now() : now) / LINK_REFRESH_WINDOW_MS);\n}\n\n/**\n * The `nocache` value for a preview mint: the generation, plus a window stamp\n * when this mint is a repair.\n *\n * A repair MUST reach the origin, and the request header the clients used to\n * rely on cannot do it. `Cache-Control: no-cache` is not a CORS-safelisted\n * request header, and the record gateway's preflight answers\n * `Access-Control-Allow-Headers` WITHOUT it (verified against the live api on\n * 2026-08-11), so a mint carrying that header is rejected by the browser before\n * it is ever sent. Every repair therefore failed, in every browser, and the chip\n * went straight to \"(unavailable)\". Only a phone noticed, because only a phone\n * drops image bodies often enough to need the repair at all.\n *\n * A query parameter has no such problem: it is part of the url, so it needs no\n * preflight and no cooperation from the cache.\n */\nexport function previewMintCacheToken(refresh?: boolean): string {\n\tif (!refresh) return String(MINT_CACHE_GENERATION);\n\treturn MINT_CACHE_GENERATION + '.' + mintCacheBustStamp();\n}\n\n/**\n * How long before a presign dies we stop handing it out.\n *\n * A url served with one second left is a 403 with extra steps: the request still\n * has to reach S3, and an image body still has to start arriving.\n */\nexport var PRESIGN_SAFETY_MARGIN_MS = 60 * 1000;\n\n/**\n * When the url in hand actually dies, read out of the url itself, or null if it\n * carries no expiry we recognise.\n *\n * Every client-side cache here ages a url from the moment it ARRIVED, which is\n * only the same thing as its lifetime when the mint went to the network. Once\n * mint responses are cacheable that assumption breaks: a mint answered from the\n * browser's store can be nearly as old as its own max-age, and the client then\n * adds its own reuse window on top, so a 20 minute credential can be handed to an\n * <img> half an hour after it was signed. Asking the url when it dies removes the\n * stacking instead of trying to budget for it.\n *\n * Both signature versions, because the platform mints SigV2 through the host\n * bucket and SigV4 elsewhere.\n */\nexport function presignExpiryEpochMs(url: string): number | null {\n\tif (!url) return null;\n\tvar q = url.indexOf('?');\n\tif (q < 0) return null;\n\tvar params: URLSearchParams;\n\ttry { params = new URLSearchParams(url.slice(q + 1)); }\n\tcatch (e) { return null; }\n\n\t// SigV2: Expires is an absolute epoch in seconds.\n\tvar v2 = params.get('Expires');\n\tif (v2 && /^\\d+$/.test(v2)) return parseInt(v2, 10) * 1000;\n\n\t// SigV4: signing time plus a duration.\n\tvar signed = params.get('X-Amz-Date');\n\tvar lifetime = params.get('X-Amz-Expires');\n\tif (signed && lifetime && /^\\d+$/.test(lifetime)) {\n\t\tvar m = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(signed);\n\t\tif (m) {\n\t\t\tvar at = Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6]);\n\t\t\treturn at + parseInt(lifetime, 10) * 1000;\n\t\t}\n\t}\n\treturn null;\n}\n\n// The two \"balanced parens\" groups match ONE CHARACTER per step, never a `+`\n// run, so each position has exactly one way to be matched: `[^()\\n]` cannot\n// start with `(`, and the nested-paren alternative always does. That disjointness\n// is load-bearing, not style.\n//\n// The obvious spelling — `(?:[^()\\n]+|\\([^()\\n]*\\))+` — is a nested quantifier:\n// a run of N plain characters can be split across the outer `+` in 2^N ways, and\n// the engine tries EVERY one before it can conclude the branch failed. A branch\n// fails on ordinary input: a link whose url contains a space (the url branch\n// forbids spaces), a link broken across a newline, or a reply truncated\n// mid-link. Measured on the unfixed pattern: `[label](` plus 30 characters with\n// no closing paren took 62 SECONDS, 45 characters never finished. Since this\n// regex is scanned over the whole reply by the typewriter (session.ts) and by\n// every message render (parseMsgParts), that is a permanently frozen tab the\n// moment such a message arrives. Same matches either way, linear time.\nexport function createInlineLinkRegex(): RegExp {\n\treturn /src::(\\S+)|\\[([^\\]\\n]+)\\]\\((https?:\\/\\/(?:[^\\s()]|\\([^\\s()]*\\))+)\\)|\\[([^\\]\\n]+)\\]\\(((?:[^()\\n]|\\([^()\\n]*\\))+)\\)|(https?:\\/\\/[^\\s<>\"']+)/g;\n}\n\nexport function safeDecodeURIComponent(v: string): string {\n\ttry { return decodeURIComponent(v); } catch (e) { return v; }\n}\n\nexport function encodePathSegments(path: string): string {\n\treturn path.split('/').filter(Boolean).map(function (s) { return encodeURIComponent(s); }).join('/');\n}\n\nexport function normalizeAttachmentPathCandidate(value: string): string {\n\treturn safeDecodeURIComponent((value || '').trim()).replace(/\\\\/g, '/').replace(/^\\/+/, '').replace(/\\/+/g, '/');\n}\n\nexport function extractRemotePathFromAttachmentHref(href: string, projectId: string): string | null {\n\ttry {\n\t\tvar parsed = new URL(href);\n\t\tif (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return null;\n\t\tvar path = normalizeAttachmentPathCandidate(parsed.pathname || '');\n\t\tvar segs = path.split('/').filter(Boolean);\n\t\tif (!segs.length) return null;\n\t\tvar HEX = /^[a-f0-9]{32,}$/i;\n\t\tvar sid = projectId || '';\n\t\tvar start = 0;\n\t\twhile (start < segs.length) {\n\t\t\tvar seg = segs[start];\n\t\t\tif (seg === sid || HEX.test(seg)) { start++; continue; }\n\t\t\tbreak;\n\t\t}\n\t\tvar real = segs.slice(start).join('/');\n\t\treturn real || null;\n\t} catch (e) { return null; }\n}\n\nexport function getExpiredAttachmentVisiblePath(remotePath: string, fallback?: string): string {\n\tvar n = normalizeAttachmentPathCandidate(remotePath);\n\tif (n) return n;\n\treturn normalizeAttachmentPathCandidate(fallback || 'file') || 'file';\n}\n\nexport function buildDisplayExpiredAttachmentHref(remotePath: string, fallback?: string): string {\n\treturn EXPIRED_ATTACHMENT_URL_ORIGIN + '/' + encodePathSegments(getExpiredAttachmentVisiblePath(remotePath, fallback));\n}\n\n// Does `href` point at THIS service's db attachment storage? A db attachment URL's\n// path always begins with the projectId segment (…/<projectId>/<hash>/<path>). Used\n// to SAFELY sanitize assistant messages — where an arbitrary external citation URL\n// must never be rewritten, only the service's own volatile db links.\nexport function isServiceDbAttachmentHref(href: string, projectId: string): boolean {\n\tif (!projectId) return false;\n\ttry {\n\t\tvar parsed = new URL(href);\n\t\tif (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false;\n\t\tvar segs = normalizeAttachmentPathCandidate(parsed.pathname || '').split('/').filter(Boolean);\n\t\treturn segs.length > 0 && segs[0] === projectId;\n\t} catch (e) { return false; }\n}\n\n/**\n * Read the storage path back out of an `_expired_.url` placeholder.\n *\n * The placeholder is not a display detail: sanitizeAttachmentLinksForHistory\n * writes it into PERSISTED history, and buildBoundedChatMessages replays it into\n * the model's context. So it round-trips constantly and MUST be recognised on the\n * way back in. Returns null for anything that is not the carrier.\n */\nexport function readExpiredAttachmentHref(href: string): string | null {\n\tif (!href) return null;\n\ttry {\n\t\tvar parsed = new URL(href);\n\t\tif (parsed.hostname !== EXPIRED_ATTACHMENT_URL_HOST) return null;\n\t\treturn normalizeAttachmentPathCandidate(parsed.pathname || '') || null;\n\t} catch (e) { return null; }\n}\n\n// Replace volatile attachment URLs with their durable `_expired_.url/<path>`\n// placeholder so a stored/replayed copy re-mints on demand instead of going stale.\n//\n// Only THIS service's db urls are rewritten, whichever role wrote them. The user\n// branch used to rewrite every url in any message that carried an \"Attached\n// files:\" block, which quietly destroyed a third-party link the user happened to\n// paste in the same message: it became a placeholder for a storage path that\n// never existed. We can only re-mint what we host, so we only rewrite what we\n// host.\nexport function sanitizeAttachmentLinksForHistory(content: string, projectId: string, forAssistant?: boolean): string {\n\tif (!content) return content;\n\tif (!forAssistant && content.indexOf('Attached files:') === -1) return content;\n\treturn content.replace(/\\[([^\\]\\n]+)\\]\\((https?:\\/\\/[^\\s)]+)\\)/g, function (_m: string, label: string, href: string) {\n\t\tif (!isServiceDbAttachmentHref(href, projectId)) return _m;\n\t\tvar remotePath = extractRemotePathFromAttachmentHref(href, projectId);\n\t\tvar fullPath = remotePath || normalizeAttachmentPathCandidate(label);\n\t\tif (!fullPath) return _m;\n\t\treturn '[' + label + '](' + buildDisplayExpiredAttachmentHref(fullPath, label) + ')';\n\t});\n}\n\n/**\n * Is this markdown link target a URL rather than a db storage path?\n *\n * The inline-link regex decides that by whether the target contains whitespace:\n * its url branch forbids it, its bare-path branch allows it (a db path really can\n * contain spaces). So a url that picked up a stray space anywhere in transit\n * falls out of the url branch and is claimed by the path branch, and the view\n * renders it as an `_expired_.url/https%3A/…` attachment chip that resolves to\n * nothing. The view asks this FIRST, so what a link IS never depends on damage.\n */\nexport function isHttpUrlLike(target: string): boolean {\n\treturn /^https?:\\/\\//i.test((target || '').trim());\n}\n\n/**\n * Repair whitespace inside a url. RFC 3986 has no legal whitespace anywhere in a\n * URI, so a space in an href is always damage, never content.\n *\n * Two repairs, because the right one differs:\n * - Our own `/download/<id>` capability links (skapi-mcp file-download.js) are\n * base64url, optionally with a single `.` separating the payload and hmac of\n * the older self-describing token. That alphabet cannot contain whitespace,\n * so the spaces are purely damage and REMOVING them restores the exact link,\n * which is what makes an already-sent message clickable again. A model\n * reproducing one of these into its reply is exactly where the spaces come\n * from, which is also why the id is now short.\n * - Anything else keeps every character and only has the whitespace encoded,\n * the same thing a browser does with a space in an href. Stripping would be\n * wrong there: `…/exports/my report.csv` is a real file whose name has a\n * space in it, and deleting it points at a file that does not exist.\n */\nexport function repairUrlWhitespace(href: string): string {\n\tif (!href || !/\\s/.test(href)) return href;\n\tvar stripped = href.replace(/\\s+/g, '');\n\tif (/^https?:\\/\\/[^/\\s]+\\/download\\/[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)?$/i.test(stripped)) return stripped;\n\treturn href.trim().replace(/\\s/g, '%20');\n}\n\n/**\n * A model reproducing a URL sometimes HTML-escapes its `&` query separators as\n * `&amp;` (or the numeric `&#38;` / `&#x26;`). Left in the href that escaping\n * survives the client's own escapeAttr -> v-html/innerHTML decode round-trip and\n * reaches the browser LITERALLY, so a presigned S3 URL is navigated with its\n * parameters named `amp;Signature`, `amp;Expires`, `amp;response-content-type`,\n * ... — the real params vanish, the signature can't be located, and S3 rejects\n * it (the \"링크가 안되\" dead export link). Undo just that entity escaping.\n *\n * This is a no-op on a clean URL: a valid link carries a raw `&` between params\n * and percent-encodes (`%26`) any literal ampersand that is data, so a real URL\n * never contains `&amp;` to begin with. Mirrors repairUrlWhitespace: it repairs\n * model damage, not the URL. The loop collapses a doubly-escaped `&amp;amp;` too.\n */\nexport function repairUrlEntities(href: string): string {\n\tif (!href || href.indexOf('&') === -1) return href;\n\tvar out = href, prev = '';\n\twhile (out !== prev) {\n\t\tprev = out;\n\t\tout = out\n\t\t\t.replace(/&amp;/gi, '&')\n\t\t\t.replace(/&#0*38;/g, '&')\n\t\t\t.replace(/&#x0*26;/gi, '&');\n\t}\n\treturn out;\n}\n\n/**\n * Trim punctuation and unmatched wrappers that cling to a token in prose.\n * `src::a/b.pdf).` -> `src::a/b.pdf`, while a balanced `file (v2).pdf` is kept.\n */\nexport function normalizeTrailingInlineToken(value: string): string {\n\tif (!value) return value;\n\tvar out = value.replace(/[.,;:!?]+$/, '');\n\tvar trimUnmatched = function (openCh: string, closeCh: string) {\n\t\twhile (out.charAt(out.length - 1) === closeCh) {\n\t\t\tvar openCount = (out.match(new RegExp('\\\\' + openCh, 'g')) || []).length;\n\t\t\tvar closeCount = (out.match(new RegExp('\\\\' + closeCh, 'g')) || []).length;\n\t\t\tif (closeCount > openCount) out = out.slice(0, -1); else break;\n\t\t}\n\t};\n\ttrimUnmatched('(', ')');\n\ttrimUnmatched('[', ']');\n\ttrimUnmatched('{', '}');\n\tout = out.replace(/[`'\"*>]+$/, '');\n\treturn out;\n}\n\n/**\n * Extensions a BROWSER can paint in an <img>, mapped to the content type the\n * presign must declare.\n *\n * The content type is not optional here. get_signed_url only sets\n * ResponseContentType when the caller passes `contentType`, and otherwise falls\n * back to application/octet-stream, which a new tab DOWNLOADS instead of\n * displaying. Since the whole point of the preview is that clicking it shows the\n * picture, the mint has to name the real type.\n *\n * Deliberately narrower than the extraction/vision lists elsewhere in the repo:\n * heic/heif out: Safari paints them, Chrome and Firefox show a broken image,\n * and it is the format every iPhone photo arrives in, so the\n * failure would be common and would read as a bug.\n * tif/wmf/emf out: no mainstream browser paints them.\n * svg out: inside an <img> an SVG is script-disabled and safe, but this\n * feature's click target is a TOP-LEVEL navigation, where an\n * SVG executes its own <script> in the serving origin with that\n * origin's cookies, from user-uploaded content. A preview is an\n * invitation to click exactly that.\n */\nexport var PREVIEWABLE_IMAGE_CONTENT_TYPES: Record<string, string> = {\n\tpng: 'image/png',\n\tjpg: 'image/jpeg',\n\tjpeg: 'image/jpeg',\n\tgif: 'image/gif',\n\twebp: 'image/webp',\n\tavif: 'image/avif',\n\tbmp: 'image/bmp',\n};\n\n/** Extension of a path or url, query and fragment stripped, '' when none. */\nexport function previewableExtOf(nameOrPath: string | null | undefined): string {\n\tvar v = String(nameOrPath || '');\n\t// A storage path may legally contain '?', so this cannot reuse extOf().\n\tvar cut = v.search(/[?#]/);\n\tif (cut !== -1) v = v.slice(0, cut);\n\tv = v.replace(/[\\\\/]+$/, '');\n\tvar dot = v.lastIndexOf('.');\n\tif (dot <= 0) return '';\n\tvar ext = v.slice(dot + 1).trim().toLowerCase();\n\treturn /^[a-z0-9]+$/.test(ext) ? ext : '';\n}\n\nexport function isPreviewableImagePath(nameOrPath: string | null | undefined): boolean {\n\treturn !!PREVIEWABLE_IMAGE_CONTENT_TYPES[previewableExtOf(nameOrPath)];\n}\n\n/** Content type to hand the presign so a new tab displays rather than downloads. */\nexport function previewImageContentType(nameOrPath: string | null | undefined): string | null {\n\treturn PREVIEWABLE_IMAGE_CONTENT_TYPES[previewableExtOf(nameOrPath)] || null;\n}\n\n/** A link the view renders. `expired` means the href is the `_expired_.url`\n * placeholder and a click must mint a fresh one from `remotePath`. */\nexport interface InlineLinkPart {\n\ttype: 'link';\n\tlabel: string;\n\tfullLabel: string;\n\thref: string;\n\texpired: boolean;\n\texpiredHref?: string;\n\tremotePath?: string;\n\t/**\n\t * Set only for a file WE host whose PATH says a browser can paint it. Its\n\t * presence IS the \"render a preview\" decision, so a view never re-tests the\n\t * label and never tests `href` (which is the _expired_.url placeholder).\n\t */\n\timage?: { ext: string; contentType: string };\n}\n\nexport interface InlineLinkContext {\n\t/** Current project id: the leading segment to strip off a db url. */\n\tprojectId: string;\n\t/** `https://db.<hostDomain>` for this deployment. */\n\tdbHostPrefix: string;\n\t/** A fresh url already minted for this placeholder, if the view cached one. */\n\tresolveFreshHref?: (expiredHref: string) => string | undefined;\n}\n\n/**\n * Decide what ONE inline-link regex match actually is, and how to render it.\n *\n * This is the single place that answers \"is this an external url, this project's\n * db file, or a bare storage path\", for every consumer. It used to live twice,\n * once in agent.vue and once in the widget, and both copies had to be found and\n * corrected for each of the link bugs this file's history records. A view now\n * supplies its own context (project id, db host, cached-href lookup) and does\n * nothing but turn the returned part into markup.\n *\n * `groups` is [g1..g6] from createInlineLinkRegex, in that order:\n * g1 src::<token> g2/g3 [label](url) g4/g5 [label](path) g6 bare url\n */\nexport function classifyInlineLink(\n\tfull: string,\n\tgroups: Array<string | undefined>,\n\tctx: InlineLinkContext,\n): { part: InlineLinkPart; tail?: string } | null {\n\tvar g1 = groups[0], g2 = groups[1], g3 = groups[2], g4 = groups[3], g5 = groups[4], g6 = groups[5];\n\tvar dbHostPrefix = (ctx.dbHostPrefix || '').toLowerCase();\n\tvar fresh = function (expiredHref: string): string | undefined {\n\t\treturn ctx.resolveFreshHref ? ctx.resolveFreshHref(expiredHref) : undefined;\n\t};\n\tvar isDbHost = function (url: string): boolean {\n\t\treturn !!dbHostPrefix && url.toLowerCase().indexOf(dbHostPrefix) === 0;\n\t};\n\t// A db path rendered as the placeholder the click handler resolves.\n\tvar asStoredFile = function (remotePath: string, label: string): { part: InlineLinkPart } | null {\n\t\tif (!remotePath) return null;\n\t\tvar expiredHref = buildDisplayExpiredAttachmentHref(remotePath, label);\n\t\tvar cached = fresh(expiredHref);\n\t\tvar part: InlineLinkPart = {\n\t\t\ttype: 'link',\n\t\t\tlabel: truncateLabelForDisplay(label),\n\t\t\tfullLabel: label,\n\t\t\thref: cached || expiredHref,\n\t\t\texpired: !cached,\n\t\t\texpiredHref: expiredHref,\n\t\t\tremotePath: remotePath,\n\t\t};\n\t\t// The PATH decides, never the label. The file is fetched by path, so the\n\t\t// path is the only claim with consequences: a model-written label reading\n\t\t// \"chart.png\" on a .xlsx would otherwise mint a url and paint a broken box.\n\t\tvar ext = previewableExtOf(remotePath);\n\t\tvar ct = PREVIEWABLE_IMAGE_CONTENT_TYPES[ext];\n\t\tif (ct) part.image = { ext: ext, contentType: ct };\n\t\treturn { part: part };\n\t};\n\n\t// src::<token> — a path, or a url the model copied out of a record.\n\tif (g1) {\n\t\tvar rawPath = normalizeTrailingInlineToken(g1);\n\t\tvar tail = full.slice(('src::' + rawPath).length);\n\t\tvar srcIsUrl = isHttpUrlLike(rawPath);\n\t\t// `src::` values come straight out of a record's unique_id, and the prompt\n\t\t// says that may be \"the file's storage path or original URL\". http:// is as\n\t\t// much a url as https://; testing only for https sent every plain-http\n\t\t// source into the storage-path branch, where it became a chip pointing at\n\t\t// this project for someone else's file.\n\t\tif (srcIsUrl && !isDbHost(rawPath) && !readExpiredAttachmentHref(rawPath)) {\n\t\t\t// decode any model-introduced `&amp;` in the URL (tail stays keyed on\n\t\t\t// the raw match length, so it is left untouched)\n\t\t\tvar srcUrl = repairUrlEntities(rawPath);\n\t\t\treturn {\n\t\t\t\tpart: { type: 'link', label: truncateLabelForDisplay(srcUrl), fullLabel: srcUrl, href: srcUrl, expired: false },\n\t\t\t\ttail: tail,\n\t\t\t};\n\t\t}\n\t\tvar srcPath = readExpiredAttachmentHref(rawPath)\n\t\t\t|| (srcIsUrl\n\t\t\t\t? (extractRemotePathFromAttachmentHref(rawPath, ctx.projectId) || normalizeAttachmentPathCandidate(rawPath))\n\t\t\t\t// bare stored path: same NON-decoding normalize as the db: branch; only\n\t\t\t\t// URL-derived paths genuinely arrive percent-encoded.\n\t\t\t\t: rawPath.trim().replace(/\\\\/g, '/').replace(/^\\/+/, '').replace(/\\/+/g, '/'));\n\t\tvar srcBuilt = asStoredFile(srcPath, srcPath);\n\t\treturn srcBuilt ? { part: srcBuilt.part, tail: tail } : null;\n\t}\n\n\t// [label](target) where target is NOT a url by the regex's reckoning.\n\tif (g4 && g5) {\n\t\t// An EXPLICIT db target, `[label](db:folder/file.csv)`, says what it is\n\t\t// instead of leaving us to infer it from the absence of \"http\". That is the\n\t\t// only form here that cannot be confused with anything else, and it matches\n\t\t// the scheme the backend already uses internally (db:<service>/<key>).\n\t\t// Accepted now so the clients tolerate it everywhere before anything starts\n\t\t// EMITTING it; until then this branch simply never fires.\n\t\tvar dbTarget = /^db:(.+)$/i.exec(g5.trim());\n\t\tif (dbTarget) {\n\t\t\t// NON-decoding normalize: the prompt guarantees a db: target is the path exactly\n\t\t\t// as stored, NOT url-encoded, and the MCP's own key builder refuses to decode\n\t\t\t// bare paths for the same corruption: percent-decoding here turned a stored name\n\t\t\t// containing a literal \"%20\" into the wrong key.\n\t\t\tvar rawDbPath = dbTarget[1].trim().replace(/\\\\/g, '/').replace(/^\\/+/, '').replace(/\\/+/g, '/');\n\t\t\tvar declared = asStoredFile(rawDbPath, g4);\n\t\t\tif (!declared) return null;\n\t\t\tdeclared.part.label = truncateLabelForDisplay(g4);\n\t\t\tdeclared.part.fullLabel = g4;\n\t\t\treturn declared;\n\t\t}\n\t\t// ...except when it is one. It only lands here because it contains\n\t\t// whitespace, which the url branch forbids and this one allows, and\n\t\t// reading a damaged url as a storage path is how a download link became a\n\t\t// dead chip. Repair it and classify it as what it is.\n\t\tif (isHttpUrlLike(g5)) {\n\t\t\treturn classifyInlineLink(full, [undefined, g4, repairUrlWhitespace(g5), undefined, undefined, undefined], ctx);\n\t\t}\n\t\t// Any OTHER scheme, or a fragment, is a link the user wrote and not a file\n\t\t// we host. `mailto:`, `tel:` and `#section` were all being turned into\n\t\t// download chips for storage paths of that literal text, so clicking one\n\t\t// asked this project for a file called \"mailto:a@b.com\".\n\t\tvar trimmedTarget = g5.trim();\n\t\tif (/^[a-z][a-z0-9+.-]*:/i.test(trimmedTarget) || trimmedTarget.charAt(0) === '#') {\n\t\t\treturn {\n\t\t\t\tpart: { type: 'link', label: truncateLabelForDisplay(g4), fullLabel: g4, href: trimmedTarget, expired: false },\n\t\t\t};\n\t\t}\n\t\tvar built = asStoredFile(normalizeAttachmentPathCandidate(g5), g4);\n\t\tif (!built) return null;\n\t\t// The label is the model's, not the path: keep it verbatim.\n\t\tbuilt.part.label = truncateLabelForDisplay(g4);\n\t\tbuilt.part.fullLabel = g4;\n\t\treturn built;\n\t}\n\n\t// [label](url) and bare urls.\n\tvar originalHref = g3 || g6 || '';\n\tif (!originalHref) return null;\n\t// A model that reproduces the URL may have HTML-escaped its `&` separators;\n\t// decode them now so every downstream check and the final href see a clean\n\t// URL (otherwise a presigned link navigates with `&amp;` and 403s).\n\toriginalHref = repairUrlEntities(originalHref);\n\t// A bare url swallows the punctuation that ends the sentence it sits in, so\n\t// `see https://host/a.pdf.` linked to `a.pdf.` and 404'd. Trim it and hand the\n\t// trimmed text back as `tail`, exactly as the src:: branch does.\n\tvar urlTail: string | undefined;\n\tif (!g3 && g6) {\n\t\tvar trimmedUrl = normalizeTrailingInlineToken(originalHref);\n\t\tif (trimmedUrl !== originalHref) urlTail = originalHref.slice(trimmedUrl.length);\n\t\toriginalHref = trimmedUrl;\n\t}\n\tvar withTail = function (r: { part: InlineLinkPart }): { part: InlineLinkPart; tail?: string } {\n\t\treturn urlTail ? { part: r.part, tail: urlTail } : r;\n\t};\n\tvar urlLabel = g2 || originalHref;\n\n\t// THE PLACEHOLDER, read back. sanitizeAttachmentLinksForHistory writes this\n\t// form into stored history and buildBoundedChatMessages replays it to the\n\t// model, so it arrives here constantly: as a rebuilt bubble on every reload,\n\t// and as text the model copied out of its own context. It has to be checked\n\t// BEFORE the generic https branch, because it IS https and it is NOT the db\n\t// host, so that branch claimed it and rendered `expired: false` — a link to a\n\t// hostname that does not resolve, with no way to ever refresh it. Every stored\n\t// attachment link went dead on reload for exactly that reason.\n\tvar carried = readExpiredAttachmentHref(originalHref);\n\tif (carried) {\n\t\tvar carriedBuilt = asStoredFile(carried, g2 || carried);\n\t\tif (carriedBuilt) {\n\t\t\tif (g2) { carriedBuilt.part.label = truncateLabelForDisplay(g2); carriedBuilt.part.fullLabel = g2; }\n\t\t\treturn withTail(carriedBuilt);\n\t\t}\n\t}\n\n\t// This project's own db url: volatile, so render it re-mintable. A db url for\n\t// a DIFFERENT project is not ours to mint, so it stays an ordinary link rather\n\t// than a chip that would query this project for someone else's key.\n\tif (isServiceDbAttachmentHref(originalHref, ctx.projectId)) {\n\t\tvar remotePath = extractRemotePathFromAttachmentHref(originalHref, ctx.projectId);\n\t\tif (remotePath) {\n\t\t\tvar dbBuilt = asStoredFile(remotePath, getExpiredAttachmentVisiblePath(remotePath, urlLabel));\n\t\t\tif (dbBuilt) return withTail(dbBuilt);\n\t\t}\n\t}\n\n\t// Everything else is a link, not a path. The old rule tested for `https://`\n\t// specifically and treated ANY other target as db storage, so a plain\n\t// `http://` citation, a `mailto:`, a `#anchor` and a `/relative` link all\n\t// rendered as download chips for storage paths that never existed, and\n\t// clicking one raised \"failed to refresh\" on a file the user never had.\n\treturn withTail({\n\t\tpart: { type: 'link', label: truncateLabelForDisplay(urlLabel), fullLabel: urlLabel, href: originalHref, expired: false },\n\t});\n}\n\n/**\n * \"We asked for a url for this file and did not get one.\"\n *\n * A chip the client cannot mint a url for is not a link: the ↗ is a promise it\n * already knows it cannot keep, and clicking it opens a dead tab or nothing at\n * all. Both views therefore keep a map of failures and render those chips\n * unavailable (renderInlineLinkHtml's `unavailable` option): greyed, ✕ instead\n * of ↗, no href.\n *\n * The MAP lives in the view (agent.vue has to re-render when it changes, and\n * that means a ref), so only the keys are here. A failure is reported with\n * exactly one identifier (an image preview knows the storage path, a click knows\n * the placeholder href), so marking writes one key and the lookup tries all of\n * them.\n */\n/**\n * Unicode form is not stable across the places a storage path travels through.\n *\n * macOS hands the browser a DECOMPOSED (NFD) filename, so a Korean name like\n * 운전면허-김대현.jpg arrives as 24 codepoints where the composed (NFC) form is 12.\n * Nothing in this engine normalized either way, so the SAME file could be keyed under\n * two different strings depending on which path it travelled: a mark left by a failed\n * mint under one form would never be cleared by a successful load under the other, and\n * the chip stayed greyed out as \"(unavailable)\" forever.\n *\n * NFC is the canonical choice: it is what the Unicode standard recommends for\n * interchange, and it is the shorter, more common form on the wire.\n */\nexport function canonicalizePathForm(value: string): string {\n\tif (!value) return value;\n\ttry { return value.normalize('NFC'); } catch (e) { return value; }\n}\n\nexport function linkUnavailableKeyForPath(remotePath: string): string {\n\t// Canonicalized so the NFC and NFD spellings of one file share ONE key.\n\treturn 'path:' + canonicalizePathForm(remotePath || '');\n}\n\nexport function linkUnavailableKeyForHref(href: string): string {\n\t// An `_expired_.url` placeholder carries the storage path percent-encoded, so NFC and\n\t// NFD spellings of one file produce two different href strings and therefore two\n\t// different keys. Route those through the path key instead, so a file has ONE key\n\t// however it is spelled and whichever carrier it arrived on.\n\tvar carried = readExpiredAttachmentHref(href);\n\tif (carried) return linkUnavailableKeyForPath(carried);\n\treturn 'href:' + canonicalizePathForm(href || '');\n}\n\n/**\n * Every key a stored file can be marked under, given only its path.\n *\n * Marking writes ONE key (whichever identifier the failing call had) and the\n * lookup ORs all of them, which is fine in one direction and wrong in the other:\n * a view that later learns the file is reachable knows only the path, and\n * clearing `path:` alone leaves a chip greyed by a failed CLICK (which marks\n * `href:` too) exactly as dead as before. The placeholder href is derived from\n * the path, so both keys can be rebuilt from it.\n */\nexport function linkUnavailableKeysForPath(remotePath: string): string[] {\n\tif (!remotePath) return [];\n\tvar keys = [\n\t\tlinkUnavailableKeyForPath(remotePath),\n\t\tlinkUnavailableKeyForHref(buildDisplayExpiredAttachmentHref(remotePath)),\n\t];\n\t// Both now canonicalize to the same key for a placeholder href, so drop the duplicate\n\t// rather than marking and clearing the same entry twice.\n\treturn keys.filter(function (k, i) { return keys.indexOf(k) === i; });\n}\n\nexport function isLinkUnavailable(\n\tlink: { href?: string; expiredHref?: string; remotePath?: string } | null | undefined,\n\tmap: Record<string, boolean | undefined> | null | undefined,\n): boolean {\n\tif (!link || !map) return false;\n\tif (link.remotePath && map[linkUnavailableKeyForPath(link.remotePath)]) return true;\n\tif (link.expiredHref && map[linkUnavailableKeyForHref(link.expiredHref)]) return true;\n\tif (link.href && map[linkUnavailableKeyForHref(link.href)]) return true;\n\treturn false;\n}\n\nexport function truncateLabelForDisplay(label: string): string {\n\tif (!label) return label;\n\tif (label.length <= LINK_LABEL_MAX_DISPLAY_CHARS) return label;\n\treturn '…' + label.slice(label.length - (LINK_LABEL_MAX_DISPLAY_CHARS - 1));\n}\n","/**\n * Token-budgeting (pure). Moved verbatim from the chatbox. Constants are shared\n * module-level values (identical in both consumers); a config knob is premature.\n * buildBoundedChatMessages now takes `projectId` in its options so it can pass it\n * to sanitizeAttachmentLinksForHistory (which used to read a global).\n */\nimport { sanitizeAttachmentLinksForHistory } from './links';\n\nexport var CONTEXT_WINDOW_DEFAULT: Record<string, number> = { claude: 200000, openai: 128000 };\n// Exact model ids first, then family keys (see getModelContextWindow: a suffixed\n// id falls back to its family rather than to the platform default). Claude\n// figures come from Anthropic's published model table; `max_input_tokens` from\n// /v1/models overrides all of this at runtime when a listing has been seen.\n// OpenAI's /v1/models carries NO context field at all, so every gpt entry here\n// is hand-maintained and is the only source for those models.\n// These are TOTAL windows (input + output), which is what the published tables\n// report and what getInputTokenBudget assumes when it subtracts the output\n// reserve. The two readings reconcile: gpt-5.6-luna is 1,050,000 total with a\n// 128,000 output cap, i.e. the ~922,000 of usable input quoted for it elsewhere.\nexport var CONTEXT_WINDOW_BY_MODEL: Record<string, number> = {\n\t// claude, exact ids\n\t'claude-fable-5': 1000000, 'claude-opus-5': 1000000,\n\t'claude-opus-4-8': 1000000, 'claude-opus-4-7': 1000000,\n\t'claude-opus-4-6': 1000000, 'claude-opus-4-5': 200000,\n\t'claude-sonnet-5': 1000000, 'claude-sonnet-4-6': 1000000,\n\t'claude-sonnet-4-5': 1000000, 'claude-sonnet-4': 200000,\n\t'claude-haiku-4-5': 200000, 'claude-3-5-sonnet': 200000,\n\t// openai, exact ids\n\t'gpt-5.6-sol': 1050000, 'gpt-5.6-terra': 1050000, 'gpt-5.6-luna': 1050000,\n\t'gpt-5.5': 1000000, 'gpt-5.4': 1050000,\n\t'gpt-5.4-mini': 400000, 'gpt-5.4-nano': 400000,\n\t'gpt-4.1': 1040000, 'gpt-4o': 128000, 'o1': 200000, 'o1-pro': 200000,\n\t// family keys\n\t'claude-fable': 1000000, 'claude-opus': 1000000, 'claude-sonnet': 1000000,\n\t'claude-haiku': 200000, 'gpt-5.6': 1050000, 'gpt-5': 128000,\n};\n// Two rows above are load-bearing rather than redundant, both because the family\n// walk drops trailing segments:\n// 'claude-opus-4-5' — a dated id like 'claude-opus-4-5-20251101' would\n// otherwise walk past it to the 'claude-opus' family and resolve 1000000 for\n// a model whose real window is 200000.\n// 'gpt-5.4-mini' and 'gpt-5.4-nano' — would otherwise walk to 'gpt-5.4' and\n// resolve 1050000 instead of their actual 400000. nano is the one that\n// matters most in practice: the indexing path selects it by name.\n// The bare 'gpt-5' family stays deliberately low: it is the catch-all for gpt-5\n// variants not listed here, and a mini-class variant is the likelier unknown.\n//\n// One asymmetry these rows expose: a total minus our output reserve can exceed a\n// model's separately-published INPUT ceiling (gpt-5.4-nano is 400000 total but\n// caps input at 272000, where 400000 - 25000 - 4000 reads as 371000). Harmless\n// today because INPUT_CAP_RATIO binds far below either figure (59360 for nano),\n// but it is why the ratio is not something to remove.\n\n// Provider hard ceilings on output tokens per request. Only used to clamp what\n// we ask for (see getMaxOutputTokens) — we never request more than\n// MAX_OUTPUT_TOKENS anyway, so this matters exactly where a model's cap is\n// BELOW that: gpt-4o at 4000 and legacy 3.5 Sonnet at 8000 would reject the\n// flat 25000 the request builder used to send unconditionally.\nexport var MAX_OUTPUT_BY_MODEL: Record<string, number> = {\n\t// claude\n\t'claude-fable-5': 128000, 'claude-opus-5': 128000,\n\t'claude-opus-4-8': 128000, 'claude-sonnet-5': 128000,\n\t'claude-sonnet-4-6': 64000, 'claude-haiku-4-5': 64000,\n\t'claude-3-5-sonnet': 8000,\n\t// openai\n\t'gpt-5.6-sol': 128000, 'gpt-5.6-terra': 128000, 'gpt-5.6-luna': 128000,\n\t'gpt-5.5': 128000, 'gpt-5.4': 128000,\n\t'gpt-5.4-mini': 128000, 'gpt-5.4-nano': 128000,\n\t'gpt-4.1': 16000, 'gpt-4o': 4000, 'o1': 100000, 'o1-pro': 100000,\n\t// family keys\n\t'claude-fable': 128000, 'claude-opus': 128000, 'claude-sonnet': 64000,\n\t'claude-haiku': 64000, 'gpt-5.6': 128000, 'gpt-5': 128000,\n};\n\n// The window a project runs at when nobody has touched the setting, clamped per\n// model by getContextWindow. Deliberately BELOW every frontier ceiling it can\n// resolve against (1,000,000 on the Claude 5 line, 1,050,000 on gpt-5.6) because\n// the client-side budget covers only the FIRST request: after that the model\n// runs a server-side tool loop whose web_fetch and MCP results accumulate in the\n// same conversation and are not counted here. The gap (120k and 170k\n// respectively) is that loop's room. It matters because no compaction beta is\n// enabled, so overrunning the real window is a hard error, not a graceful\n// degrade.\nexport var DEFAULT_CONTEXT_WINDOW = 880000;\n\n// Context windows reported by a provider's own models listing, keyed by model id.\n// Anthropic's GET /v1/models returns `max_input_tokens` per model, which is the\n// authoritative context window; OpenAI's listing carries no equivalent field, so\n// OpenAI models resolve from the table above. Populated by\n// registerModelContextWindows() when a client fetches its model list.\nvar apiReportedContextWindows: Record<string, number> = {};\nvar apiReportedMaxOutput: Record<string, number> = {};\n\n/**\n * Record context windows and output caps from a provider models listing. Reads\n * `max_input_tokens` and `max_tokens` (Anthropic); items without them are\n * skipped, so passing an OpenAI listing is a no-op rather than an error.\n *\n * Note the asymmetry against the static table: Anthropic reports\n * `max_input_tokens` (input only) where CONTEXT_WINDOW_BY_MODEL holds totals, so\n * a registered Claude window is treated as a total and loses its output cap\n * worth of budget. That is deliberate — under-spending the window is safe, and\n * with no compaction beta enabled overrunning it is a hard error.\n */\nexport function registerModelContextWindows(\n\tmodels: Array<{ id?: string; max_input_tokens?: number; max_tokens?: number }> | null | undefined,\n): void {\n\tif (!Array.isArray(models)) return;\n\tfor (var i = 0; i < models.length; i++) {\n\t\tvar m = models[i];\n\t\tvar id = (m && m.id ? String(m.id) : '').trim().toLowerCase();\n\t\tif (!id) continue;\n\t\tvar reported = m ? Number(m.max_input_tokens) : NaN;\n\t\tif (Number.isFinite(reported) && reported > 0) {\n\t\t\tapiReportedContextWindows[id] = Math.floor(reported);\n\t\t}\n\t\tvar out = m ? Number(m.max_tokens) : NaN;\n\t\tif (Number.isFinite(out) && out > 0) {\n\t\t\tapiReportedMaxOutput[id] = Math.floor(out);\n\t\t}\n\t}\n}\n\n/** Per-project override, keyed by service id. Set from the project settings. */\nvar projectContextWindows: Record<string, number> = {};\n\nexport function setProjectContextWindow(projectId: string, tokens: number | null | undefined): void {\n\tvar key = (projectId || '').trim();\n\tif (!key) return;\n\tvar n = Number(tokens);\n\tif (Number.isFinite(n) && n > 0) projectContextWindows[key] = Math.floor(n);\n\telse delete projectContextWindows[key];\n}\n\nexport function getProjectContextWindow(projectId: string): number | null {\n\tvar key = (projectId || '').trim();\n\treturn key && projectContextWindows[key] ? projectContextWindows[key] : null;\n}\n// `max_tokens` sent on every chat request. Exported so the reserve below and the\n// actual request cannot drift: they were 22000 and 25000 respectively, which\n// under-reserved by 3k on a window spent to the last token.\nexport var MAX_OUTPUT_TOKENS = 25000;\nexport var OUTPUT_TOKEN_RESERVE = MAX_OUTPUT_TOKENS;\nexport var TOOL_AND_RESPONSE_BUFFER = 4000;\nexport var MIN_INPUT_TOKEN_BUDGET = 8000;\n// Floor under INPUT_CAP_RATIO. Anthropic's default tier enforces 30,000 input\n// tokens per MINUTE on Opus, which is where the number comes from; it is applied\n// on OpenAI too so a small-window model keeps a usable attachment budget instead\n// of collapsing to the ratio.\nexport var MIN_PER_REQUEST_INPUT_CAP = 28000;\n/** @deprecated renamed to {@link MIN_PER_REQUEST_INPUT_CAP} (no longer Claude-only). */\nexport var CLAUDE_PER_REQUEST_INPUT_CAP = MIN_PER_REQUEST_INPUT_CAP;\nexport var MAX_HISTORY_MESSAGES = 20;\nexport var HISTORY_TOKEN_BUDGET = 8000;\n// Ratios that scale the two ceilings above off the resolved context window.\n// Originally calibrated to reproduce the previous fixed values at the old\n// default windows (claude 200000 -> cap 27840, openai 128000 -> history 8160).\n// Both are floored at the old constants, so they can only ever raise a budget,\n// never lower one, which is what keeps a small-window model (claude-opus-4-5 at\n// 200000) behaving as it always did.\n//\n// INPUT_CAP_RATIO now applies to BOTH platforms. It was Claude-only because it\n// encoded a Claude rate limit, but at a 880000 default it does a second job that\n// matters just as much on OpenAI: it is the headroom. Uncapped, gpt-5.6-luna\n// resolved an input budget of 851000 against a 922000 ceiling, leaving 71000 for\n// the whole server-side tool loop, and ONE web_fetch result can be 200000.\nexport var INPUT_CAP_RATIO = 0.16;\n/** @deprecated renamed to {@link INPUT_CAP_RATIO} (no longer Claude-only). */\nexport var CLAUDE_INPUT_CAP_RATIO = INPUT_CAP_RATIO;\nexport var HISTORY_BUDGET_RATIO = 0.08;\n\nexport function estimateTextTokens(text: string): number {\n\treturn Math.ceil((text || '').length / 3);\n}\n\nexport function estimateMessageTokens(msg: { role: string; content: string }): number {\n\treturn estimateTextTokens(msg.content) + estimateTextTokens(msg.role) + 6;\n}\n\n/**\n * The model's own HARD ceiling: the largest window it can be asked for at all.\n * Resolved most specific source first:\n * 1. the provider's own models listing (Anthropic `max_input_tokens`)\n * 2. an exact entry in CONTEXT_WINDOW_BY_MODEL\n * 3. a family entry, by dropping trailing '-' segments off the id\n * 4. the platform default\n *\n * Step 3 is why a new or suffixed id no longer drops straight to the platform\n * default: 'gpt-5.6-luna' resolves via 'gpt-5.6', and a dated Claude snapshot\n * such as 'claude-opus-4-7-20260101' resolves via 'claude-opus-4-7'. The walk\n * stops at the first hit, so a more specific entry always wins over its family.\n *\n * This is what the settings UI offers presets against; it is NOT what a request\n * is budgeted at. For that see getContextWindow.\n */\n/**\n * Shared id resolution for both per-model tables: provider listing, then exact\n * table entry, then family entries by dropping trailing '-' segments. Returns 0\n * when nothing matches so callers can apply their own default.\n */\nfunction resolveByModelId(\n\tapiTable: Record<string, number>,\n\tstaticTable: Record<string, number>,\n\tmodel?: string,\n): number {\n\tvar normalized = (model || '').trim().toLowerCase();\n\tif (!normalized) return 0;\n\tif (apiTable[normalized]) return apiTable[normalized];\n\tif (staticTable[normalized]) return staticTable[normalized];\n\tvar parts = normalized.split('-');\n\tfor (var end = parts.length - 1; end > 0; end--) {\n\t\tvar family = parts.slice(0, end).join('-');\n\t\tif (staticTable[family]) return staticTable[family];\n\t}\n\treturn 0;\n}\n\nexport function getModelContextWindow(platform: string, model?: string): number {\n\treturn resolveByModelId(apiReportedContextWindows, CONTEXT_WINDOW_BY_MODEL, model)\n\t\t|| CONTEXT_WINDOW_DEFAULT[platform];\n}\n\n/**\n * How many output tokens to ask for. We never want more than MAX_OUTPUT_TOKENS,\n * but a model whose own cap is lower rejects the request outright, so clamp to\n * whichever is smaller. Models with no known cap keep MAX_OUTPUT_TOKENS.\n */\nexport function getMaxOutputTokens(platform: string, model?: string): number {\n\tvar cap = resolveByModelId(apiReportedMaxOutput, MAX_OUTPUT_BY_MODEL, model);\n\treturn cap ? Math.min(MAX_OUTPUT_TOKENS, cap) : MAX_OUTPUT_TOKENS;\n}\n\n/**\n * The window a request is actually budgeted at: the per-project override when\n * one is set, otherwise DEFAULT_CONTEXT_WINDOW. Both are clamped to the model's\n * hard ceiling, because a budget above the ceiling builds a request the provider\n * rejects, and a stored override outlives the model it was chosen under.\n */\nexport function getContextWindow(platform: string, model?: string, projectId?: string): number {\n\tvar ceiling = getModelContextWindow(platform, model);\n\tvar override = projectId ? getProjectContextWindow(projectId) : null;\n\treturn Math.min(override || DEFAULT_CONTEXT_WINDOW, ceiling);\n}\n\n/**\n * Per-request input-token budget, i.e. how much of the resolved window this turn\n * may spend on system prompt + history + the latest message. The single\n * implementation behind both buildBoundedChatMessages and the composer's\n * pre-send guard, which used to be separate copies that disagreed.\n */\n/**\n * The share of the resolved window left after reserving what this request may\n * emit. The reserve is per-model rather than the flat OUTPUT_TOKEN_RESERVE\n * because getMaxOutputTokens clamps small-cap models below it.\n */\nfunction contextBasedBudgetFor(platform: string, model?: string, projectId?: string): number {\n\tvar contextWindow = getContextWindow(platform, model, projectId);\n\treturn Math.max(MIN_INPUT_TOKEN_BUDGET,\n\t\tcontextWindow - getMaxOutputTokens(platform, model) - TOOL_AND_RESPONSE_BUFFER);\n}\n\nexport function getInputTokenBudget(platform: string, model?: string, projectId?: string): number {\n\tvar contextBasedBudget = contextBasedBudgetFor(platform, model, projectId);\n\treturn Math.min(contextBasedBudget,\n\t\tMath.max(MIN_PER_REQUEST_INPUT_CAP, Math.round(contextBasedBudget * INPUT_CAP_RATIO)));\n}\n\nexport function stripFileBlocksFromHistory(content: string): string {\n\tif (!content) return content;\n\treturn content.replace(/```([^\\n`]+?\\.[^\\s.`]+)\\n[\\s\\S]*?```/g, '[file previously attached: $1]');\n}\n\nexport type BoundedChatOptions = {\n\tplatform: string;\n\tmodel?: string;\n\tsystemPrompt: string;\n\thistory: Array<{ role: string; content: string }>;\n\t/** Used to strip/rewrite expired attachment links in older user turns. */\n\tprojectId: string;\n};\n\nexport function buildBoundedChatMessages(options: BoundedChatOptions) {\n\tvar contextBasedBudget = contextBasedBudgetFor(options.platform, options.model, options.projectId);\n\t// Scaling used to be gated on an EXPLICIT per-project override so that a\n\t// project nobody had configured kept the old fixed ceilings. That gate is\n\t// gone now that DEFAULT_CONTEXT_WINDOW is itself the default: leaving it in\n\t// would mean an unconfigured project resolved 880000 and then spent 28000 of\n\t// it, making the new default purely cosmetic, and would keep the trap where\n\t// \"Default (880K)\" and an explicit 880K behaved differently.\n\t// Both ceilings derive from contextBasedBudget (pre-Claude-cap) so the two\n\t// platforms scale symmetrically rather than the Claude cap compounding down.\n\tvar availableInputBudget = getInputTokenBudget(options.platform, options.model, options.projectId);\n\tvar systemCost = estimateTextTokens(options.systemPrompt) + 12;\n\tvar historyAllowance = Math.max(HISTORY_TOKEN_BUDGET,\n\t\tMath.round(contextBasedBudget * HISTORY_BUDGET_RATIO));\n\tvar budgetForHistory = Math.max(1000, Math.min(historyAllowance, availableInputBudget - systemCost));\n\t// The message count scales alongside the token budget; otherwise 20 messages\n\t// is a second ceiling that swallows the extra budget on a raised window.\n\tvar maxHistoryMessages = Math.max(MAX_HISTORY_MESSAGES,\n\t\tMath.round(MAX_HISTORY_MESSAGES * (budgetForHistory / HISTORY_TOKEN_BUDGET)));\n\tvar windowed = options.history.slice(-maxHistoryMessages);\n\tvar latestIndex = windowed.length - 1;\n\tvar trimmed = windowed.map(function (m, i) {\n\t\tif (i === latestIndex) return m;\n\t\tvar stripped = stripFileBlocksFromHistory(m.content);\n\t\t// Sanitize BOTH roles: user turns via the \"Attached files:\" block, assistant\n\t\t// turns via the safe db-only path (forAssistant=true) so a volatile db url the\n\t\t// model emitted doesn't get replayed into the LLM context as a dead link.\n\t\tvar sanitized = sanitizeAttachmentLinksForHistory(stripped, options.projectId, m.role !== 'user');\n\t\treturn Object.assign({}, m, { content: sanitized });\n\t});\n\tvar bounded: Array<{ role: string; content: string }> = [], used = 0;\n\tfor (var i = trimmed.length - 1; i >= 0; i--) {\n\t\tvar cost = estimateMessageTokens(trimmed[i]);\n\t\tif (used + cost > budgetForHistory && bounded.length > 0) break;\n\t\tbounded.unshift(trimmed[i]); used += cost;\n\t}\n\treturn {\n\t\tmessages: bounded.map(function (m) { return { role: m.role, content: m.content }; }),\n\t\tdroppedCount: Math.max(0, options.history.length - bounded.length),\n\t\testimatedInputTokens: used + systemCost,\n\t\testimatedBudget: availableInputBudget,\n\t};\n}\n","/**\n * How a text file the chat offers as a download is encoded and labelled, so that\n * whatever opens it reads the characters correctly, in any language.\n *\n * When the model answers with a fenced ```name.ext block, the client turns that\n * block into a Blob and an <a download>. We always write UTF-8, but several very\n * common consumers do not assume UTF-8 when nothing in the file says so, and fall\n * back to the reader's local ANSI codepage: CP949 in Korea, CP932 in Japan,\n * CP936/CP950 in China and Taiwan, CP1251 for Cyrillic. The file is valid and\n * every non-ASCII character still opens as mojibake.\n *\n * There is no single fix, because the way a file declares \"this is UTF-8\" is a\n * property of the FORMAT:\n *\n * - a spreadsheet (csv/tsv) and a Windows text editor read a BOM;\n * - HTML is opened from disk with no HTTP headers, so only an in-document\n * <meta charset> survives;\n * - XML carries its encoding in its declaration, and a WRONG declaration makes\n * a conforming parser fail outright;\n * - RTF is 7-bit, so non-ASCII has to be escaped into \\uNNNN?;\n * - JSON, JSONL and YAML are UTF-8 by specification, and a BOM BREAKS them.\n *\n * Anything unrecognised is left byte-for-byte alone: an unknown extension is far\n * more likely to be machine-parsed, where an uninvited BOM is a new bug, than to\n * be opened by a legacy editor.\n *\n * MIRROR of skapi-mcp/download-encoding.js, which does the same job for files the\n * server publishes (writeReport / exportRecordsToFile). A file the user gets from\n * a fenced block and the same file published as a download must behave\n * identically, so the two have to change together.\n */\n\nexport const BOM = '';\n\n/** Files a spreadsheet or a Windows text editor opens directly. */\nexport const BOM_EXTS = new Set(['csv', 'tsv', 'tab', 'txt', 'text', 'log']);\n\n/** Read from disk with no HTTP headers, so the declaration must be in the file. */\nexport const HTML_EXTS = new Set(['html', 'htm', 'xhtml']);\nexport const XML_EXTS = new Set(['xml', 'svg', 'rss', 'atom', 'xsl', 'xslt', 'plist', 'kml']);\nexport const RTF_EXTS = new Set(['rtf']);\n\n/** Content types by extension. Every text family carries an explicit charset. */\nexport const EXT_CONTENT_TYPES: Record<string, string> = {\n\tcsv: 'text/csv; charset=utf-8',\n\ttsv: 'text/tab-separated-values; charset=utf-8',\n\ttab: 'text/tab-separated-values; charset=utf-8',\n\ttxt: 'text/plain; charset=utf-8',\n\ttext: 'text/plain; charset=utf-8',\n\tlog: 'text/plain; charset=utf-8',\n\tmd: 'text/markdown; charset=utf-8',\n\tmarkdown: 'text/markdown; charset=utf-8',\n\tjson: 'application/json; charset=utf-8',\n\tjsonl: 'application/x-ndjson; charset=utf-8',\n\tndjson: 'application/x-ndjson; charset=utf-8',\n\tgeojson: 'application/geo+json; charset=utf-8',\n\tyaml: 'text/yaml; charset=utf-8',\n\tyml: 'text/yaml; charset=utf-8',\n\ttoml: 'text/plain; charset=utf-8',\n\tini: 'text/plain; charset=utf-8',\n\tsql: 'text/plain; charset=utf-8',\n\thtml: 'text/html; charset=utf-8',\n\thtm: 'text/html; charset=utf-8',\n\txhtml: 'application/xhtml+xml; charset=utf-8',\n\txml: 'application/xml; charset=utf-8',\n\tsvg: 'image/svg+xml; charset=utf-8',\n\tcss: 'text/css; charset=utf-8',\n\tjs: 'text/javascript; charset=utf-8',\n\tts: 'text/plain; charset=utf-8',\n\tpy: 'text/x-python; charset=utf-8',\n\tsh: 'text/x-shellscript; charset=utf-8',\n\tsrt: 'application/x-subrip; charset=utf-8',\n\tvtt: 'text/vtt; charset=utf-8',\n\tics: 'text/calendar; charset=utf-8',\n\tvcf: 'text/vcard; charset=utf-8',\n\t// RTF is 7-bit ASCII by specification, so it takes no charset parameter.\n\trtf: 'application/rtf',\n\t// Binary types the model can only ever REFERENCE, never author in a fence, but\n\t// which keep the type sensible if one ever shows up.\n\tpdf: 'application/pdf',\n\tpng: 'image/png',\n\tjpg: 'image/jpeg',\n\tjpeg: 'image/jpeg',\n\tgif: 'image/gif',\n\twebp: 'image/webp',\n};\n\nexport type EncodingClass = 'bom' | 'html' | 'xml' | 'rtf' | 'none';\n\nexport function normalizeExt(ext: string | null | undefined): string {\n\treturn String(ext || '').trim().replace(/^\\./, '').toLowerCase();\n}\n\n/** Extension of a filename, '' when it has none. */\nexport function extOf(filename: string | null | undefined): string {\n\tconst name = String(filename || '');\n\tconst dot = name.lastIndexOf('.');\n\treturn dot > 0 ? normalizeExt(name.slice(dot + 1)) : '';\n}\n\n/** Which encoding declaration this format understands. */\nexport function encodingClassForExt(ext: string | null | undefined): EncodingClass {\n\tconst e = normalizeExt(ext);\n\tif (BOM_EXTS.has(e)) return 'bom';\n\tif (HTML_EXTS.has(e)) return 'html';\n\tif (XML_EXTS.has(e)) return 'xml';\n\tif (RTF_EXTS.has(e)) return 'rtf';\n\treturn 'none';\n}\n\n/** True when a file with this extension must be written BOM-first. */\nexport function needsBomForExt(ext: string | null | undefined): boolean {\n\treturn encodingClassForExt(ext) === 'bom';\n}\n\n/**\n * Content type to declare. Everything textual carries an explicit charset:\n * without one the receiving end guesses, and it guesses the local codepage.\n */\nexport function contentTypeForExt(\n\text: string | null | undefined,\n\tfallback = 'text/plain; charset=utf-8',\n): string {\n\treturn EXT_CONTENT_TYPES[normalizeExt(ext)] || fallback;\n}\n\nexport function hasBom(text: string): boolean {\n\treturn typeof text === 'string' && text.charCodeAt(0) === 0xfeff;\n}\n\n// --- HTML -------------------------------------------------------------------\n// Only the document head is inspected. A charset written further down is not one\n// a browser would act on anyway (the spec only honours a declaration in the first\n// 1024 bytes), and scanning the whole body would start matching <meta> tags that\n// a document about HTML is merely quoting.\nexport const HTML_HEAD_WINDOW = 4096;\nconst META_CHARSET_RE = /<meta[^>]+charset\\s*=\\s*[\"']?\\s*([a-z0-9_-]+)/i;\nconst META_HTTP_EQUIV_RE = /<meta[^>]+http-equiv\\s*=\\s*[\"']?content-type[\"']?[^>]*>/i;\n\n/**\n * Make an HTML document state its own encoding. Downloaded HTML is opened from\n * disk, where the Content-Type we set no longer exists, so a document with no\n * <meta charset> is decoded with the browser's locale default.\n */\nexport function ensureHtmlCharset(text: string): string {\n\tconst src = String(text == null ? '' : text);\n\tconst head = src.slice(0, HTML_HEAD_WINDOW);\n\n\tconst declared = META_CHARSET_RE.exec(head);\n\tif (declared) {\n\t\t// A declaration naming anything other than UTF-8 is actively wrong: the\n\t\t// bytes underneath it are always UTF-8. Correct it in place rather than\n\t\t// adding a second, contradictory one.\n\t\tif (declared[1].toLowerCase().replace(/[^a-z0-9]/g, '') === 'utf8') return src;\n\t\tconst start = declared.index + declared[0].length - declared[1].length;\n\t\treturn src.slice(0, start) + 'utf-8' + src.slice(start + declared[1].length);\n\t}\n\t// An http-equiv Content-Type with no charset= is still a declaration the\n\t// browser will use; replace the whole tag with the modern short form.\n\tconst httpEquiv = META_HTTP_EQUIV_RE.exec(head);\n\tif (httpEquiv) {\n\t\treturn src.slice(0, httpEquiv.index)\n\t\t\t+ '<meta charset=\"utf-8\">'\n\t\t\t+ src.slice(httpEquiv.index + httpEquiv[0].length);\n\t}\n\n\tconst tag = '<meta charset=\"utf-8\">';\n\t// As early as the document allows: inside <head> if there is one, else right\n\t// after <html>, else at the very top (a fragment is still parsed head-first).\n\tconst headOpen = /<head[^>]*>/i.exec(head);\n\tif (headOpen) {\n\t\tconst at = headOpen.index + headOpen[0].length;\n\t\treturn src.slice(0, at) + '\\n' + tag + src.slice(at);\n\t}\n\tconst htmlOpen = /<html[^>]*>/i.exec(head);\n\tif (htmlOpen) {\n\t\tconst at = htmlOpen.index + htmlOpen[0].length;\n\t\treturn src.slice(0, at) + '\\n<head>' + tag + '</head>' + src.slice(at);\n\t}\n\tconst doctype = /<!doctype[^>]*>/i.exec(head);\n\tif (doctype) {\n\t\tconst at = doctype.index + doctype[0].length;\n\t\treturn src.slice(0, at) + '\\n' + tag + src.slice(at);\n\t}\n\treturn tag + '\\n' + src;\n}\n\n// --- XML ---------------------------------------------------------------------\nconst XML_DECL_RE = /^\\s*<\\?xml\\s[^?]*\\?>/i;\n\n/**\n * Correct an XML declaration that names the wrong encoding.\n *\n * A MISSING declaration is left alone on purpose: XML with none is UTF-8 by\n * specification, so every conforming parser already gets it right. A declaration\n * naming EUC-KR over UTF-8 bytes, on the other hand, makes a parser fail outright.\n */\nexport function ensureXmlEncoding(text: string): string {\n\tconst src = String(text == null ? '' : text);\n\tconst decl = XML_DECL_RE.exec(src);\n\tif (!decl) return src;\n\n\tconst found = /encoding\\s*=\\s*[\"']([^\"']*)[\"']/i.exec(decl[0]);\n\tif (!found) return src; // declaration without an encoding is UTF-8 by spec\n\tif (found[1].toLowerCase().replace(/[^a-z0-9]/g, '') === 'utf8') return src;\n\n\tconst fixedDecl = decl[0].slice(0, found.index)\n\t\t+ found[0].replace(found[1], 'UTF-8')\n\t\t+ decl[0].slice(found.index + found[0].length);\n\treturn fixedDecl + src.slice(decl[0].length);\n}\n\n// --- RTF ----------------------------------------------------------------------\nconst RTF_SIGNATURE_RE = /^[\\s]*\\{\\\\rtf/i;\n\n/** True when the body really is RTF rather than text merely named .rtf. */\nexport function looksLikeRtf(text: string): boolean {\n\treturn RTF_SIGNATURE_RE.test(String(text == null ? '' : text));\n}\n\n/**\n * Escape every non-ASCII character into RTF's \\uNNNN? form.\n *\n * RTF is 7-bit: a literal UTF-8 byte in the body is read through the codepage the\n * header declares, which is how Korean, Japanese and Cyrillic RTF turns to\n * mojibake in Word. \\uNNNN? is codepage-independent.\n *\n * ASCII is never touched, which matters: backslashes and braces in an RTF body\n * are control syntax, and \"escaping\" them would destroy the document. \\u takes a\n * SIGNED 16-bit value, so anything above 0x7FFF is emitted negative, and astral\n * characters are emitted as their two surrogates.\n */\nexport function escapeRtfNonAscii(text: string): string {\n\tconst src = String(text == null ? '' : text);\n\tlet out = '';\n\tlet plainFrom = 0;\n\tfor (let i = 0; i < src.length; i++) {\n\t\tconst code = src.charCodeAt(i); // UTF-16 unit: surrogates arrive separately\n\t\tif (code < 0x80) continue;\n\t\tout += src.slice(plainFrom, i);\n\t\tout += `\\\\u${code > 32767 ? code - 65536 : code}?`;\n\t\tplainFrom = i + 1;\n\t}\n\treturn plainFrom === 0 ? src : out + src.slice(plainFrom);\n}\n\n/** Apply the format's encoding declaration to a whole document. */\nexport function applyEncodingDeclaration(text: string, ext: string | null | undefined): string {\n\tconst src = String(text == null ? '' : text);\n\tswitch (encodingClassForExt(ext)) {\n\t\tcase 'bom':\n\t\t\t// Never a second BOM: two U+FEFF show as a visible in the first cell.\n\t\t\treturn hasBom(src) ? src : BOM + src;\n\t\tcase 'html':\n\t\t\treturn ensureHtmlCharset(src);\n\t\tcase 'xml':\n\t\t\treturn ensureXmlEncoding(src);\n\t\tcase 'rtf':\n\t\t\t// Text merely NAMED .rtf is opened by Word as plain text, where a BOM is\n\t\t\t// what makes it read UTF-8. Escaping it would show literal \\u escapes.\n\t\t\treturn looksLikeRtf(src) ? escapeRtfNonAscii(src) : (hasBom(src) ? src : BOM + src);\n\t\tdefault:\n\t\t\treturn src;\n\t}\n}\n\n/**\n * Everything a client needs to turn a fenced ```name.ext block into a download:\n * the exact text to put in the Blob and the type to give it.\n */\nexport function prepareDownloadText(\n\tfilename: string,\n\tbody: string,\n): { ext: string; text: string; contentType: string } {\n\tconst ext = extOf(filename);\n\treturn {\n\t\text,\n\t\ttext: applyEncodingDeclaration(body, ext),\n\t\tcontentType: contentTypeForExt(ext),\n\t};\n}\n","/**\n * The chip / preview markup for one classified inline link.\n *\n * `classifyInlineLink` was consolidated into the engine because deciding what a\n * link IS had drifted between the two clients and every link bug had to be found\n * and fixed twice. The EMITTER stayed forked, byte for byte identical in\n * agent.vue and the widget. The image preview is the first behaviour that would\n * have had to be written twice, so the emitter moves here too.\n *\n * Pure string in, pure string out: no DOM, no globals, nothing reactive. That is\n * what lets agent.vue keep memoizing parseMsgParts on the message text alone.\n */\n\n/** Neither client sanitizes bubble HTML (no DOMPurify, no marked sanitize), so\n * everything interpolated here is escaped at the point of interpolation. */\nexport function escapeInlineHtml(v: string | null | undefined): string {\n\treturn String(v == null ? '' : v).replace(/[&<>\"']/g, function (ch) {\n\t\treturn ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' } as Record<string, string>)[ch];\n\t});\n}\n\n/**\n * Previews per MESSAGE. Each one costs a presign call and an image download the\n * moment it is hydrated, and a reply listing a folder can name dozens. Past this\n * many the link renders as the ordinary text chip.\n */\nexport var IMAGE_PREVIEWS_PER_MESSAGE = 8;\n\n/**\n * The glyph IS the promise: ↗ says \"click this and the file opens\". When the\n * client could not get a url for the file, keeping that glyph on a chip it knows\n * is dead is the bug: the click either opens a tab on a 403/404 or, once the\n * href is gone, does nothing at all with no explanation. ✕ says what happened.\n */\nexport var INLINE_LINK_GLYPH = '↗';\nexport var INLINE_LINK_UNAVAILABLE_GLYPH = '✕';\nexport var INLINE_LINK_UNAVAILABLE_SUFFIX = ' (unavailable)';\n\n/** Widened so each client's local link-part type is assignable. */\nexport interface RenderableInlineLink {\n\tlabel: string;\n\tfullLabel?: string;\n\thref: string;\n\texpired: boolean;\n\texpiredHref?: string;\n\tremotePath?: string;\n\timage?: { ext: string; contentType: string };\n}\n\nexport interface InlineLinkMarkupOptions {\n\t/** The view's own \"a mint is in flight for this href\" flag. */\n\trefreshing?: boolean;\n\t/** False once the caller has spent its per-message preview budget. */\n\tallowImagePreview?: boolean;\n\t/**\n\t * The view already tried to get a url for this file and failed (see\n\t * isLinkUnavailable). Renders a dead chip: ✕, greyed, no href.\n\t */\n\tunavailable?: boolean;\n}\n\nexport function renderInlineLinkHtml(link: RenderableInlineLink, opts?: InlineLinkMarkupOptions): string {\n\tvar o = opts || {};\n\tvar unavailable = !!o.unavailable;\n\t// A dead chip is never also \"fetching...\": the mint that would have cleared\n\t// that state is the one that failed.\n\tvar refreshing = !unavailable && !!o.refreshing;\n\tvar full = link.fullLabel || link.label;\n\t// No preview either. The <img> hides itself when its url fails, but a\n\t// re-render emits a FRESH element with no state, so leaving the preview in\n\t// would re-mint and re-fail once per render for the rest of the session.\n\tvar preview = !!link.image && !!link.remotePath && o.allowImagePreview !== false && !unavailable;\n\n\tvar cls = ['bq-link-button'];\n\tif (link.expired) cls.push('is-expired');\n\tif (refreshing) cls.push('is-refreshing');\n\tif (unavailable) cls.push('is-unavailable');\n\tif (preview) cls.push('is-image-preview');\n\n\tvar labelText = (unavailable ? INLINE_LINK_UNAVAILABLE_GLYPH : INLINE_LINK_GLYPH) + ' ' + link.label\n\t\t+ (unavailable ? INLINE_LINK_UNAVAILABLE_SUFFIX : refreshing ? ' (fetching...)' : '');\n\tvar attrs = ['class=\"' + cls.join(' ') + '\"'];\n\t// NO href when the file is unavailable. That is what disables the click:\n\t// an anchor with no href does not navigate, is not a tab stop and takes the\n\t// default cursor, so nothing else has to remember to swallow the event.\n\tif (unavailable) attrs.push('aria-disabled=\"true\"', 'data-bq-unavailable=\"1\"');\n\telse attrs.push('href=\"' + escapeInlineHtml(link.href) + '\"', 'target=\"_blank\"', 'rel=\"noopener noreferrer\"');\n\tattrs.push('title=\"' + escapeInlineHtml(unavailable ? full + INLINE_LINK_UNAVAILABLE_SUFFIX : full) + '\"');\n\t// `download` is ignored cross-origin and forces a save same-origin. On a\n\t// preview it states the wrong intent: the user clicked a picture to LOOK at\n\t// it. Every other chip keeps the attribute exactly where it was.\n\tif (!preview && !unavailable) attrs.push('download=\"' + escapeInlineHtml(full) + '\"');\n\tattrs.push('data-bq-link=\"1\"');\n\t// Deliberately NOT marked expired: `data-bq-expired` is what tells the\n\t// delegated click handler to mint a fresh url, and this is the chip whose\n\t// mint just failed.\n\tif (link.expired && !unavailable) attrs.push('data-bq-expired=\"1\"');\n\tif (link.expiredHref) attrs.push('data-bq-expired-href=\"' + escapeInlineHtml(link.expiredHref) + '\"');\n\tif (link.remotePath) attrs.push('data-bq-remote-path=\"' + escapeInlineHtml(link.remotePath) + '\"');\n\tif (link.fullLabel) attrs.push('data-bq-full-label=\"' + escapeInlineHtml(link.fullLabel) + '\"');\n\n\tif (!preview) return '<a ' + attrs.join(' ') + '>' + escapeInlineHtml(labelText) + '</a>';\n\n\t// NO src attribute. A stored file always classifies as the _expired_.url\n\t// placeholder until something mints a real url, so a src written here would be\n\t// a guaranteed broken image on every reload. The element carries the PATH and\n\t// hydrateImagePreviews fills the src in a DOM pass that runs after render.\n\t//\n\t// The caption is not decoration, it is the FALLBACK: if the url dies or the\n\t// file is gone the <img> hides itself and what is left is exactly the text\n\t// chip this feature replaced, still clickable.\n\treturn '<a ' + attrs.join(' ') + '>' +\n\t\t'<img class=\"bq-img-preview\" alt=\"' + escapeInlineHtml(full) + '\"' +\n\t\t' data-bq-img-path=\"' + escapeInlineHtml(link.remotePath || '') + '\"' +\n\t\t' data-bq-img-type=\"' + escapeInlineHtml(link.image ? link.image.contentType : '') + '\"' +\n\t\t// decoding=\"async\" but NOT loading=\"lazy\". Lazy guarantees the bytes arrive\n\t\t// exactly when the image is near the viewport, which is the one case the\n\t\t// scroll anchor deliberately declines to compensate for (growth at or below\n\t\t// the fold happened on screen, under a line the reader is looking at) — so it\n\t\t// shoved up to 320px of text under their eyes on every scroll toward it. It\n\t\t// saved no mint either: hydration mints for every preview in the DOM\n\t\t// regardless of viewport. It was also what turned the widget's per-notify\n\t\t// teardown into a 13x amplifier (6224px vs 450px measured).\n\t\t' decoding=\"async\">' +\n\t\t// Minting the url is a network round trip before the image even starts\n\t\t// downloading, so the wait is real and needs a state. Inline load, so the\n\t\t// dot trail, never the jumping bunny. CSS hides it the moment the <img>\n\t\t// gains a src, so no JS removes DOM and nothing re-parses.\n\t\t'<span class=\"bq-loader\" data-bq-img-loader=\"1\"></span>' +\n\t\t'<span class=\"bq-img-preview-caption\" translate=\"no\">' + escapeInlineHtml(labelText) + '</span>' +\n\t\t'</a>';\n}\n","import { LINK_REFRESH_WINDOW_MS, PRESIGN_SAFETY_MARGIN_MS, presignExpiryEpochMs } from './links';\n\n/**\n * Give a rendered preview <img> a real src.\n *\n * Why this is not part of the parse: every stored file classifies as\n * `expired: true` with the _expired_.url placeholder as its href, so the url an\n * <img> needs does not exist until something mints it. agent.vue memoizes its\n * parse on the raw message text and drops that cache whenever its link maps\n * change, so minting THROUGH those maps would clear the whole cache once per\n * image and re-run marked over the entire conversation each time. The mint\n * therefore lives here, in a cache that is not reactive and is never read by the\n * parse, and the src is written straight onto the element after render.\n *\n * DOM-free like the rest of the engine: the element type is structural, so a\n * real HTMLImageElement satisfies it while this file imports nothing from\n * lib.dom and touches no global.\n */\n\nexport interface PreviewImageEl {\n\tgetAttribute(name: string): string | null;\n\tsetAttribute(name: string, value: string): void;\n\tremoveAttribute(name: string): void;\n\taddEventListener(type: string, cb: () => void): void;\n}\n\n\nexport interface ImagePreviewContext {\n\t/** Project id. Namespaces the cache, see clearImagePreviewCache. */\n\tscope: string;\n\t/**\n\t * Mint a directly loadable url for a storage path.\n\t *\n\t * `contentType` is not advisory. get_signed_url only sets\n\t * ResponseContentType when the caller passes one and otherwise falls back to\n\t * application/octet-stream, which a new tab DOWNLOADS instead of displaying.\n\t * An implementation that drops this argument still paints the preview (an\n\t * <img> sniffs the bytes) but silently breaks the click.\n\t *\n\t * `refresh` asks for a url the browser cache cannot answer. The mint request\n\t * itself is cacheable (that is what stops a reload re-downloading every\n\t * image), so a plain re-mint can hand back the very url that just failed;\n\t * refresh is how the caller escapes its own cache.\n\t */\n\tmint: (remotePath: string, contentType: string, refresh?: boolean) => Promise<string>;\n\t/** An image finished painting. Views use it to re-pin the scroll. */\n\tonLoad?: (remotePath: string) => void;\n\t/** A preview gave up. The caption chip is now the whole answer. */\n\tonError?: (remotePath: string, err: unknown) => void;\n\t/**\n\t * This element's box just changed size, and nothing asked it to.\n\t *\n\t * Fires at the points where a preview resizes with NO DOM event of its own to\n\t * announce it: the src lands (a src-less <img> is hidden, so this is where it\n\t * starts taking space), and the src is dropped for a retry, or a mint fails\n\t * outright, where an already-painted picture collapses back to nothing.\n\t * `load` and `error` are deliberately NOT routed through here — both views\n\t * listen for those on the message box itself, which is also how they cover the\n\t * images this module never sees, a markdown `![alt](url)` among them.\n\t *\n\t * Each of these slides everything below the element, and for a reader scrolled\n\t * up into history that is a jump in the middle of a sentence. onLoad cannot\n\t * stand in for it: both views answer that with a scroll-to-bottom-if-pinned,\n\t * which by definition does nothing for the reader this hurts.\n\t *\n\t * Views wire this to their scroll anchor's absorb(). Called SYNCHRONOUSLY, so\n\t * the measurement it takes is the one the reader is looking at.\n\t */\n\tonLayoutChange?: (img: PreviewImageEl, remotePath: string) => void;\n}\n\ninterface MintedPreview { url: string; at: number; }\n\nvar previewUrlCache: Record<string, MintedPreview> = Object.create(null);\nvar previewInFlight: Record<string, Promise<string>> = Object.create(null);\n\nfunction cacheKey(scope: string, path: string): string { return scope + '\u0000' + path; }\n\n/**\n * Drop cached preview urls, for one project or all of them.\n *\n * The key carries the project because an identity-blind cache is how one\n * project's content has reached another project's chat before. Call on project\n * switch and on sign-out.\n */\nexport function clearImagePreviewCache(scope?: string): void {\n\tif (!scope) {\n\t\tpreviewUrlCache = Object.create(null);\n\t\tpreviewInFlight = Object.create(null);\n\t\tstaleImagePreviews = Object.create(null);\n\t\treturn;\n\t}\n\tvar prefix = scope + '\u0000';\n\tfor (var k in previewUrlCache) if (k.indexOf(prefix) === 0) delete previewUrlCache[k];\n\tfor (var f in previewInFlight) if (f.indexOf(prefix) === 0) delete previewInFlight[f];\n\t// Marks are keyed the same way, so a project switch must drop them too or a\n\t// mark set for project A would fire a pointless refresh in project B.\n\tfor (var s in staleImagePreviews) if (s.indexOf(prefix) === 0) delete staleImagePreviews[s];\n}\n\n/**\n * A url we already hold that is still comfortably alive, or null.\n *\n * Synchronous on purpose. Both views rebuild bubble DOM constantly (the widget\n * tears down and re-creates every node in renderMessages; Vue re-patches v-html\n * whenever the string changes), so an async-only assignment would blank every\n * visible image for a frame on each re-render. Called before paint, this makes a\n * re-render invisible.\n */\nexport function peekImagePreviewUrl(ctx: ImagePreviewContext, remotePath: string): string | null {\n\tvar hit = previewUrlCache[cacheKey(ctx.scope, remotePath)];\n\tif (!hit) return null;\n\t// Same headroom the chip cache uses: drop the url before it dies, never after.\n\tif (Date.now() - hit.at >= LINK_REFRESH_WINDOW_MS) return null;\n\t// And ask the url itself, because the line above measures from ARRIVAL. Now\n\t// that the mint response is cacheable, an arrival is not a signing: a mint\n\t// answered from the browser's store can already be most of its own max-age\n\t// old, and this window would then add its full length on top of that,\n\t// handing an <img> a credential that died in between. Both bounds, so a\n\t// device whose clock is wrong can only be over-cautious.\n\tvar dies = presignExpiryEpochMs(hit.url);\n\tif (dies !== null && Date.now() >= dies - PRESIGN_SAFETY_MARGIN_MS) return null;\n\treturn hit.url;\n}\n\n/**\n * Deduped, TTL-bounded mint for one path.\n *\n * `refresh` skips every cache in the way: this module's in-memory one, and the\n * browser's cache of the mint request itself. It is what the error path uses to\n * replace a url that has expired, and what a view would call to pick up a file\n * that changed.\n */\nexport function resolveImagePreviewUrl(\n\tctx: ImagePreviewContext,\n\tremotePath: string,\n\tcontentType: string,\n\trefresh?: boolean,\n): Promise<string> {\n\tvar key = cacheKey(ctx.scope, remotePath);\n\n\t// A file marked stale by an upload has to go to the network exactly once,\n\t// then behave normally again. Consuming the mark here (rather than at the\n\t// upload) means the refresh lands on the mint that actually paints the new\n\t// bubble, not on one issued before the render.\n\tif (staleImagePreviews[key]) {\n\t\tdelete staleImagePreviews[key];\n\t\trefresh = true;\n\t}\n\n\tif (refresh) {\n\t\tdelete previewUrlCache[key];\n\t\tdelete previewInFlight[key];\n\t} else {\n\t\tvar warm = peekImagePreviewUrl(ctx, remotePath);\n\t\tif (warm) return Promise.resolve(warm);\n\t\tvar flight = previewInFlight[key];\n\t\tif (flight) return flight;\n\t}\n\tvar run: Promise<string> = ctx.mint(remotePath, contentType, refresh).then(function (url) {\n\t\t// Only the CURRENT flight may publish. A refresh started while a plain\n\t\t// mint was still outstanding replaces previewInFlight, and without this\n\t\t// guard whichever settles last wins: the older mint would overwrite the\n\t\t// fresh url with the stale one it was already holding, and delete the\n\t\t// newer flight's bookkeeping on its way out.\n\t\tif (previewInFlight[key] === run) {\n\t\t\tpreviewUrlCache[key] = { url: url, at: Date.now() };\n\t\t\tdelete previewInFlight[key];\n\t\t}\n\t\treturn url;\n\t}, function (e) {\n\t\tif (previewInFlight[key] === run) delete previewInFlight[key];\n\t\tthrow e;\n\t});\n\tpreviewInFlight[key] = run;\n\treturn run;\n}\n\n/**\n * Declare a stored file changed, so the next mint for it goes to the network.\n *\n * The mint request is browser-cached, which is what stops a reload re-downloading\n * every image, but it also means an OVERWRITE is invisible: the file is re-posted\n * to the same storage path, so the mint url is byte-identical, so the browser\n * replays the cached mint and hands back the same signed url and the same cached\n * body. The preview would keep painting the previous picture for a day.\n *\n * Upload paths call this because they are the one place that KNOWS the bytes\n * changed. It is a marker, not a fetch: the refresh happens on the next mint,\n * which is when the new bubble actually renders. In memory only, deliberately.\n */\nexport function markImagePreviewStale(scope: string, remotePath: string): void {\n\tif (!scope || !remotePath) return;\n\tstaleImagePreviews[cacheKey(scope, remotePath)] = true;\n\tdelete previewUrlCache[cacheKey(scope, remotePath)];\n}\n\nvar staleImagePreviews: Record<string, boolean> = Object.create(null);\n\n/**\n * Hydrate every un-claimed preview <img> in the given list.\n *\n * Idempotent: an element is claimed by its own data-bq-img-state, so a full\n * re-render, a Vue patch, or two calls in one frame cannot mint twice. The\n * caller decides WHICH elements to pass, so a view can move from\n * querySelectorAll to an IntersectionObserver without an engine change.\n */\nexport function hydrateImagePreviews(imgs: ArrayLike<PreviewImageEl>, ctx: ImagePreviewContext): void {\n\tfor (var i = 0; i < imgs.length; i++) hydrateOne(imgs[i], ctx);\n}\n\nfunction hydrateOne(img: PreviewImageEl, ctx: ImagePreviewContext): void {\n\tif (img.getAttribute('data-bq-img-state')) return; // already claimed\n\tvar path = img.getAttribute('data-bq-img-path');\n\tvar type = img.getAttribute('data-bq-img-type') || '';\n\tif (!path) { img.setAttribute('data-bq-img-state', 'error'); return; }\n\timg.setAttribute('data-bq-img-state', 'loading');\n\n\timg.addEventListener('load', function () {\n\t\timg.setAttribute('data-bq-img-state', 'ready');\n\t\t// One repair per FAILURE, not one per element for the life of the tab.\n\t\t// A bubble's DOM survives as long as its text does (the parse is memoized\n\t\t// on the message), so a preview that failed, repaired and painted kept a\n\t\t// spent retry flag for hours. The next time the browser dropped the body\n\t\t// and refetched with a url that had since expired, it went straight to\n\t\t// the dead chip with no attempt. On a phone that second eviction is\n\t\t// routine, which is why this only ever showed up on mobile.\n\t\timg.removeAttribute('data-bq-img-retry');\n\t\t// The picture growing into place is absorbed by the view's own `load`\n\t\t// listener on the message box, which sees this element and every other\n\t\t// image alike. onLoad is the other half of the same moment: it re-pins a\n\t\t// reader who is at the BOTTOM, where holding a row would be wrong.\n\t\tif (ctx.onLoad) ctx.onLoad(path as string);\n\t});\n\timg.addEventListener('error', function () { onImageError(img, ctx, path as string, type); });\n\n\tvar warm = peekImagePreviewUrl(ctx, path);\n\t// A warm url is assigned in the caller's own frame, before the reader has\n\t// been anywhere: the element goes from src-less (hidden) to displaying, which\n\t// is a height change of its own even before the bytes arrive.\n\tif (warm) { img.setAttribute('src', warm); notifyLayoutChange(img, ctx, path); return; }\n\n\tresolveImagePreviewUrl(ctx, path, type).then(function (url) {\n\t\t// The element may have been torn out and replaced while we waited.\n\t\tif (img.getAttribute('data-bq-img-state') !== 'loading') return;\n\t\timg.setAttribute('src', url);\n\t\tnotifyLayoutChange(img, ctx, path);\n\t}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tnotifyLayoutChange(img, ctx, path);\n\t\tif (ctx.onError) ctx.onError(path as string, e);\n\t});\n}\n\n/**\n * One retry, then the caption chip is the answer.\n *\n * This is the LOAD-BEARING repair, not a rare fallback. Because the mint request\n * is browser-cached for far longer than a signed url lives, the expected failure\n * is: the browser evicted the image body, refetched with the cached url, and got\n * a 403 because that url expired hours ago. Re-minting fixes it, but only\n * through `refresh`, since a plain re-mint would be answered from the same\n * browser cache with the same dead url. A deleted file or a wrong path is not\n * fixed by retrying, so the second failure is final and the image stays hidden.\n */\nfunction onImageError(img: PreviewImageEl, ctx: ImagePreviewContext, path: string, type: string): void {\n\tif (img.getAttribute('data-bq-img-retry') === '1') {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tnotifyLayoutChange(img, ctx, path);\n\t\tif (ctx.onError) ctx.onError(path, new Error('image preview failed to load'));\n\t\treturn;\n\t}\n\timg.setAttribute('data-bq-img-retry', '1');\n\t// Dropping the src hides the element again (the CSS keys on the MISSING src),\n\t// so the retry collapses the picture before it repaints it.\n\timg.removeAttribute('src');\n\tnotifyLayoutChange(img, ctx, path);\n\tresolveImagePreviewUrl(ctx, path, type, true).then(function (url) {\n\t\timg.setAttribute('src', url);\n\t\tnotifyLayoutChange(img, ctx, path);\n\t}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tnotifyLayoutChange(img, ctx, path);\n\t\tif (ctx.onError) ctx.onError(path, e);\n\t});\n}\n\n/**\n * Report the box that actually resized, which is the ANCHOR, not the <img>.\n *\n * The anchor IS the preview: picture on top, the dot-trail loader beside it, the\n * caption chip underneath. When a src lands the loader collapses (a CSS sibling\n * selector) while the img is still undecoded, so measuring the img alone reports\n * a ~2px GROWTH (its border) against a real ~18px shrink. Measuring the anchor\n * makes every transition equal to what the reader saw move.\n *\n * A markdown `![alt](url)` has no such ancestor and stands for itself. Both views\n * apply the same closest() before calling absorb, so the two paths key its\n * per-element memo on the same node and cannot pay for one change twice.\n */\nfunction notifyLayoutChange(img: PreviewImageEl, ctx: ImagePreviewContext, path: string): void {\n\tif (!ctx.onLayoutChange) return;\n\tctx.onLayoutChange(previewLayoutBox(img), path);\n}\n\nexport var PREVIEW_LAYOUT_BOX_SELECTOR = 'a.bq-link-button.is-image-preview';\n\n/** The element whose height a preview's own transitions actually change. */\nexport function previewLayoutBox<T extends PreviewImageEl>(img: T): T {\n\tvar closest = (img as any).closest;\n\tif (typeof closest !== 'function') return img;\n\treturn closest.call(img, PREVIEW_LAYOUT_BOX_SELECTOR) || img;\n}\n","/**\n * Chat timestamp formatting, shared so agent.vue and the widget render an\n * identical \"small text under the bubble\". Pure and locale-aware: it formats a\n * given epoch-ms value, it never reads the current time, so it stays testable and\n * DOM-free.\n */\n\n/** Wall-clock epoch ms. Separate from the engine's monotonic nowMs() (which is\n * performance.now() when available and therefore NOT epoch): a displayed\n * timestamp must be wall time. */\nexport function wallClockNow(): number {\n\treturn Date.now();\n}\n\n/**\n * \"Jul 24, 2026, 3:42:07 PM\" (locale-formatted). Empty string for a missing or\n * non-finite value, so a caller can gate rendering on the result being truthy and\n * a pending bubble (no timestamp yet) simply shows nothing.\n */\nexport function formatChatTimestamp(ms?: number): string {\n\tif (typeof ms !== 'number' || !isFinite(ms) || ms <= 0) return '';\n\ttry {\n\t\treturn new Date(ms).toLocaleString(undefined, {\n\t\t\tyear: 'numeric',\n\t\t\tmonth: 'short',\n\t\t\tday: 'numeric',\n\t\t\thour: 'numeric',\n\t\t\tminute: '2-digit',\n\t\t\tsecond: '2-digit',\n\t\t});\n\t} catch (e) {\n\t\treturn '';\n\t}\n}\n","/**\n * The `ai_agent` service option, parsed and serialized in ONE place.\n *\n * Stored on the skapi service record as up to three '#'-delimited segments:\n *\n * none AI chat disabled\n * claude platform chosen, no model saved yet\n * claude#claude-sonnet-4-6 platform + model\n * claude#claude-sonnet-4-6#400000 platform + model + context-window override\n *\n * The third segment is new and optional, so every value written before it\n * existed parses unchanged with `contextWindow: null`. Nothing writes a third\n * segment without a model, because the window is meaningless without one.\n *\n * This lived as four separate copies (agent.vue, dbfile.vue, service.vue, and\n * the widget's index.js), which is how the format drifts. New callers should\n * import from here rather than re-deriving the split.\n */\n\nexport type AiAgentPlatform = 'claude' | 'openai' | null;\n\nexport type ParsedAiAgent = {\n\t/** null when unset or explicitly 'none'. */\n\tplatform: AiAgentPlatform;\n\t/** '' when no model has been saved. */\n\tmodel: string;\n\t/** Per-project context-window override in tokens, or null to use the model's. */\n\tcontextWindow: number | null;\n\t/** True when a real platform is configured (i.e. not unset and not 'none'). */\n\thasPlatform: boolean;\n};\n\nfunction normalizePlatform(raw: string): AiAgentPlatform {\n\tvar p = (raw || '').trim().toLowerCase();\n\treturn p === 'claude' || p === 'openai' ? p : null;\n}\n\nexport function parseAiAgentValue(value: string | null | undefined): ParsedAiAgent {\n\tvar raw = (value || '').trim();\n\tif (!raw || raw.toLowerCase() === 'none') {\n\t\treturn { platform: null, model: '', contextWindow: null, hasPlatform: false };\n\t}\n\n\t// Split into at most three parts so a '#' inside a model id (none today, but\n\t// the delimiter should not be load-bearing on the tail) cannot shift fields.\n\tvar firstHash = raw.indexOf('#');\n\tif (firstHash === -1) {\n\t\tvar only = normalizePlatform(raw);\n\t\treturn { platform: only, model: '', contextWindow: null, hasPlatform: !!only };\n\t}\n\n\tvar platform = normalizePlatform(raw.slice(0, firstHash));\n\tvar rest = raw.slice(firstHash + 1);\n\tvar secondHash = rest.indexOf('#');\n\tvar model = (secondHash === -1 ? rest : rest.slice(0, secondHash)).trim();\n\tvar windowRaw = secondHash === -1 ? '' : rest.slice(secondHash + 1).trim();\n\n\tvar parsedWindow = windowRaw ? Number(windowRaw) : NaN;\n\tvar contextWindow = Number.isFinite(parsedWindow) && parsedWindow > 0\n\t\t? Math.floor(parsedWindow)\n\t\t: null;\n\n\treturn { platform: platform, model: model, contextWindow: contextWindow, hasPlatform: !!platform };\n}\n\nexport function buildAiAgentValue(\n\tplatform: string | null | undefined,\n\tmodel?: string | null,\n\tcontextWindow?: number | null,\n): string {\n\tvar p = (platform || '').trim().toLowerCase();\n\tif (!p || p === 'none') return 'none';\n\n\tvar m = (model || '').trim();\n\tif (!m) return p;\n\n\tvar n = Number(contextWindow);\n\tif (!Number.isFinite(n) || n <= 0) return p + '#' + m;\n\treturn p + '#' + m + '#' + Math.floor(n);\n}\n","/**\n * AI request builders + dispatch transport (framework-agnostic).\n *\n * Ported from www.skapi.com/src/code/ai_agent.ts. The only changes vs the\n * original are dependency-injection seams:\n * - `skapi.clientSecretRequest*` -> chatEngineConfig().clientSecretRequest*\n * - MCP endpoint URL -> chatEngineConfig().mcpBaseUrl\n * - `poll` on each request -> pollOpt() (set per consumer; see config.ts)\n * - Vue `reactive`/`ref` removed (bgTaskQueue/agentViewMounted are app-level\n * state that stays in the consumer, not here;\n * only the BgTaskEntry TYPE lives here)\n */\nimport { buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingContinueMessage, buildIndexingRenderMessage, buildIndexingRenderContinueTemplate, buildIndexingWindowMessage } from './prompts';\nimport { isServerExtractable, isPagedReadFile, isImageVisionFile, isWindowedReadFile, makeExtractPlaceholder, makeRenderPlaceholder, makeWindowPlaceholder, RENDER_PAGES_PER_WINDOW, type ExtractDirective, type FileUrlDirective } from './office';\nimport { chatEngineConfig, pollOpt, windowedIndexingEnabled } from './config';\n// Output sizing lives in budget.ts so the request cap and the reserve the input\n// budget subtracts cannot drift; getMaxOutputTokens also clamps per model.\nimport { getMaxOutputTokens } from './budget';\n\nexport const ANTHROPIC_MESSAGES_API_URL = 'https://api.anthropic.com/v1/messages';\nconst ANTHROPIC_MODELS_API_URL = 'https://api.anthropic.com/v1/models';\nconst ANTHROPIC_VERSION = '2023-06-01';\nconst ANTHROPIC_MCP_BETA = 'mcp-client-2025-11-20';\nconst ANTHROPIC_WEB_FETCH_BETA = 'web-fetch-2025-09-10';\nconst ANTHROPIC_PROMPT_CACHING_BETA = 'prompt-caching-2024-07-31';\nconst ANTHROPIC_BETA_HEADER = `${ANTHROPIC_MCP_BETA},${ANTHROPIC_WEB_FETCH_BETA},${ANTHROPIC_PROMPT_CACHING_BETA}`;\nconst WEB_FETCH_MAX_USES = 40;\nconst WEB_FETCH_MAX_CONTENT_TOKENS = 200000;\n\nexport const OPENAI_RESPONSES_API_URL = 'https://api.openai.com/v1/responses';\nconst OPENAI_MODELS_API_URL = 'https://api.openai.com/v1/models';\nconst DEFAULT_OPENAI_IMAGE_DETAIL = 'auto';\nconst OPENAI_WEB_SEARCH_ENABLED = true;\nconst OPENAI_WEB_SEARCH_EXTERNAL_WEB_ACCESS = true;\nexport const MCP_NAME = 'BunnyQuery';\n\nexport const DEFAULT_CLAUDE_MODEL = 'claude-sonnet-5';\nexport const DEFAULT_OPENAI_MODEL = 'gpt-5.6-luna';\n\nconst mcpUrl = () => chatEngineConfig().mcpBaseUrl;\nconst clientSecretRequest = (opts: any) => chatEngineConfig().clientSecretRequest(opts);\n\n// Resolve the per-image `detail` for OpenAI. The version match tolerates a\n// trailing variant/date suffix (`gpt-5.4-nano`, `-mini`, `-2026-01-01`, …):\n// previously the pattern was anchored with no suffix allowed, so EVERY suffixed\n// model silently fell through to 'auto' — i.e. the cheap tiers that most need\n// resolution were the ones getting downsampled images.\n//\n// Variants used to resolve to 'high' rather than 'original' on the reasoning that\n// 'high' is universally supported and an unsupported value would fail the whole\n// request. The cost of that caution turned out to be real: 'high' downsamples to\n// a 512px grid, so the small tiers that most need resolution were reading dense\n// scans at the lower of the two settings, and gpt-5.4-nano reports it cannot make\n// out the text where gpt-5.4 (on 'original') can. Variants now get 'original' too.\n//\n// If a variant rejects 'original' the failure is loud and immediate (a terminal\n// 400 on the whole request, no retry), so flip VARIANT_IMAGE_DETAIL back to\n// 'high' and it is undone. That is the one word to change.\nconst VARIANT_IMAGE_DETAIL = 'original';\n\n// Extra Responses-API knobs for NANO models on INDEXING passes only.\n//\n// `detail` (above) governs what the model SEES; these govern how it thinks and how completely it\n// writes. Nano strips vision detail to hit its latency target and compresses layout when\n// transcribing, which is the documented reason to raise verbosity FOR IT SPECIFICALLY. mini and the\n// base/named models do not need it, so they are excluded rather than paying its output cost.\n//\n// Deliberately NOT applied to chat: high verbosity makes ordinary replies longer and worse, and the\n// chat path has no transcription job to justify it.\n//\n// Two things to keep in mind, both of which is why these are separate switches:\n// 1. An UNKNOWN body field is fatal here, not ignored. The engine already documents it for\n// `_skapi_window`: it \"reaches the provider as an unknown body field and the call fails\n// terminally with no retry\". If a field name is wrong, EVERY indexing pass dies. Set either\n// constant to null to remove the field entirely.\n// 2. Reasoning tokens are billed against max_output_tokens on this API. An indexing pass spends\n// its output budget emitting postRecords calls, so buying reasoning takes budget away from the\n// records themselves and can truncate them.\n//\n// Effort was OFF, and the measurement that turned it on: across one nano run's photo records, only\n// 5 of 28 image text fields carried a concrete identifier read off the tag (a part number, a tag id).\n// The other 23 held a generic scene description. Reading small handwriting off a photographed label\n// is exactly the kind of work a moment of deliberation buys, so it went on at the LOWEST setting.\n//\n// It stays 'low' for a nano that already transcribes correctly (5.6-nano), because effort is\n// billed against the same budget as the records and buying it where it is not needed can only\n// truncate them.\n//\n// OLDEST_NANO_REASONING_EFFORT raises it for gpt-5.4-nano and below ONLY, which is the tier that\n// actually reads dense scans badly. It is 'high', and what makes that affordable is not one change\n// but two:\n// - that tier's render window is SMALL_TIER_PAGES_PER_WINDOW pages, not five, so the same cap is\n// divided between far fewer pages to begin with; and\n// - the worker now DETECTS a pass that ran out of output budget (_output_truncation_reason) and\n// re-runs that window at half the page count instead of advancing past it.\n// Before the detector, over-buying reasoning was unsafe in a way that did not show up: a truncated\n// pass still returned 200, so the page loop moved on and the rest of that window's records were\n// lost silently. With it, spending too much on reasoning costs an extra pass instead of data.\n//\n// Still the first knob to lower if the logs start showing repeated truncation retries, and\n// re-measure that 5-of-28 ratio rather than assuming. null removes the field entirely.\nconst VARIANT_TEXT_VERBOSITY: string | null = 'high';\nconst VARIANT_REASONING_EFFORT: string | null = 'low';\nconst OLDEST_NANO_REASONING_EFFORT: string | null = 'high';\n\n/**\n * True only for a NANO model, including a dated nano snapshot. NOT mini, not a base model, and not\n * a named variant like gpt-5.6-luna: those transcribe faithfully on their own and do not need the\n * knob, so paying its output cost on them would be waste.\n */\nconst isOpenAINano = (model?: string) => {\n\tconst normalized = (model || DEFAULT_OPENAI_MODEL).trim().toLowerCase();\n\tif (!/(^|-)nano(-|$)/.test(normalized)) return false;\n\n\t// Family floor, same shape as getOpenAIImageDetail's. \"Contains nano\" alone also matches\n\t// gpt-4.1-nano and anything else a project might name, and these are body fields an older\n\t// model REJECTS rather than ignores: one 400 with no retry kills every indexing pass. Only\n\t// gpt-5.4 and newer are known to take `text.verbosity` and `reasoning.effort`.\n\tconst match = normalized.match(/^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/);\n\tif (!match) return false;\n\tconst major = Number(match[1]);\n\tconst minor = match[2] === undefined ? null : Number(match[2]);\n\treturn major > 5 || (major === 5 && minor !== null && minor >= 4);\n};\n\n/**\n * The indexing-only body knobs, for the ONE tier that needs them: gpt-5.4-nano.\n *\n * Both conditions are load-bearing and mean different things. isOpenAINano is the gpt-5.4\n * FLOOR - below it these fields are rejected rather than ignored, and one 400 kills every\n * indexing pass. isOldestNano is the CEILING - 5.5-nano and 5.6-nano transcribe correctly\n * on their own, so they are left on the provider's defaults exactly like mini and the base\n * models. Every other model gets an empty object, i.e. no `text` and no `reasoning` at all.\n */\nconst variantIndexingOptions = (model?: string) => {\n\tif (!isOpenAINano(model) || !isOldestNano(model)) return {};\n\treturn {\n\t\t...(VARIANT_TEXT_VERBOSITY ? { text: { verbosity: VARIANT_TEXT_VERBOSITY } } : {}),\n\t\t...(OLDEST_NANO_REASONING_EFFORT ? { reasoning: { effort: OLDEST_NANO_REASONING_EFFORT } } : {}),\n\t};\n};\nconst getOpenAIImageDetail = (model?: string) => {\n\tconst normalized = (model || DEFAULT_OPENAI_MODEL).trim().toLowerCase();\n\tconst match = normalized.match(/^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/);\n\tif (!match) {\n\t\treturn DEFAULT_OPENAI_IMAGE_DETAIL;\n\t}\n\n\tconst major = Number(match[1]);\n\tconst minor = match[2] === undefined ? null : Number(match[2]);\n\tconst isVariant = !!match[3];\n\n\tconst supportsOriginal = major > 5 || (major === 5 && minor !== null && minor >= 4);\n\tif (!supportsOriginal) {\n\t\treturn DEFAULT_OPENAI_IMAGE_DETAIL;\n\t}\n\n\treturn isVariant ? VARIANT_IMAGE_DETAIL : 'original';\n};\n\n// Per-image `detail` for WORKER-RENDERED document pages (the `_skapi_render`\n// path). Same resolution as above with one difference: these are dense scans\n// whose entire purpose is to be read, so 'auto' is never acceptable — it lets\n// the API downsample exactly the pixels the model needs to OCR. Floor it at\n// 'high'; models that support full-resolution 'original' still get it.\n//\n// Without this the worker falls back to its own model-blind default ('high'),\n// which silently denies the strongest models the 'original' detail they support.\nconst getRenderImageDetail = (model?: string) => {\n\tconst detail = getOpenAIImageDetail(model);\n\treturn detail === DEFAULT_OPENAI_IMAGE_DETAIL ? 'high' : detail;\n};\n\n/**\n * A nano at gpt-5.4 or OLDER.\n *\n * This is the observed quality boundary, not a guessed one: gpt-5.4-nano and below\n * transcribe dense scans poorly, while mini, the base models and every gpt-5.6 model\n * (5.6-nano included) read the same documents correctly. So only this tier gets\n * compensated, and everything above it is left exactly as it was — on 'original' detail\n * and a full window, because nothing about it needs fixing and every compensation costs\n * either passes or output budget.\n */\n/** The id parses as a gpt version we can reason about. An id that does NOT (o3,\n * chatgpt-4o-latest, any custom name) is left entirely alone: we cannot tell what it is,\n * and every compensation here is either a body field that can 400 or a change to how many\n * images it receives. Unknown means untouched. */\nconst OPENAI_VERSIONED_ID = /^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/;\nconst isRecognisedOpenAIVersion = (model?: string) =>\n\tOPENAI_VERSIONED_ID.test((model || DEFAULT_OPENAI_MODEL).trim().toLowerCase());\n\nconst isOldestNano = (model?: string) => {\n\tconst normalized = (model || DEFAULT_OPENAI_MODEL).trim().toLowerCase();\n\tif (!/(^|-)nano(-|$)/.test(normalized)) return false;\n\tconst match = normalized.match(/^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/);\n\t// Called \"nano\" but not a naming we recognise: treat it as the weak tier. It also\n\t// fails the 'original' gate, so it is caught by the downsampled branch first anyway.\n\tif (!match) return true;\n\tconst major = Number(match[1]);\n\tconst minor = match[2] === undefined ? null : Number(match[2]);\n\tif (major < 5) return true;\n\tif (major > 5) return false;\n\treturn minor === null || minor <= 4;\n};\n\n// Pages in one render window for a SMALL tier, against RENDER_PAGES_PER_WINDOW (5) for a\n// full one.\n//\n// This is the lever that does not risk a 400. The output budget is one number for the whole\n// pass (getMaxOutputTokens, and reasoning is billed against it), so a window of 5 dense pages leaves\n// a small model a couple of thousand tokens per page and it starts sampling rows instead of\n// transcribing them - which is exactly the \"saved 5 line items\" on a page holding twenty.\n// Halving the window does not raise the cap, it just stops dividing it so many ways, and the\n// worker's page loop already runs as many windows as a file needs.\nconst SMALL_TIER_PAGES_PER_WINDOW = 2;\n\n// Horizontal bands per page for a tier whose images the API DOWNSAMPLES before the model\n// sees them ('high' resamples onto a 512px tile grid). For those models the render DPI is\n// irrelevant - the pixels are thrown away upstream - so the only way to hand them more\n// readable text is to make each image cover less of the page. Two bands doubles the\n// resolution the model effectively gets, at the cost of one extra image per page.\n//\n// Bands are horizontal so a table row is never cut down its middle, and they overlap\n// slightly so a line landing on the seam appears whole in one of them.\nconst DOWNSAMPLED_TIER_TILE = 2;\n\n/** How a given model should be shown a rendered document. */\nexport type VisionProfile = {\n\t/** Per-image `detail` (OpenAI only). */\n\tdetail: string;\n\t/** Pages the worker renders into one window. */\n\tpagesPerWindow: number;\n\t/** Horizontal bands per page; 1 renders the whole page as one image. */\n\ttile: number;\n};\n\n/**\n * Resolve the render profile for a model.\n *\n * Three tiers, and they fail for different reasons, which is why one set of knobs cannot\n * serve all of them:\n * - full: everything ABOVE gpt-5.4-nano - the base models, mini, and every gpt-5.6\n * including 5.6-nano. These already transcribe dense scans correctly, so they get\n * 'original' detail and are otherwise untouched.\n * - gpt-5.4-nano: also gets 'original', so it sees exactly the SAME pixels as the full\n * tier. Its gap therefore is not resolution, and tiling would do nothing for it. What\n * it lacks is room: a smaller window leaves the same output budget divided between\n * fewer pages.\n * - downsampled (below the 'original' floor: gpt-5.3-nano, gpt-5-nano, gpt-4.1-nano):\n * capped at 'high', which resamples the page onto a 512px grid no matter what DPI it\n * was rendered at. Render resolution is wasted on these entirely; the only way to give\n * them readable text is to make each image cover less of the page, which is `tile`.\n */\nexport function getVisionProfile(model?: string): VisionProfile {\n\tconst detail = getRenderImageDetail(model);\n\t// An id we cannot parse is left exactly as it was: full window, no tiling. Treating\n\t// \"unknown\" as \"weak\" would quietly change how much work every custom or aliased model\n\t// does, on no evidence at all.\n\tif (!isRecognisedOpenAIVersion(model)) {\n\t\treturn { detail, pagesPerWindow: RENDER_PAGES_PER_WINDOW, tile: 1 };\n\t}\n\tif (detail !== 'original') {\n\t\treturn { detail, pagesPerWindow: SMALL_TIER_PAGES_PER_WINDOW, tile: DOWNSAMPLED_TIER_TILE };\n\t}\n\tif (isOldestNano(model)) {\n\t\treturn { detail, pagesPerWindow: SMALL_TIER_PAGES_PER_WINDOW, tile: 1 };\n\t}\n\treturn { detail, pagesPerWindow: RENDER_PAGES_PER_WINDOW, tile: 1 };\n}\n\nexport type ClaudeRole = 'user' | 'assistant';\n\nexport type ClaudeMessage = {\n\trole: ClaudeRole;\n\tcontent: string;\n};\n\nexport type OpenAIMessage = {\n\trole: ClaudeRole;\n\tcontent: string;\n};\n\nexport type ClaudeMcpToolConfig = {\n\tenabled?: boolean;\n\tdefer_loading?: boolean;\n};\n\nexport type ClaudeMcpServerRequest = {\n\tname: string;\n\turl: string;\n\tauthorizationToken?: string;\n\tdefaultConfig?: ClaudeMcpToolConfig;\n\tconfigs?: Record<string, ClaudeMcpToolConfig>;\n};\n\nconst IMAGE_URL_REGEX =\n\t/\\bhttps?:\\/\\/[^\\s<>\"'()\\[\\]]+?\\.(?:jpg|jpeg|png|gif|webp)(?:\\?[^\\s<>\"'()\\[\\]]*)?/gi;\n\nexport function transformContentWithImages(\n\tcontent: string,\n): string | Array<Record<string, any>> {\n\tif (typeof content !== 'string' || !content) {\n\t\treturn content;\n\t}\n\n\tconst matches = content.match(IMAGE_URL_REGEX);\n\n\tif (!matches || !matches.length) {\n\t\treturn content;\n\t}\n\n\tconst seen = new Set<string>();\n\tconst imageBlocks: Array<Record<string, any>> = [];\n\n\tfor (const url of matches) {\n\t\tif (seen.has(url)) continue;\n\t\tseen.add(url);\n\t\timageBlocks.push({\n\t\t\ttype: 'image',\n\t\t\tsource: { type: 'url', url },\n\t\t});\n\t}\n\n\treturn [...imageBlocks, { type: 'text', text: content }];\n}\n\nfunction prepareClaudeMessages(messages: ClaudeMessage[]) {\n\tif (!messages.length) return messages;\n\t// Only transform the most recent user message. Historical user messages\n\t// may reference image URLs that are now stale (deleted, moved, expired).\n\tconst lastIndex = messages.length - 1;\n\tconst last = messages[lastIndex];\n\tif (last.role !== 'user') return messages;\n\tconst content = transformContentWithImages(last.content);\n\tif (content === last.content) return messages;\n\tconst next = messages.slice();\n\tnext[lastIndex] = { role: last.role, content } as unknown as ClaudeMessage;\n\treturn next;\n}\n\nexport function transformContentWithOpenAIImages(\n\tcontent: string,\n\tdetail = DEFAULT_OPENAI_IMAGE_DETAIL,\n): string | Array<Record<string, any>> {\n\tif (typeof content !== 'string' || !content) {\n\t\treturn content;\n\t}\n\n\tconst matches = content.match(IMAGE_URL_REGEX);\n\n\tif (!matches || !matches.length) {\n\t\treturn content;\n\t}\n\n\tconst seen = new Set<string>();\n\tconst imageBlocks: Array<Record<string, any>> = [];\n\n\tfor (const url of matches) {\n\t\tif (seen.has(url)) continue;\n\t\tseen.add(url);\n\t\timageBlocks.push({\n\t\t\ttype: 'input_image',\n\t\t\timage_url: url,\n\t\t\tdetail,\n\t\t});\n\t}\n\n\treturn [{ type: 'input_text', text: content }, ...imageBlocks];\n}\n\nfunction prepareOpenAIMessages(\n\tmessages: OpenAIMessage[],\n\tdetail = DEFAULT_OPENAI_IMAGE_DETAIL,\n) {\n\tif (!messages.length) return messages;\n\tconst lastIndex = messages.length - 1;\n\tconst last = messages[lastIndex];\n\tif (last.role !== 'user') return messages;\n\tconst content = transformContentWithOpenAIImages(last.content, detail);\n\tif (content === last.content) return messages;\n\tconst next = messages.slice();\n\tnext[lastIndex] = { role: last.role, content } as unknown as OpenAIMessage;\n\treturn next;\n}\n\n// Attach a cache_control breakpoint to the last message of the stable history\n// prefix (everything except the final user turn) so Anthropic re-uses it at\n// ~10% input-token billing.\nfunction applyHistoryCacheBreakpoint(messages: any[]): any[] {\n\tif (messages.length < 2) return messages;\n\tconst breakpointIndex = messages.length - 2;\n\treturn messages.map((m, i) => {\n\t\tif (i !== breakpointIndex) return m;\n\t\tconst blocks = Array.isArray(m.content)\n\t\t\t? m.content.slice()\n\t\t\t: [{ type: 'text', text: m.content }];\n\t\tif (!blocks.length) return m;\n\t\tconst lastBlockIndex = blocks.length - 1;\n\t\tblocks[lastBlockIndex] = {\n\t\t\t...blocks[lastBlockIndex],\n\t\t\tcache_control: { type: 'ephemeral' },\n\t\t};\n\t\treturn { ...m, content: blocks };\n\t});\n}\n\nexport type CallClaudeWithMcpParams = {\n\tprompt: string;\n\tmessages?: ClaudeMessage[];\n\tservice: string;\n\towner: string;\n\tuserId?: string;\n\tmodel?: string;\n\tmaxTokens?: number;\n\tsystem?: string;\n\tmcpServer: ClaudeMcpServerRequest;\n\textractContent?: ExtractDirective[];\n\tfileUrls?: FileUrlDirective[];\n\tonResponse?: (res: any) => void;\n\tonError?: (err: any) => void;\n};\n// Poll cadence for every client-secret request the chat waits on. Shared by the\n// engine's own poll sites and imported by agent.vue; the widget carries its own\n// copy in src/index.js that must be kept in step.\nexport const POLL_INTERVAL = 3000;\n// Ceiling on how many BACKGROUND indexing polls may be attached at once, across\n// every poll site (the engine's drain, the engine's history load, and each\n// client's own fallback poller).\n//\n// Every unresolved bg item used to get its own poll, and a poll is a\n// POLL_INTERVAL setInterval firing one request per tick. A bulk upload from the\n// db-files page enqueues one indexing pass per FILE, so uploading 10,000 files\n// attached 10,000 concurrent intervals: ~3,300 requests/second against a browser\n// that opens six connections per host. The resulting request backlog starved the\n// uploads themselves, which is the \"frozen tab that eventually finishes\" users\n// reported.\n//\n// Capping costs nothing, because the server settles one queue's passes in FIFO\n// order (a single SQS MessageGroupId per `<user>-bg` queue). A pass cannot\n// finish before the ones ahead of it, so asking about the newest 9,994 is pure\n// waste. Each resolution frees a slot, which the next-OLDEST unpolled entry\n// takes on the drain that follows. Spending the budget oldest-first is\n// load-bearing: spend it on the newest and the batch wedges, since those cannot\n// settle until the ones ahead of them do and nothing ahead would hold a poll.\n//\n// FOREGROUND polls (a reply the user is actively waiting on) are never capped.\nexport const MAX_CONCURRENT_BG_POLLS = 6;\nexport async function callClaudeWithMcp({\n\tprompt,\n\tmessages,\n\tservice,\n\towner,\n\tuserId,\n\tmodel = DEFAULT_CLAUDE_MODEL,\n\tmaxTokens = 1000,\n\tsystem,\n\tmcpServer,\n\textractContent,\n\tfileUrls,\n}: CallClaudeWithMcpParams) {\n\tconst mcpServerDefinition: Record<string, any> = {\n\t\ttype: 'url',\n\t\tname: mcpServer.name,\n\t\turl: mcpServer.url,\n\t};\n\n\tif (mcpServer.authorizationToken) {\n\t\tmcpServerDefinition.authorization_token = mcpServer.authorizationToken;\n\t}\n\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'claude',\n\t\tqueue: userId || service,\n\t\tservice,\n\t\towner,\n\t\t...pollOpt(),\n\t\turl: ANTHROPIC_MESSAGES_API_URL,\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'content-type': 'application/json',\n\t\t\t'x-api-key': '$CLIENT_SECRET',\n\t\t\t'anthropic-version': ANTHROPIC_VERSION,\n\t\t\t'anthropic-beta': ANTHROPIC_BETA_HEADER,\n\t\t},\n\t\tdata: {\n\t\t\tmodel,\n\t\t\tmax_tokens: maxTokens,\n\t\t\t...(extractContent && extractContent.length\n\t\t\t\t? { _skapi_extract: extractContent }\n\t\t\t\t: {}),\n\t\t\t...(fileUrls && fileUrls.length\n\t\t\t\t? { _skapi_file_urls: fileUrls }\n\t\t\t\t: {}),\n\t\t\t...(system\n\t\t\t\t? {\n\t\t\t\t\t\tsystem: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\t\ttext: system,\n\t\t\t\t\t\t\t\tcache_control: { type: 'ephemeral' },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\tmessages: (() => {\n\t\t\t\tconst prepared =\n\t\t\t\t\tmessages && messages.length\n\t\t\t\t\t\t? prepareClaudeMessages(messages)\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\trole: 'user',\n\t\t\t\t\t\t\t\t\tcontent: transformContentWithImages(prompt),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t];\n\t\t\t\treturn applyHistoryCacheBreakpoint(prepared as any[]);\n\t\t\t})(),\n\t\t\tmcp_servers: [mcpServerDefinition],\n\t\t\ttools: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'mcp_toolset',\n\t\t\t\t\tmcp_server_name: mcpServer.name,\n\t\t\t\t\t...(mcpServer.defaultConfig\n\t\t\t\t\t\t? { default_config: mcpServer.defaultConfig }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(mcpServer.configs ? { configs: mcpServer.configs } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'web_fetch_20250910',\n\t\t\t\t\tname: 'web_fetch',\n\t\t\t\t\tmax_uses: WEB_FETCH_MAX_USES,\n\t\t\t\t\tcitations: { enabled: true },\n\t\t\t\t\tmax_content_tokens: WEB_FETCH_MAX_CONTENT_TOKENS,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t});\n}\n\nexport async function callClaudeWithPublicMcp(\n\tprompt: string,\n\tservice: string,\n\towner: string,\n\tmessages?: ClaudeMessage[],\n\tsystem?: string,\n\tmodel?: string,\n\tuserId?: string,\n\textractContent?: ExtractDirective[],\n\tfileUrls?: FileUrlDirective[],\n\tonResponse?: (res: any) => void,\n\tonError?: (err: any) => void,\n) {\n\treturn callClaudeWithMcp({\n\t\tprompt,\n\t\tmessages,\n\t\tservice,\n\t\towner,\n\t\tuserId,\n\t\tmodel: model || DEFAULT_CLAUDE_MODEL,\n\t\tmaxTokens: getMaxOutputTokens('claude', model || DEFAULT_CLAUDE_MODEL),\n\t\tsystem,\n\t\textractContent,\n\t\tfileUrls,\n\t\tmcpServer: {\n\t\t\tname: MCP_NAME,\n\t\t\turl: mcpUrl(),\n\t\t\tauthorizationToken: '$ACCESS_TOKEN',\n\t\t},\n\t\tonResponse,\n\t\tonError,\n\t});\n}\n\nexport async function callOpenAIWithPublicMcp(\n\tprompt: string,\n\tservice: string,\n\towner: string,\n\tmessages?: OpenAIMessage[],\n\tsystem?: string,\n\tmodel?: string,\n\tuserId?: string,\n\textractContent?: ExtractDirective[],\n\tfileUrls?: FileUrlDirective[],\n\tonResponse?: (res: any) => void,\n\tonError?: (err: any) => void,\n) {\n\tconst resolvedModel = model || DEFAULT_OPENAI_MODEL;\n\tconst imageDetail = getOpenAIImageDetail(resolvedModel);\n\tconst messageList =\n\t\tmessages && messages.length\n\t\t\t? prepareOpenAIMessages(messages, imageDetail)\n\t\t\t: [\n\t\t\t\t{\n\t\t\t\t\trole: 'user' as const,\n\t\t\t\t\tcontent: transformContentWithOpenAIImages(prompt, imageDetail),\n\t\t\t\t},\n\t\t\t];\n\n\tconst responseInput = [\n\t\t...(system\n\t\t\t? [\n\t\t\t\t{\n\t\t\t\t\trole: 'system',\n\t\t\t\t\tcontent: system,\n\t\t\t\t},\n\t\t\t]\n\t\t\t: []),\n\t\t...messageList.map((m) => ({\n\t\t\trole: m.role,\n\t\t\tcontent: m.content,\n\t\t})),\n\t];\n\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'openai',\n\t\tqueue: userId || service,\n\t\tservice,\n\t\towner,\n\t\t...pollOpt(),\n\t\turl: OPENAI_RESPONSES_API_URL,\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'content-type': 'application/json',\n\t\t\tAuthorization: 'Bearer $CLIENT_SECRET',\n\t\t},\n\t\tdata: {\n\t\t\tmodel: resolvedModel,\n\t\t\tmax_output_tokens: getMaxOutputTokens('openai', resolvedModel),\n\t\t\t...(extractContent && extractContent.length\n\t\t\t\t? { _skapi_extract: extractContent }\n\t\t\t\t: {}),\n\t\t\t...(fileUrls && fileUrls.length\n\t\t\t\t? { _skapi_file_urls: fileUrls }\n\t\t\t\t: {}),\n\t\t\tinput: responseInput,\n\t\t\ttools: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'mcp',\n\t\t\t\t\tserver_label: MCP_NAME,\n\t\t\t\t\tserver_url: mcpUrl(),\n\t\t\t\t\trequire_approval: 'never',\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tAuthorization: 'Bearer $ACCESS_TOKEN',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t...(OPENAI_WEB_SEARCH_ENABLED\n\t\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'web_search',\n\t\t\t\t\t\t\texternal_web_access: OPENAI_WEB_SEARCH_EXTERNAL_WEB_ACCESS,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t\t: []),\n\t\t\t],\n\t\t},\n\t});\n}\n\nexport type AttachmentSaveInfo = {\n\tplatform: 'claude' | 'openai';\n\tmodel?: string;\n\tservice: string;\n\t/** The PUBLIC project ID (formatted token, skapi.project_id). Shown to the model; falls back to `service`. */\n\tpublicProjectId?: string;\n\towner: string;\n\t/**\n\t * Queue base for this indexing pass: \"<userId>-bg\". REQUIRED, and it must be\n\t * the SAME value the chat turn uses (ChatSession.dispatchComposedMessage's\n\t * `id.userId || id.projectId`) — the backend serialises requests that share a\n\t * queue name and runs different ones IN PARALLEL, so a pass enqueued under a\n\t * different base does not hold the chat back at all. It was optional once,\n\t * defaulting to `service`; the chatbox omitted it, and its files were indexed\n\t * on \"<projectId>-bg\" while its question ran on \"<userId>-bg\" — the question\n\t * was answered from a file nothing had read yet. Pass `userId || projectId`.\n\t */\n\tuserId: string;\n\tserviceName?: string;\n\tserviceDescription?: string;\n\tattachment: {\n\t\tname: string;\n\t\tstoragePath: string;\n\t\tmime?: string;\n\t\tsize?: number;\n\t\turl: string;\n\t};\n\t/**\n\t * Content parsed CLIENT-SIDE by an attachment-parser plugin (e.g. an .hwp\n\t * parser). When set, it is inlined into the indexing message verbatim and\n\t * takes precedence over server-side office extraction / web_fetch.\n\t */\n\tparsedContent?: string;\n\t/**\n\t * True for a RESUME pass: a previous indexing pass could not finish this (large)\n\t * file, so continue it - always via readFileContent paging, with a \"continue\"\n\t * message telling the agent to resume from where the saved records leave off.\n\t */\n\tcontinueIndexing?: boolean;\n\t/**\n\t * For an image-vision file (PDF), the 0-based PAGE the render window should start at.\n\t * The worker renders [renderFrom, renderFrom+RENDER_PAGES_PER_WINDOW) and injects them\n\t * as image blocks; the resume loop advances this by a window each pass.\n\t */\n\trenderFrom?: number;\n};\n\n// RESUME pass: continue indexing a large file a previous pass could not finish. Same\n// dispatch as notifyAgentSaveAttachment, but forced onto the paging path with a\n// \"continue from where the saved records leave off\" message.\nexport async function notifyAgentContinueIndexing(info: AttachmentSaveInfo) {\n\treturn notifyAgentSaveAttachment({ ...info, continueIndexing: true });\n}\n\n// Background \"save into knowledge\" call (not a chat turn). A client-parsed file\n// (parser plugin) is inlined directly; otherwise office files get the\n// _skapi_extract directive + a placeholder, and everything else gets a URL.\nexport async function notifyAgentSaveAttachment(info: AttachmentSaveInfo) {\n\tconst { platform, service, owner, attachment, parsedContent } = info;\n\n\t// A CONTINUE pass resumes a large file that a previous pass could not finish.\n\tconst continuing = !!info.continueIndexing;\n\n\t// Durable run record, minted the moment a run's FIRST pass is enqueued (every\n\t// first-pass site funnels through this function, so one mint covers them all;\n\t// resume passes belong to the existing run and must not touch it). Ordering is\n\t// safe by construction: every caller runs its delete-then-repost + src:: mint\n\t// BEFORE calling here, so the record's `reference: src::<path>` resolves. The\n\t// dispatch promise is tapped below so an enqueue that never reached the queue\n\t// closes the record as an error instead of leaving 'working' dangling.\n\tif (!continuing) {\n\t\tupsertIndexRunRecordSafe(service, attachment.storagePath, {\n\t\t\tstatus: 'working',\n\t\t\tfilename: attachment.name,\n\t\t\tstarted: Date.now(),\n\t\t\tqueue: bgIndexingQueueName(info.userId, service),\n\t\t\tplatform: platform,\n\t\t});\n\t}\n\tconst tapDispatchFailure = (p: Promise<any>): Promise<any> => {\n\t\tif (continuing) return p;\n\t\treturn p.then(\n\t\t\t(ack: any) => ack,\n\t\t\t(err: any) => {\n\t\t\t\tupsertIndexRunRecordSafe(service, attachment.storagePath, {\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tfinished: Date.now(),\n\t\t\t\t\terror: (err && (err.message || String(err))) || 'The indexing request could not be enqueued.',\n\t\t\t\t});\n\t\t\t\tthrow err;\n\t\t\t},\n\t\t);\n\t};\n\n\t// VISION files (PDFs) are delivered as rendered page IMAGES injected into the message by\n\t// the worker (`_skapi_render`), because tool-result images render on neither provider.\n\t// Both the first pass and every resume pass use this; renderFrom advances the page window.\n\tconst visionFile = !parsedContent && isImageVisionFile(attachment.name, attachment.mime);\n\tconst renderFrom = Math.max(0, info.renderFrom || 0);\n\tconst renderPlaceholder = visionFile ? makeRenderPlaceholder(attachment.storagePath) : undefined;\n\t// Tell the worker what image `detail` to stamp on the injected page blocks.\n\t// The worker is model-blind, so without this it applies a one-size default and\n\t// the strongest models never get the 'original' detail they support. Only\n\t// meaningful for OpenAI — Claude has no per-image detail knob and the worker\n\t// ignores the field for it.\n\tconst renderDetail = platform === 'openai'\n\t\t? getRenderImageDetail(info.model || DEFAULT_OPENAI_MODEL)\n\t\t: undefined;\n\t// `auto_continue` + `continue_text` hand the page loop to the WORKER: when its renderer\n\t// reports pages left after this window, it builds the next pass from this template\n\t// (substituting the window's 1-based start page for RENDER_FROM_TOKEN) and enqueues it\n\t// itself. That is what makes a 500-page document index end-to-end — the loop no longer\n\t// depends on the tab staying open, nor on the model correctly declaring itself unfinished.\n\t// Window size and per-page tiling are resolved from the MODEL, not fixed: see\n\t// getVisionProfile. Claude keeps the full window (renderDetail is OpenAI-only, and its\n\t// own resizing behaviour is a separate question this does not try to answer).\n\tconst visionProfile: VisionProfile = platform === 'openai'\n\t\t? getVisionProfile(info.model || DEFAULT_OPENAI_MODEL)\n\t\t: { detail: '', pagesPerWindow: RENDER_PAGES_PER_WINDOW, tile: 1 };\n\tconst skapiRender = visionFile && renderPlaceholder\n\t\t? {\n\t\t\t_skapi_render: [\n\t\t\t\t{\n\t\t\t\t\tpath: attachment.storagePath, from: renderFrom, count: visionProfile.pagesPerWindow,\n\t\t\t\t\tplaceholder: renderPlaceholder, name: attachment.name, mime: attachment.mime, detail: renderDetail,\n\t\t\t\t\ttile: visionProfile.tile,\n\t\t\t\t\tauto_continue: true,\n\t\t\t\t\tcontinue_text: buildIndexingRenderContinueTemplate(attachment, renderPlaceholder),\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t\t: {};\n\n\t// SERVER-DRIVEN windowed read. When enabled, the worker reads one window of the file\n\t// per request and continues from the reader's own cursor until the file is exhausted,\n\t// so the traversal no longer lives inside the model's turn budget.\n\t//\n\t// Flag-gated because the BACKEND MUST SHIP FIRST: against a worker that does not strip\n\t// `_skapi_window`, the directive reaches the provider as an unknown body field and the\n\t// call fails terminally with no retry.\n\tconst windowedRead =\n\t\t!visionFile && !parsedContent && windowedIndexingEnabled() &&\n\t\tisWindowedReadFile(attachment.name, attachment.mime);\n\tconst windowPlaceholder = windowedRead ? makeWindowPlaceholder(attachment.storagePath) : undefined;\n\tconst skapiWindow = windowedRead && windowPlaceholder\n\t\t? {\n\t\t\t_skapi_window: [\n\t\t\t\t{\n\t\t\t\t\tpath: attachment.storagePath,\n\t\t\t\t\tcursor: null,\n\t\t\t\t\tplaceholder: windowPlaceholder,\n\t\t\t\t\tname: attachment.name,\n\t\t\t\t\tmime: attachment.mime,\n\t\t\t\t\tkind: 'window',\n\t\t\t\t\t// Same per-image `detail` the render path sends. Without it the worker falls\n\t\t\t\t\t// back to its model-blind default of 'high', so a spreadsheet's embedded\n\t\t\t\t\t// photos were tiled at lower resolution than the SAME model gets for a PDF\n\t\t\t\t\t// page or a chat attachment. That is why a model could describe an attached\n\t\t\t\t\t// photo but reported the pictures inside a sheet as only partly legible.\n\t\t\t\t\tdetail: renderDetail,\n\t\t\t\t\tauto_continue: true,\n\t\t\t\t\tcontinue_text: buildIndexingWindowMessage(attachment, windowPlaceholder, true),\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t\t: {};\n\n\t// Spreadsheets are read by PAGING through readFileContent (grid rows), NOT inlined - so\n\t// they skip the inline server-extract and the agent is told to page the whole file.\n\tconst pagedRead = !visionFile && !windowedRead && (continuing || (!parsedContent && isPagedReadFile(attachment.name, attachment.mime)));\n\n\t// Client-parsed content wins over server-side extraction.\n\tconst serverExtract = !visionFile && !windowedRead && !continuing && !parsedContent && !pagedRead && isServerExtractable(attachment.name, attachment.mime);\n\tconst placeholder = serverExtract ? makeExtractPlaceholder(attachment.storagePath) : undefined;\n\tconst extractContent: ExtractDirective[] | undefined =\n\t\tserverExtract && placeholder\n\t\t\t? [{ path: attachment.storagePath, placeholder, name: attachment.name, mime: attachment.mime }]\n\t\t\t: undefined;\n\tconst skapiExtract =\n\t\textractContent && extractContent.length\n\t\t\t? {\n\t\t\t\t_skapi_extract: extractContent.map((d) => ({\n\t\t\t\t\t...d,\n\t\t\t\t\t// FIRST pass of an INDEXING run only: tells the worker to also pull the\n\t\t\t\t\t// file's embedded pictures into __MEDIA__ and register their records.\n\t\t\t\t\t// Chat-turn extraction (callClaudeWithMcp / callOpenAIWithPublicMcp)\n\t\t\t\t\t// never sets this, so merely ATTACHING a file to a chat message cannot\n\t\t\t\t\t// write media records; a CONTINUE pass skips it because the first pass\n\t\t\t\t\t// already saved (the save is whole-file, not windowed).\n\t\t\t\t\tsave_media: !continuing,\n\t\t\t\t})),\n\t\t\t}\n\t\t\t: {};\n\n\t// Ask the worker to re-sign this file's url at EXECUTION time.\n\t//\n\t// The url below was minted when the file was uploaded. Indexing for a project\n\t// runs on ONE FIFO group, one pass at a time, so a row queued behind a bulk\n\t// upload can wait hours or days before it fires - by which point that url can\n\t// be dead, the provider's fetch returns nothing, and the file is recorded as\n\t// indexed with an empty index behind it. The worker rebuilds the body from the\n\t// row on every delivery, so re-signing there means the url only has to outlive\n\t// ONE invocation however long the wait was.\n\t//\n\t// Sent for every indexing pass, including CONTINUE passes: a chain spanning\n\t// days is exactly where the baked url is oldest. Harmless where the file's\n\t// content arrives another way (server-side extraction, rendered pages) - the\n\t// url still appears as the attachment link, and a dead link in front of the\n\t// model is worth avoiding either way.\n\tconst skapiFileUrls = attachment.url && attachment.storagePath\n\t\t? { _skapi_file_urls: [{ path: attachment.storagePath, url: attachment.url }] }\n\t\t: {};\n\n\tconst userMessage = (visionFile && renderPlaceholder)\n\t\t? buildIndexingRenderMessage(attachment, renderPlaceholder, renderFrom)\n\t\t: (windowedRead && windowPlaceholder)\n\t\t? buildIndexingWindowMessage(attachment, windowPlaceholder, false)\n\t\t: continuing\n\t\t\t? buildIndexingContinueMessage(attachment)\n\t\t\t: buildIndexingUserMessage(\n\t\t\t\tattachment,\n\t\t\t\tparsedContent\n\t\t\t\t\t? { inlineContent: parsedContent }\n\t\t\t\t\t: placeholder\n\t\t\t\t\t\t? { inlineContentPlaceholder: placeholder }\n\t\t\t\t\t\t: pagedRead\n\t\t\t\t\t\t\t? { pagedRead: true }\n\t\t\t\t\t\t\t: undefined,\n\t\t\t);\n\n\tconst systemPrompt = buildIndexingSystemPrompt({\n\t\t// The model copies this id verbatim into project_id tool calls, so it must be\n\t\t// the PUBLIC token whenever the host supplied one; the raw code is rejected\n\t\t// by the tools' schema pattern.\n\t\tprojectId: info.publicProjectId || service,\n\t\tserviceName: info.serviceName,\n\t\tserviceDescription: info.serviceDescription,\n\t});\n\n\tif (platform === 'openai') {\n\t\tconst resolvedModel = info.model || DEFAULT_OPENAI_MODEL;\n\t\tconst imageDetail = getOpenAIImageDetail(resolvedModel);\n\t\treturn tapDispatchFailure(clientSecretRequest({\n\t\t\tclientSecretName: 'openai',\n\t\t\tqueue: bgIndexingQueueName(info.userId, service),\n\t\t\tservice,\n\t\t\towner,\n\t\t\t...pollOpt(),\n\t\t\turl: OPENAI_RESPONSES_API_URL,\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'content-type': 'application/json',\n\t\t\t\tAuthorization: 'Bearer $CLIENT_SECRET',\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tmodel: resolvedModel,\n\t\t\t\tmax_output_tokens: getMaxOutputTokens('openai', resolvedModel),\n\t\t\t\t// Nano-only transcription knobs. Indexing only; see variantIndexingOptions.\n\t\t\t\t...variantIndexingOptions(resolvedModel),\n\t\t\t\t...skapiExtract,\n\t\t\t\t...skapiRender,\n\t\t\t\t...skapiWindow,\n\t\t\t\t...skapiFileUrls,\n\t\t\t\tinput: [\n\t\t\t\t\t{ role: 'system', content: systemPrompt },\n\t\t\t\t\t{\n\t\t\t\t\t\trole: 'user',\n\t\t\t\t\t\tcontent: transformContentWithOpenAIImages(userMessage, imageDetail),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\ttools: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'mcp',\n\t\t\t\t\t\tserver_label: MCP_NAME,\n\t\t\t\t\t\tserver_url: mcpUrl(),\n\t\t\t\t\t\trequire_approval: 'never',\n\t\t\t\t\t\theaders: { Authorization: 'Bearer $ACCESS_TOKEN' },\n\t\t\t\t\t},\n\t\t\t\t\t...(OPENAI_WEB_SEARCH_ENABLED\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: 'web_search',\n\t\t\t\t\t\t\t\t\texternal_web_access: OPENAI_WEB_SEARCH_EXTERNAL_WEB_ACCESS,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t},\n\t\t}));\n\t}\n\n\tconst resolvedModel = info.model || DEFAULT_CLAUDE_MODEL;\n\treturn tapDispatchFailure(clientSecretRequest({\n\t\tclientSecretName: 'claude',\n\t\tqueue: bgIndexingQueueName(info.userId, service),\n\t\tservice,\n\t\towner,\n\t\t...pollOpt(),\n\t\turl: ANTHROPIC_MESSAGES_API_URL,\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'content-type': 'application/json',\n\t\t\t'x-api-key': '$CLIENT_SECRET',\n\t\t\t'anthropic-version': ANTHROPIC_VERSION,\n\t\t\t'anthropic-beta': ANTHROPIC_BETA_HEADER,\n\t\t},\n\t\tdata: {\n\t\t\tmodel: resolvedModel,\n\t\t\tmax_tokens: getMaxOutputTokens('claude', resolvedModel),\n\t\t\t...skapiExtract,\n\t\t\t...skapiRender,\n\t\t\t...skapiWindow,\n\t\t\t...skapiFileUrls,\n\t\t\tsystem: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\ttext: systemPrompt,\n\t\t\t\t\tcache_control: { type: 'ephemeral' },\n\t\t\t\t},\n\t\t\t],\n\t\t\tmessages: [\n\t\t\t\t{\n\t\t\t\t\trole: 'user',\n\t\t\t\t\tcontent: transformContentWithImages(userMessage),\n\t\t\t\t},\n\t\t\t],\n\t\t\tmcp_servers: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'url',\n\t\t\t\t\tname: MCP_NAME,\n\t\t\t\t\turl: mcpUrl(),\n\t\t\t\t\tauthorization_token: '$ACCESS_TOKEN',\n\t\t\t\t},\n\t\t\t],\n\t\t\ttools: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'mcp_toolset',\n\t\t\t\t\tmcp_server_name: MCP_NAME,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'web_fetch_20250910',\n\t\t\t\t\tname: 'web_fetch',\n\t\t\t\t\tmax_uses: WEB_FETCH_MAX_USES,\n\t\t\t\t\tcitations: { enabled: true },\n\t\t\t\t\tmax_content_tokens: WEB_FETCH_MAX_CONTENT_TOKENS,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t}));\n}\n\nexport function extractClaudeText(response: any) {\n\tif (!Array.isArray(response?.content)) {\n\t\treturn '';\n\t}\n\n\treturn response.content\n\t\t.filter((block: any) => block?.type === 'text')\n\t\t.map((block: any) => block.text)\n\t\t.join('\\n');\n}\n\nexport function extractOpenAIText(response: any) {\n\tif (\n\t\ttypeof response?.output_text === 'string' &&\n\t\tresponse.output_text.length\n\t) {\n\t\treturn response.output_text;\n\t}\n\n\tif (Array.isArray(response?.output)) {\n\t\tconst text = response.output\n\t\t\t.flatMap((item: any) => item?.content || [])\n\t\t\t.filter((part: any) => part?.type === 'output_text')\n\t\t\t.map((part: any) => part.text || '')\n\t\t\t.join('\\n')\n\t\t\t.trim();\n\n\t\tif (text) {\n\t\t\treturn text;\n\t\t}\n\t}\n\n\tconst content = response?.choices?.[0]?.message?.content;\n\n\tif (typeof content === 'string') {\n\t\treturn content;\n\t}\n\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.map((part: any) => {\n\t\t\t\tif (typeof part === 'string') {\n\t\t\t\t\treturn part;\n\t\t\t\t}\n\t\t\t\tif (part?.type === 'text') {\n\t\t\t\t\treturn part.text || '';\n\t\t\t\t}\n\t\t\t\treturn '';\n\t\t\t})\n\t\t\t.join('\\n');\n\t}\n\n\treturn '';\n}\n\nexport async function listClaudeModels(service: string, owner: string) {\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'claude',\n\t\tservice,\n\t\towner,\n\t\turl: ANTHROPIC_MODELS_API_URL,\n\t\tmethod: 'GET',\n\t\theaders: {\n\t\t\t'x-api-key': '$CLIENT_SECRET',\n\t\t\t'anthropic-version': ANTHROPIC_VERSION,\n\t\t},\n\t});\n}\n\nexport async function listOpenAIModels(service: string, owner: string) {\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'openai',\n\t\tservice,\n\t\towner,\n\t\turl: OPENAI_MODELS_API_URL,\n\t\tmethod: 'GET',\n\t\theaders: {\n\t\t\tAuthorization: 'Bearer $CLIENT_SECRET',\n\t\t},\n\t});\n}\n\n// Suffix for the background-indexing queue. Must sort *before* ':' (ASCII 58)\n// so the chat-history BETWEEN query never includes bg-queue items. '-' (45) works.\nexport const BG_INDEXING_QUEUE_SUFFIX = '-bg';\n\n/**\n * unique_id of the durable \"indexing finished\" marker record for a stored file.\n *\n * Written by the BACKEND (the polling worker calls the MCP server's\n * /internal/index-complete at the end of an auto_continue chain whose final\n * window reported no more content) and, for completions a client knows\n * deterministically (single-pass settle, client-chain completion token), by the\n * consumer's mintIndexDoneMarker hook — never by the model.\n * The marker record carries `reference: \"src::<path>\"`, so the reindex flow's\n * delete of the src:: record cascades to it and a re-run starts unmarked.\n *\n * Existence semantics: present = the whole file was read to the end. Absent =\n * unknown (still running, failed partway, indexed before this marker existed,\n * or a single-pass run minted before the client hook existed) - callers must\n * fall back to the live-queue probe (fetchLiveIndexingKeys) before reading\n * absence as anything.\n */\nexport function indexDoneUniqueId(storagePath: string): string {\n\treturn 'done::' + storagePath;\n}\n\n/**\n * unique_id of the per-file indexing RUN record.\n *\n * One record per storage path, newest run wins (a reindex's delete-then-repost\n * of src:: cascade-deletes the old record first, exactly like done::). Minted\n * status='working' by the client the moment it enqueues a run's FIRST pass, and\n * closed (done/error/cancelled) by whichever side observes the ending: the\n * worker via the MCP internal routes for worker-driven chains, the client for\n * deterministic settles, cancels, and dispatch failures. It exists so chat rows\n * and files-page badges can answer \"which runs exist and how did they end\"\n * from ONE records query instead of scanning bg history.\n *\n * A 'working' record is a claim, not proof: a chain that dies without reaching\n * any error path leaves it dangling, so readers must treat a stale 'working'\n * (old `started`, no live-queue confirmation) as unknown, never as live.\n */\nexport function runIndexUniqueId(storagePath: string): string {\n\treturn 'run::' + storagePath;\n}\n\nexport type IndexRunStatus = 'working' | 'done' | 'error' | 'cancelled';\n\nexport type IndexRunPatch = {\n\tstatus: IndexRunStatus;\n\tfilename?: string;\n\tstarted?: number;\n\tfinished?: number;\n\terror?: string;\n\tqueue?: string;\n\t/** Chat that owns this run. A run:: record is keyed by storage path alone,\n\t * but a chat is per (project, platform) — without this the Claude chat's\n\t * runs surfaced as rows in the same project's ChatGPT chat, where their\n\t * passes can never load and the queue probe can never see them. */\n\tplatform?: 'claude' | 'openai';\n};\n\n/**\n * Fire-and-forget wrapper over the consumer's upsertIndexRunRecord hook.\n * Safe everywhere: missing hook, unconfigured engine, and consumer throws all\n * reduce to a no-op — a run record must never be able to break the run itself.\n */\nexport function upsertIndexRunRecordSafe(service: string, storagePath: string, patch: IndexRunPatch): void {\n\tif (!service || !storagePath) return;\n\ttry {\n\t\tconst hook = chatEngineConfig().upsertIndexRunRecord;\n\t\tif (typeof hook !== 'function') return;\n\t\thook({ service, storagePath, patch });\n\t} catch (e) {\n\t\t// best-effort by contract\n\t}\n}\n\n/**\n * The one place the background-indexing queue name is spelled out. The backend\n * serialises requests sharing a queue name and runs different names in PARALLEL,\n * so every indexing pass AND the chat turn that must wait behind them have to\n * resolve to the identical string — see AttachmentSaveInfo.userId for what\n * happens when they do not.\n */\nexport function bgIndexingQueueName(userId?: string, service?: string): string {\n\treturn (userId || service || '') + BG_INDEXING_QUEUE_SUFFIX;\n}\n\n/**\n * True when a request belongs to the background-indexing queue.\n *\n * Accepts BOTH shapes this value arrives in: the bare queue name the client sends\n * (\"<userId>-bg\"), and the server qid that comes back on history/poll responses\n * (\"<service>:<queue>|<seq>\"). Testing the tail of the raw value only works for the\n * first: a qid ends in \"|<seq>\", so `endsWith('-bg')` is always false for it — which\n * silently meant history items were NEVER recognised as background tasks.\n */\nexport function isBgIndexingQueue(queueName?: string): boolean {\n\tif (typeof queueName !== 'string' || !queueName) return false;\n\tconst prefix = queueName.split('|')[0];\n\tconst idx = prefix.lastIndexOf(':');\n\tconst name = idx === -1 ? prefix : prefix.slice(idx + 1);\n\treturn name.slice(-BG_INDEXING_QUEUE_SUFFIX.length) === BG_INDEXING_QUEUE_SUFFIX;\n}\n\n// Pending background-indexing task descriptor. NOTE: the live mutable queue\n// (a Vue `reactive([])` in agent.vue, a plain array in bunnyquery) is app-level\n// state owned by the consumer — only the TYPE lives in the engine.\nexport type BgTaskEntry = {\n\tprojectId: string;\n\tplatform: 'claude' | 'openai';\n\tid: string;\n\tfilename: string;\n\tstoragePath?: string;\n\tisReindex?: boolean;\n\tmime?: string;\n\tsize?: number;\n\tstatus: 'running' | 'pending';\n\tpoll: ((opts: { latency: number }) => Promise<any>) | undefined;\n\t/** How many CONTINUE passes have already run for this file (resume-across-passes). */\n\tresumePass?: number;\n\t/** The STAGED chat turn these files were attached to (ChatSession.stageOutgoingMessage).\n\t * drainBgTaskQueue inserts this pass's bubble directly ABOVE that turn's bubble, so the\n\t * collapsed row sits where the reader expects it — right before the message the files\n\t * came with — from the moment it appears, instead of the turn being moved down past it\n\t * once everything finishes. Absent for work with no chat turn behind it (the dbfile\n\t * page, an attachment-only send, a worker-adopted pass), which appends as before. */\n\tstageId?: string;\n};\n\n// Token the indexing agent appends to its final message ONLY when it has fully read and\n// saved the whole file. Its ABSENCE is what tells the client to run another CONTINUE pass.\n//\n// Applies to the TEXT/GRID paging path only. The vision path (rendered PDF pages) no longer\n// asks the model whether it is finished — the worker advances that loop off the renderer's\n// page count — so this marker has no say in whether a PDF keeps going.\nexport const INDEXING_COMPLETE_MARKER = 'INDEXING_COMPLETE';\n// What an indexing pass's bubble says when its ENTIRE answer was the completion\n// token and stripping it left nothing. Without a stand-in the history mappers emit\n// no bubble at all for that pass (their `else if (assistantText)` guard fails on the\n// empty string) while the live path emits one — so the same run read as finished\n// live and unfinished after a reload, and the row's loader came back.\nexport const EMPTY_INDEXING_REPLY = 'Finished reading this file.';\n// Cap on CONTINUE passes per file, so a file the agent can never mark complete (or a\n// pathological loop) stops instead of re-dispatching forever. The text/grid paging path\n// reads MANY windows within a single pass (the agent loops readFileContent in one turn), so\n// a small cap suffices.\nexport const MAX_INDEXING_RESUME_PASSES = 6;\n\n// Records per chat-history page. Bigger than skapi's own default so the first load\n// (and each scroll-up page) covers more of the conversation in one round-trip — a\n// short page leaves the box unfilled and forces the viewport-fill loop to page\n// again immediately. Callers that want a narrower page (the queue/status probes in\n// ChatSession) pass their own `limit`, which wins over this default.\n// 500, up from 100: an indexing run is dozens of rows that collapse into ONE visible\n// row, so a screenful of history behind a few indexed files took 5+ sequential\n// round trips to assemble (cursor paging cannot be parallelised - each page's\n// startKey comes from the previous response). The number is a CAP, not a payload\n// size: DynamoDB stops a page at 1MB regardless and hands back a cursor, and the\n// backend passes the limit through without looping, so heavy indexing rows page at\n// the same bytes per trip as before while light chat rows now arrive 500 at a time.\nexport const CHAT_HISTORY_PAGE_LIMIT = 500;\n\n/**\n * `queue` narrows the fetch to one processing chain; `status` narrows it to items\n * in one state. Passing both is how the client asks \"is there still unresolved\n * work on the background-indexing queue?\" without pulling a page of chat history\n * (see ChatSession._adoptWorkerIndexingPasses) — the server answers that from a\n * status-keyed index, so the reply carries only the live items, not the bodies of\n * everything already finished.\n */\nexport async function getChatHistory(\n\tparams: {\n\t\tservice?: string; owner?: string; platform: 'claude' | 'openai'; queue?: string;\n\t\tstatus?: 'pending' | 'running' | 'resolved' | 'failed';\n\t\t/** Exact-queue listing: without it the qid range is a PREFIX match, so\n\t\t * queue \"u1\" also returns \"u1-bg\" rows. Requires the updated polling\n\t\t * lambda; older backends ignore it (harmless, wider results). */\n\t\tqueue_exact?: boolean;\n\t\t/** Label/marker STUBS instead of full bodies (see the polling lambda).\n\t\t * Older backends ignore it and return full items. */\n\t\tcompact?: boolean;\n\t\t/** Drop one queue's rows from an id-prefix listing — how the surface\n\t\t * chat is fetched WITHOUT the bg-indexing queue while legacy items on\n\t\t * odd queue names survive. Older backends ignore it. */\n\t\tqueue_exclude?: string;\n\t},\n\tfetchOptions: Record<string, any>,\n) {\n\tconst url =\n\t\tparams.platform === 'claude'\n\t\t\t? ANTHROPIC_MESSAGES_API_URL\n\t\t\t: OPENAI_RESPONSES_API_URL;\n\tconst p = Object.assign(\n\t\t{\n\t\t\turl,\n\t\t\tmethod: 'POST',\n\t\t},\n\t\t{ service: params.service, owner: params.owner },\n\t\tparams.queue ? { queue: params.queue } : {},\n\t\tparams.status ? { status: params.status } : {},\n\t\tparams.queue_exact ? { queue_exact: true } : {},\n\t\tparams.compact ? { compact: true } : {},\n\t\tparams.queue_exclude ? { queue_exclude: params.queue_exclude } : {},\n\t);\n\n\treturn chatEngineConfig().clientSecretRequestHistory(\n\t\tp as { url: string; method: 'POST'; queue?: string; status?: string },\n\t\tObject.assign({ ascending: false, limit: CHAT_HISTORY_PAGE_LIMIT }, fetchOptions),\n\t);\n}\n\n/** Full server-side id of one history item, for a csr-poll POINT LOOKUP (the\n * single-item path returns the item WITH bodies — how an expanded row fetches\n * the passes a compact listing stubbed out). Mirrors the id the SDK builds:\n * `[METHOD]url#service:` + the item's own `stamp:entropy` id. */\nexport function buildHistoryItemFullId(platform: 'claude' | 'openai', service: string, itemId: string): string {\n\tconst url = platform === 'claude' ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;\n\treturn `[POST]${url.toLowerCase()}#${service}:${itemId}`;\n}\n","/**\n * History mapping (pure). Moved verbatim from the chatbox. The clear-horizon\n * timestamp and the \"Indexing: …\" display label are INJECTED (clearedAt param,\n * formatIndexingLabel callback) so the engine touches neither localStorage nor\n * view-specific display formatting. projectId is passed for link sanitization.\n */\nimport { extractClaudeText, extractOpenAIText, INDEXING_COMPLETE_MARKER, EMPTY_INDEXING_REPLY, getChatHistory, bgIndexingQueueName } from './requests';\nimport { isErrorResponseBody, getErrorMessage } from './errors';\nimport { sanitizeAttachmentLinksForHistory } from './links';\nimport type { ChatMessage } from './host';\n\nexport function filterListByClearHorizon(list: any[], clearedAt: number): any[] {\n\tif (!clearedAt) return list;\n\treturn list.filter(function (item) {\n\t\tvar updated = Number(item && item.updated);\n\t\treturn isFinite(updated) && updated > clearedAt;\n\t});\n}\n\nexport function normalizeTextContent(content: any): string {\n\tif (typeof content === 'string') return content;\n\tif (Array.isArray(content)) {\n\t\treturn content.map(function (part: any) {\n\t\t\tif (typeof part === 'string') return part;\n\t\t\tif (part && (part.type === 'text' || part.type === 'input_text' || part.type === 'output_text')) return part.text || '';\n\t\t\treturn '';\n\t\t}).join('\\n').trim();\n\t}\n\treturn '';\n}\n\nexport function extractLastUserTextFromRequest(requestBody: any): string {\n\tvar arr = requestBody && Array.isArray(requestBody.messages) ? requestBody.messages\n\t\t: (requestBody && Array.isArray(requestBody.input) ? requestBody.input : []);\n\tfor (var i = arr.length - 1; i >= 0; i--) {\n\t\tif (arr[i] && arr[i].role === 'user') {\n\t\t\tvar t = normalizeTextContent(arr[i].content);\n\t\t\tif (t) return t;\n\t\t}\n\t}\n\treturn '';\n}\n\n/** The two openings an indexing prompt can have. A bg-queue item that starts with\n * neither is an ordinary chat that happened to be routed onto that queue. */\nexport function isIndexingRequestText(userText: any): boolean {\n\tif (typeof userText !== 'string') return false;\n\treturn userText.indexOf('A new file has just been uploaded') === 0 || userText.indexOf('CONTINUE indexing') === 0;\n}\n\nexport type IndexingRequestRef = {\n\tname: string;\n\tpath?: string;\n\tmime?: string;\n\tsize?: number;\n\t/** A CONTINUE pass rather than the run's first. */\n\tcontinued: boolean;\n};\n\n/**\n * The file an indexing prompt is about, read back out of the prompt itself.\n *\n * The prompt is the only description of the pass that survives on the server, so\n * this is how BOTH a history rebuild and a worker-minted pass the client never\n * dispatched (ChatSession._adoptWorkerIndexingPasses) recover the file. Shared so\n * the two produce the same `_indexFile`, which is what makes them group together.\n */\nexport function parseIndexingRequestText(userText: any): IndexingRequestRef | null {\n\tif (typeof userText !== 'string' || !userText) return null;\n\tvar nameMatch = userText.match(/^- name: (.+)$/m);\n\tif (!nameMatch) return null;\n\tvar mimeMatch = userText.match(/^- mime type: (.+)$/m);\n\tvar sizeMatch = userText.match(/^- size \\(bytes\\): (\\d+)$/m);\n\tvar pathMatch = userText.match(/^- storage path: (.+)$/m);\n\treturn {\n\t\tname: nameMatch[1].trim(),\n\t\tpath: pathMatch ? pathMatch[1].trim() : undefined,\n\t\tmime: mimeMatch ? mimeMatch[1].trim() : undefined,\n\t\tsize: sizeMatch ? Number(sizeMatch[1]) : undefined,\n\t\tcontinued: userText.indexOf('CONTINUE indexing') === 0,\n\t};\n}\n\n// One page of the status probe below. Matches ChatSession's own\n// WORKER_PASS_ADOPT_LIMIT: the queue holds one live pass per file (plus a\n// handful pending), so a FULL page means the answer may be incomplete and the\n// probe reports checked=false rather than letting a miss read as \"finished\".\nconst LIVE_INDEX_PROBE_LIMIT = 20;\n\n// ─── Shared bg-queue probe (write-through memo) ──────────────────────────────\n// The SAME two queries — getChatHistory({queue, status: 'pending'|'running'})\n// — are fired by four independent callers: the session's live-index snapshot,\n// its worker-pass adoption ladder, its drain wait, and fetchLiveIndexingKeys\n// (the db-files page's badge probe). Navigating chat → files re-asked the queue\n// the chat had answered seconds earlier.\n//\n// This memo dedupes them WITHOUT weakening anyone's evidence:\n// • progress loops (adopt ladder, drain wait) call with maxAgeMs 0 — they\n// always fetch fresh, because their whole point is to observe a CHANGE —\n// but their answers write through into the memo;\n// • snapshot readers pass a maxAge and reuse a young answer.\n// Every entry carries `at`, the time the underlying fetch actually ran. A\n// caller that needs two INDEPENDENT looks (dbfile's green-confirm ladder) must\n// compare `at`, never its own receipt time: a memo re-serve has the same `at`\n// and therefore counts as the single look it really is.\nexport const BG_PROBE_TTL_MS = 4000;\ntype BgProbeEntry = { result: any; at: number };\nconst bgProbeCache: { [key: string]: BgProbeEntry } = {};\nconst bgProbeInflight: { [key: string]: Promise<BgProbeEntry> } = {};\n\nexport function probeBgQueue(\n\tparams: {\n\t\tservice: string;\n\t\towner: string;\n\t\tplatform: 'claude' | 'openai';\n\t\tqueue: string;\n\t\tstatus: 'pending' | 'running';\n\t\tlimit: number;\n\t},\n\topts?: { maxAgeMs?: number },\n): Promise<BgProbeEntry> {\n\tconst key = [params.service, params.owner, params.platform, params.queue, params.status, params.limit].join('|');\n\tconst maxAge = opts && typeof opts.maxAgeMs === 'number' ? opts.maxAgeMs : 0;\n\tconst cached = bgProbeCache[key];\n\tif (maxAge > 0 && cached && Date.now() - cached.at < maxAge) {\n\t\treturn Promise.resolve(cached);\n\t}\n\tconst inflight = bgProbeInflight[key];\n\tif (inflight) return inflight;\n\tconst p = Promise.resolve(getChatHistory(\n\t\t{ service: params.service, owner: params.owner, platform: params.platform, queue: params.queue, status: params.status },\n\t\t{ limit: params.limit, fetchMore: false },\n\t)).then(function (result: any) {\n\t\tconst entry: BgProbeEntry = { result: result, at: Date.now() };\n\t\tbgProbeCache[key] = entry;\n\t\treturn entry;\n\t});\n\tbgProbeInflight[key] = p;\n\t// Clear the in-flight slot on either outcome; failures are NOT cached.\n\tp.then(function () { delete bgProbeInflight[key]; }, function () { delete bgProbeInflight[key]; });\n\treturn p;\n}\n\n/**\n * One bounded look at the background-indexing queue: which files still have a\n * pass pending or running? This is the same negative signal ChatSession's\n * display layer relies on - for a worker-driven (auto_continue) run, only the\n * queue can say the run is over, because the worker enqueues continuation\n * passes the client never dispatched.\n *\n * Returns every storage path AND file name found on live passes (both, because\n * older prompts may lack the storage-path line), plus `checked`: false when a\n * page came back full, in which case absence from `keys` proves nothing and\n * the caller must keep whatever state it already had.\n *\n * SCOPE: the probed queue is \"<userId>-bg\" - THIS user's dispatches only. A\n * chain launched by another collaborator or a widget end-user lives on their\n * queue and is invisible here, so \"idle\" must never be read as \"nobody is\n * indexing this file\", only as \"this user's runs are over\". The durable done::\n * marker (indexDoneUniqueId) is the cross-user signal.\n */\nexport async function fetchLiveIndexingKeys(params: {\n\tservice: string;\n\towner: string;\n\tplatform: 'claude' | 'openai';\n\t/** Same value the dispatch used - see bgIndexingQueueName. */\n\tuserId?: string;\n}): Promise<{ keys: Set<string>; checked: boolean; at: number }> {\n\tconst queue = bgIndexingQueueName(params.userId, params.service);\n\tconst base = { service: params.service, owner: params.owner, platform: params.platform, queue };\n\tconst [pending, running] = await Promise.all([\n\t\tprobeBgQueue({ ...base, status: 'pending', limit: LIVE_INDEX_PROBE_LIMIT }, { maxAgeMs: BG_PROBE_TTL_MS }),\n\t\tprobeBgQueue({ ...base, status: 'running', limit: LIVE_INDEX_PROBE_LIMIT }, { maxAgeMs: BG_PROBE_TTL_MS }),\n\t]);\n\tconst keys = new Set<string>();\n\tlet truncated = false;\n\tfor (const entry of [pending, running]) {\n\t\tconst res = entry.result;\n\t\tconst list: any[] = (res && Array.isArray((res as any).list)) ? (res as any).list : [];\n\t\tif (list.length >= LIVE_INDEX_PROBE_LIMIT) truncated = true;\n\t\tfor (const item of list) {\n\t\t\tconst text = extractLastUserTextFromRequest(item && item.request_body);\n\t\t\tif (!text || !isIndexingRequestText(text)) continue;\n\t\t\tconst ref = parseIndexingRequestText(text);\n\t\t\tif (!ref) continue;\n\t\t\tif (ref.path) keys.add(ref.path);\n\t\t\tif (ref.name) keys.add(ref.name);\n\t\t}\n\t}\n\t// `at` = when the OLDER of the two underlying fetches ran. Consumers that\n\t// need two independent looks (dbfile's green ladder) key on this, so a\n\t// memo re-serve is correctly seen as the same single look.\n\treturn { keys, checked: !truncated, at: Math.min(pending.at, running.at) };\n}\n\n// ─── Split history fetch ─────────────────────────────────────────────────────\n// One conversation, two queues: ordinary chat lives on the user's queue (or a\n// legacy/random one), indexing passes on \"<userId>-bg\" — whose stored request\n// bodies carry whole file windows and dominated every history page. The split\n// fetches the SURFACE (id-prefix listing minus the bg queue, full bodies) and\n// the BG queue (exact, compact stubs — the lambda stubs ONLY indexing-shaped\n// items, ordinary chats deferred onto the bg queue keep full bodies) and\n// returns a getChatHistory-shaped page.\n//\n// This is v2, redesigned around the 2026-08-11 review findings:\n// • The SDK ignores explicit fetchOptions.startKeyHistory — paging rides its\n// internal per-params-hash cursors. So ALL split state lives HERE, module-\n// level, keyed by (service|owner|platform|userId): the bg overflow buffer,\n// the undelivered surface page, end flags. Callers keep echoing\n// startKeyHistory opaquely; it is bookkeeping only, on both sides.\n// • Pages TILE exactly: each page emits only items at-or-newer-than the\n// surface page's oldest item (the boundary); bg items older than that are\n// BUFFERED for the next page. Consumers' raw prepend, retainedOlder\n// pruning and clear-horizon early-end all rely on this invariant.\n// • Retry-safe: the fetched surface page is held as pendingSurface until the\n// merged page is actually returned, and every bg page lands in the buffer\n// the moment it arrives — a mid-call failure + caller retry resumes with\n// nothing skipped (the SDK's internal cursors have already advanced; the\n// state carries what they advanced past).\n// • Empty-but-not-end pages are eliminated SERVER-side (the lambda re-queries\n// past fully-filtered windows). A defensive client cap remains.\n//\n// Backwards-safe: an old backend ignores queue_exclude/compact — the surface\n// then includes bg items with bodies (exactly today's single fetch), the bg\n// call returns duplicates, and dedup-by-id (surface wins) degrades to current\n// behavior plus one redundant query, never to data loss.\n// Per-call bg fetches. Depth is LAZY: the consumers merge prepended pages by\n// timestamp, so older stubs can arrive on any later page and still land at\n// their true position — there is no need to drain the bg queue eagerly, and\n// doing so is exactly what made first paint slow (bg windows are ~1MB of RAW\n// rows, i.e. a handful of stubs per round trip). Two fetches keep the nearby\n// stubs in the same paint; scroll-up/viewport-fill pages pull the rest.\nconst BG_COVERAGE_MAX_PAGES = 2;\n\ntype SplitHistoryState = {\n\t/** Fetched bg items not yet emitted (older than the last page's boundary). */\n\tbgBuffer: any[];\n\tbgEnd: boolean;\n\t/** Whether the bg chain has fetched at least once (first call resets the\n\t * SDK's internal bg cursor with fetchMore:false; later calls continue). */\n\tbgStarted: boolean;\n\tsurfaceEnd: boolean;\n\t/** Surface page fetched but not yet delivered in a returned merged page —\n\t * reused on retry so the SDK's advanced cursor cannot skip it. Stamped\n\t * with the fetchMore mode it was fetched under: a page-1 fetch abandoned\n\t * mid-coverage must never be replayed as an OLDER page (or vice versa). */\n\tpendingSurface: { list: any[]; endOfList: boolean; startKeyHistory: any[]; forFetchMore: boolean } | null;\n\t/** Surface items fetched but HELD BACK because the bg coverage loop's hop\n\t * cap fired before the bg side reached this page's boundary: emitting\n\t * them would let the uncovered bg stubs land on a LATER page above\n\t * strictly-newer surface turns. Prepended to the next page's surface. */\n\tsurfaceCarry: any[];\n\tlastSurfaceKeys: any[];\n\t/** Newest bg item id this chain has ever seen. The head refresh compares it\n\t * against the fresh head page: a FULL head page that no longer contains it\n\t * means more than one page of bg rows landed while nobody was polling, and\n\t * the walk must reopen or the gap is unfetchable forever. */\n\tnewestBgId: string;\n};\nconst splitHistoryStates: { [key: string]: SplitHistoryState } = {};\n// Per-key serialization: a token-bumped reload can start a NEW split call\n// while an old one is mid-flight, and both would interleave on the SDK's\n// shared internal cursor chains (silently skipping pages). The newcomer waits\n// for the incumbent to settle; its stale result is discarded by the callers'\n// own token guards, and the newcomer's fetchMore:false reset then starts from\n// a clean chain.\nconst splitHistoryLocks: { [key: string]: Promise<void> } = {};\n\nfunction freshSplitState(): SplitHistoryState {\n\treturn { bgBuffer: [], bgEnd: false, bgStarted: false, surfaceEnd: false, pendingSurface: null, surfaceCarry: [], lastSurfaceKeys: [], newestBgId: '' };\n}\n\n/** Track the newest bg id the chain has seen (ids are creation-ordered). */\nfunction noteBgIds(state: SplitHistoryState, list: any[]): void {\n\tfor (const it of list) {\n\t\tconst id = it && typeof it.id === 'string' ? it.id : '';\n\t\tif (id && id > state.newestBgId) state.newestBgId = id;\n\t}\n}\n\n/** Test hook: drop split-fetch state (all keys, or one). */\nexport function __resetSplitHistoryState(key?: string): void {\n\tif (key !== undefined) { delete splitHistoryStates[key]; delete splitHistoryLocks[key]; return; }\n\tfor (const k in splitHistoryStates) delete splitHistoryStates[k];\n\tfor (const k in splitHistoryLocks) delete splitHistoryLocks[k];\n}\n\nconst createdOf = (it: any): number => {\n\tconst c = Number(it && it.created);\n\treturn isFinite(c) && c > 0 ? c : NaN;\n};\nconst oldestCreated = (lst: any[]): number => {\n\tlet m = Infinity;\n\tfor (const it of lst) {\n\t\tconst c = createdOf(it);\n\t\tif (!isNaN(c) && c < m) m = c;\n\t}\n\treturn m; // Infinity when no item carries a usable timestamp\n};\n\n// A pure-bg band can outlast the LAMBDA's own re-query cap (its raw windows\n// are 1MB and inline indexing bodies run to ~300KB, so one lambda call may\n// cross only a few dozen rows) — so the client must ALSO loop past\n// empty-but-not-end surface pages, or the fill loops upstream read them as\n// exhausted and strand older history (and an empty page 1 would blank the\n// chat). Each hop here is one more lambda call.\nconst SURFACE_EMPTY_MAX_PAGES = 10;\n\nexport type SplitHistoryResult = {\n\tlist: any[];\n\tendOfList: boolean;\n\tstartKeyHistory: any[];\n\t/** True when this chat had never been walked in this session — the first\n\t * paint. Consumers gate the \"Loading indexing history\" hint on it: a\n\t * mid-walk tab return restarts the walk for cursor safety but must stay\n\t * silent (flashing the hint on every return was the reported bug). */\n\tfirstLoad?: boolean;\n\t/** Present only when `deferBg` was requested AND bg work remains: resolves\n\t * with the stub batch fetched in the background (the per-key lock is held\n\t * until it settles, so no other history call can interleave). The caller\n\t * merges the batch by timestamp — the same path older pages use. */\n\tbgPending?: Promise<{ list: any[]; endOfList: boolean }>;\n};\n\nexport async function getSplitChatHistory(\n\tparams: { service: string; owner: string; platform: 'claude' | 'openai'; userId?: string },\n\tfetchOptions: Record<string, any>,\n\t/** Test seam: replaces getChatHistory. Not for production callers. */\n\t_fetchImpl?: typeof getChatHistory,\n): Promise<SplitHistoryResult> {\n\tconst key = [params.service, params.owner, params.platform, params.userId || ''].join('|');\n\tconst prev = splitHistoryLocks[key] || Promise.resolve();\n\t// The lock resolves when the WHOLE call — including a deferred bg batch —\n\t// has settled, so queued calls never interleave with background work. A\n\t// call that returns WITHOUT a bgPending (or throws) releases immediately;\n\t// a deferred call releases in the bg batch's own finally.\n\tlet releaseLock: () => void;\n\tconst lockTail = new Promise<void>((r) => { releaseLock = r; });\n\tconst run = () => _getSplitChatHistoryLocked(key, params, fetchOptions, releaseLock!, _fetchImpl);\n\tconst p = prev.then(run, run);\n\tp.then((res: any) => { if (!res || !res.bgPending) releaseLock(); }, () => releaseLock());\n\tsplitHistoryLocks[key] = p.then(() => lockTail, () => lockTail);\n\treturn p;\n}\n\nasync function _getSplitChatHistoryLocked(\n\tkey: string,\n\tparams: { service: string; owner: string; platform: 'claude' | 'openai'; userId?: string },\n\tfetchOptions: Record<string, any>,\n\treleaseLock: () => void,\n\t_fetchImpl?: typeof getChatHistory,\n): Promise<SplitHistoryResult> {\n\tconst fetch = _fetchImpl || getChatHistory;\n\tconst bgQueue = bgIndexingQueueName(params.userId, params.service);\n\tconst base = { service: params.service, owner: params.owner, platform: params.platform };\n\tconst fetchMore = !!(fetchOptions && fetchOptions.fetchMore);\n\tconst limit = fetchOptions && fetchOptions.limit;\n\n\t// HEAD refresh: a repeat first-page call on a chain that already walked BOTH\n\t// queues to their end (tab return, poll-side page-1 refresh). Page 1 must be\n\t// re-fetched for new settles, but what the chain LEARNED about the older\n\t// tail — \"all history fetched\" — survives. Wiping it here was the tab-return\n\t// bug: every return re-pulled the bg stub pages from scratch, reported\n\t// endOfList false, and that un-gated the viewport fill into re-walking every\n\t// older page the user had already exhausted. Only a FULLY-ended chain is\n\t// safe to preserve: its fetchMore path short-circuits without touching the\n\t// SDK cursors this page-1 refresh rewinds. A mid-walk chain still restarts.\n\t// True when this chat has never been walked in this session at all — the\n\t// consumers gate the \"Loading indexing history\" hint on it, so a mid-walk\n\t// tab return (which restarts the walk for cursor safety) stays SILENT.\n\tconst firstLoad = !splitHistoryStates[key];\n\tlet headRefresh = false;\n\tif (!splitHistoryStates[key]) {\n\t\tsplitHistoryStates[key] = freshSplitState();\n\t} else if (!fetchMore) {\n\t\tconst prev = splitHistoryStates[key];\n\t\tif (prev.surfaceEnd && prev.bgEnd) {\n\t\t\theadRefresh = true;\n\t\t\tprev.pendingSurface = null;\n\t\t\tprev.surfaceCarry = [];\n\t\t\tprev.bgBuffer = []; // fully drained by construction; defensive\n\t\t} else {\n\t\t\t// Mid-walk chain: the page-1 refresh genuinely restarts the walk\n\t\t\t// (the underlying fetchMore:false calls below reset the SDK's own\n\t\t\t// cursors to match), exactly as before.\n\t\t\tsplitHistoryStates[key] = freshSplitState();\n\t\t}\n\t}\n\tconst state = splitHistoryStates[key];\n\n\t// A held page fetched under the OTHER mode is not this call's page —\n\t// discard it rather than replay page 1 as an \"older\" page (or vice versa).\n\tif (state.pendingSurface && state.pendingSurface.forFetchMore !== fetchMore) {\n\t\tstate.pendingSurface = null;\n\t}\n\n\t// ── surface page ────────────────────────────────────────────────────────\n\tif (!state.pendingSurface) {\n\t\t// The ended-chain short-circuit serves FETCHMORE only: a head refresh\n\t\t// re-fetches page 1 for real (new settles live there), and the\n\t\t// preserved surfaceEnd keeps every later fetchMore off the wire.\n\t\tif (state.surfaceEnd && !headRefresh) {\n\t\t\tstate.pendingSurface = { list: [], endOfList: true, startKeyHistory: state.lastSurfaceKeys, forFetchMore: fetchMore };\n\t\t} else {\n\t\t\tconst sOpts: any = { fetchMore };\n\t\t\tif (limit) sOpts.limit = limit;\n\t\t\tlet s = await fetch({ ...base, queue_exclude: bgQueue }, sOpts);\n\t\t\t// Loop past empty-but-not-end pages (see SURFACE_EMPTY_MAX_PAGES).\n\t\t\tlet hops = 0;\n\t\t\twhile (s && !s.endOfList && !((s.list || []).length) && hops < SURFACE_EMPTY_MAX_PAGES) {\n\t\t\t\thops++;\n\t\t\t\tconst nOpts: any = { fetchMore: true };\n\t\t\t\tif (limit) nOpts.limit = limit;\n\t\t\t\ts = await fetch({ ...base, queue_exclude: bgQueue }, nOpts);\n\t\t\t}\n\t\t\tstate.pendingSurface = {\n\t\t\t\tlist: (s && Array.isArray(s.list)) ? s.list : [],\n\t\t\t\tendOfList: !!(s && s.endOfList),\n\t\t\t\tstartKeyHistory: (s && Array.isArray(s.startKeyHistory)) ? s.startKeyHistory : [],\n\t\t\t\tforFetchMore: fetchMore,\n\t\t\t};\n\t\t}\n\t}\n\tconst surface = state.pendingSurface;\n\n\t// ── deferred bg (first-paint mode) ──────────────────────────────────────\n\t// The caller paints the CONVERSATION from this return immediately; the\n\t// stub fetch happens behind the resolved promise, under the same lock.\n\t// Anything already buffered ships now (it costs nothing).\n\tif (fetchOptions && fetchOptions.deferBg && (!state.bgEnd || headRefresh)) {\n\t\tconst surfaceList0 = state.surfaceCarry.length ? state.surfaceCarry.concat(surface.list) : surface.list.slice();\n\t\tstate.surfaceCarry = [];\n\t\tconst emitNow: any[] = surfaceList0.concat(state.bgBuffer);\n\t\tstate.bgBuffer = [];\n\t\t// A head refresh must not let page 1's \"more pages exist\" clobber the\n\t\t// preserved end-knowledge: those pages are the tail already walked.\n\t\tif (!headRefresh) state.surfaceEnd = surface.endOfList;\n\t\tstate.lastSurfaceKeys = surface.startKeyHistory;\n\t\tstate.pendingSurface = null;\n\t\tconst bgPending = (async () => {\n\t\t\ttry {\n\t\t\t\tconst batch: any[] = [];\n\t\t\t\tif (headRefresh) {\n\t\t\t\t\t// One HEAD page only: the walked tail is complete; this\n\t\t\t\t\t// catches bg rows that settled/minted while nobody was\n\t\t\t\t\t// polling. bgEnd/bgStarted are normally left alone — the\n\t\t\t\t\t// end-knowledge survives, and the coverage loop (gated on\n\t\t\t\t\t// !bgEnd) never touches the cursor this rewinds. ONE\n\t\t\t\t\t// exception: a FULL head page that no longer contains the\n\t\t\t\t\t// newest bg id this chain had seen means more than a page\n\t\t\t\t\t// of bg rows landed while hidden — the gap is unreachable\n\t\t\t\t\t// unless the walk reopens (id-dedup makes re-walking the\n\t\t\t\t\t// tail harmless).\n\t\t\t\t\tconst bOpts: any = { fetchMore: false };\n\t\t\t\t\tif (limit) bOpts.limit = limit;\n\t\t\t\t\tconst b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);\n\t\t\t\t\tconst bList: any[] = (b && Array.isArray(b.list)) ? b.list : [];\n\t\t\t\t\tfor (const it of bList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; batch.push(it); }\n\t\t\t\t\tconst prevNewest = state.newestBgId;\n\t\t\t\t\tnoteBgIds(state, bList);\n\t\t\t\t\tif (prevNewest && !(b && b.endOfList) &&\n\t\t\t\t\t\t!bList.some((it: any) => it && it.id === prevNewest)) {\n\t\t\t\t\t\tstate.bgEnd = false;\n\t\t\t\t\t\tstate.bgStarted = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlet hops = 0;\n\t\t\t\t\twhile (!state.bgEnd && hops < BG_COVERAGE_MAX_PAGES) {\n\t\t\t\t\t\thops++;\n\t\t\t\t\t\tconst bOpts: any = { fetchMore: state.bgStarted };\n\t\t\t\t\t\tif (limit) bOpts.limit = limit;\n\t\t\t\t\t\tconst b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);\n\t\t\t\t\t\tstate.bgStarted = true;\n\t\t\t\t\t\tconst bList: any[] = (b && Array.isArray(b.list)) ? b.list : [];\n\t\t\t\t\t\tfor (const it of bList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; batch.push(it); }\n\t\t\t\t\t\tnoteBgIds(state, bList);\n\t\t\t\t\t\tstate.bgEnd = !!(b && b.endOfList);\n\t\t\t\t\t\tif (!bList.length && !state.bgEnd) break;\n\t\t\t\t\t\tif (state.bgEnd) break;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { list: batch, endOfList: state.surfaceEnd && state.bgEnd };\n\t\t\t} finally {\n\t\t\t\treleaseLock();\n\t\t\t}\n\t\t})();\n\t\treturn {\n\t\t\tlist: emitNow,\n\t\t\t// A head-refreshed ended chain KNOWS it is still ended — reporting\n\t\t\t// the hardcoded false here was what un-gated the fill loop on every\n\t\t\t// tab return. Mid-walk it computes to false exactly as before (this\n\t\t\t// branch is only entered with bgEnd false then); the bg batch still\n\t\t\t// carries the final word for that case.\n\t\t\tendOfList: state.surfaceEnd && state.bgEnd,\n\t\t\tstartKeyHistory: surface.startKeyHistory,\n\t\t\tfirstLoad,\n\t\t\tbgPending,\n\t\t};\n\t}\n\n\t// Carried-over surface items (held back by an uncovered boundary on the\n\t// previous page) lead this page's surface list.\n\tconst surfaceList = state.surfaceCarry.length ? state.surfaceCarry.concat(surface.list) : surface.list.slice();\n\n\t// The tiling line: everything at-or-newer than this is emitted now, older\n\t// bg items wait in the buffer. A finished surface (endOfList) opens the\n\t// line all the way (-Infinity) so the bg side drains over the next pages.\n\t// An empty surface page past the loop above (a pathological pure-bg band\n\t// beyond both the lambda's and our own hop caps) yields Infinity — no bg\n\t// drain, an empty page, and the consumers' empty-page guards take over.\n\tconst boundary = surface.endOfList ? -Infinity : oldestCreated(surfaceList);\n\n\t// ── bg coverage ─────────────────────────────────────────────────────────\n\tif (headRefresh) {\n\t\t// Non-deferred head refresh: the same single HEAD page the deferred\n\t\t// branch fetches, under the same rules — new settles are caught, the\n\t\t// end-knowledge (bgEnd/bgStarted) is left untouched, EXCEPT when a full\n\t\t// head page no longer contains the newest bg id this chain had seen:\n\t\t// more than a page landed while hidden, and the walk must reopen or the\n\t\t// gap is unfetchable (id-dedup makes re-walking the tail harmless).\n\t\tconst hOpts: any = { fetchMore: false };\n\t\tif (limit) hOpts.limit = limit;\n\t\tconst hb = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, hOpts);\n\t\tconst hbList: any[] = (hb && Array.isArray(hb.list)) ? hb.list : [];\n\t\tfor (const it of hbList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; state.bgBuffer.push(it); }\n\t\tconst prevNewestH = state.newestBgId;\n\t\tnoteBgIds(state, hbList);\n\t\tif (prevNewestH && !(hb && hb.endOfList) &&\n\t\t\t!hbList.some((it: any) => it && it.id === prevNewestH)) {\n\t\t\tstate.bgEnd = false;\n\t\t\tstate.bgStarted = true;\n\t\t}\n\t} else if (boundary !== Infinity || surface.endOfList) {\n\t\tlet hops = 0;\n\t\twhile (!state.bgEnd && hops < BG_COVERAGE_MAX_PAGES) {\n\t\t\tconst bufOldest = state.bgBuffer.length ? oldestCreated(state.bgBuffer) : Infinity;\n\t\t\tif (state.bgBuffer.length && bufOldest <= boundary) break;\n\t\t\thops++;\n\t\t\tconst bOpts: any = { fetchMore: state.bgStarted };\n\t\t\tif (limit) bOpts.limit = limit;\n\t\t\tconst b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);\n\t\t\tstate.bgStarted = true;\n\t\t\tconst bList: any[] = (b && Array.isArray(b.list)) ? b.list : [];\n\t\t\t// Buffer IMMEDIATELY: the SDK cursor has advanced; this is what a\n\t\t\t// retry resumes from. Tagged as bg-chain items so the consumers'\n\t\t\t// surface-frontier logic (retention boundary, clear-horizon) can\n\t\t\t// tell deep stubs from the conversation's own paging frontier.\n\t\t\tfor (const it of bList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; state.bgBuffer.push(it); }\n\t\t\tnoteBgIds(state, bList);\n\t\t\tstate.bgEnd = !!(b && b.endOfList);\n\t\t\tif (!bList.length && !state.bgEnd) break; // defensive: server loops past empties\n\t\t\tif (state.bgEnd) break;\n\t\t}\n\t}\n\n\t// ── emit ────────────────────────────────────────────────────────────────\n\t// Everything fetched ships NOW — surface items are never withheld and the\n\t// bg buffer drains into every page. Ordering across pages is the\n\t// consumers' job (stable timestamp merge on prepend), which is what\n\t// removed the old tiling/withholding machinery: it delayed the\n\t// CONVERSATION behind a full bg drain on every first visit.\n\tconst emitSurface: any[] = surfaceList;\n\tstate.surfaceCarry = [];\n\tconst emitBg: any[] = state.bgBuffer;\n\tstate.bgBuffer = [];\n\n\t// Dedup by item id, surface copy (full bodies) winning — the old-backend\n\t// degradation path, and a guard against any range overlap.\n\tconst seen: { [id: string]: boolean } = {};\n\tfor (const it of emitSurface) { if (it && typeof it.id === 'string') seen[it.id] = true; }\n\tconst merged = emitSurface.concat(emitBg.filter((it: any) => !(it && typeof it.id === 'string' && seen[it.id])));\n\n\t// ── deliver ─────────────────────────────────────────────────────────────\n\t// Same head-refresh rule as the deferred branch: page 1's own \"more pages\n\t// exist\" must not clobber a preserved end-knowledge.\n\tif (!headRefresh) state.surfaceEnd = surface.endOfList;\n\tstate.lastSurfaceKeys = surface.startKeyHistory;\n\tstate.pendingSurface = null;\n\n\treturn {\n\t\tlist: merged,\n\t\tendOfList: state.surfaceEnd && state.bgEnd && state.bgBuffer.length === 0 && state.surfaceCarry.length === 0,\n\t\t// Bookkeeping only (both the consumers and the SDK treat it opaquely);\n\t\t// the real cursors are the SDK's internal ones plus this module's state.\n\t\tstartKeyHistory: surface.startKeyHistory,\n\t\tfirstLoad,\n\t};\n}\n\n\nexport type MapHistoryOptions = {\n\tclearedAt: number;\n\tprojectId: string;\n\t/** View-side display formatter for \"Indexing:/Reindexing: …\" bubbles. */\n\tformatIndexingLabel: (name: string, mime?: string, size?: number | null, storagePath?: string, reindex?: boolean, continued?: boolean) => string;\n};\n\nexport function mapHistoryListToMessages(list: any[], platform: 'claude' | 'openai', opts: MapHistoryOptions) {\n\tvar mapped: any[] = [], runningItemIds: string[] = [];\n\tvar extractAssistantText = platform === 'openai' ? extractOpenAIText : extractClaudeText;\n\tvar filtered = filterListByClearHorizon(list, opts.clearedAt);\n\tfiltered.slice().reverse().forEach(function (item) {\n\t\tvar requestBody = item && item.request_body;\n\t\tvar isInProcess = item && item.status === 'running';\n\t\tvar isQueued = item && item.status === 'pending';\n\t\tvar isCancelledItem = item && item.status === 'cancelled';\n\t\tvar isPending = isInProcess || isQueued;\n\t\tvar isFailed = item && item.status === 'failed';\n\t\tvar response = isFailed ? (item.error != null ? item.error : item.response_body)\n\t\t\t: (item && item.response_body != null ? item.response_body : item && item.error);\n\t\t// COMPACT listing stubs (bg-queue pages fetched with `compact: true`):\n\t\t// bodies never left the server; the label line, the response head, and\n\t\t// the completion-marker bit arrive as dedicated fields. Everything the\n\t\t// COLLAPSED row needs is here; expanding a row fetches the real bodies\n\t\t// per item (buildHistoryItemFullId point lookups) and remaps.\n\t\tvar isCompact = !!(item && item.compact);\n\t\tvar userText = isCompact\n\t\t\t? (typeof item.request_text === 'string' ? item.request_text : '')\n\t\t\t: extractLastUserTextFromRequest(requestBody);\n\t\tvar assistantText = isPending ? '' : (isCompact\n\t\t\t? ((typeof item.response_text === 'string' ? item.response_text : '').trim())\n\t\t\t: ((extractAssistantText(response) || '').trim() || ''));\n\t\tvar isErrorResponse = !isPending && (isFailed || (!isCompact && isErrorResponseBody(response)));\n\t\t// Record the completion marker, then STRIP it — both, and in that order.\n\t\t// Recording gives the display layer a structured signal instead of a substring\n\t\t// search over model prose. Stripping matches the live resolution path: without\n\t\t// it the literal token rendered inside the bubble on every history load, which\n\t\t// is not a post-reload curiosity — a first-page load REPLACES the live bubbles,\n\t\t// and those responses are now on screen far more often than they used to be.\n\t\t//\n\t\t// Gated on _isBgTask: only an INDEXING pass has a protocol token to hide. An\n\t\t// ordinary reply that merely mentions it keeps its own words.\n\t\tvar reportedComplete = !!(item && item._isBgTask) && !isErrorResponse && (isCompact\n\t\t\t? item.response_complete_marker === true\n\t\t\t: (!!assistantText && assistantText.indexOf(INDEXING_COMPLETE_MARKER) !== -1));\n\t\t// Still gated on the recorded marker (i.e. an INDEXING pass): an ordinary\n\t\t// reply that merely mentions the token keeps its own words. A compact\n\t\t// head can carry the literal token too, so the strip covers both forms.\n\t\tif (reportedComplete) assistantText = assistantText.split(INDEXING_COMPLETE_MARKER).join('').trim();\n\t\tvar serverItemId = item && typeof item.id === 'string' && item.id ? item.id : undefined;\n\t\t// A USER bubble shows when the request was made (`created`); an ASSISTANT\n\t\t// bubble shows when its response landed (`updated`). Fall back to the other\n\t\t// if one is missing (older records only carried `updated`).\n\t\tvar createdTs = Number(item && item.created);\n\t\tvar updatedTs = Number(item && item.updated);\n\t\tvar userTs = isFinite(createdTs) && createdTs > 0 ? createdTs : (isFinite(updatedTs) && updatedTs > 0 ? updatedTs : undefined);\n\t\tvar replyTs = isFinite(updatedTs) && updatedTs > 0 ? updatedTs : (isFinite(createdTs) && createdTs > 0 ? createdTs : undefined);\n\n\t\tif (userText) {\n\t\t\tvar displayContent;\n\t\t\t// Structured file ref for the display layer's per-file collapsing, kept\n\t\t\t// alongside the formatted label so grouping never has to parse it back.\n\t\t\tvar indexFile: any = undefined;\n\t\t\tif (item._isBgTask) {\n\t\t\t\tvar ref = parseIndexingRequestText(userText);\n\t\t\t\tif (ref) {\n\t\t\t\t\t// A CONTINUE pass (\"CONTINUE indexing …\") gets the compact\n\t\t\t\t\t// continuation label; a first pass (\"A new file …\") gets the full\n\t\t\t\t\t// one. Mirrors agent.vue's mapHistoryListToMessages so a big file's\n\t\t\t\t\t// windows read as progress, not the same task repeating.\n\t\t\t\t\tdisplayContent = opts.formatIndexingLabel(\n\t\t\t\t\t\tref.name,\n\t\t\t\t\t\tref.mime || '',\n\t\t\t\t\t\ttypeof ref.size === 'number' ? ref.size : null,\n\t\t\t\t\t\tref.path,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\tref.continued\n\t\t\t\t\t);\n\t\t\t\t\tindexFile = ref;\n\t\t\t\t} else {\n\t\t\t\t\tdisplayContent = userText;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdisplayContent = sanitizeAttachmentLinksForHistory(userText, opts.projectId);\n\t\t\t}\n\t\t\tvar userMsg: any = { role: 'user', content: displayContent };\n\t\t\tif (item._fromBgChain) userMsg._fromBgChain = true;\n\t\t\tif (isInProcess) userMsg.isPendingInProcess = true;\n\t\t\tif (isQueued) userMsg.isPendingQueued = true;\n\t\t\tif (isCancelledItem) userMsg.isCancelled = true;\n\t\t\tif (isCompact) userMsg._compact = true;\n\t\t\tif (item._isBgTask) userMsg.isBackgroundTask = true;\n\t\t\tif (indexFile) userMsg._indexFile = indexFile;\n\t\t\tif (item._isOnBgQueue) userMsg._useBgQueue = true;\n\t\t\tif (serverItemId !== undefined) userMsg._serverItemId = serverItemId;\n\t\t\tif (userTs !== undefined) userMsg._ts = userTs;\n\t\t\tmapped.push(userMsg);\n\t\t}\n\t\tif (isCancelledItem) { /* no assistant bubble */ }\n\t\telse if (isInProcess) {\n\t\t\tvar ph: any = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true };\n\t\t\t// _ts matters even on a placeholder: the consumers' merge and any\n\t\t\t// display fallback must be able to place it without its user bubble.\n\t\t\tif (userTs !== undefined) ph._ts = userTs;\n\t\t\tif (item._fromBgChain) ph._fromBgChain = true;\n\t\t\tif (item._isBgTask) ph.isBackgroundTask = true;\n\t\t\tif (serverItemId !== undefined) { ph._serverItemId = serverItemId; runningItemIds.push(serverItemId); }\n\t\t\tmapped.push(ph);\n\t\t} else if (isQueued) { /* no assistant placeholder */ }\n\t\telse if (isErrorResponse) {\n\t\t\tvar em: any = { role: 'assistant', content: getErrorMessage(response), isError: true };\n\t\t\tif (item._fromBgChain) em._fromBgChain = true;\n\t\t\tif (item._isBgTask) em.isBackgroundTask = true;\n\t\t\tif (serverItemId !== undefined) em._serverItemId = serverItemId;\n\t\t\tif (replyTs !== undefined) em._ts = replyTs;\n\t\t\tmapped.push(em);\n\t\t// `|| reportedComplete`: a pass whose ENTIRE answer was the completion token\n\t\t// strips down to an empty string, and the plain `assistantText` guard then\n\t\t// emitted no bubble at all — while the live path emitted one. The run read as\n\t\t// finished live and unfinished after a reload, so the row's loader came back.\n\t\t} else if (assistantText || reportedComplete) {\n\t\t\t// Safe db-only sanitize (forAssistant) so a volatile db url the model\n\t\t\t// emitted renders as a re-mintable `_expired_.url` link, not a dead one.\n\t\t\tvar okm: any = { role: 'assistant', content: sanitizeAttachmentLinksForHistory(assistantText, opts.projectId, true) || EMPTY_INDEXING_REPLY };\n\t\t\tif (item._fromBgChain) okm._fromBgChain = true;\n\t\t\tif (item._isBgTask) okm.isBackgroundTask = true;\n\t\t\tif (isCompact) okm._compact = true;\n\t\t\tif (serverItemId !== undefined) okm._serverItemId = serverItemId;\n\t\t\tif (replyTs !== undefined) okm._ts = replyTs;\n\t\t\tif (reportedComplete) okm._indexComplete = true;\n\t\t\tmapped.push(okm);\n\t\t}\n\t});\n\t// Stamp the CHAT every bubble belongs to. Every cross-project guard in the\n\t// consumers reads `_ownerKey` and is written \"undefined means unknown, keep\n\t// it\" — and the mapper never set it, so SERVER-history bubbles (which is all\n\t// of them, including every indexing row) passed every one of those filters\n\t// unchallenged. That is what let one project's transcript survive on screen\n\t// into another project and be persisted under its key.\n\tif (opts.projectId) {\n\t\tvar ownerKey = opts.projectId + '#' + platform;\n\t\tfor (var oi = 0; oi < mapped.length; oi++) mapped[oi]._ownerKey = ownerKey;\n\t}\n\treturn { messages: mapped, runningItemIds: runningItemIds };\n}\n\n/* ---- rescuing in-flight bubbles across a first-page refetch ---------------\n *\n * A first-page fetch REPLACES the message list, and the list may hold bubbles the\n * server does not know about yet: a turn whose request is still in flight, a\n * staged turn whose files are still uploading, a queued turn waiting for its ack.\n * Those have to survive the replace, and nothing else may.\n *\n * The rule lived twice — agent.vue's own fetchHistoryPage and the engine's\n * loadHistory — and the two had to be edited in lockstep to stay honest. It is one\n * function now, because the failure mode when they drift is a turn rendered twice\n * and then PERSISTED into the history cache, where it survives every later visit.\n */\n\nexport interface RescueDecisionContext {\n\t/** Is this `_serverItemId` in the page that was just fetched? */\n\thasServerId: (id: string) => boolean;\n\t/**\n\t * The fetched page already shows a non-background pending assistant.\n\t *\n\t * Only meaningful for a bubble with NO server id, where it is the sole\n\t * available answer to \"is this turn already represented?\". For a bubble that\n\t * HAS one, hasServerId answers exactly the same question exactly, and applying\n\t * this on top of it would drop an in-flight turn whose server copy simply is\n\t * not in the page that was fetched.\n\t */\n\tpageHasPendingAssistant: boolean;\n\t/** state.sending: an immediate send is in flight for this chat. */\n\tsending: boolean;\n\t/** The bubble directly after this one in the local list. */\n\tnext?: ChatMessage | null;\n\t/** The chat this fetch is FOR. A bubble stamped for another must not cross. */\n\tloadKey?: string;\n}\n\nexport function shouldRescueInFlightMessage(m: ChatMessage, ctx: RescueDecisionContext): boolean {\n\tif (!m) return false;\n\t// Background indexing bubbles come back through their own merge.\n\tif (m.isBackgroundTask) return false;\n\t// Never carry another project's (or another platform's) bubbles onto this chat.\n\tif (m._ownerKey !== undefined && ctx.loadKey !== undefined && m._ownerKey !== ctx.loadKey) return false;\n\t// The page carries a fresher copy of this exact turn.\n\tif (m._serverItemId && ctx.hasServerId(m._serverItemId)) return false;\n\t// A staged turn has no server request yet, so nothing in the page can stand for\n\t// it. Unconditional: applying the pending-assistant test here would delete the\n\t// user's message mid-upload whenever some other turn happened to be in flight.\n\tif (m._stageId) return true;\n\tif (!m._serverItemId && ctx.pageHasPendingAssistant) return false;\n\t// In flight by its own flags, id or no id. The immediate-send pair is stamped\n\t// with its server id as soon as the dispatch reports one, and that id is there\n\t// to let the check above recognise the server's copy — not to disqualify the\n\t// bubble from being kept when there is no such copy.\n\tif (m.isSendingToServer || m.isPendingQueued || m.isPendingInProcess || m.isPending) return true;\n\t// An immediate-send user bubble carries no flags of its own (its in-flight-ness\n\t// lives in state.sending); what identifies it is its own unanswered placeholder\n\t// directly below it.\n\tif (ctx.sending && m.role === 'user') {\n\t\tvar next = ctx.next;\n\t\tif (!next || next.isBackgroundTask || !next.isPending) return false;\n\t\treturn next._serverItemId === undefined || next._serverItemId === m._serverItemId;\n\t}\n\treturn false;\n}\n","/**\n * Hold the reader's place in the message list.\n *\n * A chat box mutates constantly WITHOUT the reader asking for it: an older page\n * prepends, a poll resolves, an indexing row splices in or changes label, a link\n * chip goes grey, an image preview finishes decoding, the \"Fetching history...\"\n * bar appears and disappears. Every one of those changes the height of something\n * that may sit ABOVE the viewport, and the browser answers by keeping scrollTop,\n * which slides the sentence the reader was on out from under them.\n *\n * THE ONE RULE: nothing here stores a position to be applied later. Every method\n * acts at the moment it is called, against the box as it is at that moment, and\n * is finished when it returns.\n *\n * That rule is the whole design, and it was learned the hard way. An earlier\n * version of this module also had a \"park the place they left, put them back when\n * they return\" half — parked/parkedStuck/returning/returnBudget/sawFrozen, a\n * frozen mode, a retry budget. Every one of those was a stored instruction that\n * some later event would carry out, and the reader's experience of a stored\n * instruction is that the chat throws them somewhere for no reason they can see:\n * they came back from another app, tapped the composer, the on-screen keyboard\n * fired a resize, the resize triggered a fetch, the fetch settled, and the settle\n * dutifully executed an instruction recorded before they ever left. Compensating\n * at the moment of the change needs no such instruction, and a return then needs\n * no handling at all, because nothing moved the reader in the first place.\n *\n * Two shapes, both immediate:\n *\n * preserve(fn) / capture() + restore(a)\n * A mutation you can bracket. Measures immediately before and immediately\n * after, so it is exact even when the mutation tears the list down.\n *\n * remember() + hold()\n * A layout change you CANNOT bracket: an image decoding, a font arriving, a\n * re-parse from a promise. remember() runs from the view's scroll handler,\n * so the anchor is always the reader's own last position.\n *\n * hold() is not an exception to the rule, and the staleness check is why. A height\n * change above the viewport does NOT change scrollTop; the browser preserves it,\n * which is precisely why the content appears to jump. So the remembered anchor is\n * valid exactly while `box.scrollTop` still equals the value it was captured at,\n * i.e. while nothing at all has moved the box. The instant that stops being true\n * it is re-measured, never replayed. hold() can therefore only ever undo a height\n * change that just happened, and can never carry out an old intention.\n *\n * Two more consequences worth stating, because both were once done the other way:\n *\n * NO FREEZE. Compensation runs whether or not the tab is visible. Layout and\n * getBoundingClientRect are live in a hidden tab; only painting and rAF stop.\n * Suspending compensation while hidden is what created the need to restore\n * something afterwards.\n *\n * A CLAMP IS ACCEPTED. If the content below the reader shrank, their line is\n * genuinely unreachable and the browser truncates the correction. Retrying that\n * later is how a correction turns into an ambush.\n *\n * DOM-free like the rest of the engine: the element shapes below are structural,\n * so real DOM nodes satisfy them while this file imports nothing from lib.dom.\n */\n\nexport interface AnchorRect {\n\ttop: number;\n}\n\nexport interface AnchorRowEl {\n\tgetAttribute(name: string): string | null;\n\tgetBoundingClientRect(): AnchorRect;\n\toffsetHeight: number;\n\tparentNode: unknown;\n}\n\n/** Anything inside the list that resizes on its own schedule. See absorb(). */\nexport interface AnchorGrowableEl {\n\tgetBoundingClientRect(): AnchorRect;\n\toffsetHeight: number;\n}\n\nexport interface AnchorBoxEl {\n\tchildren: ArrayLike<AnchorRowEl>;\n\tgetBoundingClientRect(): AnchorRect;\n\tscrollTop: number;\n\tscrollHeight: number;\n\tclientHeight: number;\n}\n\nexport interface RowAnchor {\n\t/** data-row-key of the anchored row, or null when nothing was anchorable. */\n\tkey: string | null;\n\t/** Offset of that row from the top of the viewport. Negative above the fold. */\n\ttop: number;\n\t/** data-row-pos, present only on rows that can RELOCATE (see below). */\n\tpos: string | null;\n\t/** scrollTop at capture time. The staleness check, and the raw fallback. */\n\tscrollTop: number;\n\t/**\n\t * scrollHeight at capture time. How much the list GREW is the best available\n\t * answer when the anchored row itself cannot be found again, and the bound on\n\t * how far a correction can legitimately be.\n\t */\n\tscrollHeight: number;\n\t/**\n\t * The anchored element itself. A view that patches in place (Vue) keeps the\n\t * same node across an update, so restore is one rect read instead of a scan;\n\t * a view that rebuilds the list (the widget) drops it and falls back to the\n\t * key. Never trusted without re-checking that it is still in the box.\n\t */\n\tel: AnchorRowEl | null;\n\t/**\n\t * The next few anchorable rows below the primary, each with its own offset.\n\t *\n\t * The primary row does not always survive: a refresh can drop it, a collapsed\n\t * indexing row can be re-identified, an expanded group can fold. Without a\n\t * fallback the only thing left is lost(), which guesses from the list's total\n\t * growth — and total growth includes everything added BELOW the reader, so a\n\t * merge that lands rows on both sides of them over-pays. A second row that is\n\t * still there beats any guess, and collecting them costs nothing: capture is\n\t * already walking these rows.\n\t */\n\talts?: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }>;\n}\n\nexport interface ScrollAnchorOptions {\n\t/** The scrolling message box, or null when it is not mounted. */\n\tgetBox: () => AnchorBoxEl | null;\n\t/**\n\t * The reader is pinned to the bottom. There the bottom IS the anchor and the\n\t * scrollToBottom* paths own the position, so every method here no-ops.\n\t */\n\tisStuck: () => boolean;\n\t/**\n\t * Fall back to the raw scrollTop when the anchored row cannot be found again.\n\t *\n\t * For a view that REBUILDS the list (the widget's renderMessages), detaching\n\t * every child collapses scrollHeight and the browser clamps scrollTop to 0,\n\t * so the raw offset is strictly better than the clamp it would otherwise be\n\t * left with. For a view that patches in place (Vue) the browser has already\n\t * kept a sane position and re-imposing a stale offset is worse than nothing.\n\t */\n\trawFallback?: boolean;\n}\n\nexport interface ScrollAnchor {\n\t/** Measure the reader's current place. Null while pinned to the bottom. */\n\tcapture: () => RowAnchor | null;\n\t/** Put a captured place back. Safe to call with null. */\n\trestore: (anchor: RowAnchor | null) => void;\n\t/** capture -> mutate -> restore, for a mutation you can bracket. */\n\tpreserve: <T>(mutate: () => T) => T;\n\t/** Record the reader's place. Call from the box's scroll handler. */\n\tremember: () => void;\n\t/** Put the remembered place back, if it is still the reader's own. */\n\thold: () => void;\n\t/** Pin to the bottom, instantly, recording the write. The ONLY way to pin. */\n\tpinBottom: () => void;\n\t/** Absorb one element's own resize. See below. */\n\tabsorb: (el: AnchorGrowableEl | null | undefined) => void;\n\t/** Drop the remembered place (chat switch, unmount). */\n\tforget: () => void;\n}\n\n/**\n * A row is anchorable when it carries data-row-key. The bars that are not rows —\n * \"Fetching history...\", the greeting, the drafting bubble, an expanded group's\n * trailing loader — deliberately carry none, so they are never anchored ON while\n * still being fully covered BY the anchor: they change height above a row that\n * is held in place, and holding it is what absorbs them.\n */\nvar ROW_KEY_ATTR = 'data-row-key';\n/**\n * A collapsed indexing row names the turn it currently renders at. It is a WEAK\n * anchor because it can RELOCATE — an older page carrying earlier passes of the\n * same run moves the row itself — and pinning a row while it moves is what would\n * drag the reader along with it. So an ordinary message row is always preferred,\n * and a group row is used only when nothing else is on screen, and then only if\n * it did not move.\n */\nvar ROW_POS_ATTR = 'data-row-pos';\n/** How many standby rows capture() records. Two is enough to survive a refresh\n * that drops the reader's own row without paying for a full-list guess. */\nvar MAX_ALTS = 2;\n/** How far past the anchor collectAlts will look for them. */\nvar ALT_SCAN_LIMIT = 64;\n/** data-row-pos is present but empty: the row cannot say where it is anchored. */\nvar UNKNOWN_ROW_POS = '\\u0000?';\n\nexport function createScrollAnchor(options: ScrollAnchorOptions): ScrollAnchor {\n\tvar held: RowAnchor | null = null;\n\t// Per-element height, so absorb() needs no \"before\" call from the caller.\n\t// Weak on purpose: a re-render throws every row away and a strong map would\n\t// hold the whole conversation's DOM alive behind it.\n\tvar seen: WeakMap<object, number> | null =\n\t\ttypeof WeakMap === 'function' ? new WeakMap<object, number>() : null;\n\n\tfunction capture(): RowAnchor | null {\n\t\tvar box = options.getBox();\n\t\tif (!box || options.isStuck()) return null;\n\t\tvar boxTop = box.getBoundingClientRect().top;\n\t\tvar kids = box.children;\n\t\tvar fallback: RowAnchor | null = null;\n\t\tvar fallbackAt = -1;\n\t\t// The last few rows passed on the way down, kept as standbys of last resort.\n\t\tvar behind: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }> = [];\n\t\tfor (var i = 0; i < kids.length; i++) {\n\t\t\tvar el = kids[i];\n\t\t\tif (!el || typeof el.getAttribute !== 'function') continue;\n\t\t\tvar key = el.getAttribute(ROW_KEY_ATTR);\n\t\t\tif (!key) continue;\n\t\t\tvar top = el.getBoundingClientRect().top - boxTop;\n\t\t\t// Rows still (partly) on screen. `top` is negative when a row starts\n\t\t\t// above the fold, which is exactly the offset to preserve.\n\t\t\tif (top + el.offsetHeight <= 0) {\n\t\t\t\t// Entirely above: not the reader's place, but a free standby. The rect\n\t\t\t\t// is already in hand, and a row ABOVE the anchor survives the batches\n\t\t\t\t// that rewrite the ones below it. Anything beats lost()'s guess.\n\t\t\t\tvar bpos = el.getAttribute(ROW_POS_ATTR);\n\t\t\t\tbehind.push({\n\t\t\t\t\tkey: key, top: top,\n\t\t\t\t\tpos: bpos === null ? null : (bpos || UNKNOWN_ROW_POS), el: el,\n\t\t\t\t});\n\t\t\t\tif (behind.length > MAX_ALTS) behind.shift();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// And STOP at the bottom of the viewport. Without this the preference\n\t\t\t// for an ordinary row walks straight past a screenful of collapsed\n\t\t\t// indexing rows and anchors on a message two screens down — which is\n\t\t\t// not the reader's place, and holds the wrong thing when a row between\n\t\t\t// the two changes height.\n\t\t\tif (top >= box.clientHeight) break;\n\t\t\t// An EMPTY data-row-pos means \"this row cannot say where it is anchored\n\t\t\t// yet\" — a run:: stub has no anchorId until its real group loads. Treating\n\t\t\t// \"\" as a position made every stub -> real-group handoff read as a\n\t\t\t// relocation and abort the anchor, which is a background resolution that\n\t\t\t// happens on every fresh open. Empty is normalised to null, which also\n\t\t\t// keeps such a row from being MISTAKEN for an ordinary one: the\n\t\t\t// ordinary/group split is the attribute's PRESENCE, tested first.\n\t\t\tvar rawPos = el.getAttribute(ROW_POS_ATTR);\n\t\t\tvar pos = rawPos === null ? null : (rawPos || UNKNOWN_ROW_POS);\n\t\t\tvar cand: RowAnchor = {\n\t\t\t\tkey: key, top: top, pos: pos,\n\t\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: el,\n\t\t\t};\n\t\t\tif (rawPos === null) {\n\t\t\t\t// An ordinary row: use it, and take standbys from the rows after it in\n\t\t\t\t// the same walk, then the ones already passed. Forward first — they are\n\t\t\t\t// nearer the reader — but a batch that rewrites everything below the\n\t\t\t\t// fold leaves the rows above it alone, so backward is the better last\n\t\t\t\t// measurement.\n\t\t\t\tcand.alts = withBehind(collectAlts(box, boxTop, i + 1), behind);\n\t\t\t\treturn cand;\n\t\t\t}\n\t\t\tif (!fallback) { fallback = cand; fallbackAt = i; } // group row: last resort\n\t\t}\n\t\t// The weak anchor needs standbys MORE than the strong one does, not less: a\n\t\t// screenful of collapsed indexing rows is exactly what a background sweep\n\t\t// re-keys and re-anchors, and without them it fell straight into lost()'s\n\t\t// whole-list guess. Ordinary rows are PREFERRED, because they are the ones a\n\t\t// background batch does not rewrite — but no standby at all means the guess,\n\t\t// and a neighbouring group row is a real measurement that restore() will\n\t\t// reject anyway if it relocated. So group rows are the last thing before the\n\t\t// guess, not something to hold out against.\n\t\tif (fallback) {\n\t\t\tfallback.alts = withBehind(\n\t\t\t\tcollectAlts(box, boxTop, fallbackAt + 1, true) || collectAlts(box, boxTop, fallbackAt + 1),\n\t\t\t\tbehind,\n\t\t\t);\n\t\t\treturn fallback;\n\t\t}\n\t\treturn {\n\t\t\tkey: null, top: 0, pos: null,\n\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: null,\n\t\t};\n\t}\n\n\t/** Up to MAX_ALTS anchorable rows starting at `from`, for restore's fallback. */\n\tfunction collectAlts(box: AnchorBoxEl, boxTop: number, from: number, ordinaryOnly?: boolean) {\n\t\tvar out: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }> = [];\n\t\tvar kids = box.children;\n\t\t// Bounded: a chat can carry hundreds of collapsed rows below the fold, and\n\t\t// this must not become a full-list walk for two standbys.\n\t\tvar stop = Math.min(kids.length, from + ALT_SCAN_LIMIT);\n\t\tfor (var i = from; i < stop && out.length < MAX_ALTS; i++) {\n\t\t\tvar el = kids[i];\n\t\t\tif (!el || typeof el.getAttribute !== 'function') continue;\n\t\t\tvar key = el.getAttribute(ROW_KEY_ATTR);\n\t\t\tif (!key) continue;\n\t\t\tvar rawPos = el.getAttribute(ROW_POS_ATTR);\n\t\t\tif (ordinaryOnly && rawPos !== null) continue;\n\t\t\tout.push({\n\t\t\t\tkey: key,\n\t\t\t\ttop: el.getBoundingClientRect().top - boxTop,\n\t\t\t\tpos: rawPos === null ? null : (rawPos || UNKNOWN_ROW_POS),\n\t\t\t\tel: el,\n\t\t\t});\n\t\t}\n\t\treturn out.length ? out : undefined;\n\t}\n\n\t/** Forward standbys first, then the rows already passed, newest-first. */\n\tfunction withBehind(\n\t\tforward: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }> | undefined,\n\t\tbehind: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }>,\n\t) {\n\t\tvar out = (forward || []).concat(behind.slice().reverse());\n\t\treturn out.length ? out : undefined;\n\t}\n\n\tfunction findRow(box: AnchorBoxEl, anchor: RowAnchor): AnchorRowEl | null {\n\t\t// The same node, still in the box: one rect read instead of a scan. Vue\n\t\t// patches keyed rows in place, so this is the common path there, and it is\n\t\t// what keeps a per-update hold() cheap enough to run on every update.\n\t\tvar el = anchor.el;\n\t\tif (el && el.parentNode === (box as unknown)) return el;\n\t\tif (!anchor.key) return null;\n\t\tvar kids = box.children;\n\t\tfor (var i = 0; i < kids.length; i++) {\n\t\t\tvar kid = kids[i];\n\t\t\tif (!kid || typeof kid.getAttribute !== 'function') continue;\n\t\t\tif (kid.getAttribute(ROW_KEY_ATTR) === anchor.key) return kid;\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction restore(anchor: RowAnchor | null): void {\n\t\tvar box = options.getBox();\n\t\tif (!box || !anchor || options.isStuck()) return;\n\t\tvar el = findRow(box, anchor);\n\t\tif (el) {\n\t\t\t// A row that MOVED (an older page re-anchored a collapsed run to its true\n\t\t\t// first pass) must not be pinned: doing so would drag the reader along\n\t\t\t// with it, to wherever the run now starts. Only compare when BOTH sides\n\t\t\t// actually name a turn — a stub that has since learned its anchorId (or\n\t\t\t// lost it) has not moved, it has just started being able to answer.\n\t\t\t//\n\t\t\t// A relocation disqualifies the ROW, not the whole capture: fall through\n\t\t\t// to the standbys, which are a real measurement, rather than to lost()'s\n\t\t\t// whole-list guess.\n\t\t\tvar livePos = el.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;\n\t\t\tif (anchor.pos !== null && anchor.pos !== UNKNOWN_ROW_POS &&\n\t\t\t\tlivePos !== UNKNOWN_ROW_POS && livePos !== anchor.pos) el = null;\n\t\t}\n\t\tif (el) {\n\t\t\tvar boxTop = box.getBoundingClientRect().top;\n\t\t\tvar delta = (el.getBoundingClientRect().top - boxTop) - anchor.top;\n\t\t\t// A row can also be MOVED rather than resized: a background refetch that\n\t\t\t// merges a run's passes into the middle of page 1 relocates the bubble\n\t\t\t// this anchor is holding, and following it would carry the reader across\n\t\t\t// the conversation. A real prepend or in-place growth can only ever need a\n\t\t\t// correction on the order of what the list gained, so a delta a whole\n\t\t\t// screen beyond that is a relocation, not a resize.\n\t\t\tvar slack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;\n\t\t\t// Test the relocation in CONTENT coordinates. `delta` is measured in the\n\t\t\t// VIEWPORT, so it also contains however far the box itself moved since the\n\t\t\t// capture — and the widget's teardown clamps scrollTop to 0, which makes\n\t\t\t// delta enormous for a row that never went anywhere. Judging that as a\n\t\t\t// relocation dropped a perfectly good anchor into lost()'s whole-list\n\t\t\t// guess. Subtracting the box's own movement leaves what the ROW did.\n\t\t\tvar moved = delta - (anchor.scrollTop - box.scrollTop);\n\t\t\tif (moved > slack || moved < -slack) {\n\t\t\t\t// The row really did relocate. That disqualifies the ROW, not the\n\t\t\t\t// capture: fall through to the standbys, which are a real measurement.\n\t\t\t\tel = null;\n\t\t\t} else {\n\t\t\t\t// Sub-pixel noise is not a jump, and writing scrollTop for it costs a\n\t\t\t\t// scroll event (and a re-layout) on every settle.\n\t\t\t\tif (delta >= 1 || delta <= -1) box.scrollTop += delta;\n\t\t\t\theld = {\n\t\t\t\t\tkey: anchor.key, top: anchor.top, pos: anchor.pos,\n\t\t\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: el,\n\t\t\t\t\t// Carried, not dropped: one successful restore used to disarm the\n\t\t\t\t\t// standbys for every later hold.\n\t\t\t\t\talts: anchor.alts,\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// The anchor row is gone or it relocated: its group collapsed, the history was\n\t\t// replaced, a background sweep re-keyed it.\n\t\t// A standby row that IS still there beats lost()'s guess outright.\n\t\tvar alts = anchor.alts;\n\t\tfor (var ai = 0; alts && ai < alts.length; ai++) {\n\t\t\tvar alt = alts[ai];\n\t\t\tvar ael = findRow(box, {\n\t\t\t\tkey: alt.key, top: alt.top, pos: alt.pos,\n\t\t\t\tscrollTop: anchor.scrollTop, scrollHeight: anchor.scrollHeight, el: alt.el,\n\t\t\t});\n\t\t\tif (!ael) continue;\n\t\t\tif (alt.pos !== null && alt.pos !== UNKNOWN_ROW_POS) {\n\t\t\t\tvar altLive = ael.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;\n\t\t\t\tif (altLive !== UNKNOWN_ROW_POS && altLive !== alt.pos) continue;\n\t\t\t}\n\t\t\tvar aboxTop = box.getBoundingClientRect().top;\n\t\t\tvar adelta = (ael.getBoundingClientRect().top - aboxTop) - alt.top;\n\t\t\tvar aslack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;\n\t\t\tvar amoved = adelta - (anchor.scrollTop - box.scrollTop);\n\t\t\tif (amoved > aslack || amoved < -aslack) continue;\n\t\t\tif (adelta >= 1 || adelta <= -1) box.scrollTop += adelta;\n\t\t\theld = {\n\t\t\t\tkey: alt.key, top: alt.top, pos: alt.pos,\n\t\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: ael,\n\t\t\t\talts: alts.slice(ai + 1),\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\t\tlost(box, anchor);\n\t}\n\n\t/**\n\t * Neither the anchored row nor any standby survived: it is gone, or it moved.\n\t *\n\t * What is still known is how much the list GREW, and in the case this branch\n\t * exists for — the pager, whose page can carry the very pass that re-anchors a\n\t * collapsed row — all of that growth is above the reader. So pay it. Missing it\n\t * costs a whole page of history in one jump.\n\t *\n\t * With nothing gained there is nothing to pay, and then the two views differ:\n\t * one REBUILDS the list (its teardown clamped scrollTop to 0, so the raw offset\n\t * beats the clamp) and one patches in place (the browser already kept a sane\n\t * position, so re-imposing a stale offset is worse than nothing).\n\t */\n\tfunction lost(box: AnchorBoxEl, anchor: RowAnchor): void {\n\t\theld = null;\n\t\tvar grew = box.scrollHeight - anchor.scrollHeight;\n\t\tif (grew > 0) { box.scrollTop = anchor.scrollTop + grew; return; }\n\t\tif (options.rawFallback) box.scrollTop = anchor.scrollTop;\n\t}\n\n\tfunction preserve<T>(mutate: () => T): T {\n\t\tvar anchor = capture();\n\t\tvar result = mutate();\n\t\trestore(anchor);\n\t\treturn result;\n\t}\n\n\t/** Record the reader's place. Call from the box's scroll handler. */\n\tfunction remember(): void {\n\t\theld = capture();\n\t}\n\n\t/**\n\t * Put the remembered place back, if it is still the reader's own.\n\t *\n\t * The staleness check is what keeps this immediate rather than a stored\n\t * intention: a height change above the viewport does NOT move scrollTop, so the\n\t * anchor is valid exactly while scrollTop is still the value it was captured\n\t * at. Anything else — the reader scrolled, a clamp fired, a pin ran — means the\n\t * box moved for a reason of its own, and the answer is to re-measure, never to\n\t * replay.\n\t */\n\tfunction hold(): void {\n\t\tvar box = options.getBox();\n\t\tif (!box || options.isStuck()) { held = null; return; }\n\t\tif (!held) { held = capture(); return; }\n\t\tif (box.scrollTop !== held.scrollTop) { held = capture(); return; }\n\t\t// restore() re-stamps `held` with the position it just pinned, so repeated\n\t\t// holds (one image after another finishing) each start from a valid anchor.\n\t\trestore(held);\n\t}\n\n\t/**\n\t * Absorb a resize made by ONE element, wherever it sits.\n\t *\n\t * The row anchor cannot see this case. A reader partway through an assistant\n\t * reply taller than the viewport is anchored ON that row, and a picture decoding\n\t * higher up INSIDE it moves every line they are reading without moving the row's\n\t * own top by a pixel. Rows above the fold have the same problem in reverse:\n\t * hold() would fix them, but it cannot be allowed to run for an image as well or\n\t * the two would each pay the same debt.\n\t *\n\t * So images go through here, and it is the more precise of the two: it\n\t * compensates by the element's own height delta, and only while the element's\n\t * TOP is above the fold, which is exactly the condition for \"everything the\n\t * reader can see just moved by this much\". An element starting at or below the\n\t * fold is left alone: it grew on screen, under a line the reader is looking at,\n\t * and moving them is what would be the jump.\n\t *\n\t * The height it last saw is remembered per element, so the caller does not have\n\t * to bracket anything. An element it has never seen counts as zero, which is\n\t * what an <img> measures before it has anything to paint — including the\n\t * markdown images that have no hydration hook at all.\n\t */\n\tfunction absorb(el: AnchorGrowableEl | null | undefined): void {\n\t\tif (!el) return;\n\t\tvar box = options.getBox();\n\t\tif (!box) return;\n\t\tvar h = el.offsetHeight;\n\t\tvar prev = seen ? seen.get(el) : undefined;\n\t\t// The baseline is recorded even while pinned to the bottom (where no write is\n\t\t// wanted): forgetting it would make the next change pay for this height too.\n\t\tif (seen) seen.set(el, h);\n\t\tif (options.isStuck()) return;\n\t\tif (prev === undefined) prev = 0;\n\t\tvar delta = h - prev;\n\t\tif (delta === 0) return;\n\t\t// The element's own TOP, which a resize never moves: everything BELOW it\n\t\t// slides by delta, everything above stays. So the reader's first visible line\n\t\t// moved exactly when that top is above the fold.\n\t\tif (el.getBoundingClientRect().top >= box.getBoundingClientRect().top) return;\n\t\tbox.scrollTop += delta;\n\t\t// Re-measure the remembered anchor, do not patch it. Its scrollTop is stale\n\t\t// after that write, and so is its offset whenever the element that resized\n\t\t// lives INSIDE the anchored row: there the row's own top never moved, so\n\t\t// scrolling by delta changed the row's offset by -delta and the next hold()\n\t\t// would faithfully undo this correction.\n\t\tif (held) held = capture();\n\t}\n\n\t/**\n\t * Pin to the bottom, instantly.\n\t *\n\t * The ONE way anything is allowed to pin, and it reads the bottom at the moment\n\t * it is called rather than aiming at a remembered one. Instant because a smooth\n\t * glide fires a scroll event per frame at positions that are not the bottom, and\n\t * the hosts clear stickToBottom on each of them, so any merge landing inside the\n\t * animation strands the reader off the bottom permanently, aiming at a target\n\t * that was already stale when the glide started.\n\t */\n\tfunction pinBottom(): void {\n\t\tvar box = options.getBox();\n\t\tif (!box) return;\n\t\tbox.scrollTop = box.scrollHeight;\n\t}\n\n\tfunction forget(): void {\n\t\theld = null;\n\t}\n\n\treturn {\n\t\tcapture: capture,\n\t\trestore: restore,\n\t\tpreserve: preserve,\n\t\tremember: remember,\n\t\thold: hold,\n\t\tpinBottom: pinBottom,\n\t\tabsorb: absorb,\n\t\tforget: forget,\n\t};\n}\n","/**\n * Keep older history REACHABLE by paging until the message box actually gains\n * something to scroll to.\n *\n * Older history is paged in by one trigger only: the user scrolling to the top\n * of the message box. That trigger has two ways to die, and collapsed indexing\n * rows cause both:\n *\n * 1. The box never scrolls. A file's every indexing pass (the first plus every\n * CONTINUE pass, request AND response bubble each) folds into ONE row, so a\n * full history page — twenty-plus messages — can render as a single line.\n * Content shorter than the viewport fires no scroll event, so page 2 is\n * never requested and any conversation the user had before that upload is\n * permanently out of reach.\n * 2. The fetched page adds no height. A page that is entirely the same file's\n * earlier passes joins the collapsed row already on screen and renders\n * nothing new. The user, sitting at scrollTop 0, scrolls up again — and\n * because the position never changed, no further scroll event fires.\n *\n * Both are the same shape: fetch, re-measure, and keep going until the user\n * genuinely gained reachable content, history ran out, or the pager stopped\n * advancing. `isSatisfied` is what differs between the two (can the box scroll\n * at all / did it grow), so the loop below takes it as a predicate.\n *\n * DOM-free like the rest of the engine — the caller supplies the measurement and\n * awaits its own render before measuring, so agent.vue and the widget run the\n * identical loop over their own pagers.\n */\n\n/** Overflow (px) that counts as \"the user can scroll here\". Comfortably more\n * than the 60px top threshold that triggers the next page, so a filled box has\n * real room to scroll rather than sitting one pixel from the trigger. */\nexport const HISTORY_FILL_SLACK_PX = 64;\n\n/** Pages one fill pass will request before giving up. Reached only by a chat\n * whose history really is dozens of pages of one file's indexing passes; the\n * cap exists so a pager that stops advancing can never spin forever. */\nexport const MAX_HISTORY_FILL_PAGES = 24;\n\nexport type FillHistoryViewportOptions = {\n\t/** The user has reachable content and paging can stop. Called AFTER the\n\t * caller's own render has settled (nextTick / rAF), since only the caller\n\t * knows when its view has painted — hence the allowance for a promise. */\n\tisSatisfied: () => boolean | Promise<boolean>;\n\t/** All history is loaded — nothing left to page in. */\n\tisEndOfList: () => boolean;\n\t/** A history request is already in flight. Waited out, not treated as a stop\n\t * condition: a background first-page refresh (the queue-detect tick fires one\n\t * every couple of seconds while a file is indexing) would otherwise swallow\n\t * the user's scroll-up entirely, and scrolling up again from scrollTop 0\n\t * produces no second event to retry with. */\n\tisLoading: () => boolean;\n\t/** Messages currently loaded. Used to detect a page that added nothing, which\n\t * means the pager is not advancing and looping would never terminate. */\n\tmessageCount: () => number;\n\t/** Fetch ONE older page (the caller's own fetchMore path, scroll-restore and\n\t * all). Return `false` when the request was NOT issued (the caller's own\n\t * single-flight guard swallowed it) so the loop retries instead of reading\n\t * the unchanged message count as an exhausted pager. Anything else, including\n\t * undefined, means it was attempted. */\n\tfetchOlder: () => Promise<boolean | void | any>;\n\t/** The chat this fill was started for is gone (project switched, view\n\t * unmounted, gate token bumped). Checked between pages so a stale fill can\n\t * never keep paging another chat's history. */\n\tisStale?: () => boolean;\n\tmaxPages?: number;\n};\n\n/** How long to wait out an in-flight history request before giving up on it. */\nconst IDLE_WAIT_STEP_MS = 120;\nconst IDLE_WAIT_MAX_MS = 15000;\n\n/** Resolve once no history request is in flight. False if the wait timed out or\n * the chat went stale, in which case the caller should stop. */\nasync function waitForIdle(\n\topts: FillHistoryViewportOptions,\n\tstale: () => boolean,\n): Promise<boolean> {\n\tvar waited = 0;\n\twhile (opts.isLoading()) {\n\t\tif (stale() || waited >= IDLE_WAIT_MAX_MS) return false;\n\t\tawait new Promise(function (r) { setTimeout(r, IDLE_WAIT_STEP_MS); });\n\t\twaited += IDLE_WAIT_STEP_MS;\n\t}\n\treturn !stale();\n}\n\n/**\n * Page older history until `isSatisfied`, until history runs out, or until the\n * pager stops advancing. Never throws: a failed page ends the fill, and the\n * user's own scrolling remains the fallback trigger.\n */\nexport async function fillHistoryViewport(opts: FillHistoryViewportOptions): Promise<void> {\n\tvar maxPages = typeof opts.maxPages === 'number' ? opts.maxPages : MAX_HISTORY_FILL_PAGES;\n\tvar stale = function () { return !!(opts.isStale && opts.isStale()); };\n\tvar swallowed = 0;\n\n\tfor (var page = 0; page < maxPages; page++) {\n\t\tif (stale() || opts.isEndOfList()) return;\n\t\tif (!(await waitForIdle(opts, stale))) return;\n\t\tvar satisfied = false;\n\t\ttry {\n\t\t\tsatisfied = !!(await opts.isSatisfied());\n\t\t} catch {\n\t\t\treturn; // cannot measure (view torn down mid-fill) — stop.\n\t\t}\n\t\tif (satisfied || stale()) return;\n\n\t\t// Re-check immediately before dispatching: measuring above yields for a\n\t\t// frame, and a background first-page refresh landing in that gap would make\n\t\t// the caller's own single-flight guard swallow this request. A swallowed\n\t\t// page adds no messages, which used to read as \"the pager is exhausted\" and\n\t\t// abandoned the fill for good.\n\t\tif (!(await waitForIdle(opts, stale))) return;\n\t\tvar before = opts.messageCount();\n\t\tvar attempted: boolean | void;\n\t\ttry {\n\t\t\tattempted = await opts.fetchOlder();\n\t\t} catch {\n\t\t\treturn; // history is optional; the scroll trigger stays as the fallback.\n\t\t}\n\t\tif (stale()) return;\n\t\tif (attempted === false) {\n\t\t\t// The caller reported it never issued the request. Retry it rather than\n\t\t\t// mistaking it for an exhausted pager, but not forever.\n\t\t\tif (++swallowed > 3) return;\n\t\t\tpage--;\n\t\t\tcontinue;\n\t\t}\n\t\t// The page came back with nothing new. Either the pager is exhausted (and\n\t\t// endOfList simply has not been set) or it is stuck; either way another\n\t\t// round would request the same page again.\n\t\tif (opts.messageCount() <= before) return;\n\t}\n}\n\n/**\n * One fill loop per view, with predicates COMBINED rather than dropped.\n *\n * Fills come from several places at once — a first page finishing, a window\n * resize, a row being collapsed, and the user's own scroll to the top — and a\n * plain \"one at a time, drop the rest\" guard picks the wrong winner: a resize\n * fill (satisfied the moment the box can scroll at all) would swallow the user's\n * scroll-up (which needs content specifically ABOVE them), and the scroll-up\n * cannot be retried, because a reader parked at scrollTop 0 produces no further\n * scroll event. Dropping the guard entirely is no better: every frame of a\n * window drag would start its own 24-page loop.\n *\n * So a request that arrives mid-loop ANDs its predicate into the running one:\n * the loop then keeps paging until EVERY caller is satisfied. Predicates that\n * come true are dropped as it goes, so the cost stays flat.\n */\nexport function createHistoryFiller(\n\tbase: Omit<FillHistoryViewportOptions, 'isSatisfied'> & {\n\t\t/** Fired when the loop starts FETCHING and when it stops, and only on a real\n\t\t * change.\n\t\t *\n\t\t * This — not the caller's own per-request `isLoading` — is what \"older\n\t\t * history is still coming in\" means to a view. A fill is many pages, and\n\t\t * `isLoading` drops to false between every one of them, so anything\n\t\t * rendered off it flickers once per page for the whole loop. A collapsed\n\t\t * indexing row whose run begins above the loaded window renders exactly\n\t\t * that (\"still loading this run\" vs a status it cannot know yet), which is\n\t\t * why the loop has to publish its own span.\n\t\t *\n\t\t * Fetching, NOT requested. Most fills fetch nothing: they are fired on every\n\t\t * window resize, every row a user collapses, and every first-page load, and\n\t\t * the overwhelmingly common outcome is `isSatisfied` returning true on the\n\t\t * first look. Announcing at request time published a true/false pair for\n\t\t * each of those, and the widget's own satisfied-check spans two animation\n\t\t * frames — long enough for the browser to PAINT the intermediate state. Every\n\t\t * collapsed row strobed through \"loading\" on every resize tick. So the span\n\t\t * opens at the first actual page request, which is also the first moment the\n\t\t * claim is true. */\n\t\tonRunningChange?: (running: boolean) => void;\n\t},\n): { fill: (isSatisfied: () => boolean | Promise<boolean>) => Promise<void>; isRunning: () => boolean } {\n\tvar pending: Array<() => boolean | Promise<boolean>> = [];\n\t// One loop at a time. Set the instant a fill is REQUESTED, whether or not that\n\t// fill goes on to fetch anything.\n\tvar running = false;\n\t// What the view is told: a page is actually being fetched. Deliberately a\n\t// different fact from `running` — see onRunningChange.\n\tvar fetching = false;\n\n\t// The callback can NEVER break the loop, and the swallow is the point. It is a\n\t// view render (the widget rebuilds its whole message list from here), so it is\n\t// the least trustworthy code this module touches, and it is invoked from two\n\t// places that must both survive it: inside the fetch wrapper, and inside `done`\n\t// — where a throw would reject the promise `fill()` returns and leave the\n\t// closing edge unsent, pinning every row that renders off this at \"loading\"\n\t// forever. A view that cannot paint is the view's problem, not the pager's.\n\tfunction announce(next: boolean): void {\n\t\tif (fetching === next) return;\n\t\tfetching = next;\n\t\tif (!base.onRunningChange) return;\n\t\ttry { base.onRunningChange(next); } catch (e) { /* never break the pager */ }\n\t}\n\n\tasync function allSatisfied(): Promise<boolean> {\n\t\tvar next: Array<() => boolean | Promise<boolean>> = [];\n\t\tfor (var i = 0; i < pending.length; i++) {\n\t\t\tif (!(await pending[i]())) next.push(pending[i]);\n\t\t}\n\t\tpending = next;\n\t\treturn pending.length === 0;\n\t}\n\n\treturn {\n\t\t// The published fact, so a view and `isRunning()` can never disagree about\n\t\t// what they are showing. A fill that never fetches is not something anyone\n\t\t// outside this module has any use for knowing about.\n\t\tisRunning: function () { return fetching; },\n\t\tfill: function (isSatisfied) {\n\t\t\tpending.push(isSatisfied);\n\t\t\tif (running) return Promise.resolve();\n\t\t\trunning = true;\n\t\t\tvar done = function () { pending = []; running = false; announce(false); };\n\t\t\treturn fillHistoryViewport({\n\t\t\t\tisSatisfied: allSatisfied,\n\t\t\t\tisEndOfList: base.isEndOfList,\n\t\t\t\tisLoading: base.isLoading,\n\t\t\t\tmessageCount: base.messageCount,\n\t\t\t\t// The span opens HERE, at the first real page request: past\n\t\t\t\t// isEndOfList, past isStale, past isSatisfied. Everything before this\n\t\t\t\t// point is a fill that concluded there was nothing to do.\n\t\t\t\tfetchOlder: function () { announce(true); return base.fetchOlder(); },\n\t\t\t\tisStale: base.isStale,\n\t\t\t\tmaxPages: base.maxPages,\n\t\t\t}).then(done, done);\n\t\t},\n\t};\n}\n","/**\n * ChatSession — framework-agnostic stateful chat orchestration.\n *\n * Ported verbatim from the bunnyquery widget's in-place state machine (which was\n * itself ported from agent.vue), with three mechanical substitutions:\n * CS.<field> -> this.state.<field>\n * renderMessages() -> this.host.notify()\n * S.<x> / skapi -> this.host.getIdentity().<x> / this.host.cancelRequest / refreshSession\n * scroll/refresh -> this.host.scrollToBottom(IfSticky) / refreshMessageBubble\n * Module-level singletons (bgTaskQueue, aiChatHistoryCache, pendingAgentRequests,\n * cancelledServerIds, historyItemPolls) become instance fields. The provider\n * request builders are reached through the engine (which already has the skapi\n * transport + poll injected via configureChatEngine), so cancel/poll behavior is\n * preserved.\n *\n * The view (per consumer) keeps: rendering, markdown PARSE, DOM refs + scroll\n * measurement, attachment chips, and the auth/account shell. It drives the\n * session via the public methods and re-renders in host.notify().\n */\nimport {\n\tcallClaudeWithPublicMcp,\n\tcallOpenAIWithPublicMcp,\n\tnotifyAgentSaveAttachment,\n\tnotifyAgentContinueIndexing,\n\tINDEXING_COMPLETE_MARKER,\n\tEMPTY_INDEXING_REPLY,\n\tMAX_INDEXING_RESUME_PASSES,\n\textractClaudeText,\n\textractOpenAIText,\n\tgetChatHistory,\n\tPOLL_INTERVAL,\n\tMAX_CONCURRENT_BG_POLLS,\n\tbgIndexingQueueName,\n\tisBgIndexingQueue,\n\tbuildHistoryItemFullId,\n\tANTHROPIC_MESSAGES_API_URL,\n\tOPENAI_RESPONSES_API_URL,\n\tupsertIndexRunRecordSafe,\n\ttype IndexRunStatus,\n\ttype IndexRunPatch,\n\ttype BgTaskEntry,\n} from './requests';\nimport { isPagedReadFile, isImageVisionFile, isWindowedReadFile } from './office';\nimport { windowedIndexingEnabled, chatEngineConfig } from './config';\nimport { isErrorResponseBody, isAuthExpiredError, isNonRetryableRequestError, getErrorMessage } from './errors';\nimport { buildBoundedChatMessages } from './budget';\nimport { createInlineLinkRegex, sanitizeAttachmentLinksForHistory } from './links';\nimport { markImagePreviewStale } from './image_preview';\nimport { mapHistoryListToMessages, extractLastUserTextFromRequest, isIndexingRequestText, parseIndexingRequestText, probeBgQueue, BG_PROBE_TTL_MS, getSplitChatHistory, shouldRescueInFlightMessage } from './history';\nimport { wallClockNow } from './time';\nimport { parseAttachmentContent } from './attachment_parsers';\nimport type { ChatHost, ChatState, ChatMessage, ChatIdentity, PinnedDispatchContext } from './host';\nimport type { IndexingGroup } from './indexing_groups';\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise(function (r) { setTimeout(r, ms); });\n}\n\n// How many live items one look at the background-indexing queue asks for. The\n// queue is FIFO per user, so a healthy chain has one running plus at most a\n// couple queued; the cap only bounds a pathological backlog.\nconst WORKER_PASS_ADOPT_LIMIT = 20;\n// How stale the \"which files are indexing\" snapshot may be when it is used to\n// refuse a DUPLICATE index dispatch. Short, because the answer decides whether a\n// file gets indexed at all; long enough that one upload batch asks once, not once\n// per file.\nconst LIVE_INDEX_SNAPSHOT_MAX_AGE_MS = 5000;\n// How long a client holds a file's indexing slot from the moment it decides to\n// dispatch. It only has to outlive the gap between that decision and the queue\n// admitting the pass (a request, plus the status index catching up); after that\n// the bgTaskQueue entry and the pass's own bubble carry the fact. Bounded so a\n// dispatch that died without releasing cannot lock a file out for the session.\nconst INDEX_DISPATCH_CLAIM_MS = 2 * 60 * 1000;\n// Delays before each look (the first is immediate). More than one because the\n// worker writes the next pass's row a few milliseconds AFTER it resolves the\n// current one, so a look that wins that race sees an empty queue for a chain\n// that is still alive. Fixed and finite: this must never become a poll.\nconst WORKER_PASS_ADOPT_ATTEMPTS = [0, 2000, 6000];\n\n// awaitIndexingDrained: how often it re-asks the background-indexing queue, and\n// how many consecutive empty answers it needs before believing the chains are\n// over. More than one for the same reason the adopt ladder above looks twice —\n// pass N+1 is written just after pass N resolves, so a single look lands in that\n// gap and reports an idle queue for a file that is still being read.\n//\n// Two cadences: while work is visibly running there is nothing to be gained by\n// asking often (an indexing pass takes tens of seconds, and a big file can hold\n// the queue for many minutes), but once the queue looks empty the confirming\n// look is all that stands between the user and their answer.\n// Early point-lookups for a foreground reply, before the flat POLL_INTERVAL tick lands.\n// Widening on purpose: the first two catch a short reply (a greeting, a one-line answer) that\n// would otherwise idle until 3s, and after ~1.7s a reply is long enough that the 3s interval is\n// no longer the dominant cost, so probing further would just add requests. Three probes is at\n// most three extra point lookups per turn, and none of them fire once the reply has landed.\nconst EARLY_PROBE_SCHEDULE_MS = [400, 900, 1700];\n\nconst INDEXING_DRAIN_BUSY_POLL_MS = 8000;\nconst INDEXING_DRAIN_CONFIRM_POLL_MS = 3000;\nconst INDEXING_DRAIN_IDLE_LOOKS = 2;\n// Floor on the whole wait. The status index is eventually consistent, so the\n// pass this turn's own upload just enqueued can be missing from the first looks —\n// releasing on those would send the chat ahead of the very files it is asking\n// about. Costs nothing in the normal case, where the queue reports work\n// immediately and the wait is far longer than this anyway.\nconst INDEXING_DRAIN_MIN_MS = 8000;\n\n// Ownership sequence for state.bgHistoryLoading (see the deferred-batch handler\n// in loadHistory): the latest minted batch owns the flag; older handlers\n// settling late must neither clear nor keep it.\nlet _bgHistoryBatchSeq = 0;\n// Ceiling on that wait. Past it the turn is sent regardless: an answer computed\n// against a partly-indexed file is a poor outcome, but a question that is never\n// asked at all because one chain wedged server-side is a worse one.\nconst INDEXING_DRAIN_TIMEOUT_MS = 15 * 60 * 1000;\n// A look that never comes back would hang the whole wait forever — there is no\n// pending timer to fall back on, so the turn is never sent and its bubble never\n// stops saying \"(Indexing files...)\". A look that outlives this is abandoned and\n// counted as UNKNOWN, i.e. as busy, which costs one more cycle and nothing else.\n//\n// Set well above any plausible slow answer rather than just above a fast one. An\n// abandoned look counts as busy and there is no way back: an index that reliably\n// answers slower than this can never produce two agreeing idle looks, so the turn\n// would sit at \"(Indexing files...)\" until the 15-minute ceiling. The cost of\n// being generous is one extra cycle in the case this is meant to catch, which by\n// definition never returns at all.\nconst INDEXING_DRAIN_LOOK_TIMEOUT_MS = 45000;\n// Closest a nudged look may follow the previous one. Bounds the extra request\n// rate when a bulk upload finishes many chains at once; the unnudged cadence is\n// one pair of requests per INDEXING_DRAIN_BUSY_POLL_MS.\nconst INDEXING_DRAIN_NUDGE_MIN_GAP_MS = 1500;\n\n// requestAnimationFrame / high-res clock, reached through globalThis so the\n// engine stays DOM-free at the type level (and degrades gracefully in non-DOM\n// / test environments where these globals are absent).\nvar _g: any = typeof globalThis !== 'undefined' ? globalThis : {};\nfunction nowMs(): number {\n\treturn (_g.performance && typeof _g.performance.now === 'function') ? _g.performance.now() : Date.now();\n}\nfunction nextFrame(cb: (t: number) => void): void {\n\tif (typeof _g.requestAnimationFrame === 'function') { _g.requestAnimationFrame(cb); return; }\n\tsetTimeout(function () { cb(nowMs()); }, 16);\n}\n\n/** A live poll registered in ChatSession.historyItemPolls. */\nexport type PollHandle = {\n\t/** 'bg' = background indexing, pausable. 'fg' = a reply the user is waiting on. */\n\tkind: 'fg' | 'bg';\n\t/** Absent on an older skapi-js that cannot stop an attached poll. */\n\tstop?: () => void;\n};\n\n/**\n * True when a poll result came from stopPolling rather than the server. Duck-typed on\n * purpose — see the note above about not importing skapi-js here.\n */\nfunction isPollStopped(res: any): boolean {\n\treturn !!res && typeof res === 'object' && res.status === 'stopped';\n}\n\nexport class ChatSession {\n\thost: ChatHost;\n\tstate: ChatState;\n\tbgTaskQueue: BgTaskEntry[];\n\tcancelledServerIds: Set<string>;\n\t/** Files whose indexing the user stopped, keyed exactly as buildChatDisplayList\n\t * keys a group (storage path, else filename). Cancelling one pass is not\n\t * enough on its own: the client dispatches CONTINUE passes for paged files, so\n\t * without this the next pass is enqueued the moment the cancelled one settles.\n\t * Cleared when a FIRST pass for the same file is queued again (a re-upload or a\n\t * Reindex from the file manager), so stopping a file never poisons it. */\n\tcancelledIndexKeys: Set<string>;\n\tpendingAgentRequests: Record<string, Promise<any>>;\n\taiChatHistoryCache: Record<string, { messages: ChatMessage[]; endOfList: boolean; startKeyHistory: string[] }>;\n\thistoryItemPolls: Map<string, PollHandle>;\n\t/** Non-empty while polling is paused; keyed by reason so overlapping causes\n\t * (view detached AND tab hidden) do not resume each other prematurely. */\n\tprivate _pauseReasons: Set<string>;\n\tprivate _resuming: boolean;\n\tprivate _lidSeq: number;\n\tprivate _stageSeq: number;\n\t/** How many attachment-upload batches are running. uploadingAttachments is a\n\t * single flag but batches overlap (the composer stays live, so the user can\n\t * send a second one while the first uploads), and a nested finish must not\n\t * clear the flag out from under the batch still running. */\n\tprivate _uploadBatches: number;\n\t/** Indexing requests whose ack has not come back yet. Until it does the item\n\t * is not on the server's queue, so awaitIndexingDrained cannot see it — and\n\t * would read the gap between \"pass N settled\" and \"pass N+1 accepted\" as the\n\t * file being finished. */\n\tprivate _indexDispatchesInFlight: number;\n\t/** Live awaitIndexingDrained waiters, one callback each. A nudge only pulls that\n\t * waiter's NEXT look forward; it can never make one conclude anything, so a\n\t * wrong nudge costs one pair of requests and the look reports busy. Overlapping\n\t * waiters are normal — the composer stays live, so a second send can be\n\t * uploading while the first waits. */\n\tprivate _drainNudges: Array<() => void>;\n\t/** Stages whose upload/dispatch chain is still running in THIS page. Lives and\n\t * dies with those chains, so it is what tells a staged bubble restored from the\n\t * history cache whether anything is still working on it (see\n\t * settleDeadStagedMessages). Today the cache dies with the page too and every\n\t * restored stage is live; this stays correct if that ever changes. */\n\tprivate _liveStages: { [stageId: string]: boolean };\n\t/** Files the SERVER currently has unresolved indexing work for, by the same key\n\t * a collapsed row uses (storage path, else filename), and whether we have asked\n\t * even once for this chat.\n\t *\n\t * This is the only thing that can tell a WORKER-driven run (a PDF's page loop, a\n\t * windowed read) that it is over. Those chains are advanced inside the worker off\n\t * the renderer's page count; the client sees passes appear and settle and can\n\t * never tell \"between passes\" from \"finished\" by looking at them. Asking the\n\t * queue is how it finds out. Until it has asked, `checked` is false and the view\n\t * says \"still working\", which is the honest reading of not knowing — and the one\n\t * that does not repeat the bug where a row claimed \"Indexed\" mid-run. */\n\t/** The chat the live-index snapshot (state.liveIndexKeys) was taken for, so a\n\t * project switch drops it. */\n\tprivate _liveIndexKey: string;\n\t/** When the snapshot was last published (wall clock ms), so a caller that needs\n\t * a CURRENT answer can tell whether to re-ask. 0 = never. */\n\tprivate _liveIndexAt: number;\n\t/** Files this client has an index dispatch in flight for, by scoped path ->\n\t * wall clock. See claimIndexRun. */\n\tprivate _indexClaims: { [scopedPath: string]: number };\n\n\tconstructor(host: ChatHost) {\n\t\tthis.host = host;\n\t\tthis.state = {\n\t\t\tmessages: [],\n\t\t\tattachments: [],\n\t\t\tuploadingAttachments: false,\n\t\t\tsending: false,\n\t\t\ttyping: false,\n\t\t\ttypingAbort: false,\n\t\t\tloadingHistory: false,\n\t\t\tloadingOlderHistory: false,\n\t\t\t// A deferred bg stub batch (first-paint split) is still in flight; the\n\t\t\t// views show a small 'loading indexing history' hint while true.\n\t\t\tbgHistoryLoading: false,\n\t\t\thistoryEndOfList: false,\n\t\t\thistoryStartKeyHistory: [],\n\t\t\thistoryRequestToken: 0,\n\t\t\tgateRefreshToken: 0,\n\t\t\tliveIndexKeys: {},\n\t\t\tliveIndexChecked: false,\n\t\t\tstoppedIndexIds: {},\n\t\t};\n\t\tthis.bgTaskQueue = [];\n\t\tthis.cancelledServerIds = new Set();\n\t\tthis.cancelledIndexKeys = new Set();\n\t\tthis.pendingAgentRequests = {};\n\t\tthis.aiChatHistoryCache = {};\n\t\tthis.historyItemPolls = new Map();\n\t\tthis._pauseReasons = new Set();\n\t\tthis._resuming = false;\n\t\tthis._lidSeq = 0;\n\t\tthis._stageSeq = 0;\n\t\tthis._uploadBatches = 0;\n\t\tthis._indexDispatchesInFlight = 0;\n\t\tthis._drainNudges = [];\n\t\tthis._liveStages = {};\n\t\tthis._liveIndexKey = '';\n\t\tthis._liveIndexAt = 0;\n\t\tthis._indexClaims = {};\n\t}\n\n\t/** What the display layer needs to decide whether a run is finished. `keys` holds\n\t * every file the server still has indexing work for; `checked` is false until the\n\t * first answer for this chat, and false means \"we do not know yet\". */\n\tgetLiveIndexState(): { keys: { [fileKey: string]: boolean }; checked: boolean } {\n\t\treturn { keys: this.state.liveIndexKeys, checked: this.state.liveIndexChecked };\n\t}\n\n\t/** Passes that were on a row when the user stopped it, so the display layer can\n\t * still tell that this run was stopped once the stop has left no other trace.\n\t * See cancelIndexingGroup, which fills it, and buildChatDisplayList, which is\n\t * the only reader. */\n\tgetStoppedIndexIds(): { [serverItemId: string]: boolean } {\n\t\treturn this.state.stoppedIndexIds;\n\t}\n\n\t/**\n\t * Is this file ALREADY being indexed by this client?\n\t *\n\t * One live run per file, and the reason is what a second one looks like: the\n\t * conversation grows a SECOND collapsed row for the same file (a run is opened\n\t * by every FIRST pass, so two of them are two rows), the same document is read\n\t * twice at full provider cost, and the two chains fight over the same records —\n\t * the delete-then-repost that starts run 2 wipes what run 1 has saved so far.\n\t *\n\t * Asked of this client's own live work, so it cannot be wrong in the dangerous\n\t * direction: a queued/running pass keeps its bgTaskQueue entry until its bubble\n\t * settles, and a settled run answers false, which is what a genuine later\n\t * re-index needs.\n\t *\n\t * The retry that made this necessary: a chip whose INDEX request failed is\n\t * handed back to the composer to be retried on the next send, and an index\n\t * request can fail from the client's side (a lost ack, an expired token on the\n\t * response) while the server has already queued the pass. The retry then indexes\n\t * a file that was never not being indexed.\n\t */\n\thasLiveIndexRun(storagePath?: string): boolean {\n\t\tif (!storagePath) return false;\n\t\t// A dispatch this client has STARTED but not yet heard back about. Nothing\n\t\t// else can see one: a bgTaskQueue entry exists only once the ack lands, the\n\t\t// bubble only once the drain runs after that, and the server's own status\n\t\t// index is eventually consistent — the adopt ladder retries at 0/2s/6s\n\t\t// precisely because a row created seconds ago can be missing from it. So\n\t\t// between deciding to index a file and the queue admitting it, EVERY source\n\t\t// of truth says \"not indexing\", and a second dispatch in that window is\n\t\t// exactly the duplicate this guard exists to stop. Observed live: two first\n\t\t// passes four seconds apart, two collapsed rows.\n\t\tvar claimed = this._indexClaims[this._indexClaimKey(storagePath)];\n\t\tif (claimed && nowMs() - claimed < INDEX_DISPATCH_CLAIM_MS) return true;\n\t\tvar id = this.host.getIdentity();\n\t\tfor (var i = 0; i < this.bgTaskQueue.length; i++) {\n\t\t\tvar e = this.bgTaskQueue[i];\n\t\t\tif (e && e.storagePath === storagePath && e.projectId === id.projectId && e.platform === id.platform) return true;\n\t\t}\n\t\treturn this.state.messages.some(function (m) {\n\t\t\tif (!m.isBackgroundTask || m.role !== 'user' || m.isCancelled) return false;\n\t\t\tif (!(m.isPendingQueued || m.isPendingInProcess || m.isSendingToServer)) return false;\n\t\t\treturn !!m._indexFile && m._indexFile.path === storagePath;\n\t\t});\n\t}\n\n\t/** Storage paths are project-relative, and one ChatSession serves every\n\t * project, so a claim has to be scoped the way a stop is (_indexKeyOf). */\n\tprivate _indexClaimKey(storagePath: string): string {\n\t\treturn this.getHistoryCacheKey() + '|' + storagePath;\n\t}\n\n\t/**\n\t * Take this file's indexing slot, or report that someone already has it.\n\t *\n\t * The check-and-CLAIM is what makes it safe against a second caller arriving\n\t * mid-flight: the claim is written SYNCHRONOUSLY, before the first await, so a\n\t * concurrent caller sees it even though no request has completed and no queue\n\t * has admitted anything. Ask-then-dispatch could not do that — every source it\n\t * consults only learns about a dispatch after the ack.\n\t *\n\t * Returns true when the caller owns the slot and should dispatch. A caller that\n\t * then fails to dispatch MUST releaseIndexRun, or the file waits out the claim\n\t * (a few minutes) before it can be retried.\n\t */\n\tclaimIndexRun(storagePath?: string): Promise<boolean> {\n\t\tvar self = this;\n\t\tif (!storagePath) return Promise.resolve(true);\n\t\tif (this.hasLiveIndexRun(storagePath)) return Promise.resolve(false);\n\t\tthis._indexClaims[this._indexClaimKey(storagePath)] = nowMs();\n\t\treturn this._refreshLiveIndexKeys(LIVE_INDEX_SNAPSHOT_MAX_AGE_MS)\n\t\t\t.then(function () {\n\t\t\t\tif (!self.state.liveIndexKeys[storagePath]) return true;\n\t\t\t\tself.releaseIndexRun(storagePath);\n\t\t\t\treturn false;\n\t\t\t})\n\t\t\t.catch(function () { return true; });\n\t}\n\n\t/** Give the slot back — the dispatch failed, or was abandoned. */\n\treleaseIndexRun(storagePath?: string): void {\n\t\tif (storagePath) delete this._indexClaims[this._indexClaimKey(storagePath)];\n\t}\n\n\t/**\n\t * The same question, asked of the SERVER when this page cannot answer it.\n\t *\n\t * hasLiveIndexRun only knows what this page did. That is not enough for the\n\t * case duplicates actually come from: the first run was started before a\n\t * reload, or in another tab, or its bubble has since been paged out of the\n\t * loaded window — and then the retry finds nothing locally and starts a second\n\t * run of a file that is still being indexed. The queue is the one place that\n\t * knows, and it is already asked for exactly this list.\n\t *\n\t * Only a POSITIVE answer is used. Absence proves nothing here (the query is\n\t * capped, and `liveIndexChecked` records that), so an unanswerable question\n\t * falls back to dispatching — the cost of a wrong \"no\" is the duplicate this\n\t * exists to prevent, and the cost of a wrong \"yes\" is a file that never gets\n\t * indexed at all. Only one of those is recoverable by the user.\n\t */\n\tisIndexRunLive(storagePath?: string): Promise<boolean> {\n\t\tvar self = this;\n\t\tif (!storagePath) return Promise.resolve(false);\n\t\tif (this.hasLiveIndexRun(storagePath)) return Promise.resolve(true);\n\t\treturn this._refreshLiveIndexKeys(LIVE_INDEX_SNAPSHOT_MAX_AGE_MS)\n\t\t\t.then(function () { return !!self.state.liveIndexKeys[storagePath]; })\n\t\t\t.catch(function () { return false; });\n\t}\n\n\t/** Re-ask the queue which files are still being indexed, unless the answer we\n\t * have is younger than `maxAgeMs`. Shared by every caller that needs a current\n\t * one; the display layer's own refresh path is the adopt ladder. */\n\tprivate _refreshLiveIndexKeys(maxAgeMs: number): Promise<void> {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\tvar platform = id.platform;\n\t\tif (!id.projectId || (platform !== 'claude' && platform !== 'openai')) return Promise.resolve();\n\t\t// The chat this query is FOR, snapshotted before the round trip. The record\n\t\t// below is gated on it still being the chat on screen: the adopt ladder makes\n\t\t// the same resolve-time identity check, and without it a project switch inside\n\t\t// this query's RTT published chat A's queue answer as chat B's snapshot —\n\t\t// where absence reads as a green \"Indexed\" for files B is indexing right now.\n\t\tvar askedKey = this.getHistoryCacheKey();\n\t\tif (this._liveIndexKey === askedKey && nowMs() - this._liveIndexAt < maxAgeMs) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tvar queue = bgIndexingQueueName(id.userId, id.projectId);\n\t\t// Snapshot reader: a young shared answer (this session's own adopt\n\t\t// ladder, or the db-files page's probe) is as good as a fresh one.\n\t\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(probeBgQueue(\n\t\t\t\t{ service: id.projectId, owner: id.owner, platform: platform as 'claude' | 'openai', queue: queue, status: status, limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t{ maxAgeMs: BG_PROBE_TTL_MS },\n\t\t\t)).then(function (entry) { return entry.result; }).catch(function () { return null; });\n\t\t};\n\t\treturn Promise.all([ask('pending'), ask('running')]).then(function (results) {\n\t\t\tif (results[0] === null || results[1] === null) return;\n\t\t\tif (self.getHistoryCacheKey() !== askedKey) return;\n\t\t\tself._liveIndexKey = askedKey;\n\t\t\tself._recordLiveIndexKeys(results);\n\t\t});\n\t}\n\n\t/**\n\t * Replace the live-index snapshot from a queue query's raw items.\n\t *\n\t * Whole-snapshot, never incremental: the query returns everything unresolved on\n\t * the queue, so a file MISSING from it is precisely the fact we are after. Merging\n\t * would make a finished file impossible to observe.\n\t */\n\tprivate _recordLiveIndexKeys(lists: any[]): void {\n\t\tvar next: { [k: string]: boolean } = {};\n\t\t// A page that came back FULL is not a whole-queue answer: the query is capped\n\t\t// and ordered newest-first, so a bulk upload of 40 files returns the 20 newest\n\t\t// and omits the 20 about to run. Absence would then read as \"finished\" for\n\t\t// exactly the files that have not been touched yet. Report not-knowing instead.\n\t\tvar truncated = false;\n\t\t// Locally settled already. The adopt path refuses these items for the same\n\t\t// reason and says why: the status index is eventually consistent, so the pass\n\t\t// that just finished can still come back as running. Counting it as live work\n\t\t// leaves a finished file spinning with nothing left to ever settle and correct\n\t\t// it — the two readings of one payload must not disagree.\n\t\tvar settledIds: { [id: string]: boolean } = {};\n\t\tthis.state.messages.forEach(function (m) {\n\t\t\tif (!m._serverItemId) return;\n\t\t\tif (m.isPending || m.isPendingInProcess || m.isPendingQueued) return;\n\t\t\tsettledIds[m._serverItemId] = true;\n\t\t});\n\t\tfor (var li = 0; li < lists.length; li++) {\n\t\t\tvar list = lists[li] && Array.isArray(lists[li].list) ? lists[li].list : [];\n\t\t\tif (list.length >= WORKER_PASS_ADOPT_LIMIT) truncated = true;\n\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\tvar item = list[i];\n\t\t\t\tif (!item || (item.status !== 'pending' && item.status !== 'running')) continue;\n\t\t\t\tif (item.id && settledIds[item.id]) continue;\n\t\t\t\tvar text = extractLastUserTextFromRequest(item.request_body);\n\t\t\t\tif (!isIndexingRequestText(text)) continue; // an ordinary chat on this queue\n\t\t\t\tvar ref = parseIndexingRequestText(text);\n\t\t\t\tif (!ref) continue;\n\t\t\t\t// BOTH, not `path || name`. A row's key is normally the storage path,\n\t\t\t\t// but buildChatDisplayList falls back to the filename when the pass it\n\t\t\t\t// opened the run with carried no path (an old cached bubble, a label\n\t\t\t\t// with no link). A key recorded one way and looked up the other misses,\n\t\t\t\t// and a miss reads as FINISHED — the one direction that must never\n\t\t\t\t// happen by accident. Recording both can only over-match, which shows a\n\t\t\t\t// loader on a file that is done: visibly cautious instead of silently\n\t\t\t\t// wrong.\n\t\t\t\tif (ref.path) next[ref.path] = true;\n\t\t\t\tif (ref.name) next[ref.name] = true;\n\t\t\t}\n\t\t}\n\t\tvar nowChecked = !truncated;\n\t\tvar was = this.state.liveIndexKeys, changed = this.state.liveIndexChecked !== nowChecked;\n\t\tif (!changed) {\n\t\t\tfor (var k in next) if (!was[k]) { changed = true; break; }\n\t\t\tif (!changed) for (var k2 in was) if (!next[k2]) { changed = true; break; }\n\t\t}\n\t\tthis.state.liveIndexKeys = next;\n\t\tthis.state.liveIndexChecked = nowChecked;\n\t\tthis._liveIndexAt = nowMs();\n\t\t// Claim the snapshot for the CURRENT chat. Both callers verify identity before\n\t\t// recording, so this is always true - but only _refreshLiveIndexKeys used to say\n\t\t// so, and the adopt ladder (the path every plain page load actually seeds\n\t\t// through) never did. _liveIndexKey then stayed '', and the first-page reset in\n\t\t// loadHistory ('loadKey !== _liveIndexKey') fired on EVERY load - including every\n\t\t// tab refocus - wiping checked/keys and flipping every settled indexing row back\n\t\t// to the grey \"checking status\" until the queue answered again. With the claim,\n\t\t// that reset fires only on a genuine project/platform switch; a refocus keeps\n\t\t// showing the last known state (green/yellow) and the re-poll that follows\n\t\t// replaces the snapshot atomically when its answer lands.\n\t\tthis._liveIndexKey = this.getHistoryCacheKey();\n\t\tif (changed) this.host.notify();\n\t}\n\n\t/** Forget the snapshot: it describes ONE chat's queue, and the answer for the\n\t * project the user just switched to is unknown until it is asked for again. */\n\tprivate _resetLiveIndexKeys(): void {\n\t\tthis.state.liveIndexKeys = {};\n\t\tthis.state.liveIndexChecked = false;\n\t\tthis._liveIndexAt = 0;\n\t}\n\n\t/**\n\t * Ask the queue what is still indexing, once, for the chat that is on screen.\n\t *\n\t * Seeds the snapshot on a history load. Without it a reloaded chat has no way to\n\t * learn that a run it can see is over: the adopt ladder that normally answers this\n\t * only fires when a pass SETTLES, and after a reload there is no pass left to\n\t * settle — so every finished worker-driven row would spin forever.\n\t *\n\t * Best-effort: a failure leaves `checked` false, which reads as \"still working\"\n\t * rather than as a false all-clear.\n\t *\n\t * Delegates to the adopt ladder rather than asking once. A single empty look is\n\t * exactly what that ladder exists to distrust — the worker writes pass N+1 a few\n\t * milliseconds AFTER flipping pass N to resolved, so a query landing in that gap\n\t * sees an empty queue for a chain that is very much alive. One look would turn\n\t * that into a confident \"Indexed\" with a green check, on the one scenario this\n\t * whole feature is for, and nothing would ever re-ask: the ladder is normally\n\t * triggered by a pass SETTLING, and after a reload there is no pass left to\n\t * settle. The ladder re-asks at 0/2s/6s, records each answer, and as a bonus\n\t * adopts and polls any live pass it finds, which makes the row genuinely active\n\t * instead of merely unconfirmed.\n\t */\n\trefreshLiveIndexState(): void {\n\t\t// PASSIVE: this is the first-page/resume refresh, not a settle. One\n\t\t// fresh look (two status queries) always happens; the 2s/6s ladder\n\t\t// climb is reserved for when there is EVIDENCE of live work — the\n\t\t// pass-boundary gap the ladder exists for presumes a chain was alive,\n\t\t// and on an idle tab return the climb was three round trips of asking\n\t\t// a question whose answer had not changed.\n\t\tthis._adoptWorkerIndexingPasses(0, true);\n\t}\n\n\t/** Forget what we know about which files are indexing — but ONLY when the\n\t * snapshot was taken for a different chat than the one on screen now. For a\n\t * consumer whose history loading is its own fork and so never reaches\n\t * loadHistory's reset — a snapshot describes ONE chat's queue, and carrying it\n\t * into another project would let a row there claim to be finished on someone\n\t * else's evidence.\n\t *\n\t * Conditional for the same reason loadHistory's own reset is (the\n\t * `loadKey !== _liveIndexKey` gate): the view calls this on every mount, and\n\t * an unconditional wipe turned every re-entry to the chat into a grey\n\t * \"Checking status:\" sweep across rows whose state was already known. A\n\t * RE-entry keeps showing the last answer (green/yellow) while the first-page\n\t * refresh re-asks quietly; only a genuine project/platform switch starts from\n\t * \"not known yet\". Claiming `_liveIndexKey` here (before any answer) is the\n\t * same fudge loadHistory makes: it marks WHOSE chat the empty snapshot is\n\t * for, so repeated calls do not re-wipe, and _recordLiveIndexKeys re-claims\n\t * it when the real answer lands. */\n\tresetLiveIndexState(): void {\n\t\tvar key = this.getHistoryCacheKey();\n\t\tif (key === this._liveIndexKey) return;\n\t\tthis._liveIndexKey = key;\n\t\tthis._resetLiveIndexKeys();\n\t}\n\n\t/** Wrap an indexing-request dispatch so awaitIndexingDrained counts it as\n\t * live work from the moment it is sent, not from the moment it is acked. */\n\ttrackIndexDispatch<T>(p: Promise<T>): Promise<T> {\n\t\tvar self = this;\n\t\tthis._indexDispatchesInFlight += 1;\n\t\t// Deliberately does NOT nudge the drain when the count reaches zero. That\n\t\t// moment is a pass being ACCEPTED — new work ENTERING the queue — not work\n\t\t// ending. Nudging there pulled a waiting turn's two confirming looks into a\n\t\t// fixed ~4.5s window after the ack, which is inside the several seconds a\n\t\t// worker-minted pass can take to show up in the status index (the same\n\t\t// staleness WORKER_PASS_ADOPT_ATTEMPTS exists for). It turned a rare unlucky\n\t\t// alignment into a reliable one: the turn dispatched ahead of its own file's\n\t\t// remaining passes and the model answered from a partly-read file. There was\n\t\t// nothing to gain either — the pass it signals is work, so the pulled-forward\n\t\t// look can only report busy, or lie.\n\t\tvar release = function () { self._indexDispatchesInFlight = Math.max(0, self._indexDispatchesInFlight - 1); };\n\t\treturn p.then(function (v) { release(); return v; }, function (e) { release(); throw e; });\n\t}\n\n\t/**\n\t * Something just happened that plausibly ENDED indexing work, so let any waiting\n\t * turn look now instead of sitting out the rest of its busy interval.\n\t *\n\t * A nudge changes only WHEN a look happens, never what it concludes: the two\n\t * agreeing idle looks, the confirm gap between them, \"a failed look counts as\n\t * busy\" and the minimum wait are all untouched. That is why it is safe to fire\n\t * from places that are merely good guesses.\n\t *\n\t * Fired from end-of-chain points ONLY: the adopt ladder giving up, a resume\n\t * declining to continue, a pass failing. Not from every settling pass (one nudge\n\t * per pass per file for the whole run), and not from an indexing request being\n\t * accepted — see the note in trackIndexDispatch for why that one is actively\n\t * harmful rather than merely wasteful.\n\t */\n\tprivate _nudgeIndexingDrain(): void {\n\t\tif (!this._drainNudges.length) return;\n\t\tvar list = this._drainNudges.slice(); // a nudge may de-register itself\n\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\ttry { list[i](); } catch (e) { /* best-effort: never break the caller */ }\n\t\t}\n\t}\n\n\t/**\n\t * Register a live poll so (a) a remount dedupes against it instead of stacking a\n\t * SECOND poll on the same item, and (b) pausePolling can stop it.\n\t *\n\t * `stop` comes from the SDK and may be absent on an older skapi-js, in which case the\n\t * poll simply cannot be stopped and is left running — see pausePolling.\n\t *\n\t * (This block documents _trackPoll, further down. The two methods below sit between it\n\t * and its subject.)\n\t */\n\t/**\n\t * Foreground poll with an early-probe race.\n\t *\n\t * skapi's poll() is a bare setInterval(fn, latency) with NO check at t=0, so the earliest a\n\t * reply can be observed is one full POLL_INTERVAL (3s) after dispatch. For a long generation\n\t * that granularity is free. For a SHORT one it is nearly pure dead time: a greeting that the\n\t * provider finishes in 1s still waits until the 3s tick, which measured as a large share of a\n\t * 5s \"yo\" round trip.\n\t *\n\t * So keep the 3s interval as the steady state, and additionally point-look-up the item a few\n\t * times early, on a widening schedule. Whichever answers first wins and the other is stopped.\n\t * The probe uses the csrHistoryItemLookup hook both clients already implement; without it this\n\t * degrades to exactly the old behaviour.\n\t *\n\t * FOREGROUND ONLY. Background indexing polls keep the flat cadence: nobody is watching them,\n\t * and they are the ones bounded by MAX_CONCURRENT_BG_POLLS, so adding probes there would spend\n\t * the request budget the cap exists to protect.\n\t */\n\tattachForegroundPoll(source: any, itemId: string, opts?: any): any {\n\t\treturn this._fgPollWithEarlyProbe(source, itemId, opts);\n\t}\n\n\tprivate _fgPollWithEarlyProbe(source: any, itemId: string, opts?: any): any {\n\t\tvar self = this;\n\t\t// Callbacks ride along on the interval path exactly as before; the probe path below\n\t\t// fires onResponse itself, because a caller that only reacts through the callback\n\t\t// (the history drain does) would otherwise never learn the probe won.\n\t\tvar base = source.poll(Object.assign({ latency: POLL_INTERVAL }, opts || {}));\n\n\t\tvar lookup = chatEngineConfig().csrHistoryItemLookup;\n\t\tvar ident = this.host.getIdentity();\n\t\tvar platform = ident && ident.platform;\n\t\tif (!lookup || !itemId || !ident || !ident.projectId\n\t\t\t|| (platform !== 'claude' && platform !== 'openai')) {\n\t\t\treturn base;\n\t\t}\n\n\t\tvar settled = false;\n\t\tvar timers: any[] = [];\n\t\tvar clearProbes = function () {\n\t\t\tfor (var i = 0; i < timers.length; i++) clearTimeout(timers[i]);\n\t\t\ttimers = [];\n\t\t};\n\t\tvar stopBase = base && typeof base.stop === 'function' ? base.stop.bind(base) : null;\n\n\t\tvar raced: any = new Promise(function (resolve, reject) {\n\t\t\tbase.then(function (res: any) {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true; clearProbes(); resolve(res);\n\t\t\t}, function (err: any) {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true; clearProbes(); reject(err);\n\t\t\t});\n\n\t\t\tvar fullId = buildHistoryItemFullId(platform as 'claude' | 'openai', ident.projectId, itemId);\n\t\t\tEARLY_PROBE_SCHEDULE_MS.forEach(function (delay) {\n\t\t\t\ttimers.push(setTimeout(function () {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tPromise.resolve(lookup!(fullId, ident.projectId, ident.owner)).then(function (body: any) {\n\t\t\t\t\t\tif (settled || !body || typeof body !== 'object') return;\n\t\t\t\t\t\t// Still working: leave it to the next probe or the interval.\n\t\t\t\t\t\tif (body.status === 'pending' || body.status === 'running') return;\n\t\t\t\t\t\t// A stop is not a result; the normal stop path handles that.\n\t\t\t\t\t\tif (isPollStopped(body)) return;\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tclearProbes();\n\t\t\t\t\t\t// The interval would otherwise keep firing against a finished item.\n\t\t\t\t\t\tif (stopBase) { try { stopBase(); } catch (e) { /* already gone */ } }\n\t\t\t\t\t\tif (opts && typeof opts.onResponse === 'function') {\n\t\t\t\t\t\t\ttry { opts.onResponse(body); } catch (e) { /* caller's problem, not the poll's */ }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve(body);\n\t\t\t\t\t}, function () { /* probe failures are not errors: the interval is the source of truth */ });\n\t\t\t\t}, delay));\n\t\t\t});\n\t\t});\n\n\t\t// _trackPoll and the cancel path both reach for .stop, so the wrapper has to carry it.\n\t\traced.stop = function () {\n\t\t\tsettled = true;\n\t\t\tclearProbes();\n\t\t\tif (stopBase) stopBase();\n\t\t};\n\t\treturn raced;\n\t}\n\n\tprivate _trackPoll(id: string, kind: 'fg' | 'bg', p: any): any {\n\t\tvar stop = p && typeof p.stop === 'function' ? p.stop.bind(p) : undefined;\n\t\tif (!stop) {\n\t\t\t// The SDK could not give us a handle. Almost always means an older skapi-js\n\t\t\t// is loaded (or a stale bundler dep cache) — the poll will be unstoppable.\n\t\t\tconsole.debug('[chat-engine] poll has no stop handle', { id: id, kind: kind });\n\t\t}\n\t\tthis.historyItemPolls.set(id, { kind: kind, stop: stop });\n\t\treturn p;\n\t}\n\n\t/** Background polls currently attached, for the MAX_CONCURRENT_BG_POLLS budget.\n\t * Counts the registry rather than a separate tally so it cannot drift: every\n\t * attach goes through _trackPoll and every detach deletes the entry. Note an\n\t * entry left behind by pausePolling on an older skapi-js (no stop handle)\n\t * still counts, which is correct — that poll really is still running. */\n\tprivate _countBgPolls(): number {\n\t\tvar n = 0;\n\t\tthis.historyItemPolls.forEach(function (handle) {\n\t\t\tif (handle && handle.kind === 'bg') n++;\n\t\t});\n\t\treturn n;\n\t}\n\n\t/**\n\t * Stop and forget one item's poll. Used after a cancel: the row is either gone\n\t * (cancelled while queued) or flagged cancelled (cancelled while running), so\n\t * asking about it again only burns requests. Safe when no poll is attached, and\n\t * safe on an older skapi-js with no stop handle (the entry is then LEFT in the\n\t * map so a later drain cannot stack a second, unstoppable poll on the id).\n\t */\n\tprivate _stopPoll(id: string): void {\n\t\tvar handle = this.historyItemPolls.get(id);\n\t\tif (!handle) return;\n\t\tif (typeof handle.stop !== 'function') return;\n\t\ttry { handle.stop(); } catch (e) { /* best effort */ }\n\t\tthis.historyItemPolls.delete(id);\n\t}\n\n\t/** True while any pause reason is active. */\n\tisPollingPaused(): boolean {\n\t\treturn this._pauseReasons.size > 0;\n\t}\n\n\t/**\n\t * Stop BACKGROUND polling until resumePolling. Foreground polls (a reply the user is\n\t * waiting on) keep running deliberately: their results must still land in the history\n\t * cache so resumePendingRequest can render them on return, otherwise a user who sends\n\t * a message then navigates away comes back to a permanently stuck \"Thinking...\".\n\t *\n\t * Server-side work is untouched; this only stops asking about it. That is safe for\n\t * document indexing because the worker drives that loop itself.\n\t */\n\tpausePolling(reason: string): void {\n\t\tthis._pauseReasons.add(reason || 'paused');\n\t\tvar self = this;\n\t\tvar stopped: string[] = [];\n\t\tthis.historyItemPolls.forEach(function (handle, id) {\n\t\t\tif (!handle || handle.kind !== 'bg') return;\n\t\t\t// No stop available (older SDK): LEAVE the entry in place. Deleting it would\n\t\t\t// let a later drain attach a second, uncancellable poll on the same item.\n\t\t\tif (typeof handle.stop !== 'function') return;\n\t\t\ttry { handle.stop(); } catch (e) { /* best effort */ }\n\t\t\tstopped.push(id);\n\t\t});\n\t\t// Delete only what we actually stopped, one at a time. NEVER clear() the map:\n\t\t// wholesale clearing is what previously let loadHistory attach a duplicate poll\n\t\t// on a live item, producing duplicate replies and stranded \"Thinking\" bubbles.\n\t\tstopped.forEach(function (id) { self.historyItemPolls.delete(id); });\n\n\t}\n\n\t/**\n\t * Lift a pause reason WITHOUT running the reconcile. For a caller that is about to\n\t * reload history anyway (a view remounting), letting resumePolling also reconcile\n\t * would race that load and can double-attach.\n\t */\n\tclearPauseReason(reason: string): void {\n\t\tthis._pauseReasons.delete(reason || 'paused');\n\t}\n\n\t/**\n\t * Clear a pause reason and, once none remain, re-attach polling and reconcile.\n\t * Deliberately does NOT touch gateRefreshToken: bumping it would silently discard\n\t * the results of anything still in flight across the pause.\n\t */\n\tresumePolling(reason: string): Promise<void> {\n\t\tthis._pauseReasons.delete(reason || 'paused');\n\t\tif (this._pauseReasons.size > 0 || this._resuming) return Promise.resolve();\n\t\tif (!this.host.isViewMounted || !this.host.isViewMounted()) return Promise.resolve();\n\t\tvar self = this;\n\t\tthis._resuming = true;\n\t\treturn Promise.resolve()\n\t\t\t.then(function () {\n\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\treturn self.loadHistory(false, self.state.gateRefreshToken);\n\t\t\t})\n\t\t\t.catch(function (e: any) { console.error('[chat-engine] resume polling failed', e); })\n\t\t\t.then(function () { self._resuming = false; });\n\t}\n\n\tprivate _newLocalId(): string {\n\t\tthis._lidSeq += 1;\n\t\treturn 'lid_' + this._lidSeq;\n\t}\n\n\tgetHistoryCacheKey(): string {\n\t\tvar id = this.host.getIdentity();\n\t\tif (!id.projectId || id.platform === 'none') return '';\n\t\treturn id.projectId + '#' + id.platform;\n\t}\n\n\t// ─── compact-stub hydration ─────────────────────────────────────────────\n\t// Split-fetch bg pages arrive as label stubs (no bodies). When the user\n\t// expands a row, the real reply text is fetched per item (csr-poll point\n\t// lookup) and MEMOIZED per chat: every later remap (first-page refresh,\n\t// queue-detect tick, cache restore) re-applies the memo, so a hydrated\n\t// bubble can never silently revert to its 200-char head.\n\tprivate _hydratedBodies: { [chatKey: string]: { [itemId: string]: string } } = {};\n\tprivate _hydratingItems: { [key: string]: boolean } = {};\n\n\t/** Re-apply memoized hydrated texts onto freshly-mapped messages. Both\n\t * clients call this right after their mapper runs (loadHistory does it\n\t * internally); it mutates the given array's items in place. */\n\tapplyHydratedBodies(messages: ChatMessage[]): void {\n\t\tvar key = this.getHistoryCacheKey();\n\t\tvar memo = key ? this._hydratedBodies[key] : null;\n\t\tif (!memo) return;\n\t\tvar id = this.host.getIdentity();\n\t\tfor (var i = 0; i < messages.length; i++) {\n\t\t\tvar m: any = messages[i];\n\t\t\tif (!m || !m._compact || m.role !== 'assistant' || !m._serverItemId) continue;\n\t\t\tvar text = memo[m._serverItemId];\n\t\t\tif (typeof text !== 'string') continue;\n\t\t\tm.content = sanitizeAttachmentLinksForHistory(text, id.projectId, true) || EMPTY_INDEXING_REPLY;\n\t\t\tdelete m._compact;\n\t\t}\n\t}\n\n\t/** Fetch the real response bodies for compact history stubs (one csr-poll\n\t * point lookup per item id), memoize, and swap them into the live list.\n\t * Best-effort: a failed lookup leaves the stub (its head + fallback line\n\t * still render) and a later expand retries. */\n\thydrateCompactItems(itemIds: string[]): Promise<void> {\n\t\tvar self = this;\n\t\tvar lookup = chatEngineConfig().csrHistoryItemLookup;\n\t\tif (!lookup || !itemIds || !itemIds.length) return Promise.resolve();\n\t\tvar id = this.host.getIdentity();\n\t\tvar platform = id.platform;\n\t\tif (!id.projectId || (platform !== 'claude' && platform !== 'openai')) return Promise.resolve();\n\t\tvar chatKey = this.getHistoryCacheKey();\n\t\tif (!chatKey) return Promise.resolve();\n\t\tvar jobs = itemIds.map(function (itemId) {\n\t\t\tif (!itemId) return Promise.resolve();\n\t\t\tvar already = self._hydratedBodies[chatKey] && self._hydratedBodies[chatKey][itemId] !== undefined;\n\t\t\tvar inflightKey = chatKey + '|' + itemId;\n\t\t\tif (already || self._hydratingItems[inflightKey]) return Promise.resolve();\n\t\t\tself._hydratingItems[inflightKey] = true;\n\t\t\treturn Promise.resolve(lookup(buildHistoryItemFullId(platform as 'claude' | 'openai', id.projectId, itemId), id.projectId, id.owner)).then(function (body: any) {\n\t\t\t\t// Chat may have switched while the lookup flew; the memo is\n\t\t\t\t// per-chat so record under the key we started with, and only\n\t\t\t\t// touch the live list if it is still that chat's.\n\t\t\t\tvar text = ((platform === 'openai' ? extractOpenAIText(body) : extractClaudeText(body)) || '').trim();\n\t\t\t\tif (text.indexOf(INDEXING_COMPLETE_MARKER) !== -1) text = text.split(INDEXING_COMPLETE_MARKER).join('').trim();\n\t\t\t\tif (!self._hydratedBodies[chatKey]) self._hydratedBodies[chatKey] = {};\n\t\t\t\tself._hydratedBodies[chatKey][itemId] = text;\n\t\t\t\tif (self.getHistoryCacheKey() !== chatKey) return;\n\t\t\t\tfor (var i = 0; i < self.state.messages.length; i++) {\n\t\t\t\t\tvar m: any = self.state.messages[i];\n\t\t\t\t\tif (m && m._compact && m.role === 'assistant' && m._serverItemId === itemId) {\n\t\t\t\t\t\tm.content = sanitizeAttachmentLinksForHistory(text, id.projectId, true) || EMPTY_INDEXING_REPLY;\n\t\t\t\t\t\tdelete m._compact;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}).catch(function () { /* stub stays; expand retries */ }).then(function () {\n\t\t\t\tdelete self._hydratingItems[inflightKey];\n\t\t\t});\n\t\t});\n\t\treturn Promise.all(jobs).then(function () {\n\t\t\tif (self.getHistoryCacheKey() !== chatKey) return;\n\t\t\tself.host.notify();\n\t\t\tself.updateHistoryCache();\n\t\t});\n\t}\n\n\tupdateHistoryCache(): void {\n\t\tvar key = this.getHistoryCacheKey();\n\t\tif (!key) return;\n\t\t// Never persist another chat's in-flight bubbles under THIS key. The\n\t\t// dashboard shares one ChatSession across projects, so a turn dispatched\n\t\t// in project A can still be sitting in state.messages while the identity\n\t\t// (and therefore `key`) already points at project B — without this filter\n\t\t// A's user + \"Thinking...\" bubbles get written into B's cache entry and\n\t\t// replay on every later visit to B. Bubbles with no _ownerKey (server\n\t\t// history, bg tasks) are always kept. Single pass: this runs on the\n\t\t// typewriter hot path.\n\t\t//\n\t\t// Staged bubbles (_stageId) ARE cached, deliberately. They used to be dropped\n\t\t// on the theory that a reload kills the upload but not the cache, leaving a\n\t\t// message that uploads forever — but this cache is an in-memory field on a\n\t\t// singleton created at module load, so a reload takes it and the upload chain\n\t\t// together and that state is unreachable. What dropping them DID cost was\n\t\t// real: state.messages is shared across projects, so both clients filter it by\n\t\t// _ownerKey on every chat switch, and with no cached copy the bubble was\n\t\t// destroyed outright. A user who sent a question with a file and then looked at\n\t\t// another project lost the question for the whole indexing wait and got it back\n\t\t// at the bottom minutes later.\n\t\t//\n\t\t// isLiveStage + settleDeadStagedMessages keep the original concern honest if\n\t\t// this cache is ever persisted: a restored stage whose upload no longer exists\n\t\t// settles into a plain message instead of uploading forever.\n\t\tthis.aiChatHistoryCache[key] = {\n\t\t\tmessages: this.state.messages.filter(function (m) {\n\t\t\t\treturn m._ownerKey === undefined || m._ownerKey === key;\n\t\t\t}),\n\t\t\tendOfList: this.state.historyEndOfList,\n\t\t\tstartKeyHistory: this.state.historyStartKeyHistory.slice(),\n\t\t};\n\t}\n\n\t/**\n\t * Give the immediate-send pair the server's id for their turn, the moment the\n\t * dispatch learns it.\n\t *\n\t * WHY THIS EXISTS. An immediate send pushes its user bubble and its\n\t * \"Thinking...\" placeholder locally, and until now neither ever carried a\n\t * _serverItemId — only the QUEUED path stamped one, off its ack. So for the\n\t * whole life of the turn there was no way to tell the local copy and the\n\t * server's copy of the SAME turn apart, and the history merge fell back to a\n\t * heuristic: rescue the local pair unless the freshly-fetched page happens to\n\t * contain a pending assistant.\n\t *\n\t * That heuristic has a hole exactly one poll interval wide. The server settles\n\t * the request; for up to POLL_INTERVAL the client has not noticed, so\n\t * `state.sending` is still true and the local pair is still on screen — while a\n\t * history fetch issued in that window returns the turn ALREADY SETTLED, with no\n\t * pending assistant in it. The rescue then re-appends the local pair below the\n\t * server's copy (the question, twice), and when the poll finally resolves,\n\t * typewriteLatestReply writes the answer into the rescued placeholder because it\n\t * is the only pending assistant left (the answer, twice). updateHistoryCache\n\t * persists the result, so it survives every later visit.\n\t *\n\t * Navigating away while waiting and coming back is what lands a fetch in that\n\t * window: a remount runs refreshGate -> a fresh first page, at an arbitrary\n\t * moment relative to the 3s poll.\n\t *\n\t * With the id on the bubbles, both clients' rescue loops skip them through the\n\t * dedup they already have (`_serverItemId is in this page`), the reply the\n\t * dispatch caches inherits the id too, and nothing needs a new special case.\n\t *\n\t * Matched by _localId, never by index: a file's indexing rows are spliced in\n\t * above these bubbles while the request is in flight.\n\t */\n\tprivate _stampTurnWithItemId(key: string, userLid: string | undefined, placeholderLid: string | undefined, itemId: string): void {\n\t\t// placeholderLid is undefined for a QUEUED send: that path has no\n\t\t// \"Thinking...\" bubble of its own until promoteNextQueuedToRunning makes one,\n\t\t// and that copies the user bubble's id itself.\n\t\tif (!itemId) return;\n\t\tvar changed = false;\n\t\tvar stamp = function (list: ChatMessage[]) {\n\t\t\tvar hit = false;\n\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\tvar m = list[i];\n\t\t\t\tif (!m || !m._localId) continue;\n\t\t\t\tif (m._localId !== userLid && m._localId !== placeholderLid) continue;\n\t\t\t\tif (m._serverItemId === itemId) continue;\n\t\t\t\tlist[i] = Object.assign({}, m, { _serverItemId: itemId });\n\t\t\t\thit = true;\n\t\t\t}\n\t\t\treturn hit;\n\t\t};\n\t\tchanged = stamp(this.state.messages);\n\t\t// And in the cache, which is what a remount renders BEFORE the fetch lands.\n\t\t// A cached copy still missing the id would be rescued by the very merge this\n\t\t// is here to satisfy.\n\t\tvar cached = key ? this.aiChatHistoryCache[key] : undefined;\n\t\tif (cached) {\n\t\t\tvar msgs = cached.messages.slice();\n\t\t\tif (stamp(msgs)) {\n\t\t\t\tthis.aiChatHistoryCache[key] = {\n\t\t\t\t\tmessages: msgs, endOfList: cached.endOfList, startKeyHistory: cached.startKeyHistory,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tif (changed) this.host.notify();\n\t}\n\n\t/**\n\t * Land a resolved reply in the history cache of a chat that is NOT currently\n\t * visible, without touching state.messages. Mirrors the cache-only path in\n\t * dispatchAgentRequest: REPLACE the trailing pending \"Thinking...\" bubble\n\t * (append only when there is none), and settle the matching pending user\n\t * bubble, so the cached copy never keeps a stuck \"Thinking...\" that a later\n\t * cache-first load would re-render forever.\n\t */\n\tprivate _applyReplyToCache(key: string, reply: ChatMessage, serverId?: string): void {\n\t\tif (!key) return;\n\t\tvar existing = this.aiChatHistoryCache[key] || { messages: [], endOfList: false, startKeyHistory: [] };\n\t\tvar msgs = existing.messages.slice();\n\n\t\tvar thIdx = -1;\n\t\tfor (var i = msgs.length - 1; i >= 0; i--) {\n\t\t\tvar m = msgs[i];\n\t\t\tif (!m || !m.isPending || m.role !== 'assistant' || m.isBackgroundTask) continue;\n\t\t\tif (serverId && m._serverItemId && m._serverItemId !== serverId) continue;\n\t\t\tthIdx = i; break;\n\t\t}\n\t\tif (thIdx !== -1) {\n\t\t\tif (reply._serverItemId === undefined && msgs[thIdx]._serverItemId !== undefined) reply._serverItemId = msgs[thIdx]._serverItemId;\n\t\t\tmsgs[thIdx] = reply;\n\t\t} else {\n\t\t\t// No pending placeholder left to replace. Before appending, check whether\n\t\t\t// this turn is ALREADY in the cache — a history fetch may have mapped the\n\t\t\t// resolved turn in while the reply was in flight. Appending blindly is how\n\t\t\t// one turn ended up rendered twice (the duplicated question+answer): the\n\t\t\t// cache is restored verbatim on the next mount, so a duplicate written\n\t\t\t// here survives every later visit.\n\t\t\tvar dupIdx = -1;\n\t\t\tif (serverId) {\n\t\t\t\tfor (var d = msgs.length - 1; d >= 0; d--) {\n\t\t\t\t\tvar dm = msgs[d];\n\t\t\t\t\tif (dm && dm.role === 'assistant' && dm._serverItemId === serverId) { dupIdx = d; break; }\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (dupIdx !== -1) msgs[dupIdx] = reply;\n\t\t\telse msgs.push(reply);\n\t\t}\n\n\t\t// Settle the user bubble this turn belongs to (first pending one, or the\n\t\t// one carrying serverId) so it stops rendering as still in flight.\n\t\tfor (var j = 0; j < msgs.length; j++) {\n\t\t\tvar u = msgs[j];\n\t\t\tif (!u || u.role !== 'user' || u.isBackgroundTask) continue;\n\t\t\t// A STAGED bubble matches this shape exactly — pending, no server id, so the\n\t\t\t// id test below cannot rule it out — and sits EARLIER in the list than the\n\t\t\t// turn actually resolving. Settling it would strip its _stageId and its\n\t\t\t// upload state, silently killing a turn whose files are still going up.\n\t\t\tif (u._stageId) continue;\n\t\t\tif (!(u.isPendingQueued || u.isPendingInProcess || u.isSendingToServer)) continue;\n\t\t\tif (serverId && u._serverItemId && u._serverItemId !== serverId) continue;\n\t\t\tvar settled: ChatMessage = { role: 'user', content: u.content };\n\t\t\tif (u._serverItemId !== undefined) settled._serverItemId = u._serverItemId;\n\t\t\tif (u._ownerKey !== undefined) settled._ownerKey = u._ownerKey;\n\t\t\tmsgs[j] = settled;\n\t\t\tbreak;\n\t\t}\n\n\t\tthis.aiChatHistoryCache[key] = {\n\t\t\tmessages: msgs,\n\t\t\tendOfList: existing.endOfList,\n\t\t\tstartKeyHistory: existing.startKeyHistory,\n\t\t};\n\t}\n\n\t/**\n\t * projectId/owner are passed explicitly by every caller: a request can be\n\t * dispatched after the user moved to another project, and re-reading the live\n\t * identity here would silently send the turn to THAT project instead of the\n\t * one it was composed for. Falls back to the live read only when a caller\n\t * omits them.\n\t */\n\tprivate _callProviderFor(platform: string, prompt: string, messages: any, system: string, model: string | undefined, userId: string, extractContent: any, fileUrls?: any, projectId?: string, owner?: string) {\n\t\tif (projectId === undefined || owner === undefined) {\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (projectId === undefined) projectId = id.projectId;\n\t\t\tif (owner === undefined) owner = id.owner;\n\t\t}\n\t\treturn platform === 'openai'\n\t\t\t? callOpenAIWithPublicMcp(prompt, projectId, owner, messages, system, model, userId, extractContent, fileUrls)\n\t\t\t: callClaudeWithPublicMcp(prompt, projectId, owner, messages, system, model, userId, extractContent, fileUrls);\n\t}\n\n\tdispatchAgentRequest(params: any) {\n\t\tvar self = this;\n\t\t// Id of the in-flight item this dispatch polls. Recorded in\n\t\t// historyItemPolls (set below, deleted when the dispatch settles) so a\n\t\t// remount / history refetch dedups against THIS poll instead of stacking\n\t\t// a duplicate history poll on the same item. (The cacheKey guard alone\n\t\t// stops covering an item once pendingAgentRequests clears — e.g. a queued\n\t\t// message still in flight after the immediate one resolved.)\n\t\tvar dispatchItemId: string | undefined;\n\t\tvar sendAndPoll = function () {\n\t\t\treturn Promise.resolve(\n\t\t\t\tself._callProviderFor(params.aiPlatform, params.text, params.boundedMessages, params.systemPrompt, params.aiModel, params.userId, params.extractContent, params.fileUrls, params.projectId, params.owner)\n\t\t\t).then(function (initial: any) {\n\t\t\t\tif (initial && initial.poll && (initial.status === 'pending' || initial.status === 'running')) {\n\t\t\t\t\tif (initial.id) {\n\t\t\t\t\t\tif (dispatchItemId && dispatchItemId !== initial.id) self.historyItemPolls.delete(dispatchItemId);\n\t\t\t\t\t\tdispatchItemId = initial.id;\n\t\t\t\t\t\t// Hand the id to the caller so the bubbles already on screen can\n\t\t\t\t\t\t// carry it. An auth-refresh retry re-enters here with a NEW id,\n\t\t\t\t\t\t// so this reports every time, not once.\n\t\t\t\t\t\tif (typeof params.onItemId === 'function') params.onItemId(initial.id);\n\t\t\t\t\t}\n\t\t\t\t\tvar dp = self._fgPollWithEarlyProbe(initial, initial.id);\n\t\t\t\t\tif (initial.id) self._trackPoll(initial.id, 'fg', dp);\n\t\t\t\t\treturn dp;\n\t\t\t\t}\n\t\t\t\treturn initial;\n\t\t\t});\n\t\t};\n\t\tvar run = sendAndPoll()\n\t\t\t.catch(function (err: any) {\n\t\t\t\t// Only auth-expiry is worth a refresh+resend; a malformed-request 400\n\t\t\t\t// (e.g. the `_skapi_extract`/unknown-parameter class) re-fails identically,\n\t\t\t\t// so never loop on it — guard against isAuthExpiredError's heuristic\n\t\t\t\t// misfiring on a param name that merely contains \"token\".\n\t\t\t\tif (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(sendAndPoll);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.then(function (response: any) {\n\t\t\t\tif (isErrorResponseBody(response) && isAuthExpiredError(response) && !isNonRetryableRequestError(response)) {\n\t\t\t\t\treturn self.host.refreshSession().then(sendAndPoll);\n\t\t\t\t}\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.then(function (response: any) {\n\t\t\t\tif (isErrorResponseBody(response)) return { content: getErrorMessage(response), isError: true };\n\t\t\t\tvar answer = (params.aiPlatform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response));\n\t\t\t\tanswer = (answer || '').trim();\n\t\t\t\treturn { content: answer || 'No text response received from AI provider.', isError: false };\n\t\t\t})\n\t\t\t.catch(function (err: any) { return { content: getErrorMessage(err), isError: true }; })\n\t\t\t.then(function (result: any) {\n\t\t\t\t// Land the resolved reply in the shared history cache. This runs\n\t\t\t\t// independently of the view lifecycle, so a reply is captured even\n\t\t\t\t// if the chatbox unmounted mid-request.\n\t\t\t\tdelete self.pendingAgentRequests[params.key];\n\t\t\t\tif (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);\n\t\t\t\tvar reply: ChatMessage = { role: 'assistant', content: result.content, isError: result.isError };\n\t\t\t\tif (dispatchItemId) reply._serverItemId = dispatchItemId;\n\n\t\t\t\t// REPLACE the trailing pending \"Thinking...\" bubble in the cache with\n\t\t\t\t// the answer, regardless of whether this chat is the currently-visible\n\t\t\t\t// view. The cache must NEVER retain a pending \"Thinking...\" bubble: even\n\t\t\t\t// when the chatbox is showing this chat, typewriteLatestReply swaps the\n\t\t\t\t// bubble only in state.messages and NEVER re-snapshots the cache — so\n\t\t\t\t// leaving a pending copy here would have a later cache-first remount\n\t\t\t\t// re-render that \"Thinking...\" forever. typewriteLatestReply still finds\n\t\t\t\t// this reply (it reads the latest non-pending assistant from the cache),\n\t\t\t\t// so replacing is correct for the visible case too.\n\t\t\t\t//\n\t\t\t\t// _applyReplyToCache rather than an inline copy of it. This used to be\n\t\t\t\t// its own loop with the same replace-or-append shape MINUS the\n\t\t\t\t// dedup-before-append its twin already had, and the append is reachable:\n\t\t\t\t// once the local pair carries its server id (_stampTurnWithItemId), a\n\t\t\t\t// first-page fetch that lands after the server settles the item\n\t\t\t\t// correctly drops both local copies and re-snapshots a cache with no\n\t\t\t\t// pending placeholder left to replace. The blind push then wrote the\n\t\t\t\t// answer in a SECOND time, with no id on it, and the cache is rendered\n\t\t\t\t// verbatim on the next mount — so the fix that stopped the turn\n\t\t\t\t// duplicating on screen would have moved the duplicate into the cache.\n\t\t\t\tself._applyReplyToCache(params.key, reply, dispatchItemId);\n\t\t\t\treturn result;\n\t\t\t});\n\t\tthis.pendingAgentRequests[params.key] = run;\n\t\treturn run;\n\t}\n\n\t/**\n\t * Put a turn on screen the INSTANT the user hits Send, before its attachments\n\t * have finished uploading. Uploads run in the background now (the composer is\n\t * cleared and stays usable), so without a staged bubble the message would\n\t * appear only once its files were up — below anything the user sent in the\n\t * meantime, in an order that never matches what they typed.\n\t *\n\t * Staged bubbles carry _useBgQueue because that is where a turn with\n\t * attachments ultimately dispatches (behind its own indexing tasks). That flag\n\t * is also what keeps promoteNextQueuedToRunning / resolveQueuedUserBubble off\n\t * them: those advance the SERVER queue, and a staged turn has no server\n\t * request behind it yet.\n\t *\n\t * Returns the id to hand back as PinnedDispatchContext.stageId at dispatch.\n\t */\n\tstageOutgoingMessage(displayText: string): string {\n\t\tthis._stageSeq += 1;\n\t\tvar stageId = 'stg_' + this._stageSeq;\n\t\tvar key = this.getHistoryCacheKey();\n\t\tvar staged: ChatMessage = {\n\t\t\trole: 'user', content: displayText,\n\t\t\tisPendingQueued: true, isUploadingAttachments: true, isSendingToServer: true,\n\t\t\t_dimSending: true,\n\t\t\t// A staged bubble has no server id for minutes, and its indexing rows are\n\t\t\t// now inserted ABOVE it — so its array index moves. Both views fall back to\n\t\t\t// the index when a bubble has no id, which would re-key (and in Vue, remount)\n\t\t\t// this bubble on every file, restarting its transition and losing it as a\n\t\t\t// scroll anchor. A local id it keeps for its whole life fixes both.\n\t\t\t_localId: this._newLocalId(),\n\t\t\t_useBgQueue: true, _stageId: stageId, _ts: wallClockNow(),\n\t\t};\n\t\tif (key) staged._ownerKey = key;\n\t\tthis._liveStages[stageId] = true;\n\t\tthis.state.messages.push(staged);\n\t\tthis.host.notify(); this.host.scrollToBottom(true);\n\t\treturn stageId;\n\t}\n\n\t/** Is anything in this page still uploading/dispatching for this stage? */\n\tisLiveStage(stageId?: string): boolean {\n\t\treturn !!stageId && !!this._liveStages[stageId];\n\t}\n\n\t/**\n\t * Settle any staged bubble in `list` whose chain no longer exists, and return the\n\t * list (a new array only if something changed).\n\t *\n\t * The caller is a cache restore. A staged bubble is the one kind of message whose\n\t * resolution lives entirely in page memory — no server request stands behind it\n\t * yet — so a copy that outlives its upload would render \"(Uploading files...)\"\n\t * forever with nothing left to finish it. Today nothing can: this cache dies with\n\t * the page, so every restored stage is still live and this is a no-op. It exists\n\t * so that stops being a silent assumption.\n\t */\n\tsettleDeadStagedMessages(list: ChatMessage[]): ChatMessage[] {\n\t\tif (!Array.isArray(list)) return list;\n\t\tvar self = this;\n\t\tvar dead = false;\n\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\tvar m = list[i];\n\t\t\tif (m && m._stageId && !self._liveStages[m._stageId]) { dead = true; break; }\n\t\t}\n\t\tif (!dead) return list;\n\t\treturn list.map(function (m) {\n\t\t\tif (!m || !m._stageId || self._liveStages[m._stageId]) return m;\n\t\t\tvar settled: ChatMessage = { role: 'user', content: m.content };\n\t\t\tif (m._ownerKey !== undefined) settled._ownerKey = m._ownerKey;\n\t\t\tif (m._ts !== undefined) settled._ts = m._ts;\n\t\t\tif (m._localId !== undefined) settled._localId = m._localId;\n\t\t\treturn settled;\n\t\t});\n\t}\n\n\tprivate _stageIndex(list: ChatMessage[], stageId?: string): number {\n\t\tif (!stageId) return -1;\n\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\tif (list[i] && list[i]._stageId === stageId) return i;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Staged turn, phase 2: its files are up and it is now waiting for the whole\n\t * indexing chain behind them. Swaps \"(Uploading files...)\" for\n\t * \"(Indexing files...)\"; the bubble stays dimmed, because from the user's side\n\t * nothing has been handed over yet.\n\t *\n\t * It deliberately does NOT say \"(In queue)\" here. The turn is not queued behind\n\t * anything the server knows about yet — it is waiting on work that can run for\n\t * minutes — and claiming otherwise is what made the wait look like a stall.\n\t */\n\tmarkStagedMessageIndexing(stageId: string): void {\n\t\tvar idx = this._stageIndex(this.state.messages, stageId);\n\t\tif (idx === -1) return;\n\t\tvar ex = this.state.messages[idx];\n\t\tif (!ex.isUploadingAttachments) return;\n\t\tthis.state.messages[idx] = Object.assign({}, ex, {\n\t\t\tisUploadingAttachments: false, isAwaitingIndexing: true,\n\t\t});\n\t\tthis.host.notify();\n\t}\n\n\t/**\n\t * Staged turn, phase 3: the last of its files has finished indexing, so the turn\n\t * is genuinely just queued now. Full opacity + \"(In queue)\".\n\t *\n\t * Clears the PRESENTATIONAL _dimSending only; isSendingToServer stays set until\n\t * the server actually acks (it is the token that ack matches on). Called by the\n\t * clients the instant awaitIndexingDrained resolves, i.e. immediately before the\n\t * dispatch that replaces this bubble — dispatchComposedMessage carries the\n\t * cleared flag onto the replacement so the turn does not blink back to dimmed.\n\t */\n\tmarkStagedMessageReady(stageId: string): void {\n\t\tvar idx = this._stageIndex(this.state.messages, stageId);\n\t\tif (idx === -1) return;\n\t\tvar ex = this.state.messages[idx];\n\t\tif (!ex.isAwaitingIndexing && !ex._dimSending && !ex.isUploadingAttachments) return;\n\t\tthis.state.messages[idx] = Object.assign({}, ex, {\n\t\t\tisUploadingAttachments: false, isAwaitingIndexing: false, _dimSending: false,\n\t\t});\n\t\tthis.host.notify();\n\t}\n\n\t/**\n\t * Resolves once this project's background-indexing queue has nothing left to\n\t * run, so a chat enqueued right after it is genuinely last.\n\t *\n\t * Sending the chat as soon as the uploads finish is not enough, which is the\n\t * whole reason this exists: indexing a file is a CHAIN, and each pass is only\n\t * enqueued once the previous one lands (the client mints CONTINUE passes for\n\t * text/grid files, the worker mints them for PDFs and windowed reads). Every\n\t * one of those passes therefore queues up BEHIND a chat sent at upload time,\n\t * and the model answers from a file it has only partly read.\n\t *\n\t * The queue is read from the server's status index rather than from\n\t * bgTaskQueue: that mirror holds only what this client dispatched or adopted,\n\t * and it stops being maintained once the view unmounts. An empty answer has to\n\t * repeat before it is believed — see INDEXING_DRAIN_IDLE_LOOKS — and a look\n\t * that fails counts as busy, so a dropped request delays the turn instead of\n\t * releasing it early.\n\t *\n\t * Reads the identity PINNED at Send time, never a live one: the user may be in\n\t * another project by now, and this must keep asking about the one they sent\n\t * from.\n\t */\n\tawaitIndexingDrained(identity: ChatIdentity): Promise<'drained' | 'timedout' | 'skipped'> {\n\t\tvar self = this;\n\t\tvar svcId = identity && identity.projectId;\n\t\tvar platform = identity && identity.platform;\n\t\tif (!svcId || (platform !== 'claude' && platform !== 'openai')) return Promise.resolve('skipped' as const);\n\t\tvar owner = identity.owner;\n\t\tvar queue = bgIndexingQueueName(identity.userId, svcId);\n\t\tvar startedAt = nowMs();\n\t\tvar deadline = startedAt + INDEXING_DRAIN_TIMEOUT_MS;\n\t\tvar idleLooks = 0;\n\t\t// null = \"could not find out\", which the loop below counts as busy. The race\n\t\t// is what makes the timeout necessary rather than tidy: a getChatHistory that\n\t\t// never settles leaves no pending timer behind, so the whole wait — and the\n\t\t// turn, and its bubble — would hang on it indefinitely.\n\t\tvar ask = function (status: 'pending' | 'running') {\n\t\t\tvar answered = false;\n\t\t\treturn new Promise<any>(function (res) {\n\t\t\t\tvar bail: any = null;\n\t\t\t\tvar settle = function (v: any) {\n\t\t\t\t\tif (answered) return;\n\t\t\t\t\tanswered = true;\n\t\t\t\t\tif (bail) { clearTimeout(bail); bail = null; }\n\t\t\t\t\tres(v);\n\t\t\t\t};\n\t\t\t\tbail = setTimeout(function () { settle(null); }, INDEXING_DRAIN_LOOK_TIMEOUT_MS);\n\t\t\t\t// maxAgeMs 0: this loop is WAITING for the queue to change, so a\n\t\t\t\t// cached answer is useless to it — but its fresh answers write\n\t\t\t\t// through into the shared probe memo for the snapshot readers.\n\t\t\t\tPromise.resolve(probeBgQueue(\n\t\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status, limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t\t{ maxAgeMs: 0 },\n\t\t\t\t)).then(function (entry: any) { settle(entry.result); }, function () { settle(null); });\n\t\t\t});\n\t\t};\n\t\t// Ordinary chats are routed onto this queue too (_isOnBgQueue), and those\n\t\t// are not work this turn has to wait behind — the server runs the queue in\n\t\t// order, so being enqueued after them is enough.\n\t\tvar hasLiveIndexing = function (res: any): boolean {\n\t\t\tvar list = res && Array.isArray(res.list) ? res.list : [];\n\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\tvar item = list[i];\n\t\t\t\tif (!item || (item.status !== 'pending' && item.status !== 'running')) continue;\n\t\t\t\tif (isIndexingRequestText(extractLastUserTextFromRequest(item.request_body))) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t\treturn new Promise(function (resolve) {\n\t\t\tvar timer: any = null;\n\t\t\tvar lastLookAt = -Infinity;\n\t\t\tvar nudgedThisInterval = false;\n\t\t\t// A look's queries are OUT. Nothing may start a second one alongside it:\n\t\t\t// two overlapping looks share idleLooks, so both coming back idle would\n\t\t\t// count as the two agreeing looks WITHOUT the confirm gap between them —\n\t\t\t// the one guard that stands between the user and an answer computed from a\n\t\t\t// half-indexed file.\n\t\t\tvar inFlight = false;\n\t\t\tvar finish = function (v: 'drained' | 'timedout') {\n\t\t\t\tif (timer) { clearTimeout(timer); timer = null; }\n\t\t\t\t// De-register on BOTH exits or the waiter leaks a closure per send, and\n\t\t\t\t// a later settle re-arms a timer for a turn that has already gone out.\n\t\t\t\tvar ni = self._drainNudges.indexOf(nudge);\n\t\t\t\tif (ni !== -1) self._drainNudges.splice(ni, 1);\n\t\t\t\tresolve(v);\n\t\t\t};\n\t\t\tvar again = function (ms?: number) {\n\t\t\t\tif (timer) { clearTimeout(timer); timer = null; }\n\t\t\t\tvar wait = ms == null ? (idleLooks > 0 ? INDEXING_DRAIN_CONFIRM_POLL_MS : INDEXING_DRAIN_BUSY_POLL_MS) : ms;\n\t\t\t\ttimer = setTimeout(look, wait);\n\t\t\t};\n\t\t\t// Indexing just ended somewhere (see _nudgeIndexingDrain): ask now rather\n\t\t\t// than waiting out the rest of the busy interval, which is what made the\n\t\t\t// turn sit dimmed for another ten seconds after its files were visibly done.\n\t\t\tvar nudge = function () {\n\t\t\t\t// Already on the confirm cadence — the two agreeing looks and the gap\n\t\t\t\t// between them are the guard, and pulling the second one forward is\n\t\t\t\t// exactly what must not happen.\n\t\t\t\tif (idleLooks > 0) return;\n\t\t\t\tif (inFlight) return; // a look is already asking; nothing to pull forward\n\t\t\t\tif (nudgedThisInterval) return; // one pull-forward per interval\n\t\t\t\t// A look now would short-circuit on this anyway. Nothing re-fires when\n\t\t\t\t// the count reaches zero, deliberately (see trackIndexDispatch): the\n\t\t\t\t// cost is up to one busy interval of extra dim, and the alternative is\n\t\t\t\t// a nudge fired by work STARTING, which can release a turn early.\n\t\t\t\tif (self._indexDispatchesInFlight > 0) return;\n\t\t\t\tnudgedThisInterval = true;\n\t\t\t\tagain(Math.max(0, INDEXING_DRAIN_NUDGE_MIN_GAP_MS - (nowMs() - lastLookAt)));\n\t\t\t};\n\t\t\tvar look = function () {\n\t\t\t\ttimer = null;\n\t\t\t\t// Belt to the nudge's brace: never two sets of queries out at once.\n\t\t\t\tif (inFlight) return;\n\t\t\t\tlastLookAt = nowMs(); nudgedThisInterval = false;\n\t\t\t\tif (nowMs() >= deadline) { finish('timedout'); return; }\n\t\t\t\t// A pass whose ack is still in flight is not on the queue yet, so no\n\t\t\t\t// look can see it.\n\t\t\t\tif (self._indexDispatchesInFlight > 0) { idleLooks = 0; again(); return; }\n\t\t\t\tinFlight = true;\n\t\t\t\tPromise.all([ask('running'), ask('pending')]).then(function (res: any[]) {\n\t\t\t\t\tinFlight = false;\n\t\t\t\t\tvar unknown = res[0] === null || res[1] === null;\n\t\t\t\t\tif (unknown || hasLiveIndexing(res[0]) || hasLiveIndexing(res[1])) idleLooks = 0;\n\t\t\t\t\telse idleLooks += 1;\n\t\t\t\t\tif (idleLooks >= INDEXING_DRAIN_IDLE_LOOKS && nowMs() - startedAt >= INDEXING_DRAIN_MIN_MS) {\n\t\t\t\t\t\tfinish('drained'); return;\n\t\t\t\t\t}\n\t\t\t\t\tagain();\n\t\t\t\t}, function () { inFlight = false; idleLooks = 0; again(); });\n\t\t\t};\n\t\t\tself._drainNudges.push(nudge);\n\t\t\tlook();\n\t\t});\n\t}\n\n\t/**\n\t * Abandon a staged turn — its uploads failed outright, so nothing will be\n\t * dispatched. The bubble stays (the user's text is not silently thrown away)\n\t * but settles into a plain, non-pending message; the caller reports the\n\t * failure separately.\n\t */\n\tsettleStagedMessage(stageId: string): void {\n\t\t// Retired even when the bubble is not on screen (another project is): the\n\t\t// chain is over either way, and a cached copy must not read as still working.\n\t\tdelete this._liveStages[stageId];\n\t\tvar idx = this._stageIndex(this.state.messages, stageId);\n\t\tif (idx === -1) return;\n\t\tvar ex = this.state.messages[idx];\n\t\tvar settled: ChatMessage = { role: 'user', content: ex.content };\n\t\tif (ex._ownerKey !== undefined) settled._ownerKey = ex._ownerKey;\n\t\tif (ex._ts !== undefined) settled._ts = ex._ts;\n\t\t// Same key across the settle: it has no server id and never will.\n\t\tif (ex._localId !== undefined) settled._localId = ex._localId;\n\t\tthis.state.messages[idx] = settled;\n\t\tthis.host.notify(); this.updateHistoryCache();\n\t}\n\n\t// composed = clean display text; composedForLlm carries office-extraction\n\t// placeholders for the provider only. useBgQueue routes a post-attachment turn\n\t// onto the \"-bg\" queue so it runs after indexing.\n\tdispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any, pinned?: PinnedDispatchContext): void {\n\t\tvar self = this;\n\t\t// This turn may already have a bubble on screen, staged at Send time while\n\t\t// its attachments uploaded. Every exit from here has to account for it:\n\t\t// dispatching replaces it in place (so it keeps the position the user sent\n\t\t// it in), and bailing settles it (so it never sits uploading forever).\n\t\tvar stageId = pinned ? pinned.stageId : undefined;\n\t\tif (!composed) { if (stageId) this.settleStagedMessage(stageId); return; }\n\t\t// A send can be dispatched LONG after the user hit Send (attachment\n\t\t// uploads are awaited first), by which time the live identity may have\n\t\t// moved to another project. The caller pins the identity + system prompt\n\t\t// it captured at Send time so the request still goes to the project the\n\t\t// question was actually asked of. Falls back to the live read when the\n\t\t// caller doesn't pin (the widget, which has only one project anyway).\n\t\tvar id = pinned ? pinned.identity : this.host.getIdentity();\n\t\tif (id.platform === 'none') { if (stageId) this.settleStagedMessage(stageId); return; }\n\t\t// Past every bail: this turn is going out, so its stage is over whichever\n\t\t// branch below takes it, and whether or not the bubble is still on screen.\n\t\tif (stageId) delete this._liveStages[stageId];\n\n\t\tvar llmComposed = composedForLlm || composed;\n\n\t\t// Cache key of the chat this turn belongs to. Every locally-created\n\t\t// bubble is stamped with it so a project switch (which flips\n\t\t// getIdentity()/getHistoryCacheKey() to the new project) can't\n\t\t// misattribute this turn's bubbles to that project.\n\t\t// (platform === 'none' already returned above, so projectId is the only gate)\n\t\tvar key = !id.projectId ? '' : id.projectId + '#' + id.platform;\n\t\t// True when the pinned chat is NOT the one currently on screen. Then\n\t\t// state.messages belongs to a different project and MUST NOT be touched:\n\t\t// the turn is staged in the pinned chat's cache instead and shows up when\n\t\t// the user navigates back to it.\n\t\tvar offChat = !!key && key !== this.getHistoryCacheKey();\n\n\t\tvar isQueuedSend = !offChat && (useBgQueue || this.state.sending || this.state.messages.some(function (m) {\n\t\t\treturn (m.isPending || m.isPendingQueued) && !m.isBackgroundTask && !m._useBgQueue;\n\t\t}));\n\n\t\tvar aiPlatform = id.platform;\n\t\tvar aiModel = id.model || undefined;\n\t\tvar systemPrompt = pinned ? pinned.systemPrompt : this.host.buildSystemPrompt();\n\t\tvar userId = id.userId || id.projectId;\n\t\t// Same string the indexing passes are enqueued under (bgIndexingQueueName),\n\t\t// which is the whole reason this turn ends up behind them: the backend runs\n\t\t// different queue names in parallel and only serialises a shared one.\n\t\tvar chatQueue = useBgQueue ? bgIndexingQueueName(userId) : userId;\n\t\t// _stageIndex is -1 when nothing was staged, or when the staged bubble is\n\t\t// gone (a remount rebuilds the list from the cache, which never holds staged\n\t\t// bubbles); either way the branches below fall back to appending.\n\n\t\tif (offChat) {\n\t\t\t// Stage the turn in the pinned chat's cache and dispatch. The\n\t\t\t// client-side queue can't be consulted (its state is the other\n\t\t\t// project's), but the SERVER serializes per queue name, so ordering\n\t\t\t// within the pinned chat still holds. dispatchAgentRequest replaces\n\t\t\t// the pending bubble in this same cache entry when the reply lands.\n\t\t\tvar offHistory = (this.aiChatHistoryCache[key] ? this.aiChatHistoryCache[key].messages : []).filter(function (m) {\n\t\t\t\treturn !m.isPending && !m.isPendingQueued && !m.isPendingInProcess && !m.isPendingOlder &&\n\t\t\t\t\t!m.isCancelled && !m.isBackgroundTask && !m.isError;\n\t\t\t});\n\t\t\tvar offBounded = buildBoundedChatMessages({\n\t\t\t\tplatform: aiPlatform, model: aiModel, systemPrompt: systemPrompt, projectId: id.projectId,\n\t\t\t\thistory: offHistory.concat([{ role: 'user', content: llmComposed }]),\n\t\t\t});\n\t\t\tvar offExisting = this.aiChatHistoryCache[key] || { messages: [], endOfList: false, startKeyHistory: [] };\n\t\t\tvar offUser: ChatMessage = { role: 'user', content: composed, _ownerKey: key, _ts: wallClockNow() };\n\t\t\t// The user hit Send here, then navigated away before the uploads\n\t\t\t// finished. The staged bubble belongs to THAT chat, not the one now on\n\t\t\t// screen, and the turn it stood in for is being cached below — so drop\n\t\t\t// it from the live list instead of leaving a bubble that uploads\n\t\t\t// forever in a project it does not belong to.\n\t\t\tvar offStage = this._stageIndex(this.state.messages, stageId);\n\t\t\tif (offStage !== -1) {\n\t\t\t\tif (this.state.messages[offStage]._ts !== undefined) offUser._ts = this.state.messages[offStage]._ts;\n\t\t\t\tthis.state.messages.splice(offStage, 1);\n\t\t\t\tthis.host.notify();\n\t\t\t}\n\t\t\t// The cached copy of that same staged bubble has to go with it. offUser is\n\t\t\t// the turn it stood in for, appended just below; leaving both would show the\n\t\t\t// question twice on the next visit, permanently — the cache is restored\n\t\t\t// verbatim. (Its _ts is recovered above only when the live bubble is still\n\t\t\t// there; take it from the cached copy otherwise, so the turn keeps the time\n\t\t\t// the user sent it at rather than the upload's finish time.)\n\t\t\tvar offCached = offExisting.messages;\n\t\t\tif (stageId) {\n\t\t\t\toffCached = offCached.filter(function (m) {\n\t\t\t\t\tif (m._stageId !== stageId) return true;\n\t\t\t\t\tif (offStage === -1 && m._ts !== undefined) offUser._ts = m._ts;\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.aiChatHistoryCache[key] = {\n\t\t\t\tmessages: offCached.concat([\n\t\t\t\t\toffUser,\n\t\t\t\t\t{ role: 'assistant', content: '', isPending: true, isPendingInProcess: true, _ownerKey: key },\n\t\t\t\t]),\n\t\t\t\tendOfList: offExisting.endOfList,\n\t\t\t\tstartKeyHistory: offExisting.startKeyHistory,\n\t\t\t};\n\t\t\tthis.dispatchAgentRequest({\n\t\t\t\tkey: key, projectId: id.projectId, owner: id.owner, aiPlatform: aiPlatform, aiModel: aiModel,\n\t\t\t\tsystemPrompt: systemPrompt, text: composed, boundedMessages: offBounded.messages, userId: chatQueue,\n\t\t\t\textractContent: extractContent, fileUrls: fileUrls,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (isQueuedSend) {\n\t\t\tvar resolvedHistory = this.state.messages.filter(function (m) {\n\t\t\t\treturn !m.isPending && !m.isPendingQueued && !m.isPendingInProcess && !m.isPendingOlder &&\n\t\t\t\t\t!m.isCancelled && !m.isBackgroundTask && !m.isError;\n\t\t\t});\n\t\t\tvar boundedQ = buildBoundedChatMessages({\n\t\t\t\tplatform: aiPlatform, model: aiModel, systemPrompt: systemPrompt, projectId: id.projectId,\n\t\t\t\thistory: resolvedHistory.concat([{ role: 'user', content: llmComposed }]),\n\t\t\t});\n\t\t\t// _localId for the same reason as immediateUser below: a queued turn can be\n\t\t\t// renumbered by indexing rows spliced in above it, and an id-less bubble is\n\t\t\t// keyed by index. Overwritten by the staged bubble's own id when replacing one.\n\t\t\tvar queuedBubble: ChatMessage = { role: 'user', content: composed, isPendingQueued: true, isSendingToServer: true, _dimSending: true, _localId: this._newLocalId(), _ts: wallClockNow() };\n\t\t\tif (key) queuedBubble._ownerKey = key;\n\t\t\tif (useBgQueue) queuedBubble._useBgQueue = true;\n\t\t\tvar qStage = this._stageIndex(this.state.messages, stageId);\n\t\t\tif (qStage !== -1) {\n\t\t\t\t// Replace IN PLACE. The turn already sits below its own indexing rows —\n\t\t\t\t// drainBgTaskQueue inserted each of them directly above this bubble as\n\t\t\t\t// the file's pass started — so there is nothing left to reorder, and the\n\t\t\t\t// row order the reader has been looking at all along is the same one the\n\t\t\t\t// server will report on the next load.\n\t\t\t\tvar qEx = this.state.messages[qStage];\n\t\t\t\t// Keep the send time the user saw, not the upload's finish time.\n\t\t\t\tif (qEx._ts !== undefined) queuedBubble._ts = qEx._ts;\n\t\t\t\t// This turn waited out its uploads AND its whole indexing chain in full\n\t\t\t\t// view; markStagedMessageReady un-dimmed it when that finished. Re-dimming\n\t\t\t\t// it now for the one remaining request would read as the wait restarting.\n\t\t\t\tif (qEx._dimSending === false) queuedBubble._dimSending = false;\n\t\t\t\tif (qEx._localId) queuedBubble._localId = qEx._localId;\n\t\t\t\tthis.state.messages.splice(qStage, 1, queuedBubble);\n\t\t\t} else {\n\t\t\t\tthis.state.messages.push(queuedBubble);\n\t\t\t}\n\t\t\tthis.host.notify(); this.updateHistoryCache(); this.scrollForDispatch(stageId);\n\n\t\t\tvar capturedComposed = composed, capturedPlatform = aiPlatform, capturedKey = key;\n\t\t\tvar capturedQueuedLid = queuedBubble._localId;\n\t\t\tPromise.resolve(this._callProviderFor(aiPlatform, composed, boundedQ.messages, systemPrompt, aiModel, chatQueue, extractContent, fileUrls, id.projectId, id.owner))\n\t\t\t\t.then(function (result: any) {\n\t\t\t\t\t// Only ack a bubble that belongs to THIS chat — the search is\n\t\t\t\t\t// positional, so on another project it would stamp this turn's\n\t\t\t\t\t// _serverItemId onto that project's unrelated in-flight bubble.\n\t\t\t\t\t// Staged bubbles (_stageId) are skipped for the same reason: they\n\t\t\t\t\t// sit EARLIER in the list and match this shape exactly, so a turn\n\t\t\t\t\t// whose files are still uploading would take the ack — and the\n\t\t\t\t\t// server id — belonging to the turn that actually just sent.\n\t\t\t\t\tvar sendingIdx = self.getHistoryCacheKey() !== capturedKey ? -1 : self.state.messages.findIndex(function (m) {\n\t\t\t\t\t\treturn m.isSendingToServer && (m.isPendingQueued || m.isPendingInProcess) && m.role === 'user' &&\n\t\t\t\t\t\t\t!m._stageId && (m._ownerKey === undefined || m._ownerKey === capturedKey);\n\t\t\t\t\t});\n\t\t\t\t\tvar serverId = result && typeof result.id === 'string' ? result.id : undefined;\n\t\t\t\t\tif (sendingIdx >= 0) {\n\t\t\t\t\t\tvar upd = Object.assign({}, self.state.messages[sendingIdx], { isSendingToServer: false, _dimSending: false });\n\t\t\t\t\t\tif (serverId) upd._serverItemId = serverId;\n\t\t\t\t\t\tself.state.messages[sendingIdx] = upd; self.host.notify();\n\t\t\t\t\t}\n\t\t\t\t\t// And into the CACHE, which the block above never touched: a remount\n\t\t\t\t\t// renders the cache first, so an unstamped copy there is a bubble the\n\t\t\t\t\t// first-page merge cannot recognise as the turn the server just sent\n\t\t\t\t\t// back — which is how a queued turn came back doubled. Keyed to\n\t\t\t\t\t// capturedKey and matched by _localId, so it lands correctly even\n\t\t\t\t\t// when the user has already moved to another project (plain\n\t\t\t\t\t// updateHistoryCache writes under the LIVE key, which by then is a\n\t\t\t\t\t// different chat).\n\t\t\t\t\tif (serverId) self._stampTurnWithItemId(capturedKey, capturedQueuedLid, undefined, serverId);\n\t\t\t\t\tif (result && result.poll && (result.status === 'pending' || result.status === 'running')) {\n\t\t\t\t\t\t// Track this queued item's poll so a remount/refetch dedups\n\t\t\t\t\t\t// against it instead of attaching a duplicate history poll.\n\t\t\t\t\t\tvar qp = self._fgPollWithEarlyProbe(result, serverId);\n\t\t\t\t\t\tif (serverId) self._trackPoll(serverId, 'fg', qp);\n\t\t\t\t\t\treturn qp\n\t\t\t\t\t\t\t.then(function (res: any) { if (isPollStopped(res)) return; return self.onQueuedSendResponse(capturedComposed, res, capturedPlatform, serverId, capturedKey); })\n\t\t\t\t\t\t\t.catch(function (err: any) { return self.onQueuedSendError(capturedComposed, err, serverId, capturedKey); });\n\t\t\t\t\t}\n\t\t\t\t\treturn self.onQueuedSendResponse(capturedComposed, result, capturedPlatform, serverId, capturedKey);\n\t\t\t\t})\n\t\t\t\t.catch(function (err: any) { return self.onQueuedSendError(capturedComposed, err, undefined, capturedKey); });\n\t\t\treturn;\n\t\t}\n\n\t\t// immediate send — cache+resume model (mirrors agent.vue). The reply is\n\t\t// appended to aiChatHistoryCache by dispatchAgentRequest (so it survives a\n\t\t// view unmount), then rendered from the cache via typewriteLatestReply. A\n\t\t// later resumePendingRequest() re-renders it if the view remounted while the\n\t\t// request was still in flight.\n\t\t// _localId on the user bubble too, not just the staged one it may replace: an\n\t\t// ordinary turn sent while another is staged sits BELOW that turn, so every\n\t\t// indexing row spliced in above renumbers it — and a view that keys an id-less\n\t\t// bubble by index would tear it down and rebuild it on every uploaded file.\n\t\tvar immediateUser: ChatMessage = { role: 'user', content: composed, _localId: this._newLocalId(), _ts: wallClockNow(), ...(key ? { _ownerKey: key } : {}) };\n\t\t// _localId on the placeholder too. It is how the server item id finds these\n\t\t// two bubbles again once the dispatch reports it (see onItemId below), and\n\t\t// indexing rows spliced in above move both of them, so an index will not do.\n\t\tvar immediatePlaceholder: ChatMessage = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, _localId: this._newLocalId(), ...(key ? { _ownerKey: key } : {}) };\n\t\tvar iStage = this._stageIndex(this.state.messages, stageId);\n\t\tif (iStage !== -1) {\n\t\t\t// Replace IN PLACE — see the queued branch above for why nothing moves.\n\t\t\tvar iEx = this.state.messages[iStage];\n\t\t\t// Keep the send time the user saw, not the upload's finish time.\n\t\t\tif (iEx._ts !== undefined) immediateUser._ts = iEx._ts;\n\t\t\t// Same id across the swap, so the row is not re-keyed (and in Vue, remounted)\n\t\t\t// at the very moment the turn goes out.\n\t\t\tif (iEx._localId) immediateUser._localId = iEx._localId;\n\t\t\tthis.state.messages.splice(iStage, 1, immediateUser, immediatePlaceholder);\n\t\t} else {\n\t\t\tthis.state.messages.push(immediateUser);\n\t\t\tthis.state.messages.push(immediatePlaceholder);\n\t\t}\n\t\tthis.host.notify(); this.updateHistoryCache(); this.state.sending = true; this.scrollForDispatch(stageId);\n\n\t\t// Same filter as the offChat and isQueuedSend paths above. It must drop the\n\t\t// pending flags too: the `isPending` placeholder pushed two lines up is the\n\t\t// in-flight \"Thinking...\" bubble, and leaving it in sent a trailing\n\t\t// `{role:'assistant', content:''}` upstream on EVERY immediate send. That is\n\t\t// a last-assistant-turn prefill, which the Claude platform rejects outright,\n\t\t// and on both platforms it made the history end on an assistant turn, so\n\t\t// prepareOpenAIMessages / prepareClaudeMessages bailed at their\n\t\t// `last.role !== 'user'` guard and silently stopped converting attached\n\t\t// images into image blocks.\n\t\t//\n\t\t// `isError` is dropped in all three paths for a different reason: those\n\t\t// bubbles are written by THIS client, never by the model. Every site that\n\t\t// sets `isError: true` fills content from getErrorMessage() or the literal\n\t\t// 'Request was cancelled.', so filtering them discards no model-authored\n\t\t// text. Keeping them handed the model a turn it never produced (\"The AI\n\t\t// provider is temporarily unreachable...\"), attributed to itself, because the\n\t\t// flag is stripped when buildBoundedChatMessages maps down to {role,content}.\n\t\t// The cost is that a retry now follows an unanswered question with no stated\n\t\t// reason, which is a true account of what happened rather than a false one.\n\t\t//\n\t\t// The turn being sent is appended LAST rather than left wherever its bubble\n\t\t// sits. A staged turn keeps the position it was sent in, which is NOT the\n\t\t// end of the list once a message sent after it (while its files uploaded)\n\t\t// has already been answered — and a history that ends on an assistant turn\n\t\t// hits exactly the `last.role !== 'user'` bail described above.\n\t\tvar historyForLlm = this.state.messages.filter(function (m) {\n\t\t\tif (m === immediateUser) return false;\n\t\t\treturn !m.isPending && !m.isPendingQueued && !m.isPendingInProcess && !m.isPendingOlder &&\n\t\t\t\t!m.isCancelled && !m.isBackgroundTask && !m.isError;\n\t\t});\n\t\thistoryForLlm.push({ role: 'user', content: llmComposed });\n\t\tvar bounded = buildBoundedChatMessages({\n\t\t\tplatform: aiPlatform, model: aiModel, systemPrompt: systemPrompt, projectId: id.projectId,\n\t\t\thistory: historyForLlm,\n\t\t});\n\t\tvar immediateUserLid = immediateUser._localId, immediatePlaceholderLid = immediatePlaceholder._localId;\n\t\tvar run = this.dispatchAgentRequest({\n\t\t\tkey: key, projectId: id.projectId, owner: id.owner, aiPlatform: aiPlatform, aiModel: aiModel,\n\t\t\tsystemPrompt: systemPrompt, text: composed, boundedMessages: bounded.messages, userId: chatQueue,\n\t\t\textractContent: extractContent, fileUrls: fileUrls,\n\t\t\t// THE fix for a turn rendering twice after navigate-away-and-back. Until\n\t\t\t// this existed the immediate-send pair carried no server id for its whole\n\t\t\t// life (only the QUEUED path stamped one, off its ack), so nothing could\n\t\t\t// tell the local copy and the server's copy of the same turn apart. See\n\t\t\t// _stampTurnWithItemId.\n\t\t\tonItemId: function (itemId: string) { self._stampTurnWithItemId(key, immediateUserLid, immediatePlaceholderLid, itemId); },\n\t\t});\n\t\t// Render the reply into the \"Thinking...\" bubble whenever the chatbox is\n\t\t// CURRENTLY showing this chat — even after an unmount/remount. The old\n\t\t// guard bailed on `requestToken !== gateRefreshToken`, but EVERY remount\n\t\t// bumps gateRefreshToken (refreshGate), so a request that finished after\n\t\t// the user navigated away and back left a stuck \"Thinking...\" (no view\n\t\t// typewriter ever ran, and resumePendingRequest bails when a pending\n\t\t// bubble is already present). Gate on \"is this the visible chat\" instead.\n\t\t// When it ISN'T (unmounted / another project), dispatchAgentRequest has\n\t\t// already replaced the pending bubble with the answer IN THE CACHE, so a\n\t\t// later loadChatHistory renders it.\n\t\tPromise.resolve(run).catch(function () { }).then(function () {\n\t\t\t// Clear `sending` UNCONDITIONALLY. It is session-global (it gates\n\t\t\t// isQueuedSend above, plus the platform/model pickers in the view), so\n\t\t\t// leaving it set when the user navigated to another project wedged\n\t\t\t// every subsequent send in EVERY project onto the queued path and kept\n\t\t\t// the view's user-bubble rescue arm armed forever. Only the RENDER of\n\t\t\t// the reply stays gated on still showing this chat — when it isn't,\n\t\t\t// dispatchAgentRequest has already written the answer into the cache\n\t\t\t// under `key`, so a later loadChatHistory renders it.\n\t\t\tself.state.sending = false;\n\t\t\tif (!(self.host.isViewMounted() && self.getHistoryCacheKey() === key)) return;\n\t\t\treturn Promise.resolve(self.typewriteLatestReply(key)).then(function () { self.host.scrollToBottomIfSticky(true); });\n\t\t});\n\t}\n\n\t/**\n\t * Scroll for a dispatch that is going out NOW, but never for one arriving late.\n\t *\n\t * A turn with attachments does not dispatch when the user hits Send: it waits out\n\t * its uploads and then its whole indexing chain, which is minutes\n\t * (awaitIndexingDrained). By then the reader has very often scrolled up into\n\t * history to pass the time, and the forcing scrollToBottom yanked them out of it\n\t * — and worse, force-pinned stickToBottom, which no-ops every method on the\n\t * scroll anchor and re-arms the queue-detect poll whose only bail is\n\t * !stickToBottom.\n\t *\n\t * `stageId` is the exact marker for that case: only the attachment path ever\n\t * produces one. The gesture itself was already paid for at stage time, where\n\t * stageOutgoingMessage forces the scroll while the user is still looking at the\n\t * composer. Deliberately NOT gated on \"did we find the staged bubble\" — a remount\n\t * rebuilds from the cache and the turn is appended rather than replaced, which is\n\t * just as late and just as unrequested.\n\t */\n\tprivate scrollForDispatch(stageId?: string): void {\n\t\tif (stageId) this.host.scrollToBottomIfSticky(true);\n\t\telse this.host.scrollToBottom(true);\n\t}\n\n\tpromoteNextBgQueuedToRunning(): void {\n\t\tif (this.state.messages.some(function (m) { return m.isPending && m.role === 'assistant' && m.isBackgroundTask; })) return;\n\t\tvar nextIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.isPendingQueued && m.role === 'user' && m.isBackgroundTask;\n\t\t});\n\t\tif (nextIdx === -1) return;\n\t\tvar existing = this.state.messages[nextIdx];\n\t\tvar promoted: ChatMessage = { role: 'user', content: existing.content, isPendingInProcess: true, isBackgroundTask: true };\n\t\tif (existing._indexFile) promoted._indexFile = existing._indexFile;\n\t\tif (existing._ts !== undefined) promoted._ts = existing._ts;\n\t\tif (existing._serverItemId !== undefined) promoted._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) promoted._ownerKey = existing._ownerKey;\n\t\tthis.state.messages[nextIdx] = promoted;\n\t\tvar placeholder: ChatMessage = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, isBackgroundTask: true };\n\t\tif (existing._serverItemId !== undefined) placeholder._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) placeholder._ownerKey = existing._ownerKey;\n\t\tthis.state.messages.splice(nextIdx + 1, 0, placeholder);\n\t\tthis.host.notify();\n\t}\n\n\tpromoteNextQueuedToRunning(): void {\n\t\tif (this.state.messages.some(function (m) { return m.isPending && m.role === 'assistant' && !m.isBackgroundTask; })) return;\n\t\tvar nextIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.isPendingQueued && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue;\n\t\t});\n\t\tif (nextIdx === -1) return;\n\t\tvar existing = this.state.messages[nextIdx];\n\t\tvar promoted: ChatMessage = { role: 'user', content: existing.content, isPendingInProcess: true };\n\t\tif (existing.isBackgroundTask) promoted.isBackgroundTask = true;\n\t\tif (existing._indexFile) promoted._indexFile = existing._indexFile;\n\t\tif (existing._ts !== undefined) promoted._ts = existing._ts;\n\t\tif (existing._serverItemId !== undefined) promoted._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) promoted._ownerKey = existing._ownerKey;\n\t\tif (existing.isSendingToServer) promoted.isSendingToServer = true;\n\t\t// Carried alongside isSendingToServer, never derived from it: an attachment\n\t\t// turn promoted to running while its ack is still out was already un-dimmed\n\t\t// by markStagedMessageReady and must stay that way.\n\t\tif (existing._dimSending) promoted._dimSending = true;\n\t\t// A turn promoted BEFORE its ack has no server id, so this is the only stable\n\t\t// render key it has; dropping it here re-keyed the bubble by index and undid\n\t\t// the reason it was minted (rows spliced in above renumber it).\n\t\tif (existing._localId !== undefined) promoted._localId = existing._localId;\n\t\tthis.state.messages[nextIdx] = promoted;\n\t\t// Carry the promoted turn's _serverItemId onto the \"Thinking...\" placeholder\n\t\t// (mirrors promoteNextBgQueuedToRunning). Without it, when this promoted turn\n\t\t// is resolved via the history-poll path — applyHistoryItemResolution, which\n\t\t// matches the pending assistant by _serverItemId — the placeholder is not\n\t\t// found, so the reply is spliced in BESIDE it and the \"Thinking...\" is\n\t\t// stranded forever (e.g. after a reload, or when a cancel advances the queue).\n\t\t// onQueuedSendResponse still finds it by position, so the queued-send path is\n\t\t// unaffected.\n\t\tvar placeholder: ChatMessage = { role: 'assistant', content: '', isPending: true };\n\t\tif (existing._serverItemId !== undefined) placeholder._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) placeholder._ownerKey = existing._ownerKey;\n\t\tthis.state.messages.splice(nextIdx + 1, 0, placeholder);\n\t\tthis.host.notify();\n\t}\n\n\t/**\n\t * The \"Thinking...\" placeholder belonging to the user bubble at `userIdx`, or -1.\n\t *\n\t * Every path that creates one puts it IMMEDIATELY after its user bubble\n\t * (promoteNextQueuedToRunning, the immediate-send pair, applyHistoryItemResolution),\n\t * so ownership is adjacency — modulo background bubbles, which get spliced in\n\t * around them. Taking the first pending assistant ANYWHERE below instead was a\n\t * hijack: a turn sent with attachments never gets a placeholder of its own\n\t * (promoteNextQueuedToRunning skips _useBgQueue turns) and now keeps the position\n\t * it was sent in, so an ordinary turn sent while its files indexed sits BELOW it\n\t * with a placeholder of its own — and the attachment turn's answer was rendered\n\t * as the answer to that unrelated question.\n\t */\n\tprivate _ownThinkingIndex(userIdx: number, serverId?: string): number {\n\t\tif (userIdx < 0) return -1;\n\t\tfor (var i = userIdx + 1; i < this.state.messages.length; i++) {\n\t\t\tvar m = this.state.messages[i];\n\t\t\tif (!m) return -1;\n\t\t\tif (m.isBackgroundTask) continue; // an indexing row spliced between the pair\n\t\t\tif (m.isPending && m.role === 'assistant') {\n\t\t\t\t// A placeholder stamped for a DIFFERENT request is not this turn's, even\n\t\t\t\t// adjacent: ids are authoritative wherever both sides have one.\n\t\t\t\tif (serverId && m._serverItemId && m._serverItemId !== serverId) return -1;\n\t\t\t\treturn i;\n\t\t\t}\n\t\t\treturn -1; // the next real turn starts here; this one has no placeholder\n\t\t}\n\t\treturn -1;\n\t}\n\n\tresolveQueuedUserBubble(serverId?: string): number | undefined {\n\t\t// The two fallbacks below match by POSITION, not identity, so they must\n\t\t// never consider a bubble stamped for a different chat.\n\t\tvar liveKey = this.getHistoryCacheKey();\n\t\tvar isLocal = function (m: ChatMessage) { return m._ownerKey === undefined || m._ownerKey === liveKey; };\n\t\tvar userIdx = -1;\n\t\tif (serverId) {\n\t\t\tuserIdx = this.state.messages.findIndex(function (m) {\n\t\t\t\treturn m._serverItemId === serverId && (m.isPendingInProcess || m.isPendingQueued) &&\n\t\t\t\t\tm.role === 'user' && !m.isBackgroundTask;\n\t\t\t});\n\t\t}\n\t\tif (userIdx === -1) {\n\t\t\tuserIdx = this.state.messages.findIndex(function (m) {\n\t\t\t\treturn m.isPendingInProcess && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue && isLocal(m);\n\t\t\t});\n\t\t}\n\t\tif (userIdx === -1) {\n\t\t\tuserIdx = this.state.messages.findIndex(function (m) {\n\t\t\t\treturn m.isPendingQueued && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue && isLocal(m);\n\t\t\t});\n\t\t}\n\t\tif (serverId && this.cancelledServerIds.has(serverId)) {\n\t\t\tthis.cancelledServerIds.delete(serverId);\n\t\t\tif (userIdx >= 0) {\n\t\t\t\tvar ex = this.state.messages[userIdx];\n\t\t\t\tthis.state.messages[userIdx] = { role: 'user', content: ex.content, isCancelled: true, _serverItemId: ex._serverItemId, ...(ex._ownerKey !== undefined ? { _ownerKey: ex._ownerKey } : {}) };\n\t\t\t\tvar thIdx = this._ownThinkingIndex(userIdx, serverId);\n\t\t\t\tif (thIdx !== -1) this.state.messages.splice(thIdx, 1);\n\t\t\t}\n\t\t\tthis.promoteNextQueuedToRunning();\n\t\t\treturn undefined;\n\t\t}\n\t\tif (userIdx >= 0) {\n\t\t\tvar exist = this.state.messages[userIdx];\n\t\t\tvar repl: ChatMessage = { role: 'user', content: exist.content };\n\t\t\tif (exist._serverItemId !== undefined) repl._serverItemId = exist._serverItemId;\n\t\t\tif (exist._ownerKey !== undefined) repl._ownerKey = exist._ownerKey;\n\t\t\tif (exist._ts !== undefined) repl._ts = exist._ts;\n\t\t\t// Kept so the bubble is not re-keyed (and in Vue, remounted) at the moment\n\t\t\t// its answer arrives; the views prefer _serverItemId, this is the fallback.\n\t\t\tif (exist._localId !== undefined) repl._localId = exist._localId;\n\t\t\tthis.state.messages[userIdx] = repl;\n\t\t}\n\t\tvar thinkingIdx = this._ownThinkingIndex(userIdx, serverId);\n\t\treturn thinkingIdx !== -1 ? thinkingIdx : (userIdx >= 0 ? userIdx + 1 : -1);\n\t}\n\n\tinsertAtTarget(msg: ChatMessage, targetIdx: number): void {\n\t\t// Error/direct replies land here rather than through the typewriter, so this\n\t\t// is where they pick up their display time.\n\t\tif (msg && msg.role === 'assistant' && msg._ts === undefined) msg._ts = wallClockNow();\n\t\t// Overwrite only a placeholder that genuinely belongs to the turn above it.\n\t\t// Two things now sit at this index that must never be replaced by a chat\n\t\t// answer: a background \"Indexing:\" placeholder (a file's rows are inserted\n\t\t// directly above the turn they belong to, so one can land here) — replacing it\n\t\t// deletes a live pass from its collapsed row — and another request's\n\t\t// placeholder, which resolveQueuedUserBubble deliberately declined to claim.\n\t\t// Anything else is spliced in beside it.\n\t\tvar tgt = targetIdx >= 0 ? this.state.messages[targetIdx] : undefined;\n\t\tvar replaceable = !!tgt && !!tgt.isPending && !tgt.isBackgroundTask &&\n\t\t\tthis._isOwnPlaceholderOf(targetIdx, this._owningUserIndex(targetIdx));\n\t\tif (replaceable) this.state.messages[targetIdx] = msg;\n\t\telse if (targetIdx >= 0) this.state.messages.splice(targetIdx, 0, msg);\n\t\telse this.state.messages.push(msg);\n\t}\n\n\t/**\n\t * The server's OWN copy of this turn is already on screen.\n\t *\n\t * A first-page fetch can land between the server settling the item and this\n\t * poll's tick, and now that the local bubbles carry the item id\n\t * (_stampTurnWithItemId) the rescue correctly drops them and renders the\n\t * server's settled pair instead. There is then nothing left to resolve: the\n\t * -1 fallback would push the answer in a SECOND time at the bottom of the list,\n\t * and the positional fallbacks would hijack some other turn's bubble.\n\t *\n\t * The USER bubble counts, not just a settled assistant: an item whose answer is\n\t * empty produces no assistant bubble at all in the mapper, and that variant\n\t * would otherwise still bottom-push \"No text response received...\". While a turn\n\t * is genuinely live its user bubble is always pending (the queued branch sets\n\t * isPendingQueued, promoteNextQueuedToRunning sets isPendingInProcess), so this\n\t * cannot fire early.\n\t */\n\tprivate _turnAlreadyRendered(serverId?: string): boolean {\n\t\tif (!serverId) return false;\n\t\treturn this.state.messages.some(function (m) {\n\t\t\treturn m._serverItemId === serverId &&\n\t\t\t\t!m.isPending && !m.isPendingQueued && !m.isPendingInProcess;\n\t\t});\n\t}\n\n\tonQueuedSendResponse(_composed: string, response: any, platform: string, serverId?: string, ownerKey?: string): void {\n\t\tif (serverId) this.historyItemPolls.delete(serverId);\n\t\t// This turn resolved while a DIFFERENT chat is on screen (the user moved to\n\t\t// another project mid-flight). state.messages now belongs to that chat, and\n\t\t// resolveQueuedUserBubble's positional fallbacks would happily hijack ITS\n\t\t// pending bubble — or, finding nothing, push this answer onto its list.\n\t\t// Settle in the owning chat's cache instead and leave the view untouched.\n\t\tif (ownerKey && this.getHistoryCacheKey() !== ownerKey) {\n\t\t\tvar offReply: ChatMessage = isErrorResponseBody(response)\n\t\t\t\t? { role: 'assistant', content: getErrorMessage(response), isError: true }\n\t\t\t\t: { role: 'assistant', content: ((platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '').trim() || 'No text response received from AI provider.' };\n\t\t\tthis._applyReplyToCache(ownerKey, offReply, serverId);\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\treturn;\n\t\t}\n\t\tif (this._turnAlreadyRendered(serverId)) {\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar targetIdx = this.resolveQueuedUserBubble(serverId);\n\t\tif (targetIdx === undefined) { this.host.notify(); this.updateHistoryCache(); return; }\n\t\tif (isErrorResponseBody(response)) {\n\t\t\tthis.insertAtTarget({ role: 'assistant', content: getErrorMessage(response), isError: true }, targetIdx);\n\t\t} else {\n\t\t\tvar answer = (platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response));\n\t\t\tanswer = (answer || '').trim() || 'No text response received from AI provider.';\n\t\t\tvar lid = this._newLocalId();\n\t\t\tif (targetIdx >= 0 && this.state.messages[targetIdx] && this.state.messages[targetIdx].isPending) {\n\t\t\t\tthis.state.messages[targetIdx] = { role: 'assistant', content: '', _localId: lid };\n\t\t\t\tthis.host.notify(); this.enqueueTypewrite(targetIdx, answer, lid);\n\t\t\t} else if (targetIdx >= 0) {\n\t\t\t\tthis.state.messages.splice(targetIdx, 0, { role: 'assistant', content: '', _localId: lid });\n\t\t\t\tthis.host.notify(); this.enqueueTypewrite(targetIdx, answer, lid);\n\t\t\t} else {\n\t\t\t\tvar aiIdx = this.state.messages.length;\n\t\t\t\tthis.state.messages.push({ role: 'assistant', content: '', _localId: lid });\n\t\t\t\tthis.host.notify(); this.enqueueTypewrite(aiIdx, answer, lid);\n\t\t\t}\n\t\t}\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.promoteNextQueuedToRunning();\n\t\tthis.updateHistoryCache();\n\t\tthis.host.notify();\n\t\t// ARRIVAL, not a user action: only follow if the user is still pinned to\n\t\t// the bottom. Scrolled-up readers keep their position.\n\t\tthis.host.scrollToBottomIfSticky(true);\n\t}\n\n\tonQueuedSendError(_composed: string, err: any, serverId?: string, ownerKey?: string): void {\n\t\tvar self = this;\n\t\tif (serverId) this.historyItemPolls.delete(serverId);\n\t\t// Off-chat resolution — see onQueuedSendResponse. Settle in the owning\n\t\t// chat's cache rather than mutating whatever chat is on screen now.\n\t\tif (ownerKey && this.getHistoryCacheKey() !== ownerKey) {\n\t\t\tvar isGone = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\t\tthis._applyReplyToCache(ownerKey, isGone\n\t\t\t\t? { role: 'assistant', content: 'Request was cancelled.', isError: true }\n\t\t\t\t: { role: 'assistant', content: getErrorMessage(err), isError: true }, serverId);\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\treturn;\n\t\t}\n\t\t// Same reason as onQueuedSendResponse: with the server's settled copy already\n\t\t// on screen there is no pending bubble left that belongs to this turn, and\n\t\t// every fallback below would write onto some other turn's — or push a second\n\t\t// bubble at the bottom.\n\t\tif (this._turnAlreadyRendered(serverId)) {\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar isNotExists = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\tif (isNotExists) {\n\t\t\tvar userIdx = serverId\n\t\t\t\t? this.state.messages.findIndex(function (m) { return m._serverItemId === serverId && (m.isPendingInProcess || m.isPendingQueued) && m.role === 'user' && !m.isBackgroundTask; })\n\t\t\t\t: this.state.messages.findIndex(function (m) { return m.isPendingInProcess && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue; });\n\t\t\tif (!serverId && userIdx === -1) {\n\t\t\t\tuserIdx = this.state.messages.findIndex(function (m) { return m.isPendingQueued && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue; });\n\t\t\t}\n\t\t\tif (userIdx >= 0) {\n\t\t\t\tvar ex = this.state.messages[userIdx];\n\t\t\t\tvar repl: ChatMessage = { role: 'user', content: ex.content, isCancelled: true };\n\t\t\t\tif (ex._serverItemId !== undefined) repl._serverItemId = ex._serverItemId;\n\t\t\t\tthis.state.messages[userIdx] = repl;\n\t\t\t}\n\t\t\tif (serverId) {\n\t\t\t\tvar thById = this.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.isPending && m.role === 'assistant' && !m.isBackgroundTask; });\n\t\t\t\tif (thById !== -1) this.state.messages.splice(thById, 1);\n\t\t\t\telse if (userIdx >= 0) {\n\t\t\t\t\tvar thPos = this.state.messages.findIndex(function (m, i) { return i > userIdx && m.isPending && m.role === 'assistant' && !m.isBackgroundTask; });\n\t\t\t\t\tif (thPos !== -1) this.state.messages.splice(thPos, 1);\n\t\t\t\t}\n\t\t\t} else if (userIdx >= 0) {\n\t\t\t\tvar thPos2 = this.state.messages.findIndex(function (m, i) { return i > userIdx && m.isPending && m.role === 'assistant' && !m.isBackgroundTask; });\n\t\t\t\tif (thPos2 !== -1) this.state.messages.splice(thPos2, 1);\n\t\t\t}\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\tthis._removeStrayPendingAssistants();\n\t\t\tthis.promoteNextQueuedToRunning(); this.updateHistoryCache(); this.host.notify(); this.host.scrollToBottomIfSticky(true);\n\t\t\treturn;\n\t\t}\n\t\tvar targetIdx = this.resolveQueuedUserBubble(serverId);\n\t\tif (targetIdx === undefined) { this.host.notify(); this.updateHistoryCache(); return; }\n\t\tthis.insertAtTarget({ role: 'assistant', content: getErrorMessage(err), isError: true }, targetIdx);\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.promoteNextQueuedToRunning(); this.updateHistoryCache(); this.host.notify(); this.host.scrollToBottomIfSticky(true);\n\t}\n\n\tcancelQueuedMessage(msg: ChatMessage, idx: number): void {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\tvar serverId = msg._serverItemId;\n\t\tif (!serverId || msg._cancelling) return;\n\t\tvar platform = id.platform;\n\t\tif (platform !== 'claude' && platform !== 'openai') return;\n\t\tvar url = platform === 'claude' ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;\n\t\tvar queueBase = id.userId || id.projectId;\n\t\tvar queue = (msg.isBackgroundTask || msg._useBgQueue) ? bgIndexingQueueName(queueBase) : queueBase;\n\t\t// `idx` is the index the VIEW rendered this bubble at, and the list can have\n\t\t// moved under it since: indexing rows are inserted above the turn they belong\n\t\t// to (drainBgTaskQueue), so a pass that starts between the last render and the\n\t\t// click shifts every bubble below it down. Writing blind at a stale index\n\t\t// overwrites an unrelated message with a copy of this one. The server id is the\n\t\t// identity — cancelQueuedMessage already refuses to run without one.\n\t\t// The role test belongs on BOTH arms: a request bubble and its reply share one\n\t\t// _serverItemId, so an id-only fast path would paint \"Stopping...\" on the\n\t\t// reply whenever the list shifted UP by one instead (a stray placeholder\n\t\t// swept, a sibling pass cancelled, a NOT_EXISTS splice).\n\t\tvar at = (this.state.messages[idx] && this.state.messages[idx]._serverItemId === serverId && this.state.messages[idx].role === msg.role)\n\t\t\t? idx\n\t\t\t: this.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.role === msg.role; });\n\t\t// Gone from the list entirely (a history refetch rebuilt it): skip the paint —\n\t\t// writing at the rendered index would clobber a stranger — but still SEND the\n\t\t// cancel. The user asked for it, and the server request is the part that matters.\n\t\tif (at !== -1) {\n\t\t\tthis.state.messages[at] = Object.assign({}, this.state.messages[at], { _cancelling: true, _cancelError: undefined });\n\t\t}\n\t\tthis.host.notify();\n\t\tPromise.resolve(this.host.cancelRequest({\n\t\t\turl: url, method: 'POST', id: serverId, queue: queue, service: id.projectId, owner: id.owner,\n\t\t})).then(function (result: any) {\n\t\t\tif (result && result.removed) {\n\t\t\t\tself.cancelledServerIds.add(serverId as string);\n\t\t\t\tself._stopPoll(serverId as string);\n\t\t\t\tvar qi = self.bgTaskQueue.findIndex(function (e) { return e.id === serverId; });\n\t\t\t\tif (qi !== -1) self.bgTaskQueue.splice(qi, 1);\n\t\t\t\tvar removeIdx = self.state.messages.findIndex(function (m) {\n\t\t\t\t\treturn m._serverItemId === serverId && (m.isPendingQueued || m.isPendingInProcess) && m.role === 'user';\n\t\t\t\t});\n\t\t\t\tif (removeIdx !== -1) {\n\t\t\t\t\t// Carry the background/file markers onto the rebuild. Dropping them\n\t\t\t\t\t// took a cancelled INDEXING pass out of its file's collapsed row\n\t\t\t\t\t// (buildChatDisplayList only groups isBackgroundTask bubbles), so the\n\t\t\t\t\t// row stayed \"Indexing…\" forever while a bare \"Indexing: file\" bubble\n\t\t\t\t\t// appeared beside it.\n\t\t\t\t\tvar wasMsg = self.state.messages[removeIdx];\n\t\t\t\t\tvar cancelledMsg: ChatMessage = { role: 'user', content: wasMsg.content, isCancelled: true, _serverItemId: serverId };\n\t\t\t\t\tif (wasMsg.isBackgroundTask) cancelledMsg.isBackgroundTask = true;\n\t\t\t\t\tif (wasMsg._indexFile) cancelledMsg._indexFile = wasMsg._indexFile;\n\t\t\t\t\tif (wasMsg._useBgQueue) cancelledMsg._useBgQueue = true;\n\t\t\t\t\tif (wasMsg._ownerKey !== undefined) cancelledMsg._ownerKey = wasMsg._ownerKey;\n\t\t\t\t\tself.state.messages[removeIdx] = cancelledMsg;\n\t\t\t\t\tvar thById = self.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.isPending && m.role === 'assistant'; });\n\t\t\t\t\tif (thById !== -1) self.state.messages.splice(thById, 1);\n\t\t\t\t\telse {\n\t\t\t\t\t\tvar thPos = self.state.messages.findIndex(function (m, i) {\n\t\t\t\t\t\t\treturn i > removeIdx && m.isPending && m.role === 'assistant' &&\n\t\t\t\t\t\t\t\t(msg.isBackgroundTask ? !!m.isBackgroundTask : !m.isBackgroundTask);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (thPos !== -1) self.state.messages.splice(thPos, 1);\n\t\t\t\t\t}\n\t\t\t\t\tif (msg.isBackgroundTask) self.promoteNextBgQueuedToRunning(); else self.promoteNextQueuedToRunning();\n\t\t\t\t\tself.updateHistoryCache();\n\t\t\t\t}\n\t\t\t\tself.host.notify();\n\t\t\t} else {\n\t\t\t\tvar errMsg = result && typeof result.message === 'string' && result.message ? result.message : 'Could not remove from queue.';\n\t\t\t\tvar ci = self.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.role === 'user'; });\n\t\t\t\tif (ci !== -1) { self.state.messages[ci] = Object.assign({}, self.state.messages[ci], { _cancelling: false, _cancelError: errMsg }); self.host.notify(); }\n\t\t\t}\n\t\t}).catch(function (err: any) {\n\t\t\tvar errMsg = err && typeof err.message === 'string' && err.message ? err.message : 'Could not remove from queue.';\n\t\t\tvar ci = self.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.role === 'user'; });\n\t\t\tif (ci !== -1) { self.state.messages[ci] = Object.assign({}, self.state.messages[ci], { _cancelling: false, _cancelError: errMsg }); self.host.notify(); }\n\t\t});\n\t}\n\n\t/**\n\t * Stop indexing a file, from its collapsed row — every pass at once, not just\n\t * the bubble the user happens to see.\n\t *\n\t * A big file is indexed as a CHAIN of passes, so cancelling only the live one\n\t * accomplishes nothing: the next pass is dispatched as soon as it settles.\n\t * Three things end the chain:\n\t * 1. every queued/running pass of this file is cancelled server-side\n\t * (csr-cancel deletes a queued row and flags a running one \"cancelled\",\n\t * which is also the worker's gate for NOT enqueueing the next window);\n\t * 2. the file is remembered in cancelledIndexKeys, so the client-driven\n\t * resume (maybeResumeIndexing) stops dispatching CONTINUE passes; and\n\t * 3. any of its passes still sitting in bgTaskQueue is dropped by the next\n\t * drain rather than surfacing a fresh \"Indexing…\" bubble; and\n\t * 4. the RUN is remembered (state.stoppedIndexIds), because none of the above\n\t * necessarily leaves a mark on the conversation — see below — and without\n\t * it the collapsed row reported the stopped file as finished.\n\t *\n\t * Records already written by the passes that DID run are kept — this stops the\n\t * work, it does not undo it.\n\t */\n\tcancelIndexingGroup(group: IndexingGroup): void {\n\t\tvar self = this;\n\t\tif (!group || !group.key) return;\n\t\t// The group belongs to the chat on screen, so scope its key the same way\n\t\t// _indexKeyOf scopes a queued task's.\n\t\tvar scoped = this.getHistoryCacheKey() + '|' + group.key;\n\t\tthis.cancelledIndexKeys.add(scoped);\n\t\t// Remember WHICH RUN was stopped, by the ids of the passes it is made of.\n\t\t// Everything else here stops the work without leaving any mark on the\n\t\t// conversation: a running pass cannot be un-run (it finishes and writes an\n\t\t// ordinary answer), and a queued continuation is dropped before it is ever\n\t\t// surfaced — so a stopped run's newest bubble is routinely a successful pass,\n\t\t// and the row read \"Indexed\" over a file the user had just stopped. Ids, not\n\t\t// the file key, so a re-upload or Reindex of the same path is a new run with\n\t\t// new ids and starts clean; and on the reactive state so the row updates the\n\t\t// moment this is recorded, since a stop with nothing left to cancel changes\n\t\t// no message at all.\n\t\t//\n\t\t// Not for a run that is already OVER, though — you cannot stop what has\n\t\t// finished, and marking it stopped would relabel a fully-indexed file as\n\t\t// cancelled on the strength of a click that arrived too late. (`finished` is\n\t\t// only ever positively established: \"still running\" and \"we have not found\n\t\t// out\" both read as false here, so the doubt goes to recording the stop.)\n\t\tif (!group.finished) {\n\t\t\tvar stoppedIds: { [id: string]: boolean } = {};\n\t\t\tfor (var sk in this.state.stoppedIndexIds) stoppedIds[sk] = true;\n\t\t\t(group.members || []).forEach(function (m) {\n\t\t\t\tvar sid = m && m.msg && m.msg._serverItemId;\n\t\t\t\tif (sid) stoppedIds[sid] = true;\n\t\t\t});\n\t\t\t// The queue's own view of this file, which is not always the row's: an\n\t\t\t// entry can be waiting for its bubble, and the FIRST pass's entry outlives\n\t\t\t// the moment its bubble settles. _applyIndexCancellations reads this to\n\t\t\t// tell a pass that existed when the user hit Stop from a genuinely new\n\t\t\t// indexing request, and only the latter is allowed to lift the stop.\n\t\t\tthis.bgTaskQueue.forEach(function (e) {\n\t\t\t\tif (e && e.id && self._indexKeyOf(e) === scoped) stoppedIds[e.id] = true;\n\t\t\t});\n\t\t\tthis.state.stoppedIndexIds = stoppedIds;\n\t\t\t// Close the durable run:: record too — inside this !finished guard on\n\t\t\t// purpose, for the same reason as stoppedIndexIds: a stop that landed\n\t\t\t// after the run was over must not relabel an indexed file as cancelled.\n\t\t\t// Path over key: `key` degrades to a bare filename for path-less compact\n\t\t\t// stubs, and run:: is keyed by storage path only — no derivable path\n\t\t\t// means no record to close (restored stubs of old runs), which is fine.\n\t\t\tvar runPath = group.path || '';\n\t\t\tif (!runPath) {\n\t\t\t\t(group.members || []).some(function (m) {\n\t\t\t\t\tvar p = m && m.msg && m.msg._indexFile && m.msg._indexFile.path;\n\t\t\t\t\tif (p) { runPath = p; return true; }\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!runPath) {\n\t\t\t\tthis.bgTaskQueue.some(function (e) {\n\t\t\t\t\tif (e && e.storagePath && self._indexKeyOf(e) === scoped) { runPath = e.storagePath; return true; }\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (runPath) {\n\t\t\t\tvar ident = this.host.getIdentity();\n\t\t\t\tif (ident && ident.projectId) {\n\t\t\t\t\tupsertIndexRunRecordSafe(ident.projectId, runPath, { status: 'cancelled', finished: Date.now() });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Ask the QUEUE what else is live for this file, and cancel that too.\n\t\t//\n\t\t// The ids above are the passes THIS client knows about, and for a\n\t\t// worker-driven file that is routinely none of them: the worker mints the\n\t\t// next window itself and the client only learns its id on a later look. A\n\t\t// stop that reaches no server row at all is a stop that dies with the tab —\n\t\t// the chain keeps running, and the only record of the stop is this page's\n\t\t// memory. The adopt ladder is the existing machinery for exactly this\n\t\t// question; anything it turns up for a stopped file is dropped and\n\t\t// server-cancelled by _applyIndexCancellations on the next drain, which is\n\t\t// also what makes the worker stop enqueueing windows.\n\t\tthis._adoptWorkerIndexingPasses(0);\n\t\tvar ids = group.cancellableIds || [];\n\t\tif (!ids.length) { this.host.notify(); return; }\n\t\tids.forEach(function (serverId) {\n\t\t\t// Address the message by IDENTITY, not by the index captured when the\n\t\t\t// display list was built: an earlier cancel in this same loop may already\n\t\t\t// have spliced the array (a group can have more than one live pass), and a\n\t\t\t// stale index would mark the WRONG bubble as cancelling.\n\t\t\tvar idx = self.state.messages.findIndex(function (m) {\n\t\t\t\treturn m._serverItemId === serverId && m.role === 'user' &&\n\t\t\t\t\t(m.isPendingQueued || m.isPendingInProcess);\n\t\t\t});\n\t\t\tif (idx === -1) return;\n\t\t\tself.cancelQueuedMessage(self.state.messages[idx], idx);\n\t\t});\n\t}\n\n\t// --- typewriter -------------------------------------------------------\n\t// Reveal `fullText` into a message bubble at a constant wall-clock RATE\n\t// (chars/second) driven by requestAnimationFrame, rather than a fixed number\n\t// of characters per fixed-delay tick. This is what keeps typing smooth and\n\t// cheap on slow machines:\n\t//\n\t// * Each frame reveals `elapsed_ms * CHARS_PER_SEC` characters, so the\n\t// visual speed is the same regardless of how long a frame actually took.\n\t// * As the bubble's markdown grows, each re-render gets more expensive, so\n\t// frames get longer — which makes each frame reveal MORE characters and\n\t// therefore do FEWER, larger renders. That converts the old O(n^2)\n\t// \"re-render the whole growing string once per 3 characters\" (which got\n\t// slower and slower and pegged the CPU) into roughly O(n): the number of\n\t// renders self-throttles to what the machine can actually paint.\n\t// * rAF paces us to the browser's paint cycle and pauses in background\n\t// tabs, so we never queue work faster than it can be drawn.\n\ttypewriteIntoIndex(idx: number, fullText: string, localId?: string): Promise<void> {\n\t\tvar self = this;\n\t\tif (!fullText) return Promise.resolve();\n\n\t\tvar CHARS_PER_SEC = 300; // reveal rate (was ~188 = 3 chars / 16ms) — a bit faster\n\t\tvar MIN_STEP = 1; // always make progress, even on a sub-ms frame\n\t\tvar MAX_FRAME_MS = 1000; // cap catch-up after a long stall / backgrounded tab\n\n\t\t// Atomic regions that must never be left half-revealed: file fences\n\t\t// (shown as a download chip / hidden as \"[generating …]\" while unclosed —\n\t\t// and potentially huge, so revealed in one jump) and inline links\n\t\t// (a partial link is broken markdown). If a frame's reveal boundary lands\n\t\t// inside one, snap it to the region end so the chip/link appears whole.\n\t\tvar regions: Array<{ start: number; end: number }> = [], m;\n\t\tvar fenceRegex = /```[^\\n`]+?\\.[^\\s.`]+\\n[\\s\\S]*?```/g;\n\t\twhile ((m = fenceRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });\n\t\tvar linkRegex = createInlineLinkRegex();\n\t\twhile ((m = linkRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });\n\t\tregions.sort(function (a, b) { return a.start - b.start; });\n\n\t\tthis.state.typing = true; this.state.typingAbort = false;\n\t\tvar i = 0;\n\t\tvar last = nowMs();\n\n\t\treturn new Promise<void>(function (resolve) {\n\t\t\tvar done = false;\n\t\t\tvar doc: any = _g.document;\n\t\t\tfunction isHidden(): boolean { return !!(doc && doc.hidden); }\n\t\t\tfunction cleanup(): void {\n\t\t\t\tif (doc && doc.removeEventListener) doc.removeEventListener('visibilitychange', onVisibility);\n\t\t\t}\n\t\t\tfunction finish(): void {\n\t\t\t\tif (done) return;\n\t\t\t\tdone = true;\n\t\t\t\tcleanup();\n\t\t\t\tif (!self.state.typingAbort) {\n\t\t\t\t\t// Re-find the bubble by localId and, if it's gone, bail WITHOUT\n\t\t\t\t\t// writing — never fall back to the numeric idx, which a concurrent\n\t\t\t\t\t// array mutation may have repurposed for an unrelated message\n\t\t\t\t\t// (mirrors frame()'s currentIdx===-1 bail below).\n\t\t\t\t\tvar fi = localId ? self.state.messages.findIndex(function (mm) { return mm._localId === localId; }) : idx;\n\t\t\t\t\tif (fi !== -1) {\n\t\t\t\t\t\tvar t = self.state.messages[fi];\n\t\t\t\t\t\tif (t) { t.content = fullText; self.host.refreshMessageBubble(fi); }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tself.state.typing = false;\n\t\t\t\tresolve();\n\t\t\t}\n\t\t\t// requestAnimationFrame is PAUSED in a backgrounded tab (setTimeout only\n\t\t\t// throttles), so an rAF-driven reveal would freeze there — leaving a blank\n\t\t\t// bubble and stalling the sequential enqueueTypewrite queue until refocus.\n\t\t\t// When the page is (or becomes) hidden, skip the animation and show the\n\t\t\t// full text immediately so the queue keeps draining.\n\t\t\tfunction onVisibility(): void { if (isHidden()) finish(); }\n\t\t\tif (doc && doc.addEventListener) doc.addEventListener('visibilitychange', onVisibility);\n\t\t\tfunction frame(t: number): void {\n\t\t\t\tif (done) return;\n\t\t\t\tif (self.state.typingAbort || i >= fullText.length || isHidden()) { finish(); return; }\n\n\t\t\t\tvar dt = t - last; last = t;\n\t\t\t\tif (!(dt > 0)) dt = 16; // first frame / clock glitch\n\t\t\t\tif (dt > MAX_FRAME_MS) dt = MAX_FRAME_MS;\n\t\t\t\tvar step = Math.round(dt * CHARS_PER_SEC / 1000);\n\t\t\t\tif (step < MIN_STEP) step = MIN_STEP;\n\t\t\t\tvar next = Math.min(fullText.length, i + step);\n\n\t\t\t\t// Extend past any atomic region the newly-revealed span (i, next]\n\t\t\t\t// cuts into. Iterate to convergence so back-to-back regions (e.g. a\n\t\t\t\t// link right after a fence) are all revealed whole in one frame.\n\t\t\t\tfor (var changed = true; changed;) {\n\t\t\t\t\tchanged = false;\n\t\t\t\t\tfor (var k = 0; k < regions.length; k++) {\n\t\t\t\t\t\tvar r = regions[k];\n\t\t\t\t\t\tif (next > r.start && i < r.end && r.end > next) { next = r.end; changed = true; }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (next > fullText.length) next = fullText.length;\n\t\t\t\ti = next;\n\n\t\t\t\tvar currentIdx = localId ? self.state.messages.findIndex(function (mm) { return mm._localId === localId; }) : idx;\n\t\t\t\tif (currentIdx === -1) { finish(); return; }\n\t\t\t\tvar target = self.state.messages[currentIdx];\n\t\t\t\tif (!target) { finish(); return; }\n\t\t\t\ttarget.content = fullText.slice(0, i);\n\t\t\t\tself.host.refreshMessageBubble(currentIdx);\n\t\t\t\tself.host.scrollToBottomIfSticky();\n\t\t\t\tnextFrame(frame);\n\t\t\t}\n\t\t\tif (isHidden()) { finish(); return; }\n\t\t\tnextFrame(frame);\n\t\t});\n\t}\n\n\tprivate typewriterQueue: Promise<any> = Promise.resolve();\n\tenqueueTypewrite(idx: number, fullText: string, localId?: string): Promise<any> {\n\t\tvar self = this;\n\t\t// Stamp the reply bubble's display time as it starts revealing. This is the\n\t\t// single chokepoint every typed reply (immediate, queued, and bg-resolution)\n\t\t// passes through, so it is where a live reply gets its \"when it arrived\"\n\t\t// timestamp; a history reload later replaces it with the server `updated`.\n\t\tvar target = this.state.messages[idx];\n\t\tif (target && target._ts === undefined) target._ts = wallClockNow();\n\t\tthis.typewriterQueue = this.typewriterQueue.then(function () { return self.typewriteIntoIndex(idx, fullText, localId); });\n\t\treturn this.typewriterQueue;\n\t}\n\n\t// --- cache+resume immediate-send rendering -----------------------------\n\t// Render the just-resolved reply (read from aiChatHistoryCache) into the\n\t// pending assistant bubble, character-by-character. Runs AFTER the reply is\n\t// already in the cache (dispatchAgentRequest appended it); errors are shown\n\t// instantly (no typing). Promotes the next queued message immediately so its\n\t// \"Thinking…\" bubble appears without waiting for this typewriter to finish.\n\ttypewriteLatestReply(key: string): Promise<any> {\n\t\tvar cached = this.aiChatHistoryCache[key];\n\t\tif (!cached || !cached.messages.length) return Promise.resolve();\n\t\tvar latest: ChatMessage | undefined;\n\t\tfor (var i = cached.messages.length - 1; i >= 0; i--) {\n\t\t\tvar m = cached.messages[i];\n\t\t\tif (m.role === 'assistant' && !m.isPending) { latest = m; break; }\n\t\t}\n\t\tif (!latest) return Promise.resolve();\n\t\tvar pendingIdx = this.state.messages.findIndex(function (mm) {\n\t\t\treturn mm.isPending && mm.role === 'assistant' && !mm.isBackgroundTask;\n\t\t});\n\t\tif (pendingIdx === -1) return Promise.resolve();\n\t\tif (latest.isError || !latest.content) {\n\t\t\tthis.state.messages[pendingIdx] = { role: 'assistant', content: latest.content || '', isError: !!latest.isError };\n\t\t\tthis._removeStrayPendingAssistants();\n\t\t\tthis.host.notify();\n\t\t\tthis.promoteNextQueuedToRunning();\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tvar lid = this._newLocalId();\n\t\tthis.state.messages[pendingIdx] = { role: 'assistant', content: '', isPending: false, _localId: lid };\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.host.notify();\n\t\tthis.promoteNextQueuedToRunning();\n\t\treturn this.enqueueTypewrite(pendingIdx, latest.content, lid);\n\t}\n\n\t// Remove leftover non-background pending (\"Thinking…\") assistant bubbles: the\n\t// duplicate that appears when a concurrent history refetch re-maps the still-\n\t// \"running\" turn into a pending placeholder (with a real _serverItemId) while the\n\t// local pending bubble (no _serverItemId) is rescued and re-appended (see the\n\t// loadHistory rescue below), and the orphan a resolve leaves when it splices its\n\t// reply beside a placeholder instead of into it. Each resolve path only replaces\n\t// ONE pending bubble, so without this a stray \"Thinking…\" survives forever next to\n\t// the reply. MUST run AFTER the resolved bubble has been made non-pending and\n\t// BEFORE promoteNext*() (which only adds a Thinking once none remains).\n\t//\n\t// It used to take EVERY one, on the premise that there is at most one at a time\n\t// because promoteNext* refuses to add a second. That premise never covered the\n\t// immediate-send path, which creates its pair directly — and a turn sent with\n\t// attachments does not block the composer and resolves on its own queue, so an\n\t// ordinary question asked while files index is in flight, with a placeholder of\n\t// its own, exactly when the attachment turn resolves. Sweeping it left that\n\t// question with no spinner and, worse, nowhere for its answer to land:\n\t// typewriteLatestReply bails when there is no pending assistant, so the reply\n\t// reached the cache and never the screen.\n\t//\n\t// The discriminator is the owning USER bubble. A live immediate send's user bubble\n\t// carries NO pending flags (its in-flight-ness lives in state.sending), while every\n\t// duplicate this sweep is for belongs to a user bubble that is still pending — and\n\t// an orphan has no user bubble above it at all.\n\t_removeStrayPendingAssistants(): void {\n\t\tfor (var k = this.state.messages.length - 1; k >= 0; k--) {\n\t\t\tvar m = this.state.messages[k];\n\t\t\tif (!m || !m.isPending || m.role !== 'assistant' || m.isBackgroundTask) continue;\n\t\t\tif (this._isLiveImmediatePlaceholder(k)) continue;\n\t\t\tthis.state.messages.splice(k, 1);\n\t\t}\n\t}\n\n\t/** Index of the USER bubble the message at `idx` belongs to — the nearest one\n\t * above it, stepping over background bubbles (a file's indexing rows are\n\t * inserted between turns). -1 when the nearest thing above is not a user turn,\n\t * which for a placeholder means it is an orphan. */\n\tprivate _owningUserIndex(idx: number): number {\n\t\tfor (var j = idx - 1; j >= 0; j--) {\n\t\t\tvar p = this.state.messages[j];\n\t\t\tif (!p) return -1;\n\t\t\tif (p.isBackgroundTask) continue;\n\t\t\treturn p.role === 'user' ? j : -1;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/** The bubble at `idx` is the \"Thinking…\" of a DIFFERENT turn that is still\n\t * waiting for its answer, so the sweep above must leave it alone. */\n\tprivate _isLiveImmediatePlaceholder(idx: number): boolean {\n\t\tvar ui = this._owningUserIndex(idx);\n\t\tif (ui === -1) return false; // orphan\n\t\tvar p = this.state.messages[ui];\n\t\t// Its own turn, still unanswered and not one of the pending duplicates: a live\n\t\t// immediate send's user bubble carries no pending flags at all.\n\t\treturn !p.isPending && !p.isPendingQueued && !p.isPendingInProcess &&\n\t\t\t!p.isPendingOlder && !p.isSendingToServer && !p.isCancelled;\n\t}\n\n\t/** A pending assistant at `idx` is the placeholder OF the turn above it, so a\n\t * reply may take its slot. Every path that makes one copies the parent's\n\t * _serverItemId (or neither has one yet), so a mismatch means the slot belongs to\n\t * some other request and the reply must be spliced in beside it, not on top. */\n\tprivate _isOwnPlaceholderOf(idx: number, userIdx: number): boolean {\n\t\tif (userIdx === -1) return false;\n\t\tvar ph = this.state.messages[idx], u = this.state.messages[userIdx];\n\t\tif (!ph || !u) return false;\n\t\tif (ph._serverItemId === undefined || u._serverItemId === undefined) return true;\n\t\treturn ph._serverItemId === u._serverItemId;\n\t}\n\n\t// Drop the pending flags on the resolved turn's USER bubble (preserving its\n\t// content + background-task marker). Needed because a bg \"Indexing:\" turn's user\n\t// bubble carries isPendingInProcess; leaving it set keeps the bubble visually\n\t// stuck and keeps its bgTaskQueue entry alive forever.\n\t_clearPendingUserBubble(itemId: string): void {\n\t\tvar uIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.role === 'user' && m._serverItemId === itemId &&\n\t\t\t\t(m.isPendingInProcess || m.isPendingQueued || m.isSendingToServer);\n\t\t});\n\t\tif (uIdx === -1) return;\n\t\tvar u = this.state.messages[uIdx];\n\t\tvar cleaned: ChatMessage = { role: 'user', content: u.content, _serverItemId: itemId };\n\t\tif (u.isBackgroundTask) cleaned.isBackgroundTask = true;\n\t\tif (u._ts !== undefined) cleaned._ts = u._ts;\n\t\t// Carry the file ref: it is what keeps this pass in its file's collapsed\n\t\t// row (the label parser is only a fallback for older cached bubbles).\n\t\tif (u._indexFile) cleaned._indexFile = u._indexFile;\n\t\tthis.state.messages[uIdx] = cleaned;\n\t}\n\n\t// If an immediate-send request for the current cache key is still in flight\n\t// (e.g. the view unmounted then remounted mid-request), show the sending\n\t// state, await it, then render the reply from the cache. Skipped when the\n\t// list already has its own pending/queued bubbles (those resolve via their\n\t// own polls). The displayed reply also lands via dispatchComposedMessage's\n\t// own finally if the view never unmounted — this is the remount recovery.\n\tresumePendingRequest(token: number): Promise<void> {\n\t\tvar self = this;\n\t\tvar key = this.getHistoryCacheKey();\n\t\tvar pending = key ? this.pendingAgentRequests[key] : undefined;\n\t\tif (!pending) return Promise.resolve();\n\t\tif (this.state.messages.some(function (m) { return (m.isPending || m.isPendingQueued) && !m.isBackgroundTask && !m._useBgQueue; })) return Promise.resolve();\n\t\tthis.state.sending = true;\n\t\tthis.host.scrollToBottomIfSticky(true);\n\t\treturn Promise.resolve(pending).catch(function () { }).then(function () {\n\t\t\tif (token !== self.state.gateRefreshToken) return;\n\t\t\tself.state.sending = false;\n\t\t\treturn Promise.resolve(self.typewriteLatestReply(key)).then(function () { self.host.scrollToBottomIfSticky(true); });\n\t\t});\n\t}\n\n\t// --- background-task resolution + drain -------------------------------\n\thandleHistoryItemResolution(itemId: string, response: any, platform: string): void {\n\t\t// Which file this turn was indexing, read BEFORE the resolution rewrites the\n\t\t// bubbles. Every settling turn funnels through here — the bg drain's own\n\t\t// poll, the history poll, and agent.vue's forked history poll, which calls\n\t\t// straight into this method — so hooking the chain follow-up here is what\n\t\t// makes it work in both clients without either of them forking a call site.\n\t\tvar indexRef = this._indexRefOfItem(itemId);\n\t\tthis.applyHistoryItemResolution(itemId, response, platform);\n\t\tthis.promoteNextBgQueuedToRunning();\n\t\t// applyHistoryItemResolution just released this item's poll slot. Under\n\t\t// MAX_CONCURRENT_BG_POLLS that slot is what the next-oldest unpolled entry\n\t\t// is waiting for, and every settling turn funnels through here — including\n\t\t// the history poll, whose resolution has no other path back to the drain.\n\t\tthis.drainBgTaskQueue();\n\t\t// A worker-driven chain has no client-side record of its next pass, so a\n\t\t// settling pass is the only moment there is to go looking for one.\n\t\tif (indexRef) this._followWorkerIndexingChain(indexRef.name, indexRef.mime);\n\t}\n\n\t/** The file an already-rendered background pass is about, off its request\n\t * bubble. Null for an ordinary turn, which is most of them. */\n\tprivate _indexRefOfItem(itemId: string): { name?: string; mime?: string } | null {\n\t\tif (!itemId) return null;\n\t\tfor (var i = 0; i < this.state.messages.length; i++) {\n\t\t\tvar m = this.state.messages[i];\n\t\t\tif (m._serverItemId !== itemId || m.role !== 'user' || !m.isBackgroundTask) continue;\n\t\t\treturn m._indexFile || null;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Settle a turn the server reports as cancelled: the request bubble goes to its\n\t * cancelled form and the \"Thinking...\" placeholder goes away. The same shape\n\t * cancelQueuedMessage produces locally, so a cancel this client made and one it\n\t * merely found out about render identically — and an indexing pass keeps the\n\t * markers that hold it in its file's collapsed row.\n\t */\n\tprivate _settleCancelledItem(itemId: string): void {\n\t\tvar uIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.role === 'user' && m._serverItemId === itemId && !m.isCancelled;\n\t\t});\n\t\tif (uIdx !== -1) {\n\t\t\tvar u = this.state.messages[uIdx];\n\t\t\tvar cancelled: ChatMessage = { role: 'user', content: u.content, isCancelled: true, _serverItemId: itemId };\n\t\t\tif (u.isBackgroundTask) cancelled.isBackgroundTask = true;\n\t\t\tif (u._indexFile) cancelled._indexFile = u._indexFile;\n\t\t\tif (u._useBgQueue) cancelled._useBgQueue = true;\n\t\t\tif (u._ownerKey !== undefined) cancelled._ownerKey = u._ownerKey;\n\t\t\tif (u._ts !== undefined) cancelled._ts = u._ts;\n\t\t\tthis.state.messages[uIdx] = cancelled;\n\t\t}\n\t\tvar pIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.isPending && m.role === 'assistant' && m._serverItemId === itemId;\n\t\t});\n\t\tif (pIdx !== -1) this.state.messages.splice(pIdx, 1);\n\t\tthis.cancelledServerIds.delete(itemId);\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.host.notify();\n\t\tthis.updateHistoryCache();\n\t}\n\n\t/**\n\t * A poll that came back saying the request was CANCELLED, rather than with an\n\t * answer.\n\t *\n\t * The server keeps a cancelled request as a terminal row instead of deleting it\n\t * (that row is the durable record of the stop, and the chat history it belongs\n\t * to), so a poll still running when the cancel lands now RESOLVES on it. It used\n\t * to reject with NOT_EXISTS, and the resolution path below reads a status object\n\t * as an answer with no text — which would stamp \"No text response received from\n\t * AI provider\" over a turn the user had just stopped.\n\t *\n\t * Reachable whenever the poll was not stopped by whoever cancelled: another tab,\n\t * another device, or the row being cancelled server-side by the file's own stop.\n\t */\n\tprivate _isCancelledPollResult(response: any): boolean {\n\t\tif (!response || typeof response !== 'object' || response.status !== 'cancelled') return false;\n\t\t// The POLL's own shape (id + queue fields, no provider payload), not a\n\t\t// provider body that happens to carry a `status` — OpenAI's Responses API\n\t\t// has a \"cancelled\" status of its own, and that one is an answer to render,\n\t\t// not a row that was removed from the queue.\n\t\tif (response.content !== undefined || response.output !== undefined) return false;\n\t\treturn response.queue_name !== undefined || response.in_queue !== undefined;\n\t}\n\n\tapplyHistoryItemResolution(itemId: string, response: any, platform: string): void {\n\t\tthis.historyItemPolls.delete(itemId);\n\t\tif (this._isCancelledPollResult(response)) {\n\t\t\tthis._settleCancelledItem(itemId);\n\t\t\treturn;\n\t\t}\n\t\tvar isErr = isErrorResponseBody(response);\n\t\tvar answer = isErr ? getErrorMessage(response)\n\t\t\t: ((platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '').trim();\n\t\t// Record the marker BEFORE hiding it from the displayed summary: the display\n\t\t// layer needs it as a structured fact, and searching the shown text for it\n\t\t// afterwards would find nothing. Mirrors history.ts, so a run reads the same\n\t\t// live and after a reload.\n\t\t//\n\t\t// The STRIP happens in the background branches only, not here. It used to run\n\t\t// on every answer, so an ordinary chat reply that merely mentioned the token\n\t\t// had it silently cut out of the user's text (leaving a double space) — and\n\t\t// the history mappers never did that, so the same reply read differently\n\t\t// before and after a reload. Only an INDEXING pass has a protocol token to\n\t\t// hide.\n\t\tvar reportedComplete = !isErr && !!answer && answer.indexOf(INDEXING_COMPLETE_MARKER) !== -1;\n\t\tvar stripMarker = function (t: string): string {\n\t\t\treturn reportedComplete ? t.split(INDEXING_COMPLETE_MARKER).join('').trim() : t;\n\t\t};\n\t\tvar idx = this.state.messages.findIndex(function (m) { return m.isPending && m._serverItemId === itemId; });\n\t\tif (idx !== -1) {\n\t\t\t// A bg \"Indexing:\" turn pushes a user bubble (isPendingInProcess) ALONGSIDE\n\t\t\t// the assistant Thinking; replacing only the assistant leaves that user\n\t\t\t// bubble stuck pending — and drainBgTaskQueue then never clears its queue\n\t\t\t// entry (its stillPending check stays true). Un-pend it here too.\n\t\t\tthis._clearPendingUserBubble(itemId);\n\t\t\t// Carry isBackgroundTask onto the REPLACEMENT. These rebuilds are fresh\n\t\t\t// object literals, so anything not copied is lost — and dropping this flag\n\t\t\t// made a pass that resolved LIVE fall out of its file's collapsed row\n\t\t\t// (buildChatDisplayList only considers isBackgroundTask messages), while\n\t\t\t// the same pass rebuilt from history stayed grouped. That mismatch is the\n\t\t\t// \"new indexing response renders outside the group\" bug.\n\t\t\tvar wasBgTask = !!this.state.messages[idx].isBackgroundTask;\n\t\t\tif (isErr) {\n\t\t\t\tthis.state.messages[idx] = { role: 'assistant', content: answer, isError: true, _serverItemId: itemId };\n\t\t\t\tif (wasBgTask) this.state.messages[idx].isBackgroundTask = true;\n\t\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t\t}\n\t\t\tvar text = answer || 'No text response received from AI provider.';\n\t\t\t// A background-indexing reply is INSIDE a collapsed row: nothing of it is\n\t\t\t// on screen. Typewriting it anyway put it on the one shared, serial\n\t\t\t// typewriter queue, so the user's own next reply — which IS on screen —\n\t\t\t// lost its \"Thinking...\" spinner and sat as an EMPTY bubble for however\n\t\t\t// long the invisible indexing summary took to reveal (seconds per pass,\n\t\t\t// additive across files). It also held state.typing true for the whole\n\t\t\t// time, which disables the platform/model pickers and no-ops Clear\n\t\t\t// history, and ran a per-frame scroll for content nobody can see.\n\t\t\t// Write it straight in; expanding the row then shows it complete.\n\t\t\tif (wasBgTask) {\n\t\t\t\tthis.state.messages[idx] = { role: 'assistant', content: stripMarker(text) || EMPTY_INDEXING_REPLY, isBackgroundTask: true, _serverItemId: itemId, ...(reportedComplete ? { _indexComplete: true } : {}) };\n\t\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t\t}\n\t\t\tvar lid = this._newLocalId();\n\t\t\tthis.state.messages[idx] = { role: 'assistant', content: '', _localId: lid, _serverItemId: itemId };\n\t\t\tthis.host.notify(); this.enqueueTypewrite(idx, text, lid);\n\t\t\tthis.updateHistoryCache(); return;\n\t\t}\n\t\tvar userIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.role === 'user' && m._serverItemId === itemId && (m.isPendingQueued || m.isPendingInProcess);\n\t\t});\n\t\tif (userIdx === -1) return;\n\t\tvar ex = this.state.messages[userIdx];\n\t\t// Same carry-over as above, plus _indexFile / _useBgQueue: this rebuild is\n\t\t// what keeps an indexing REQUEST bubble in its file's collapsed row (and a\n\t\t// bg-queued chat cancelling against the right queue) once the pass settles.\n\t\tvar settledUser: ChatMessage = { role: 'user', content: ex.content, _serverItemId: itemId };\n\t\tif (ex.isBackgroundTask) settledUser.isBackgroundTask = true;\n\t\tif (ex._ts !== undefined) settledUser._ts = ex._ts;\n\t\tif (ex._indexFile) settledUser._indexFile = ex._indexFile;\n\t\tif (ex._useBgQueue) settledUser._useBgQueue = true;\n\t\tthis.state.messages[userIdx] = settledUser;\n\t\tif (isErr) {\n\t\t\tvar errReply: ChatMessage = { role: 'assistant', content: answer, isError: true, _serverItemId: itemId };\n\t\t\tif (ex.isBackgroundTask) errReply.isBackgroundTask = true;\n\t\t\tthis.state.messages.splice(userIdx + 1, 0, errReply);\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar text2 = answer || 'No text response received from AI provider.';\n\t\t// Same as above: a collapsed row's reply is not on screen, so revealing it\n\t\t// character by character only blocks the queue the visible reply needs.\n\t\tif (ex.isBackgroundTask) {\n\t\t\tthis.state.messages.splice(userIdx + 1, 0, { role: 'assistant', content: stripMarker(text2) || EMPTY_INDEXING_REPLY, isBackgroundTask: true, _serverItemId: itemId, ...(reportedComplete ? { _indexComplete: true } : {}) });\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar lid2 = this._newLocalId();\n\t\tvar reply: ChatMessage = { role: 'assistant', content: '', _localId: lid2, _serverItemId: itemId };\n\t\tthis.state.messages.splice(userIdx + 1, 0, reply);\n\t\tthis.host.notify(); this.enqueueTypewrite(userIdx + 1, text2, lid2);\n\t\tthis.updateHistoryCache();\n\t}\n\n\t/** How a bg task maps onto a collapsed row: the row's own key (storage path\n\t * when known, else the filename), scoped to the chat it belongs to. A storage\n\t * path is project-relative (\"report.xlsx\"), and ONE ChatSession serves every\n\t * project — unscoped, stopping a file in one project would silently suppress\n\t * the same filename's continuations in another. */\n\tprivate _indexKeyOf(entry: BgTaskEntry): string {\n\t\tif (!entry) return '';\n\t\tvar file = entry.storagePath || entry.filename;\n\t\tif (!file) return '';\n\t\treturn entry.projectId + '#' + entry.platform + '|' + file;\n\t}\n\n\t/**\n\t * Reconcile the bg queue with the files the user has stopped.\n\t *\n\t * A FIRST pass (no resumePass) is a fresh indexing request — a re-upload, or a\n\t * Reindex from the file manager — so it LIFTS the stop: the key is a storage\n\t * path, and without this an earlier cancel would silently kill every future\n\t * index of the same path. A continuation of a stopped file is dropped instead,\n\t * covering the pass that was dispatched in the moment before the cancel landed.\n\t *\n\t * \"Fresh\" is the load-bearing word, and it used to be missing. A run's OWN first\n\t * pass sits in this queue for as long as it runs (entries are only dropped once\n\t * their bubble settles), so stopping a file during its first pass — which is\n\t * exactly when a user who has just uploaded it does — met that first-pass entry\n\t * on the very next drain and lifted the stop the user had just asked for. The\n\t * chain then carried on, one worker-minted window after another, with nothing\n\t * client-side left to suppress it. The ids recorded at stop time are what tells\n\t * the two apart: a pass that was already there when the user hit Stop cannot be\n\t * the new request that lifts it.\n\t */\n\tprivate _applyIndexCancellations(): void {\n\t\tif (!this.cancelledIndexKeys.size) return;\n\t\t// Passes already on screen. Dropping the queue entry for one of those kills\n\t\t// its poll and leaves the bubble pending forever — a row stuck on \"Indexing\"\n\t\t// with no way to ever settle. _sweepCancelledIndexing (which runs straight\n\t\t// after this, on the same drain) cancels those properly, rebuilding the bubble\n\t\t// as cancelled; the splice below is only right for an entry with no bubble yet.\n\t\tvar surfaced: { [id: string]: boolean } = {};\n\t\tthis.state.messages.forEach(function (m) {\n\t\t\tif (!m._serverItemId) return;\n\t\t\tif (m.isPending || m.isPendingQueued || m.isPendingInProcess) surfaced[m._serverItemId] = true;\n\t\t});\n\t\tfor (var i = this.bgTaskQueue.length - 1; i >= 0; i--) {\n\t\t\tvar entry = this.bgTaskQueue[i];\n\t\t\tvar key = this._indexKeyOf(entry);\n\t\t\tif (!key || !this.cancelledIndexKeys.has(key)) continue;\n\t\t\tif (!entry.resumePass && !this.state.stoppedIndexIds[entry.id]) {\n\t\t\t\tthis.cancelledIndexKeys.delete(key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (surfaced[entry.id]) continue;\n\t\t\tthis.bgTaskQueue.splice(i, 1);\n\t\t\tthis._stopPoll(entry.id);\n\t\t\tthis._cancelServerItem(entry.id);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel any live pass of a stopped file that turned up on its own.\n\t *\n\t * The client is not the only thing that continues a file: for PDFs and (when\n\t * windowed indexing is on) text/grid files the WORKER enqueues the next window\n\t * itself, and that pass reaches the chat through the history poll, never\n\t * through bgTaskQueue. The worker's own gate stops the chain when the running\n\t * row is cancelled — but if the row had already finished when the user hit\n\t * stop, the next window was queued a moment earlier and still arrives. Stop it\n\t * here rather than making the user hit stop again.\n\t *\n\t * Runs from drainBgTaskQueue, which both clients call after a history load.\n\t */\n\tprivate _sweepCancelledIndexing(): void {\n\t\tif (!this.cancelledIndexKeys.size) return;\n\t\tvar self = this;\n\t\tvar chatKey = this.getHistoryCacheKey();\n\t\tvar targets: { msg: ChatMessage; idx: number }[] = [];\n\t\tthis.state.messages.forEach(function (m, i) {\n\t\t\tif (!m.isBackgroundTask || m.role !== 'user' || !m._serverItemId) return;\n\t\t\tif (m._cancelling || m.isSendingToServer) return;\n\t\t\tif (!(m.isPendingQueued || m.isPendingInProcess)) return;\n\t\t\tvar ref = m._indexFile;\n\t\t\tvar file = ref && (ref.path || ref.name);\n\t\t\tif (!file || !self.cancelledIndexKeys.has(chatKey + '|' + file)) return;\n\t\t\ttargets.push({ msg: m, idx: i });\n\t\t});\n\t\ttargets.forEach(function (t) {\n\t\t\tvar idx = self.state.messages.indexOf(t.msg);\n\t\t\tself.cancelQueuedMessage(t.msg, idx === -1 ? t.idx : idx);\n\t\t});\n\t}\n\n\t/**\n\t * True when the WORKER, not this client, drives the rest of this file's chain.\n\t * The mirror image of the early returns in maybeResumeIndexing: whatever that\n\t * refuses to continue is exactly what nothing client-side is tracking.\n\t */\n\tprivate _isWorkerDrivenIndexing(filename?: string, mime?: string): boolean {\n\t\tif (!isPagedReadFile(filename, mime)) return false;\n\t\tif (isImageVisionFile(filename, mime)) return true;\n\t\treturn windowedIndexingEnabled() && isWindowedReadFile(filename, mime);\n\t}\n\n\t/**\n\t * Pick up indexing passes the WORKER minted, which no client ever dispatched.\n\t *\n\t * For a PDF (and for text/grid when windowed indexing is on) the worker writes\n\t * pass N+1's row itself, inside pass N's invocation, right after saving pass\n\t * N's result. That row reaches this client through nothing at all: it is not in\n\t * bgTaskQueue (the client never asked for it) and it is not in state.messages\n\t * (only a first-page history load maps it in, which happens on mount, project\n\t * switch or tab return). So between two worker passes every pass the client\n\t * knows about is settled, and the collapsed row renders \"Indexed N passes\"\n\t * with no spinner and no Stop, for a file that is still being read. A user who\n\t * believes that then asks questions against a half-indexed file — which is what\n\t * this exists to prevent.\n\t *\n\t * So when a background indexing pass settles, ask the bg queue what is still\n\t * unresolved on it and adopt anything unknown as an ordinary BgTaskEntry.\n\t * drainBgTaskQueue then treats it exactly like a pass this client dispatched:\n\t * same bubble, same `_indexFile` (so it joins the file's collapsed row), same\n\t * poll — and that poll settling runs this again, so the chain is followed to\n\t * its end. `status`-scoped so the reply carries the live items only, never a\n\t * page of finished ones with their bodies.\n\t *\n\t * Termination: the only trigger is a pass SETTLING, which happens once per\n\t * pass. An adopted item that is still running is not re-adopted (its id is\n\t * already polled), and when the queue holds nothing unknown the chain stops on\n\t * its own. Nothing here is periodic — a timer that re-reads history is the\n\t * shape that previously looped fetchHistoryPage after an already-DONE index.\n\t */\n\tprivate _adoptingWorkerPasses = false;\n\tprivate _adoptWorkerIndexingPasses(attempt: number, passive?: boolean): void {\n\t\tvar self = this;\n\t\t// One in flight at a time. The query is queue-WIDE, so a second file's pass\n\t\t// settling in the same moment is covered by the query already running.\n\t\tif (this._adoptingWorkerPasses) return;\n\t\tvar id = this.host.getIdentity();\n\t\tvar platform = id.platform;\n\t\tif (!id.projectId || (platform !== 'claude' && platform !== 'openai')) return;\n\t\tif (this.isPollingPaused() || !this.host.isViewMounted()) return;\n\t\tvar svcId = id.projectId, owner = id.owner;\n\t\tvar queue = bgIndexingQueueName(id.userId, id.projectId);\n\t\t// maxAgeMs 0: adoption exists to notice passes the worker JUST minted,\n\t\t// so it must always look fresh — but its answers write through into the\n\t\t// shared probe memo, which is what keeps the snapshot readers (and the\n\t\t// db-files page's badge probe) from re-asking seconds later.\n\t\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(probeBgQueue(\n\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status, limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t{ maxAgeMs: 0 },\n\t\t\t)).then(function (entry) { return entry.result; }).catch(function () { return null; });\n\t\t};\n\t\tthis._adoptingWorkerPasses = true;\n\t\tPromise.all([ask('running'), ask('pending')]).then(function (results: any[]) {\n\t\t\tself._adoptingWorkerPasses = false;\n\t\t\t// The chat may have changed under the query; adopting into another\n\t\t\t// project's session is the cross-project bubble leak all over again.\n\t\t\tvar now = self.host.getIdentity();\n\t\t\tif (now.projectId !== svcId || now.platform !== platform) return;\n\t\t\tif (!self.host.isViewMounted()) return;\n\t\t\t// Free: this is already the whole-queue snapshot the display layer needs to\n\t\t\t// tell a worker-driven run's \"between passes\" from its \"finished\".\n\t\t\t//\n\t\t\t// A null is a FAILED query, and the adoption loop below reads it as an empty\n\t\t\t// list — harmless there (nothing to adopt) but not here: recording it would\n\t\t\t// publish \"the queue holds nothing\" on the strength of a request that never\n\t\t\t// answered, which reads as finished. Not knowing is the honest state.\n\t\t\tif (results[0] !== null && results[1] !== null) self._recordLiveIndexKeys(results);\n\t\t\tvar adoptedIds: string[] = [];\n\t\t\tfor (var ri = 0; ri < results.length; ri++) {\n\t\t\t\tvar list = results[ri] && Array.isArray(results[ri].list) ? results[ri].list : [];\n\t\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\t\tif (self._adoptWorkerIndexingItem(list[i], svcId, platform as 'claude' | 'openai')) adoptedIds.push(list[i].id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (adoptedIds.length) {\n\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\t// Only an item the drain KEPT means the chain is still going. One it\n\t\t\t\t// threw straight back out is not progress and must not end the ladder:\n\t\t\t\t// the status index is eventually consistent, so a look taken the\n\t\t\t\t// instant a pass settles can still report that pass as running, and a\n\t\t\t\t// pass belonging to a file the user stopped is dropped on sight. Both\n\t\t\t\t// used to read as \"found the next pass\", which ended the search for a\n\t\t\t\t// pass that had not been written yet.\n\t\t\t\tif (self._isTrackingAny(adoptedIds)) return;\n\t\t\t}\n\t\t\t// Nothing yet. The worker writes pass N+1 a few milliseconds AFTER it\n\t\t\t// flips pass N to resolved, so a poll that lands in that gap sees an\n\t\t\t// empty queue for a chain that is very much alive — and with no pass\n\t\t\t// left to settle, nothing would ever ask again. Look once or twice more\n\t\t\t// before believing the file is finished.\n\t\t\t//\n\t\t\t// PASSIVE calls (first-page/resume refresh) climb only on EVIDENCE of\n\t\t\t// live work — a queued local entry for this project, a live key the\n\t\t\t// look above just recorded, or an attached poll. The gap rationale\n\t\t\t// presumes a chain was alive; with nothing suggesting one, the climb\n\t\t\t// re-asked an unchanged question three more times on every tab return.\n\t\t\t// (No nudge here either: a send waiting on indexing implies local\n\t\t\t// entries, which IS evidence, so the passive stop never starves it.)\n\t\t\tif (passive && !self._hasLiveIndexEvidence(svcId)) return;\n\t\t\tif (attempt + 1 >= WORKER_PASS_ADOPT_ATTEMPTS.length) {\n\t\t\t\t// The ladder is the only thing that can tell a worker-driven chain has\n\t\t\t\t// really ended, and it just did. This is the earliest honest moment to\n\t\t\t\t// let a turn waiting on these files stop waiting.\n\t\t\t\tself._nudgeIndexingDrain();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetTimeout(function () {\n\t\t\t\tvar later = self.host.getIdentity();\n\t\t\t\tif (later.projectId !== svcId || later.platform !== platform) return;\n\t\t\t\tif (self.isPollingPaused() || !self.host.isViewMounted()) return;\n\t\t\t\tself._adoptWorkerIndexingPasses(attempt + 1, passive);\n\t\t\t}, WORKER_PASS_ADOPT_ATTEMPTS[attempt + 1]);\n\t\t}, function () { self._adoptingWorkerPasses = false; });\n\t}\n\n\t/** Anything at all suggesting THIS project's indexing may be live: a queued\n\t * local entry, a recorded live key (the adopt look just wrote them), or an\n\t * attached poll. Gates the passive adopt ladder's climb. */\n\tprivate _hasLiveIndexEvidence(svcId: string): boolean {\n\t\tfor (var i = 0; i < this.bgTaskQueue.length; i++) {\n\t\t\tvar e = this.bgTaskQueue[i];\n\t\t\tif (e && e.projectId === svcId) return true;\n\t\t}\n\t\tvar keys = this.state.liveIndexKeys || {};\n\t\tfor (var k in keys) { if (keys[k]) return true; }\n\t\t// BG polls only: a pending ORDINARY chat turn also holds a poll, and\n\t\t// counting it made every tab return during a conversation climb the\n\t\t// full passive ladder for indexing that does not exist.\n\t\tvar found = false;\n\t\tthis.historyItemPolls.forEach(function (h: any) { if (h && h.kind === 'bg') found = true; });\n\t\treturn found;\n\t}\n\n\t/** Any of these ids still queued or still polled, i.e. surviving work. */\n\tprivate _isTrackingAny(ids: string[]): boolean {\n\t\tfor (var i = 0; i < ids.length; i++) {\n\t\t\tif (this.historyItemPolls.has(ids[i])) return true;\n\t\t\tfor (var q = 0; q < this.bgTaskQueue.length; q++) {\n\t\t\t\tif (this.bgTaskQueue[q].id === ids[i]) return true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** One live bg-queue item -> a BgTaskEntry, if it is an indexing pass this\n\t * client is not already tracking. Returns whether it was adopted. */\n\tprivate _adoptWorkerIndexingItem(item: any, svcId: string, platform: 'claude' | 'openai'): boolean {\n\t\tif (!item || typeof item.id !== 'string' || !item.id) return false;\n\t\tif (item.status !== 'pending' && item.status !== 'running') return false;\n\t\tif (typeof item.poll !== 'function') return false;\n\t\t// Already known: a pass this client dispatched, or one adopted earlier that\n\t\t// has not settled yet. Adopting twice would stack a second poll on one item.\n\t\tif (this.historyItemPolls.has(item.id)) return false;\n\t\tfor (var q = 0; q < this.bgTaskQueue.length; q++) {\n\t\t\tif (this.bgTaskQueue[q].id === item.id) return false;\n\t\t}\n\t\t// Already SETTLED here. The status index is eventually consistent, so the\n\t\t// pass that just finished can still come back as running; re-adopting it\n\t\t// would re-poll a dead item and, worse, read as the chain continuing.\n\t\tfor (var m = 0; m < this.state.messages.length; m++) {\n\t\t\tvar msg = this.state.messages[m];\n\t\t\tif (msg._serverItemId !== item.id) continue;\n\t\t\tif (!(msg.isPending || msg.isPendingInProcess || msg.isPendingQueued)) return false;\n\t\t}\n\t\t// The bg queue also carries ordinary chats routed onto it (_isOnBgQueue), and\n\t\t// both platforms share one queue name, so check the shape as well: a claude\n\t\t// request body has `messages`, an openai one has `input`. Adopting the other\n\t\t// platform's item would poll it against this platform's url.\n\t\tvar body = item.request_body;\n\t\tif (!body || typeof body !== 'object') return false;\n\t\tif (platform === 'claude' ? !Array.isArray((body as any).messages) : !Array.isArray((body as any).input)) return false;\n\t\tvar userText = extractLastUserTextFromRequest(body);\n\t\tif (!isIndexingRequestText(userText)) return false;\n\t\tvar ref = parseIndexingRequestText(userText);\n\t\tif (!ref || !ref.name) return false;\n\t\t// Only chains the worker drives. A client-driven file is already tracked by\n\t\t// the entry that dispatched it, and adopting a copy of it would hand\n\t\t// maybeResumeIndexing an entry whose resumePass no longer counts that\n\t\t// chain's passes — which is the cap that stops it running forever.\n\t\tif (!this._isWorkerDrivenIndexing(ref.name, ref.mime)) return false;\n\t\tthis.bgTaskQueue.push({\n\t\t\tprojectId: svcId,\n\t\t\tplatform: platform,\n\t\t\tid: item.id,\n\t\t\tfilename: ref.name,\n\t\t\tstoragePath: ref.path,\n\t\t\tmime: ref.mime,\n\t\t\tsize: ref.size,\n\t\t\tstatus: item.status === 'running' ? 'running' : 'pending',\n\t\t\tpoll: item.poll,\n\t\t\t// Drives the \"(continuing)\" label and marks this as a continuation for\n\t\t\t// _applyIndexCancellations, which must not read a CONTINUE pass as the\n\t\t\t// fresh first pass that lifts a stop.\n\t\t\tresumePass: ref.continued ? 1 : 0,\n\t\t});\n\t\treturn true;\n\t}\n\n\t/** Follow the chain on from a background indexing pass that just settled. */\n\tprivate _followWorkerIndexingChain(filename?: string, mime?: string): void {\n\t\tif (!this._isWorkerDrivenIndexing(filename, mime)) return;\n\t\tthis._adoptWorkerIndexingPasses(0);\n\t}\n\n\t/** Best-effort server-side cancel of a bg-queue item that has no bubble (so\n\t * cancelQueuedMessage, which drives one, has nothing to act on). */\n\tprivate _cancelServerItem(serverId: string): void {\n\t\tvar id = this.host.getIdentity();\n\t\tif (!serverId || (id.platform !== 'claude' && id.platform !== 'openai')) return;\n\t\tvar url = id.platform === 'claude' ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;\n\t\tPromise.resolve(this.host.cancelRequest({\n\t\t\turl: url, method: 'POST', id: serverId,\n\t\t\tqueue: bgIndexingQueueName(id.userId, id.projectId),\n\t\t\tservice: id.projectId, owner: id.owner,\n\t\t})).catch(function () { /* the pass may already have finished; nothing to do */ });\n\t}\n\n\t// Inject \"Indexing: <file>\" bubbles for queued bg tasks + attach their polls.\n\tdrainBgTaskQueue(): void {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\tvar svcId = id.projectId, plat = id.platform;\n\t\tif (!svcId || plat === 'none' || !this.host.isViewMounted()) return;\n\t\t// Before anything is surfaced: drop continuations of files the user stopped\n\t\t// (and let a fresh first pass lift the stop), then cancel any worker-queued\n\t\t// pass of a stopped file that reached the chat through history.\n\t\tthis._applyIndexCancellations();\n\t\tthis._sweepCancelledIndexing();\n\t\t// Index messages by _serverItemId ONCE, so the per-entry presence/pending\n\t\t// checks below are O(1) instead of a full messages.some() scan each. With a\n\t\t// large bg queue (bulk uploads) the old nested scan was O(queue x messages)\n\t\t// per drain, and the drain runs once per uploaded file (O(n^3) overall).\n\t\tvar presentIds: { [id: string]: boolean } = {};\n\t\tvar pendingIds: { [id: string]: boolean } = {};\n\t\tthis.state.messages.forEach(function (m) {\n\t\t\tvar sid = m._serverItemId;\n\t\t\tif (sid == null) return;\n\t\t\tpresentIds[sid] = true;\n\t\t\tif (m.isPending || m.isPendingInProcess || m.isPendingQueued) pendingIds[sid] = true;\n\t\t});\n\t\tfor (var i = this.bgTaskQueue.length - 1; i >= 0; i--) {\n\t\t\tvar e = this.bgTaskQueue[i];\n\t\t\tif (e.projectId !== svcId || e.platform !== plat) continue;\n\t\t\tif (presentIds[e.id] && !pendingIds[e.id]) {\n\t\t\t\t// Settled while nobody was polling (hidden tab, dead poll): the\n\t\t\t\t// answer reached the chat as HISTORY, so no settle handler ever\n\t\t\t\t// ran for this entry — maybeResumeIndexing's flips included. For\n\t\t\t\t// a single-pass file that settle IS the whole run; close its\n\t\t\t\t// records off the settled bubbles' own flags before the entry\n\t\t\t\t// goes. (8 of 10 files in a real batch hit exactly this.)\n\t\t\t\tthis._flipRunFromSettledEntry(e);\n\t\t\t\tthis.bgTaskQueue.splice(i, 1);\n\t\t\t}\n\t\t}\n\t\t// Poll budget for this drain (see MAX_CONCURRENT_BG_POLLS). bgTaskQueue is\n\t\t// in push order, i.e. oldest first, which is also the order the server\n\t\t// settles them in — so spending the budget from the front spends it on the\n\t\t// only entries that can resolve next. Bubbles are still injected for EVERY\n\t\t// entry; only the polling is rationed, and an unpolled entry picks up a\n\t\t// poll on the drain that follows the next resolution.\n\t\tvar bgPollBudget = MAX_CONCURRENT_BG_POLLS - this._countBgPolls();\n\t\t// Set by the injection branch; drives the single render/cache/scroll below.\n\t\tvar injectedAny = false;\n\t\tthis.bgTaskQueue.forEach(function (entry) {\n\t\t\tif (entry.projectId !== svcId || entry.platform !== plat) return;\n\t\t\t// Bubble injection and poll attachment are INDEPENDENT. An entry whose bubble\n\t\t\t// already exists may still need a poll — that is exactly the state a paused\n\t\t\t// drain leaves behind, and returning early here stranded it as a permanent\n\t\t\t// \"Thinking...\" once polling resumed.\n\t\t\tif (!presentIds[entry.id]) {\n\t\t\tvar isRunning = entry.status === 'running';\n\t\t\tvar userBubble: ChatMessage = {\n\t\t\t\trole: 'user',\n\t\t\t\tcontent: self.host.formatIndexingLabel(entry.filename, entry.mime, entry.size, entry.storagePath, entry.isReindex, !!entry.resumePass),\n\t\t\t\tisBackgroundTask: true,\n\t\t\t\t_serverItemId: entry.id,\n\t\t\t\t// Structured ref so this live pass groups with the same file's passes\n\t\t\t\t// rebuilt from history (see indexing_groups.buildChatDisplayList).\n\t\t\t\t_indexFile: {\n\t\t\t\t\tname: entry.filename,\n\t\t\t\t\tpath: entry.storagePath,\n\t\t\t\t\tmime: entry.mime,\n\t\t\t\t\tsize: entry.size,\n\t\t\t\t\tisReindex: !!entry.isReindex,\n\t\t\t\t\tcontinued: !!entry.resumePass,\n\t\t\t\t},\n\t\t\t};\n\t\t\tif (isRunning) userBubble.isPendingInProcess = true; else userBubble.isPendingQueued = true;\n\t\t\t// Directly ABOVE the chat turn these files were attached to, when that turn\n\t\t\t// is still on screen as a staged bubble. The row then appears where it\n\t\t\t// belongs from the start — right before the message the files came with,\n\t\t\t// which is also the order the server reports once the turn is sent (its\n\t\t\t// request id is newer than every pass it waits for). Appending instead put\n\t\t\t// the row BELOW the message and left the turn to be moved down past it at\n\t\t\t// dispatch, minutes later: a swap under the reader, at the one moment they\n\t\t\t// were watching for the turn to go out.\n\t\t\t//\n\t\t\t// -1 (no stage id, or a staged bubble already replaced/rebuilt away) appends,\n\t\t\t// which is the old behaviour and the right one for work with no chat turn\n\t\t\t// behind it: the dbfile page, an attachment-only send, a worker-adopted pass.\n\t\t\t// Resolved PER ENTRY: one drain can inject several passes, and a hoisted\n\t\t\t// index would insert each one before the last and reverse them.\n\t\t\tvar stageAt = self._stageIndex(self.state.messages, entry.stageId);\n\t\t\tvar runningBubble: ChatMessage | null = isRunning\n\t\t\t\t? { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, isBackgroundTask: true, _serverItemId: entry.id }\n\t\t\t\t: null;\n\t\t\tif (stageAt === -1) {\n\t\t\t\tself.state.messages.push(userBubble);\n\t\t\t\tif (runningBubble) self.state.messages.push(runningBubble);\n\t\t\t} else if (runningBubble) {\n\t\t\t\t// One splice, so the request and its placeholder stay ADJACENT: an\n\t\t\t\t// id-less response bubble is attributed to the message immediately\n\t\t\t\t// above it (indexing_groups) and replies are spliced at userIdx + 1.\n\t\t\t\tself.state.messages.splice(stageAt, 0, userBubble, runningBubble);\n\t\t\t} else {\n\t\t\t\t// AT the staged bubble, so this pass lands after any pass already\n\t\t\t\t// inserted for the same turn — files keep their upload order.\n\t\t\t\tself.state.messages.splice(stageAt, 0, userBubble);\n\t\t\t}\n\t\t\tpresentIds[entry.id] = true; // keep the index consistent with the pushed bubbles\n\t\t\t// Render/cache/scroll are hoisted OUT of this loop (see injectedAny below).\n\t\t\t// They used to run per injected entry, and updateHistoryCache filters the\n\t\t\t// whole of state.messages into a fresh array each call — so a bulk upload\n\t\t\t// injecting one bubble per file did O(files x messages) element visits and\n\t\t\t// left one throwaway array per file for the GC. In the widget it was worse\n\t\t\t// still: its notify() is a full DOM re-render of the message list. The end\n\t\t\t// state is identical either way; only the discarded intermediate renders\n\t\t\t// are gone.\n\t\t\tinjectedAny = true;\n\t\t\t}\n\t\t\tif (bgPollBudget > 0 && !self.isPollingPaused() && !self.historyItemPolls.has(entry.id) && typeof entry.poll === 'function') {\n\t\t\t\tbgPollBudget--;\n\t\t\t\tvar capturedId = entry.id, capturedPlat = plat;\n\t\t\t\tvar capturedEntry = entry;\n\t\t\t\tvar wasStopped = false;\n\t\t\t\tvar bp = entry.poll({ latency: POLL_INTERVAL });\n\t\t\t\tself._trackPoll(entry.id, 'bg', bp);\n\t\t\t\tbp.then(function (response: any) {\n\t\t\t\t\t// A stopped poll is not a result: leave the bubble and the queue entry\n\t\t\t\t\t// exactly as they were so resumePolling can re-attach.\n\t\t\t\t\tif (isPollStopped(response)) { wasStopped = true; return; }\n\t\t\t\t\tself.handleHistoryItemResolution(capturedId, response, capturedPlat);\n\t\t\t\t\tself.maybeResumeIndexing(capturedEntry, response, capturedPlat);\n\t\t\t\t}).catch(function (err: any) {\n\t\t\t\t\tself.historyItemPolls.delete(capturedId);\n\t\t\t\t\tvar isNotExists = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\t\t\t\t// Settle the REQUEST bubble first, unconditionally. Only a RUNNING\n\t\t\t\t\t// pass gets an assistant placeholder, so for a queued one the lookup\n\t\t\t\t\t// below finds nothing and every branch was skipped — leaving the\n\t\t\t\t\t// request bubble isPendingQueued with its queue entry about to be\n\t\t\t\t\t// spliced away, i.e. no poll left to ever clear it. One such bubble\n\t\t\t\t\t// pins the whole collapsed row to \"active\": a spinner and a Stop\n\t\t\t\t\t// button against a dead id, until the page is reloaded.\n\t\t\t\t\tself._clearPendingUserBubble(capturedId);\n\t\t\t\t\tvar bi = self.state.messages.findIndex(function (m) { return m.isPending && m._serverItemId === capturedId; });\n\t\t\t\t\tif (bi !== -1) {\n\t\t\t\t\t\tif (isNotExists) self.state.messages.splice(bi, 1);\n\t\t\t\t\t\telse self.state.messages[bi] = { role: 'assistant', content: getErrorMessage(err), isError: true, isBackgroundTask: true, _serverItemId: capturedId };\n\t\t\t\t\t} else if (!isNotExists) {\n\t\t\t\t\t\t// No placeholder to turn into the error (a queued pass). Put one\n\t\t\t\t\t\t// after the request bubble so the row reports the failure instead\n\t\t\t\t\t\t// of quietly settling to \"Indexed\".\n\t\t\t\t\t\tvar ui = self.state.messages.findIndex(function (m) { return m.role === 'user' && m._serverItemId === capturedId; });\n\t\t\t\t\t\tif (ui !== -1) {\n\t\t\t\t\t\t\tself.state.messages.splice(ui + 1, 0, { role: 'assistant', content: getErrorMessage(err), isError: true, isBackgroundTask: true, _serverItemId: capturedId });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tself.host.notify(); self.updateHistoryCache();\n\t\t\t\t\t// A pass that FAILED dispatches no continuation on any path, so a\n\t\t\t\t\t// CLIENT-driven file is finished either way — let a turn waiting on it\n\t\t\t\t\t// look now. Not for a worker-driven one: this catch also fires on a\n\t\t\t\t\t// dropped poll, and the worker may have resolved that pass and written\n\t\t\t\t\t// the next one regardless. Nudging there would pull the two confirming\n\t\t\t\t\t// looks into the window where the new pass is not yet in the status\n\t\t\t\t\t// index, which is the same way a nudge on work STARTING went wrong.\n\t\t\t\t\tif (!self._isWorkerDrivenIndexing(capturedEntry.filename, capturedEntry.mime)) {\n\t\t\t\t\t\t// Also close the run record: for a CLIENT-driven file a failed\n\t\t\t\t\t\t// pass ends the chain on every path, and a removed row reads as\n\t\t\t\t\t\t// a cancel. Worker-driven files are excluded for the same reason\n\t\t\t\t\t\t// as the nudge — this catch fires on dropped polls too, and the\n\t\t\t\t\t\t// worker may be writing the next pass regardless.\n\t\t\t\t\t\tif (isNotExists) self._flipRunRecord(capturedEntry, 'cancelled');\n\t\t\t\t\t\telse self._flipRunRecord(capturedEntry, 'error', self._runErrorText(err));\n\t\t\t\t\t\tself._nudgeIndexingDrain();\n\t\t\t\t\t}\n\t\t\t\t}).then(function () {\n\t\t\t\t\t// Keep the queue entry when the poll was merely stopped, or resuming\n\t\t\t\t\t// would have nothing left to re-attach to.\n\t\t\t\t\tif (wasStopped) return;\n\t\t\t\t\tvar qi = self.bgTaskQueue.findIndex(function (q) { return q.id === capturedId; });\n\t\t\t\t\tif (qi !== -1) self.bgTaskQueue.splice(qi, 1);\n\t\t\t\t\t// This resolution freed a slot in the MAX_CONCURRENT_BG_POLLS budget,\n\t\t\t\t\t// so hand it to the next-oldest unpolled entry. Load-bearing under the\n\t\t\t\t\t// cap: with thousands of entries queued, only the handful holding\n\t\t\t\t\t// polls can ever settle, and without this re-drain the remaining\n\t\t\t\t\t// entries would sit unpolled forever. Not left to a host-side watcher\n\t\t\t\t\t// on bgTaskQueue — agent.vue has one, the widget does not.\n\t\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t// One render, one cache write, one scroll for the whole drain — however many\n\t\t// bubbles it injected. See the injectedAny comment above.\n\t\tif (injectedAny) {\n\t\t\tthis.host.notify();\n\t\t\tthis.updateHistoryCache();\n\t\t\tthis.host.scrollToBottomIfSticky(false);\n\t\t}\n\t\tthis.promoteNextBgQueuedToRunning();\n\t}\n\n\t// Resume-across-passes: if a background INDEXING task for a paged file (spreadsheet or\n\t// text) finished WITHOUT the completion marker, the agent ran out of room before reading\n\t// the whole file - dispatch a CONTINUE pass (up to a cap) that resumes from where the\n\t// already-saved records leave off. Additive + guarded so it never loops forever and\n\t// never breaks the resolution path.\n\t//\n\t// VISION files (PDFs rendered to page images) are NOT resumed here: the proxy worker\n\t// advances their page window itself, off the renderer's true page count. Driving them\n\t// from the browser is what used to lose pages on long documents - the chain lived in tab\n\t// memory (a reload or a closed tab ended it), and it stopped whenever the model claimed\n\t// completion, which on an 88-page file happened at page 15. Continuing to dispatch here\n\t// as well would now double-index every window.\n\t/** Fire the consumer's done::-marker hook for a run whose completion this\n\t * client knows DETERMINISTICALLY (see the two call sites in\n\t * maybeResumeIndexing). Best-effort by contract; identity-checked so a\n\t * project switch mid-settle cannot stamp the wrong service. */\n\t_mintDoneMarker(entry: BgTaskEntry): void {\n\t\ttry {\n\t\t\tvar mint = chatEngineConfig().mintIndexDoneMarker;\n\t\t\tif (!mint || !entry || !entry.storagePath || !entry.projectId) return;\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (!id || id.projectId !== entry.projectId) return;\n\t\t\tmint({ service: entry.projectId, storagePath: entry.storagePath });\n\t\t} catch (_e) { /* best-effort */ }\n\t}\n\n\t/** Short, storable form of an error body for the run:: record. */\n\t_runErrorText(response: any): string {\n\t\tvar msg = '';\n\t\ttry { msg = String(getErrorMessage(response) || ''); } catch (_e) { }\n\t\tmsg = msg.replace(/\\s+/g, ' ').trim();\n\t\treturn msg ? msg.slice(0, 300) : 'Indexing failed.';\n\t}\n\n\t/** Close the records of a run whose pass settled OFF-POLL — the answer came\n\t * back as history (hidden tab, dead poll, resume refetch), so none of the\n\t * poll-side settle handlers ran. Only for SINGLE-PASS files, where one\n\t * settled pass is deterministically the whole run (the same contract as\n\t * maybeResumeIndexing's single-pass branch); paged files stay with their\n\t * drivers. Outcome is read from the settled bubbles' own flags, which is\n\t * all the history mapping left us. Best-effort and idempotent throughout. */\n\t_flipRunFromSettledEntry(entry: BgTaskEntry): void {\n\t\ttry {\n\t\t\tif (!entry || !entry.storagePath || !entry.id || !entry.projectId) return;\n\t\t\tif (isPagedReadFile(entry.filename, entry.mime)) return;\n\t\t\t// A stopped run's verdict belongs to the stop funnel — never let a\n\t\t\t// late clean settle of its pass relabel 'cancelled' as 'done'.\n\t\t\tif (this.cancelledIndexKeys.has(this._indexKeyOf(entry))) return;\n\t\t\tif (this.state.stoppedIndexIds[entry.id]) return;\n\t\t\tvar userMsg: any = null, replyMsg: any = null;\n\t\t\tthis.state.messages.forEach(function (m: any) {\n\t\t\t\tif (m._serverItemId !== entry.id) return;\n\t\t\t\tif (m.role === 'user') { if (!userMsg) userMsg = m; }\n\t\t\t\telse if (!replyMsg) replyMsg = m;\n\t\t\t});\n\t\t\tif ((userMsg && userMsg.isCancelled) || (replyMsg && replyMsg.isCancelled)) {\n\t\t\t\tthis._flipRunRecord(entry, 'cancelled');\n\t\t\t} else if (replyMsg && replyMsg.isError) {\n\t\t\t\tvar errText = typeof replyMsg.content === 'string'\n\t\t\t\t\t? replyMsg.content.replace(/\\s+/g, ' ').trim().slice(0, 300) : '';\n\t\t\t\tthis._flipRunRecord(entry, 'error', errText || 'Indexing failed.');\n\t\t\t} else if (replyMsg) {\n\t\t\t\tthis._mintDoneMarker(entry);\n\t\t\t\tthis._flipRunRecord(entry, 'done');\n\t\t\t}\n\t\t\t// No reply bubble at all: nothing to judge from — leave the record.\n\t\t} catch (_e) { /* best-effort */ }\n\t}\n\n\t/** Close the durable run:: record for an ending THIS client observed.\n\t * service comes from the ENTRY, not the current identity: unlike the done::\n\t * mint above, a status flip must land even if the user switched projects\n\t * mid-settle — otherwise the record lies 'working' forever. Best-effort\n\t * through upsertIndexRunRecordSafe; the consumer's precedence guard keeps\n\t * repeats and races harmless. */\n\t_flipRunRecord(entry: BgTaskEntry, status: IndexRunStatus, error?: string): void {\n\t\tif (!entry || !entry.storagePath || !entry.projectId) return;\n\t\tvar patch: IndexRunPatch = { status: status, finished: Date.now() };\n\t\tif (error) patch.error = error;\n\t\tupsertIndexRunRecordSafe(entry.projectId, entry.storagePath, patch);\n\t}\n\n\tmaybeResumeIndexing(entry: BgTaskEntry, response: any, platform: string): void {\n\t\tvar self = this;\n\t\t// This client is the ONLY driver of the chains that reach the returns below,\n\t\t// so its decision not to continue one is authoritative and immediate — the\n\t\t// earliest honest \"these files are done\" a waiting turn can get. Used only to\n\t\t// make awaitIndexingDrained look sooner; it still has to agree twice.\n\t\t// NOT called for the worker-driven returns further down (the worker may be\n\t\t// about to write the next pass) or for a stopped file (its queued passes are\n\t\t// still being cancelled).\n\t\tvar endOfClientChain = function () { self._nudgeIndexingDrain(); };\n\t\ttry {\n\t\t\tif (!entry || !entry.storagePath) return;\n\t\t\t// The user stopped this file from its collapsed row. Dispatching the next\n\t\t\t// pass here is exactly what \"stop\" has to prevent — the cancelled pass\n\t\t\t// settles, and without this the chain simply carries on.\n\t\t\tif (this.cancelledIndexKeys.has(this._indexKeyOf(entry))) return;\n\t\t\tif (!isPagedReadFile(entry.filename, entry.mime)) {\n\t\t\t\t// Single-pass file: one settled pass IS the whole job. This is\n\t\t\t\t// deterministic knowledge (this client is the only dispatcher),\n\t\t\t\t// so record the durable done:: marker — single-pass runs never\n\t\t\t\t// get one from the worker. Errors don't count as completion\n\t\t\t\t// (this branch sits above the error check on purpose: the chain\n\t\t\t\t// is over either way, but only success gets a marker), and\n\t\t\t\t// neither does a CANCELLED poll shape — a row stopped from\n\t\t\t\t// another tab/device settles through here as {status:\n\t\t\t\t// 'cancelled', queue fields} with no provider payload, and\n\t\t\t\t// cancelledIndexKeys only records stops issued from THIS tab.\n\t\t\t\tif (!isErrorResponseBody(response) && !this._isCancelledPollResult(response)) {\n\t\t\t\t\tthis._mintDoneMarker(entry);\n\t\t\t\t\tthis._flipRunRecord(entry, 'done');\n\t\t\t\t} else if (this._isCancelledPollResult(response)) {\n\t\t\t\t\t// Stopped elsewhere (another tab/device): the stopping side\n\t\t\t\t\t// usually wrote 'cancelled' already; writing it again is a\n\t\t\t\t\t// same-value terminal update, and it closes the record when\n\t\t\t\t\t// the stopping tab died before its write landed.\n\t\t\t\t\tthis._flipRunRecord(entry, 'cancelled');\n\t\t\t\t} else {\n\t\t\t\t\tthis._flipRunRecord(entry, 'error', this._runErrorText(response));\n\t\t\t\t}\n\t\t\t\tendOfClientChain(); return;\n\t\t\t}\n\t\t\tif (isImageVisionFile(entry.filename, entry.mime)) return; // worker owns this loop (PDF vision)\n\t\t\t// When windowed indexing is on, the WORKER drives the text/grid loop too. The\n\t\t\t// client MUST NOT also resume, or two drivers each enqueue a continuation per\n\t\t\t// pass and the chain FORKS - duplicate records, runaway passes. Same reason\n\t\t\t// PDFs early-return above. Gated on the flag so the old client-driven path is\n\t\t\t// untouched when windowing is off.\n\t\t\tif (windowedIndexingEnabled() && isWindowedReadFile(entry.filename, entry.mime)) return;\n\t\t\tif (isErrorResponseBody(response)) {\n\t\t\t\t// A failed pass is not \"incomplete\" — the client-driven chain is over.\n\t\t\t\tthis._flipRunRecord(entry, 'error', this._runErrorText(response));\n\t\t\t\tendOfClientChain(); return;\n\t\t\t}\n\t\t\tvar answer = (platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '';\n\t\t\tif (answer.indexOf(INDEXING_COMPLETE_MARKER) !== -1) {\n\t\t\t\t// Client-driven chain, and the model's reply carried the\n\t\t\t\t// completion token — the same signal the worker requires before\n\t\t\t\t// minting for its own chains. Deterministic here: this client\n\t\t\t\t// is the only dispatcher and it is deciding, right now, that no\n\t\t\t\t// further pass will run.\n\t\t\t\tthis._mintDoneMarker(entry);\n\t\t\t\tthis._flipRunRecord(entry, 'done');\n\t\t\t\tendOfClientChain(); return; // fully indexed\n\t\t\t}\n\t\t\tvar pass = (entry.resumePass || 0) + 1;\n\t\t\tif (pass > MAX_INDEXING_RESUME_PASSES) {\n\t\t\t\t// Gave up after the cap: the file is only partially indexed, and no\n\t\t\t\t// further pass will ever run. 'error' rather than 'done' — the badge\n\t\t\t\t// must not claim a file the chain abandoned.\n\t\t\t\tthis._flipRunRecord(entry, 'error', 'Stopped after ' + MAX_INDEXING_RESUME_PASSES + ' passes without finishing.');\n\t\t\t\tendOfClientChain(); return;\n\t\t\t}\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (!id || id.platform === 'none' || id.projectId !== entry.projectId) {\n\t\t\t\t// This client is the only driver of this chain and it just declined\n\t\t\t\t// to dispatch the next pass — the chain is over, as an ending, not a\n\t\t\t\t// pause: the queue entry is spliced on settle and nothing revisits\n\t\t\t\t// it. Close the record (it writes with entry.projectId, so it lands\n\t\t\t\t// after a project switch) or it lies 'working' for the stale window.\n\t\t\t\tthis._flipRunRecord(entry, 'error', 'Indexing stopped: the session or project changed before the file finished.');\n\t\t\t\tendOfClientChain();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Counted as live work from here, not from the ack: awaitIndexingDrained\n\t\t\t// asks the SERVER what is queued, and this pass is not queued until the\n\t\t\t// call below returns. Without it a chat can slip in between two passes.\n\t\t\tthis.trackIndexDispatch(notifyAgentContinueIndexing({\n\t\t\t\tplatform: id.platform as 'claude' | 'openai',\n\t\t\t\tmodel: id.model,\n\t\t\t\tservice: id.projectId,\n\t\t\t\t// Without this the resume pass rebuilds its system prompt from the RAW\n\t\t\t\t// regional id (requests.ts falls back to `service`), and the model copies\n\t\t\t\t// that id verbatim into project_id tool calls, which the MCP schema\n\t\t\t\t// pattern rejects - the whole continue pass saves nothing.\n\t\t\t\tpublicProjectId: id.publicProjectId,\n\t\t\t\towner: id.owner,\n\t\t\t\tuserId: id.userId || id.projectId,\n\t\t\t\tserviceName: id.serviceName,\n\t\t\t\tserviceDescription: id.serviceDescription,\n\t\t\t\tattachment: {\n\t\t\t\t\tname: entry.filename,\n\t\t\t\t\tstoragePath: entry.storagePath,\n\t\t\t\t\tmime: entry.mime,\n\t\t\t\t\tsize: entry.size,\n\t\t\t\t\turl: '',\n\t\t\t\t},\n\t\t\t}).then(function (ack: any) {\n\t\t\t\tif (ack && typeof ack.id === 'string') {\n\t\t\t\t\tself.bgTaskQueue.push({\n\t\t\t\t\t\tprojectId: id.projectId, platform: id.platform as 'claude' | 'openai', id: ack.id,\n\t\t\t\t\t\tfilename: entry.filename, storagePath: entry.storagePath,\n\t\t\t\t\t\tisReindex: entry.isReindex, mime: entry.mime, size: entry.size,\n\t\t\t\t\t\tstatus: ack.status === 'running' ? 'running' : 'pending',\n\t\t\t\t\t\tpoll: ack.poll, resumePass: pass,\n\t\t\t\t\t\t// Deliberately NOT stamped with entry.stageId. Only a batch's FIRST\n\t\t\t\t\t\t// pass anchors to the turn; a continuation appends, which is the\n\t\t\t\t\t\t// order the server queued it in and therefore the order\n\t\t\t\t\t\t// promoteNextBgQueuedToRunning should spin it in. It costs nothing\n\t\t\t\t\t\t// on screen: a continuation is folded into the run whose row\n\t\t\t\t\t\t// already sits above the turn, and renders nothing at its own\n\t\t\t\t\t\t// index (indexing_groups anchors a run at its FIRST loaded pass).\n\t\t\t\t\t});\n\t\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\t}\n\t\t\t}, function (e: any) { console.error('[chat-engine] resume-indexing dispatch failed', e); }));\n\t\t} catch (e) { /* best-effort: resume must never break bg-task resolution */ }\n\t}\n\n\t// --- history fetch + pagination --------------------------------------\n\t// Initial load (fetchMore=false) replaces the list (with in-flight rescue +\n\t// cancelled-merge) and attaches polls to running/pending items; pagination\n\t// (fetchMore=true) prepends older messages. The DOM scroll-restore for the\n\t// older-prepend is the VIEW's job (it captures the pre-prepend scroll position\n\t// and restores after this resolves) — the engine never measures the DOM.\n\tloadHistory(fetchMore?: boolean, token?: number): Promise<void> {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\t// Key this fetch is FOR, snapshotted from the same identity read the\n\t\t// request is built from. The rescue below compares against this rather\n\t\t// than a live getHistoryCacheKey(), so a project switch mid-fetch can't\n\t\t// make another chat's in-flight bubbles look local.\n\t\tvar loadKey = (!id.projectId || id.platform === 'none') ? '' : id.projectId + '#' + id.platform;\n\t\tif (token === undefined) token = this.state.gateRefreshToken;\n\t\tif ((this.state.loadingHistory && this.state.historyRequestToken === token) || id.platform === 'none' || !id.projectId) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tthis.state.historyRequestToken = token;\n\t\tthis.state.loadingHistory = true;\n\t\t// A first-page load is the one moment the chat may have changed under us. The\n\t\t// old snapshot describes the previous project's queue; keeping it would let a\n\t\t// row here claim it was finished on evidence from somewhere else. Re-seeded\n\t\t// when this load lands.\n\t\tif (!fetchMore && loadKey !== this._liveIndexKey) {\n\t\t\tthis._liveIndexKey = loadKey;\n\t\t\tthis._resetLiveIndexKeys();\n\t\t}\n\t\tif (fetchMore) this.state.loadingOlderHistory = true;\n\t\tthis.host.notify(); // surface \"Fetching history...\" while it loads\n\t\tvar platform = id.platform as 'claude' | 'openai';\n\t\tvar projectId = id.projectId, owner = id.owner;\n\t\tvar options: any = { fetchMore: fetchMore };\n\t\tif (fetchMore && this.state.historyStartKeyHistory.length) options.startKeyHistory = this.state.historyStartKeyHistory.slice();\n\t\t// First page: paint the CONVERSATION immediately and let the indexing\n\t\t// stubs arrive as a deferred batch (merged below when it lands).\n\t\tif (!fetchMore) options.deferBg = true;\n\n\t\t// Split fetch v2: surface (full bodies, bg queue excluded) + bg compact\n\t\t// stubs, tiled to the surface page's time window with module-level\n\t\t// state (buffering + retry safety) — see getSplitChatHistory. Returns\n\t\t// the exact single-fetch shape; startKeyHistory is bookkeeping only.\n\t\tvar fetchHistory = function () { return getSplitChatHistory({ service: projectId, owner: owner, platform: platform, userId: id.userId }, options); };\n\n\t\treturn Promise.resolve().then(fetchHistory).catch(function (err: any) {\n\t\t\tif (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);\n\t\t\tthrow err;\n\t\t}).then(function (history: any) {\n\t\t\tif (token !== self.state.gateRefreshToken) return;\n\t\t\tvar chatList = history && Array.isArray(history.list) ? history.list : [];\n\t\t\tchatList.forEach(function (item: any) {\n\t\t\t\tif (isBgIndexingQueue(item.queue_name)) {\n\t\t\t\t\t// Compact stubs carry the label as request_text — the body\n\t\t\t\t\t// never left the server — so classify from whichever form\n\t\t\t\t\t// this item arrived in.\n\t\t\t\t\tvar clsText = item.compact ? item.request_text : extractLastUserTextFromRequest(item.request_body);\n\t\t\t\t\tif (isIndexingRequestText(clsText)) item._isBgTask = true;\n\t\t\t\t\telse item._isOnBgQueue = true;\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar list = chatList.sort(function (a: any, b: any) {\n\t\t\t\tvar ai = typeof a.id === 'string' ? a.id : '', bi = typeof b.id === 'string' ? b.id : '';\n\t\t\t\treturn ai > bi ? -1 : (ai < bi ? 1 : 0);\n\t\t\t});\n\t\t\tvar mapped = mapHistoryListToMessages(list, platform, {\n\t\t\t\tclearedAt: self.host.getClearedAt(),\n\t\t\t\tprojectId: id.projectId,\n\t\t\t\tformatIndexingLabel: self.host.formatIndexingLabel,\n\t\t\t}).messages;\n\t\t\t// Re-apply any previously-hydrated compact bodies: a refresh maps\n\t\t\t// fresh stubs, and without this a bubble the user already expanded\n\t\t\t// would silently revert to its 200-char head.\n\t\t\tself.applyHydratedBodies(mapped);\n\n\t\t\t// Set when a first-page refresh re-prepended already-loaded older pages,\n\t\t\t// so the cursor reset below knows not to rewind to page 1's boundary.\n\t\t\tvar keptOlderPages = false;\n\t\t\t// The empty-page-1 keep below was taken ONLY on the strength of a\n\t\t\t// deferred batch still flying — if that batch then proves the chat\n\t\t\t// empty server-side, the kept screen must be let go (see the batch\n\t\t\t// handler), or an emptied transcript is indelible.\n\t\t\tvar keptScreenAwaitingBg = false;\n\n\t\t\tif (fetchMore) {\n\t\t\t\t// STRIP-THEN-MERGE keyed on SERVER ITEM ID. Incoming bubbles are\n\t\t\t\t// the fresher server state (queued→running→settled transitions),\n\t\t\t\t// so existing copies of incoming id|role bubbles are REMOVED first\n\t\t\t\t// (in-flight cancel flags carried over), then the page merges by\n\t\t\t\t// item id — ids are creation-ordered and BOTH lists are already\n\t\t\t\t// id-sorted, unlike _ts (assistant _ts is `updated`, which any\n\t\t\t\t// long-running turn makes non-monotonic and would misorder the\n\t\t\t\t// walk). Id-less bubbles on screen (staged/local, always the tail)\n\t\t\t\t// end the merge region; id-less incoming sorts first (oldest).\n\t\t\t\tvar incomingKeys: any = {};\n\t\t\t\tmapped.forEach(function (m: any) { if (m._serverItemId) incomingKeys[m._serverItemId + '|' + m.role] = m; });\n\t\t\t\tvar existing = self.state.messages.filter(function (m: any) {\n\t\t\t\t\tif (!m._serverItemId) return true;\n\t\t\t\t\tvar inc = incomingKeys[m._serverItemId + '|' + m.role];\n\t\t\t\t\tif (!inc) return true;\n\t\t\t\t\tif (m._cancelling) inc._cancelling = m._cancelling;\n\t\t\t\t\tif (m._cancelError) inc._cancelError = m._cancelError;\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t\tvar mergedList: ChatMessage[] = [];\n\t\t\t\tvar pi = 0, ei = 0;\n\t\t\t\twhile (pi < mapped.length && ei < existing.length) {\n\t\t\t\t\tvar pm: any = mapped[pi], em: any = existing[ei];\n\t\t\t\t\tvar eid = em._serverItemId;\n\t\t\t\t\tif (typeof eid !== 'string') break; // staged/local tail\n\t\t\t\t\tvar pid = pm._serverItemId;\n\t\t\t\t\tif (typeof pid !== 'string' || pid <= eid) { mergedList.push(pm); pi++; }\n\t\t\t\t\telse { mergedList.push(em); ei++; }\n\t\t\t\t}\n\t\t\t\twhile (pi < mapped.length) mergedList.push(mapped[pi++]);\n\t\t\t\twhile (ei < existing.length) mergedList.push(existing[ei++]);\n\t\t\t\tself.state.messages = mergedList;\n\t\t\t} else if (!mapped.length && history && (history.endOfList === false || (history as any).bgPending)\n\t\t\t\t&& self.state.messages.some(function (m: any) { return m._ownerKey === undefined || m._ownerKey === loadKey; })) {\n\t\t\t\t// Empty first page that cannot judge the chat empty: either\n\t\t\t\t// empty-but-not-end (a pure-bg band past every hop cap), or an\n\t\t\t\t// empty DEFERRED page whose bg batch is still flying — a chat\n\t\t\t\t// whose whole conversation rides the bg queue has a genuinely\n\t\t\t\t// empty surface (endOfList true on a head refresh), and the\n\t\t\t\t// batch carries everything. REPLACING with it would blank the\n\t\t\t\t// chat for the batch's flight time — the greeting flashed over\n\t\t\t\t// real messages on every tab return. Keep what is on screen.\n\t\t\t\t// Kept ONLY on the batch's word: the batch handler revisits.\n\t\t\t\tif (history.endOfList !== false) keptScreenAwaitingBg = true;\n\t\t\t} else {\n\t\t\t\tif (self.state.typing) self.state.typingAbort = true;\n\t\t\t\tvar serverIds: any = {};\n\t\t\t\tmapped.forEach(function (m: any) { if (m._serverItemId) serverIds[m._serverItemId] = 1; });\n\t\t\t\t// The retention boundary must be the SURFACE frontier: page 1 also\n\t\t\t\t// emits bg stubs reaching arbitrarily deep, and keying retention on\n\t\t\t\t// a weeks-old stub id would wipe (or gap) the scrolled-in pages.\n\t\t\t\tvar surfaceOldestId: string | undefined = undefined;\n\t\t\t\tmapped.forEach(function (m: any) {\n\t\t\t\t\tif (typeof m._serverItemId !== 'string' || m._fromBgChain) return;\n\t\t\t\t\tif (surfaceOldestId === undefined || m._serverItemId < surfaceOldestId) surfaceOldestId = m._serverItemId;\n\t\t\t\t});\n\t\t\t\tvar locallyCancelled: any = {};\n\t\t\t\tself.state.messages.forEach(function (m) { if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = m; });\n\t\t\t\t// A cancel the server has not acknowledged yet. Without carrying these\n\t\t\t\t// across the replace, a collapsed row mid-cancel drops its \"Stopping...\"\n\t\t\t\t// state and re-offers Stop; the second click cancels an id that is\n\t\t\t\t// already gone and writes a bogus \"Could not remove from queue.\" onto a\n\t\t\t\t// run that WAS stopped successfully.\n\t\t\t\tvar inFlightCancel: any = {};\n\t\t\t\tself.state.messages.forEach(function (m) {\n\t\t\t\t\tif (!m._serverItemId) return;\n\t\t\t\t\tif (m._cancelling || m._cancelError) inFlightCancel[m._serverItemId] = m;\n\t\t\t\t});\n\t\t\t\t// If the freshly-mapped server list ALREADY shows this in-flight turn\n\t\t\t\t// as a pending placeholder (a non-bg pending assistant, which carries\n\t\t\t\t// a real _serverItemId), re-pushing the local no-_serverItemId\n\t\t\t\t// user+Thinking would DUPLICATE it. Each resolve path only clears the\n\t\t\t\t// first pending bubble, so the duplicate strands a \"Thinking…\" beside\n\t\t\t\t// the reply/error. There is at most one in-flight regular turn, so a\n\t\t\t\t// mapped pending assistant IS this turn — skip the redundant local copy.\n\t\t\t\tvar mappedHasPendingAssistant = mapped.some(function (m: any) {\n\t\t\t\t\treturn m.isPending && m.role === 'assistant' && !m.isBackgroundTask;\n\t\t\t\t});\n\t\t\t\t// One rule, shared with agent.vue's own fetchHistoryPage — see\n\t\t\t\t// shouldRescueInFlightMessage for what it decides and why.\n\t\t\t\tvar rescued: ChatMessage[] = [];\n\t\t\t\tfor (var ri = 0; ri < self.state.messages.length; ri++) {\n\t\t\t\t\tvar mm = self.state.messages[ri];\n\t\t\t\t\tif (shouldRescueInFlightMessage(mm, {\n\t\t\t\t\t\thasServerId: function (sid) { return !!serverIds[sid]; },\n\t\t\t\t\t\tpageHasPendingAssistant: mappedHasPendingAssistant,\n\t\t\t\t\t\tsending: !!self.state.sending,\n\t\t\t\t\t\tnext: self.state.messages[ri + 1],\n\t\t\t\t\t\tloadKey: loadKey,\n\t\t\t\t\t})) rescued.push(mm);\n\t\t\t\t}\n\t\t\t\t// PRESERVE already-loaded older pages. `mapped` is only page 1, so a\n\t\t\t\t// blind replace threw away every page the user had scrolled in. This\n\t\t\t\t// path runs from resumePolling (visibilitychange), so merely leaving\n\t\t\t\t// the tab and coming back wiped the whole scrolled-in history.\n\t\t\t\t//\n\t\t\t\t// The list is oldest-first (fetchMore PREPENDS), and ids sort with\n\t\t\t\t// newest largest, so anything already in the list whose _serverItemId\n\t\t\t\t// sorts BELOW page 1's oldest id is an older page. Those are disjoint\n\t\t\t\t// from `mapped` (strict <), so re-prepending cannot duplicate.\n\t\t\t\tvar oldestInPage1: string | undefined = undefined;\n\t\t\t\tmapped.forEach(function (m: any) {\n\t\t\t\t\tvar sid = m._serverItemId;\n\t\t\t\t\tif (typeof sid !== 'string') return;\n\t\t\t\t\tif (oldestInPage1 === undefined || sid < (oldestInPage1 as string)) oldestInPage1 = sid;\n\t\t\t\t});\n\t\t\t\t// Only merge when the current list is genuinely a continuation of THIS\n\t\t\t\t// page 1 (shares at least one id with it). A project switch, a cleared\n\t\t\t\t// horizon, or a wholly-new page means the head is unrelated history and\n\t\t\t\t// must be replaced, not spliced.\n\t\t\t\tvar sharesPage1 = self.state.messages.some(function (m) {\n\t\t\t\t\treturn typeof m._serverItemId === 'string' && !!serverIds[m._serverItemId as string];\n\t\t\t\t});\n\t\t\t\tvar deferredBg = !!(history && (history as any).bgPending);\n\t\t\t\t// Boundary for retention: the SURFACE frontier when page 1 has any\n\t\t\t\t// surface item (bg stubs can reach weeks deeper and would otherwise\n\t\t\t\t// wipe or gap the scrolled-in pages); whole-page oldest only as the\n\t\t\t\t// fallback for a surface-empty page.\n\t\t\t\tvar retainBoundary: string | undefined = surfaceOldestId !== undefined ? surfaceOldestId : oldestInPage1;\n\t\t\t\tvar retainedOlder: ChatMessage[] = (!sharesPage1 || retainBoundary === undefined) ? [] : self.state.messages.filter(function (m) {\n\t\t\t\t\t// Settled server history only; in-flight bubbles are the rescue\n\t\t\t\t\t// loop's job below and would otherwise be kept twice.\n\t\t\t\t\tif (typeof m._serverItemId !== 'string') return false;\n\t\t\t\t\t// Same ownership predicate as the rescue loop: never carry another\n\t\t\t\t\t// project's bubbles onto this chat (the cross-project leak fix).\n\t\t\t\t\t// Compare against the snapshotted loadKey, never a live read.\n\t\t\t\t\tif (m._ownerKey !== undefined && m._ownerKey !== loadKey) return false;\n\t\t\t\t\t// While a deferred stub batch is in flight, KEEP already-loaded\n\t\t\t\t\t// indexing bubbles wherever they sit — the surface-only page has\n\t\t\t\t\t// none, and dropping them here would flicker every row until the\n\t\t\t\t\t// batch lands (its apply strips+re-merges them by id anyway).\n\t\t\t\t\tif (deferredBg && m.isBackgroundTask) return true;\n\t\t\t\t\t// Bg-chain bubbles already on screen stay put regardless of the\n\t\t\t\t\t// boundary — their ids interleave with deep history and the strip\n\t\t\t\t\t// in later merges replaces them when fresher copies arrive.\n\t\t\t\t\tif (m._fromBgChain) return true;\n\t\t\t\t\treturn (m._serverItemId as string) < (retainBoundary as string);\n\t\t\t\t});\n\t\t\t\t// Prepend only the STRICTLY-older bubbles. Retained bg bubbles whose\n\t\t\t\t// ids sit inside page 1's own range are ID-MERGED into it instead —\n\t\t\t\t// blanket prepending hoisted every indexing row above the whole\n\t\t\t\t// conversation, and after a head refresh the single-page batch\n\t\t\t\t// never re-placed the deep ones, so they sat hoisted for good.\n\t\t\t\tvar prependOlder: ChatMessage[] = [];\n\t\t\t\tvar interleave: ChatMessage[] = [];\n\t\t\t\tretainedOlder.forEach(function (m) {\n\t\t\t\t\tvar sid = m._serverItemId as string;\n\t\t\t\t\tif (serverIds[sid]) return; // page 1 carries a fresher copy\n\t\t\t\t\tif (retainBoundary !== undefined && sid < (retainBoundary as string)) prependOlder.push(m);\n\t\t\t\t\telse interleave.push(m);\n\t\t\t\t});\n\t\t\t\tvar page1: ChatMessage[] = mapped;\n\t\t\t\tif (interleave.length) {\n\t\t\t\t\t// Both sides are id-sorted oldest-first (retention preserves the\n\t\t\t\t\t// on-screen order; the mapper emits oldest-first).\n\t\t\t\t\tvar mergedP: ChatMessage[] = [];\n\t\t\t\t\tvar ii2 = 0, mi2 = 0;\n\t\t\t\t\twhile (ii2 < interleave.length && mi2 < mapped.length) {\n\t\t\t\t\t\tvar iv: any = interleave[ii2], mv: any = mapped[mi2];\n\t\t\t\t\t\tvar mid2 = typeof mv._serverItemId === 'string' ? mv._serverItemId : undefined;\n\t\t\t\t\t\tif (mid2 === undefined) break; // defensive: id-less tail\n\t\t\t\t\t\tif ((iv._serverItemId as string) <= mid2) { mergedP.push(iv); ii2++; }\n\t\t\t\t\t\telse { mergedP.push(mv); mi2++; }\n\t\t\t\t\t}\n\t\t\t\t\twhile (ii2 < interleave.length) mergedP.push(interleave[ii2++]);\n\t\t\t\t\twhile (mi2 < mapped.length) mergedP.push(mapped[mi2++]);\n\t\t\t\t\tpage1 = mergedP;\n\t\t\t\t}\n\t\t\t\tkeptOlderPages = prependOlder.length > 0 || interleave.length > 0;\n\t\t\t\tself.state.messages = prependOlder.length ? prependOlder.concat(page1) : page1;\n\t\t\t\trescued.forEach(function (m) {\n\t\t\t\t\t// Rescue can now carry a bubble that has a server id, and the\n\t\t\t\t\t// retained-older merge above carries ids too. One turn must not\n\t\t\t\t\t// arrive down both routes.\n\t\t\t\t\tif (m._serverItemId && self.state.messages.some(function (x) {\n\t\t\t\t\t\treturn x._serverItemId === m._serverItemId && x.role === m.role;\n\t\t\t\t\t})) return;\n\t\t\t\t\tself.state.messages.push(m);\n\t\t\t\t});\n\t\t\t\tif (Object.keys(locallyCancelled).length) {\n\t\t\t\t\tfor (var ci = 0; ci < self.state.messages.length; ci++) {\n\t\t\t\t\t\tvar c = self.state.messages[ci];\n\t\t\t\t\t\tif (!c._serverItemId || !locallyCancelled[c._serverItemId] || c.isCancelled) continue;\n\t\t\t\t\t\t// Rebuild FROM the mapped bubble rather than as a bare literal:\n\t\t\t\t\t\t// dropping isBackgroundTask / _indexFile here ejected a stopped\n\t\t\t\t\t\t// indexing pass from its file's collapsed row, where it then rendered\n\t\t\t\t\t\t// as a standalone \"Indexing: <file>\" chat bubble and left the row\n\t\t\t\t\t\t// recomputing its passes as if that one had never happened.\n\t\t\t\t\t\tself.state.messages[ci] = {\n\t\t\t\t\t\t\trole: 'user', content: c.content, isCancelled: true, _serverItemId: c._serverItemId,\n\t\t\t\t\t\t\tisBackgroundTask: c.isBackgroundTask, _indexFile: c._indexFile,\n\t\t\t\t\t\t\t_useBgQueue: c._useBgQueue, _ownerKey: c._ownerKey,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (ci + 1 < self.state.messages.length && self.state.messages[ci + 1].isPending && self.state.messages[ci + 1]._serverItemId === c._serverItemId) {\n\t\t\t\t\t\t\tself.state.messages.splice(ci + 1, 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Re-stamp a cancel that is still in flight (see inFlightCancel above).\n\t\t\t\t// Only onto a bubble the server still reports as pending — once it has\n\t\t\t\t// settled the flags describe nothing the user can act on.\n\t\t\t\tfor (var fi = 0; fi < self.state.messages.length; fi++) {\n\t\t\t\t\tvar fm = self.state.messages[fi];\n\t\t\t\t\tvar was = fm._serverItemId && inFlightCancel[fm._serverItemId];\n\t\t\t\t\tif (!was || fm.isCancelled) continue;\n\t\t\t\t\tif (!(fm.isPendingQueued || fm.isPendingInProcess || fm.isPending)) continue;\n\t\t\t\t\tif (was._cancelling) fm._cancelling = true;\n\t\t\t\t\tif (was._cancelError) fm._cancelError = was._cancelError;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Only adopt page 1's cursor when page 1 IS the whole list. If older pages\n\t\t\t// survived the merge, rewinding here would make the next scroll-up\n\t\t\t// re-fetch page 2 (already on screen) and duplicate it.\n\t\t\tif (!keptOlderPages) {\n\t\t\t\tself.state.historyEndOfList = !!(history && history.endOfList);\n\t\t\t\tself.state.historyStartKeyHistory = history && Array.isArray(history.startKeyHistory) ? history.startKeyHistory : [];\n\t\t\t\tvar clearedAt = self.host.getClearedAt();\n\t\t\t\tif (clearedAt) {\n\t\t\t\t\t// SURFACE items only: page 1 also carries bg stubs reaching far\n\t\t\t\t\t// past the horizon, and reading their age as \"the frontier is\n\t\t\t\t\t// pre-horizon\" falsely ended the pager with post-horizon surface\n\t\t\t\t\t// pages still unfetched.\n\t\t\t\t\tvar surfaceItems = chatList.filter(function (it: any) { return !(it && it._fromBgChain); });\n\t\t\t\t\tif (surfaceItems.length > 0) {\n\t\t\t\t\t\tvar oldestUpdated = Number(surfaceItems[surfaceItems.length - 1] && surfaceItems[surfaceItems.length - 1].updated);\n\t\t\t\t\t\tif (isFinite(oldestUpdated) && oldestUpdated <= clearedAt) self.state.historyEndOfList = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Clear loading flags BEFORE this render so the final paint is\n\t\t\t// indicator-free (and the view's scroll-restore math sees matching heights).\n\t\t\tif (self.state.historyRequestToken === token) { self.state.loadingHistory = false; self.state.loadingOlderHistory = false; }\n\t\t\tself.updateHistoryCache();\n\t\t\tself.host.notify();\n\n\t\t\t// ── deferred indexing-stub batch (first-paint split) ──────────────\n\t\t\t// The conversation is already on screen; when the stub batch lands it\n\t\t\t// is classified/mapped like any page and STRIP-THEN-MERGED: existing\n\t\t\t// copies of incoming ids are removed first (retained rows may sit at\n\t\t\t// provisional positions), then the batch merges by timestamp.\n\t\t\tvar bgPending = !fetchMore && history && (history as any).bgPending;\n\t\t\tif (bgPending) {\n\t\t\t\t// Ownership id for the shared loading flag: a same-token refetch can\n\t\t\t\t// mint a SECOND bgPending, and the older handler settling later must\n\t\t\t\t// not clear (or keep) the flag the newer batch owns.\n\t\t\t\tvar batchId = ++_bgHistoryBatchSeq;\n\t\t\t\t// SILENT unless this is the chat's genuine FIRST PAINT. Two quiet\n\t\t\t\t// cases: an ended chain's head refresh (endOfList already true),\n\t\t\t\t// and a MID-WALK tab return — the walk restarts for cursor\n\t\t\t\t// safety, but the conversation is already on screen and flashing\n\t\t\t\t// \"Loading indexing history\" over it on every return was the\n\t\t\t\t// reported bug. Only a never-walked chat announces the batch.\n\t\t\t\tif (history.endOfList !== true && (history as any).firstLoad === true) {\n\t\t\t\t\tself.state.bgHistoryLoading = true;\n\t\t\t\t\tself.host.notify();\n\t\t\t\t}\n\t\t\t\tvar releaseBgFlag = function () {\n\t\t\t\t\tif (_bgHistoryBatchSeq === batchId) self.state.bgHistoryLoading = false;\n\t\t\t\t};\n\t\t\t\t(bgPending as Promise<any>).then(function (batch: any) {\n\t\t\t\t\tif (token !== self.state.gateRefreshToken) { releaseBgFlag(); return; }\n\t\t\t\t\tvar bList: any[] = (batch && Array.isArray(batch.list)) ? batch.list : [];\n\t\t\t\t\tbList.forEach(function (item: any) {\n\t\t\t\t\t\tif (isBgIndexingQueue(item.queue_name)) {\n\t\t\t\t\t\t\tvar t = item.compact ? item.request_text : extractLastUserTextFromRequest(item.request_body);\n\t\t\t\t\t\t\tif (isIndexingRequestText(t)) item._isBgTask = true;\n\t\t\t\t\t\t\telse item._isOnBgQueue = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tvar sorted = bList.sort(function (a: any, b: any) {\n\t\t\t\t\t\tvar ai = typeof a.id === 'string' ? a.id : '', bi = typeof b.id === 'string' ? b.id : '';\n\t\t\t\t\t\treturn ai > bi ? -1 : (ai < bi ? 1 : 0);\n\t\t\t\t\t});\n\t\t\t\t\tvar m2 = mapHistoryListToMessages(sorted, platform, {\n\t\t\t\t\t\tclearedAt: self.host.getClearedAt(),\n\t\t\t\t\t\tprojectId: id.projectId,\n\t\t\t\t\t\tformatIndexingLabel: self.host.formatIndexingLabel,\n\t\t\t\t\t}).messages;\n\t\t\t\t\tself.applyHydratedBodies(m2);\n\t\t\t\t\tif (keptScreenAwaitingBg && !m2.length && batch && batch.endOfList === true) {\n\t\t\t\t\t\t// The empty page 1 was kept ONLY on this batch's word — and it\n\t\t\t\t\t\t// just proved the chat empty server-side (an emptied/cleared\n\t\t\t\t\t\t// transcript). Let the kept screen go: drop this chat's settled\n\t\t\t\t\t\t// server bubbles, keep staged and in-flight local work and any\n\t\t\t\t\t\t// other chat's strays for their own reconcilers, and remember\n\t\t\t\t\t\t// the end. Without this the stale transcript was indelible and\n\t\t\t\t\t\t// even re-persisted itself into the history cache.\n\t\t\t\t\t\tself.state.messages = self.state.messages.filter(function (m: any) {\n\t\t\t\t\t\t\tif (typeof m._serverItemId !== 'string') return true;\n\t\t\t\t\t\t\tif (m._ownerKey !== undefined && m._ownerKey !== loadKey) return true;\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t});\n\t\t\t\t\t\tself.state.historyEndOfList = true;\n\t\t\t\t\t\treleaseBgFlag();\n\t\t\t\t\t\tself.updateHistoryCache();\n\t\t\t\t\t\tself.host.notify();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tvar incoming: any = {};\n\t\t\t\t\tm2.forEach(function (m: any) { if (m._serverItemId) incoming[m._serverItemId + '|' + m.role] = true; });\n\t\t\t\t\tvar baseList = self.state.messages.filter(function (m: any) { return !(m._serverItemId && incoming[m._serverItemId + '|' + m.role]); });\n\t\t\t\t\tvar mergedList: ChatMessage[] = [];\n\t\t\t\t\tvar pi2 = 0, ei2 = 0;\n\t\t\t\t\twhile (pi2 < m2.length && ei2 < baseList.length) {\n\t\t\t\t\t\tvar pm2: any = m2[pi2], em2: any = baseList[ei2];\n\t\t\t\t\t\tvar eid2 = em2._serverItemId;\n\t\t\t\t\t\tif (typeof eid2 !== 'string') break; // staged/local tail\n\t\t\t\t\t\tvar pid2 = pm2._serverItemId;\n\t\t\t\t\t\tif (typeof pid2 !== 'string' || pid2 <= eid2) { mergedList.push(pm2); pi2++; }\n\t\t\t\t\t\telse { mergedList.push(em2); ei2++; }\n\t\t\t\t\t}\n\t\t\t\t\twhile (pi2 < m2.length) mergedList.push(m2[pi2++]);\n\t\t\t\t\twhile (ei2 < baseList.length) mergedList.push(baseList[ei2++]);\n\t\t\t\t\tself.state.messages = mergedList;\n\t\t\t\t\tif (batch && batch.endOfList === true) self.state.historyEndOfList = true;\n\t\t\t\t\treleaseBgFlag();\n\t\t\t\t\tself.updateHistoryCache();\n\t\t\t\t\tself.host.notify();\n\t\t\t\t\t// The other half of the refresh. Everything this batch brought in\n\t\t\t\t\t// sits ABOVE or AMONG the newest turn, so a reader pinned to the\n\t\t\t\t\t// bottom was left stranded above it by exactly the batch's height,\n\t\t\t\t\t// with nothing to put them back (every scroll-anchor method no-ops\n\t\t\t\t\t// while pinned, and this handler ended here).\n\t\t\t\t\tif (self.host.settleScroll) self.host.settleScroll();\n\t\t\t\t}, function () {\n\t\t\t\t\t// Stubs missing until the next refresh re-asks; never fatal.\n\t\t\t\t\treleaseBgFlag();\n\t\t\t\t\tself.host.notify();\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!fetchMore) {\n\t\t\t\t// Ration BACKGROUND polls here exactly as the drain does (see\n\t\t\t\t// MAX_CONCURRENT_BG_POLLS); foreground items — a reply the user is\n\t\t\t\t// waiting on — are never rationed. The allow-set is taken from the\n\t\t\t\t// OLDEST bg items: ids sort with newest largest (the same ordering the\n\t\t\t\t// older-page merge above relies on) and the server settles a queue\n\t\t\t\t// FIFO, so the oldest are the only ones that can resolve next. Taking\n\t\t\t\t// the newest instead would wedge the batch — they cannot settle until\n\t\t\t\t// everything ahead of them has, and nothing ahead would hold a poll.\n\t\t\t\tvar bgAllow: { [id: string]: boolean } = {};\n\t\t\t\tvar bgHistBudget = MAX_CONCURRENT_BG_POLLS - self._countBgPolls();\n\t\t\t\tif (bgHistBudget > 0) {\n\t\t\t\t\tvar bgIds = chatList.filter(function (it: any) {\n\t\t\t\t\t\tif (it.status !== 'running' && it.status !== 'pending') return false;\n\t\t\t\t\t\tif (!it.poll || !it.id) return false;\n\t\t\t\t\t\tif (!(it._isBgTask || it._isOnBgQueue)) return false;\n\t\t\t\t\t\treturn !self.historyItemPolls.has(it.id);\n\t\t\t\t\t}).map(function (it: any) { return it.id as string; }).sort();\n\t\t\t\t\tfor (var ba = 0; ba < bgIds.length && ba < bgHistBudget; ba++) bgAllow[bgIds[ba]] = true;\n\t\t\t\t}\n\t\t\t\tchatList.forEach(function (item: any) {\n\t\t\t\t\tif (item.status !== 'running' && item.status !== 'pending') return;\n\t\t\t\t\tif (!item.poll || !item.id) return;\n\t\t\t\t\t// Every live poll registers its item id in historyItemPolls — an\n\t\t\t\t\t// immediate dispatch (dispatchAgentRequest ~123), a queued send\n\t\t\t\t\t// (~253), a bg task (drain), or an earlier history poll — so the\n\t\t\t\t\t// has() check below already skips exactly the items a live poll\n\t\t\t\t\t// covers (including the one the current dispatch is polling). Do NOT\n\t\t\t\t\t// additionally skip every OTHER running/pending item just because\n\t\t\t\t\t// some immediate dispatch is in flight: that dispatch polls only ITS\n\t\t\t\t\t// item, so blanket-skipping stranded a concurrent \"-bg\" indexing item\n\t\t\t\t\t// (a separate server queue runs in parallel) — or any item whose own\n\t\t\t\t\t// poll had since died — with no live poller, leaving a \"Thinking...\"\n\t\t\t\t\t// that never clears even after the server settled everything.\n\t\t\t\t\tif (self.historyItemPolls.has(item.id)) return;\n\t\t\t\t\t// An in-flight immediate dispatch polls its own MAIN-QUEUE item but\n\t\t\t\t\t// registers that id in historyItemPolls only AFTER its provider POST\n\t\t\t\t\t// returns; in the sliver before that, a remount can surface the item\n\t\t\t\t\t// here still unregistered. Skip re-polling MAIN-QUEUE items while a\n\t\t\t\t\t// dispatch is in flight so we don't stack a 2nd poll on the item the\n\t\t\t\t\t// dispatch is about to poll. Bg-queue items (_isBgTask indexing tasks\n\t\t\t\t\t// and _isOnBgQueue chats) run on a SEPARATE queue the immediate\n\t\t\t\t\t// dispatch never polls, so they MUST still get their poll — skipping\n\t\t\t\t\t// them was the stranded-\"Thinking\" bug this guard must not revive.\n\t\t\t\t\tif (self.pendingAgentRequests[self.getHistoryCacheKey()] && !item._isBgTask && !item._isOnBgQueue) return;\n\t\t\t\t\t// Background indexing polls are suppressed while paused; foreground\n\t\t\t\t\t// replies the user is waiting on are not.\n\t\t\t\t\tif ((item._isBgTask || item._isOnBgQueue) && self.isPollingPaused()) return;\n\t\t\t\t\t// Over the bg poll budget: leave this one unpolled. The drain picks\n\t\t\t\t\t// it up once an attached poll settles and frees a slot.\n\t\t\t\t\tif ((item._isBgTask || item._isOnBgQueue) && !bgAllow[item.id]) return;\n\t\t\t\t\tvar capturedId = item.id;\n\t\t\t\t\tvar isBg = !!(item._isBgTask || item._isOnBgQueue);\n\t\t\t\t\t// A foreground item here is a reply the user is still waiting on (a reload or a tab\n\t\t\t\t\t// return re-attaches it), so it gets the same early probe as a fresh send. Background\n\t\t\t\t\t// items keep the flat cadence: nobody is watching, and they are what the\n\t\t\t\t\t// MAX_CONCURRENT_BG_POLLS budget exists to protect.\n\t\t\t\t\tvar pollOpts = {\n\t\t\t\t\t\tonResponse: function (response: any) { if (isPollStopped(response)) return; self.handleHistoryItemResolution(capturedId, response, platform); },\n\t\t\t\t\t\tonError: function (err: any) {\n\t\t\t\t\t\t\tself.historyItemPolls.delete(capturedId);\n\t\t\t\t\t\t\tvar isNotExists = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\t\t\t\t\t\tvar aIdx = self.state.messages.findIndex(function (m) { return m.isPending && m._serverItemId === capturedId; });\n\t\t\t\t\t\t\tif (isNotExists) {\n\t\t\t\t\t\t\t\tvar uIdx = self.state.messages.findIndex(function (m) { return m.role === 'user' && m._serverItemId === capturedId && !m.isCancelled; });\n\t\t\t\t\t\t\t\t// Decide bg-ness from whichever bubble actually exists. A\n\t\t\t\t\t\t\t\t// QUEUED pass has no assistant placeholder (history.ts emits\n\t\t\t\t\t\t\t\t// none), so reading it off the placeholder alone classified\n\t\t\t\t\t\t\t\t// every queued indexing pass as foreground: the rebuild below\n\t\t\t\t\t\t\t\t// then dropped isBackgroundTask/_indexFile, ejecting the pass\n\t\t\t\t\t\t\t\t// from its collapsed row as a raw \"Indexing: <file>\" chat\n\t\t\t\t\t\t\t\t// bubble, and promoteNextQueuedToRunning span up a \"Thinking...\"\n\t\t\t\t\t\t\t\t// on an unrelated queued FOREGROUND message.\n\t\t\t\t\t\t\t\tvar isBg = (aIdx !== -1 && !!self.state.messages[aIdx].isBackgroundTask)\n\t\t\t\t\t\t\t\t\t|| (uIdx !== -1 && !!self.state.messages[uIdx].isBackgroundTask);\n\t\t\t\t\t\t\t\tif (aIdx !== -1) self.state.messages.splice(aIdx, 1);\n\t\t\t\t\t\t\t\tif (!isBg) {\n\t\t\t\t\t\t\t\t\tif (uIdx !== -1) { var ex = self.state.messages[uIdx]; self.state.messages[uIdx] = { role: 'user', content: ex.content, isCancelled: true, _serverItemId: ex._serverItemId }; }\n\t\t\t\t\t\t\t\t\tself.cancelledServerIds.delete(capturedId); self.promoteNextQueuedToRunning();\n\t\t\t\t\t\t\t\t} else if (uIdx !== -1) {\n\t\t\t\t\t\t\t\t\t// Same carry-over every other rebuild does, so the pass stays\n\t\t\t\t\t\t\t\t\t// a member of its file's row while reading as cancelled.\n\t\t\t\t\t\t\t\t\tvar bex = self.state.messages[uIdx];\n\t\t\t\t\t\t\t\t\tvar bcancelled: ChatMessage = { role: 'user', content: bex.content, isCancelled: true, isBackgroundTask: true, _serverItemId: bex._serverItemId };\n\t\t\t\t\t\t\t\t\tif (bex._indexFile) bcancelled._indexFile = bex._indexFile;\n\t\t\t\t\t\t\t\t\tif (bex._useBgQueue) bcancelled._useBgQueue = true;\n\t\t\t\t\t\t\t\t\tself.state.messages[uIdx] = bcancelled;\n\t\t\t\t\t\t\t\t\tself.promoteNextBgQueuedToRunning();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tself.host.notify(); self.updateHistoryCache(); return;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (aIdx !== -1) {\n\t\t\t\t\t\t\t\tvar wasBg = self.state.messages[aIdx].isBackgroundTask;\n\t\t\t\t\t\t\t\tself.state.messages[aIdx] = { role: 'assistant', content: getErrorMessage(err), isError: true };\n\t\t\t\t\t\t\t\tif (wasBg) self.state.messages[aIdx].isBackgroundTask = true;\n\t\t\t\t\t\t\t\tself.host.notify(); self.updateHistoryCache();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tvar pp = isBg\n\t\t\t\t\t\t? item.poll(Object.assign({ latency: POLL_INTERVAL }, pollOpts))\n\t\t\t\t\t\t: self._fgPollWithEarlyProbe(item, capturedId, pollOpts);\n\t\t\t\t\t// Anything on the BACKGROUND queue is pausable, not just items whose\n\t\t\t\t\t// prompt text we recognise as an indexing task. _isBgTask vs\n\t\t\t\t\t// _isOnBgQueue is a DISPLAY distinction (\"Indexing: file\" vs a normal\n\t\t\t\t\t// chat bubble); keying the pause off _isBgTask alone left every\n\t\t\t\t\t// bg-queue item we could not text-match polling forever.\n\t\t\t\t\tself._trackPoll(capturedId, (item._isBgTask || item._isOnBgQueue) ? 'bg' : 'fg', pp);\n\t\t\t\t\tif (pp && pp.catch) pp.catch(function () { });\n\t\t\t\t});\n\t\t\t\tself.drainBgTaskQueue();\n\t\t\t}\n\n\t\t\t// Learn which files the queue is still working on. Only on a FIRST page:\n\t\t\t// this describes the whole queue, not the page, so paging older history\n\t\t\t// would re-ask for an answer that has not changed.\n\t\t\tif (!fetchMore) self.refreshLiveIndexState();\n\n\t\t\t// Sticky, NOT forcing: this runs after every first-page load, including\n\t\t\t// the one resumePolling fires on visibilitychange. Forcing yanked a\n\t\t\t// reader who had scrolled up back to the bottom. On a genuine mount the\n\t\t\t// user is still pinned, so this behaves identically there.\n\t\t\t//\n\t\t\t// settleScroll when the host has one: it makes the same decision, and it\n\t\t\t// is also called again once the deferred bg batch merges, so a pinned\n\t\t\t// reader lands on the REAL bottom instead of the surface page's.\n\t\t\tif (!fetchMore) return self.host.settleScroll ? self.host.settleScroll() : self.host.scrollToBottomIfSticky();\n\t\t}).catch(function (err: any) {\n\t\t\tconsole.warn('[chat-engine] getChatHistory failed', err);\n\t\t}).then(function () {\n\t\t\tif (self.state.historyRequestToken === token) {\n\t\t\t\tvar wasLoading = self.state.loadingHistory || self.state.loadingOlderHistory;\n\t\t\t\tself.state.loadingHistory = false; self.state.loadingOlderHistory = false;\n\t\t\t\tif (wasLoading) self.host.notify();\n\t\t\t}\n\t\t\t// Every first-page load ends here — mount, resumePolling, a cache-restore\n\t\t\t// refresh — and every one of them can leave a box too short to scroll,\n\t\t\t// which is the only trigger there is for reaching page 2. The view (which\n\t\t\t// alone can measure) pages its way out of it. Fired after the flags are\n\t\t\t// cleared so the fill loop does not see a request still in flight.\n\t\t\tif (self.host.onHistoryLoaded) self.host.onHistoryLoaded(!!fetchMore, token as number);\n\t\t});\n\t}\n\n\t// --- attachment upload orchestration ---------------------------------\n\t// Upload one attachment (a file = 1 member, a folder = N) to db storage and\n\t// queue indexing per member. The bytes I/O + chip rendering go through host\n\t// hooks; the overwrite/reindex flow, status lifecycle, and indexing live here.\n\tuploadSingleAttachment(att: any, stageId?: string): Promise<Array<{ name: string; url: string; storagePath: string }>> {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\t// progress stays null until the first byte-progress event. Every upload\n\t\t// opens with a get-signed-url round trip that reports nothing, so a chip\n\t\t// initialised to 0 rendered an empty, motionless bar for the whole\n\t\t// preparing phase and read as hung. null is the signal for \"preparing\"\n\t\t// (barber pole); a number means bytes are actually moving (real bar).\n\t\tatt.status = 'uploading'; att.progress = null; att.errorMessage = '';\n\t\tatt.errorCode = ''; att.errorDetail = ''; // clear any prior failure (retry)\n\t\tthis.host.renderAttachmentChips();\n\t\tvar members = (att.kind === 'folder')\n\t\t\t? (att.files || []).map(function (f: any) { return { file: f.file, relPath: f.path, storagePath: self.host.storagePathFor(f.path) }; })\n\t\t\t: [{ file: att.file, relPath: att.name, storagePath: this.host.storagePathFor(att.name) }];\n\t\tvar total = members.length;\n\t\tif (!total) return Promise.reject(new Error('Empty attachment'));\n\t\tvar urls: Array<{ name: string; url: string; storagePath: string }> = [];\n\t\tvar anyIndexFailed = false;\n\t\tvar chain: Promise<any> = Promise.resolve();\n\t\tmembers.forEach(function (member: any, idx: number) {\n\t\t\tchain = chain.then(function () {\n\t\t\t\tvar hadExists = false;\n\t\t\t\tvar skipped = false;\n\t\t\t\t// True when the file already existed and we are re-indexing over it\n\t\t\t\t// (user chose Reindex, OR Overwrite replaced the bytes). Drives the\n\t\t\t\t// delete-then-repost of the stale \"src::\" record below. Kept separate\n\t\t\t\t// from hadExists, which must keep driving ONLY the Reindexing/Indexing\n\t\t\t\t// label (isReindex) — overwrite still labels as \"Indexing:\".\n\t\t\t\tvar existedBefore = false;\n\t\t\t\tvar onProg = function (p: any) {\n\t\t\t\t\tif (p && p.total) {\n\t\t\t\t\t\tatt.progress = Math.floor(((idx + p.loaded / p.total) / total) * 100);\n\t\t\t\t\t\tself.host.renderAttachmentChips();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tvar doMemberUpload = function (checkExistence: boolean) {\n\t\t\t\t\treturn self.host.uploadFile({\n\t\t\t\t\t\tfile: member.file, storagePath: member.storagePath, checkExistence: checkExistence,\n\t\t\t\t\t\tonProgress: onProg, setAbort: function (abort) { att._abort = abort; },\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t\treturn doMemberUpload(true).catch(function (err: any) {\n\t\t\t\t\tvar code = err && (err.code || (err.body && err.body.code));\n\t\t\t\t\tvar msg = err && (err.message || (err.body && err.body.message) || (typeof err === 'string' ? err : ''));\n\t\t\t\t\tvar isExists = code === 'EXISTS' || (msg && /exist/i.test(msg));\n\t\t\t\t\tif (!isExists) throw err; // a member upload failed → whole attachment fails (red)\n\t\t\t\t\treturn self.host.promptOverwrite(member.file.name).then(function (choice) {\n\t\t\t\t\t\tif (choice === 'overwrite') {\n\t\t\t\t\t\t\texistedBefore = true;\n\t\t\t\t\t\t\t// The bytes at this path are about to change while the\n\t\t\t\t\t\t\t// path itself does not, so the browser-cached mint for\n\t\t\t\t\t\t\t// it would keep handing back the old signed url and the\n\t\t\t\t\t\t\t// old cached body. This is the one place that knows,\n\t\t\t\t\t\t\t// so it marks the path for a refreshed mint.\n\t\t\t\t\t\t\tmarkImagePreviewStale(self.host.getIdentity().projectId || 'default', member.storagePath);\n\t\t\t\t\t\t\treturn doMemberUpload(false); // replace the existing file\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (choice === 'skip') { skipped = true; return; } // leave it untouched; no upload/index\n\t\t\t\t\t\thadExists = true; existedBefore = true; // keep it; Reindex\n\t\t\t\t\t});\n\t\t\t\t}).then(function () {\n\t\t\t\t\tif (skipped) return; // user skipped this member — no url, no index request\n\t\t\t\t\treturn self.host.getTemporaryUrl(member.storagePath);\n\t\t\t\t}).then(function (url: string) {\n\t\t\t\t\tif (skipped) return; // guard the indexing branch for a skipped member\n\t\t\t\t\turls.push({ name: member.relPath, url: url, storagePath: member.storagePath });\n\t\t\t\t\tif (att.kind !== 'folder') { att.uploadedUrl = url; att.storagePath = member.storagePath; }\n\t\t\t\t\tvar mime = member.file.type || self.host.getMimeType(member.file.name);\n\t\t\t\t\t// Delete-then-repost: when the file already existed (Reindex or\n\t\t\t\t\t// Overwrite), delete the stale \"src::<storagePath>\" index record\n\t\t\t\t\t// first — the skapi backend cascades the delete to its\n\t\t\t\t\t// reference-linked children — so re-indexing REPLACES rather than\n\t\t\t\t\t// colliding/duplicating. Awaited before the index request is\n\t\t\t\t\t// enqueued. Best-effort + optional-hook guarded: a missing record,\n\t\t\t\t\t// a permission error, or a host without the hook must not block\n\t\t\t\t\t// indexing.\n\t\t\t\t\t// Then CREATE the file record before any pass is enqueued. Ordering matters: the\n\t\t\t\t\t// delete above wipes it (and cascades to its rows), so creating first would just\n\t\t\t\t\t// delete what we made. Every pass references \"src::<path>\", and a pass is a\n\t\t\t\t\t// separate model turn that cannot know whether an earlier one created it, so\n\t\t\t\t\t// guaranteeing it here is what stops the backend rejecting whole windows with\n\t\t\t\t\t// NOT_EXISTS on reference.unique_id.\n\t\t\t\t\t// Already being indexed: a second run would open a second collapsed row\n\t\t\t\t\t// for the same file and re-read the whole document. Decided BEFORE the\n\t\t\t\t\t// delete-then-repost, which would otherwise wipe the records the LIVE\n\t\t\t\t\t// run has already written and then not re-index them. Asked of the\n\t\t\t\t\t// QUEUE, not just this page — see isIndexRunLive.\n\t\t\t\t\tvar alreadyIndexing = false;\n\t\t\t\t\tvar preIndex = self.claimIndexRun(member.storagePath).then(function (claimed) {\n\t\t\t\t\t\talreadyIndexing = !claimed;\n\t\t\t\t\t\tif (alreadyIndexing) {\n\t\t\t\t\t\t\tconsole.log('[chat-engine] skipping a duplicate index request for', member.storagePath);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (existedBefore && typeof self.host.deleteExistingFileRecord === 'function') {\n\t\t\t\t\t\t\treturn Promise.resolve(self.host.deleteExistingFileRecord(member.storagePath)).catch(function () { });\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tpreIndex = preIndex.then(function () {\n\t\t\t\t\t\tif (alreadyIndexing) return;\n\t\t\t\t\t\tif (typeof self.host.ensureFileIndexRecord !== 'function') return;\n\t\t\t\t\t\treturn Promise.resolve(self.host.ensureFileIndexRecord(member.storagePath, {\n\t\t\t\t\t\t\tname: member.file.name,\n\t\t\t\t\t\t\tmime: mime || undefined,\n\t\t\t\t\t\t\tsize: member.file.size,\n\t\t\t\t\t\t})).catch(function () { });\n\t\t\t\t\t});\n\t\t\t\t\t// Run a client-side attachment parser (e.g. .hwp) if one matches; its\n\t\t\t\t\t// output is inlined into the indexing request (falls back to office\n\t\t\t\t\t// extraction / web_fetch when no parser matches or it yields nothing).\n\t\t\t\t\treturn preIndex.then(function () {\n\t\t\t\t\t\treturn parseAttachmentContent(member.file, member.file.name, mime || undefined);\n\t\t\t\t\t}).then(function (parsedContent: string | null) {\n\t\t\t\t\tif (alreadyIndexing) return;\n\t\t\t\t\t// Tracked so a chat waiting on awaitIndexingDrained cannot be sent\n\t\t\t\t\t// in the window between this call and the queue accepting it.\n\t\t\t\t\treturn self.trackIndexDispatch(notifyAgentSaveAttachment({\n\t\t\t\t\t\tplatform: id.platform as 'claude' | 'openai',\n\t\t\t\t\t\tmodel: id.model,\n\t\t\t\t\t\tservice: id.projectId,\n\t\t\t\t\t\tpublicProjectId: id.publicProjectId,\n\t\t\t\t\t\towner: id.owner,\n\t\t\t\t\t\tuserId: id.userId || id.projectId,\n\t\t\t\t\t\tserviceName: id.serviceName,\n\t\t\t\t\t\tserviceDescription: id.serviceDescription,\n\t\t\t\t\t\tattachment: {\n\t\t\t\t\t\t\tname: member.file.name, storagePath: member.storagePath,\n\t\t\t\t\t\t\tmime: mime || undefined, size: member.file.size, url: url,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tparsedContent: parsedContent || undefined,\n\t\t\t\t\t}).then(function (ack: any) {\n\t\t\t\t\t\tif (ack && typeof ack.id === 'string') {\n\t\t\t\t\t\t\tself.bgTaskQueue.push({\n\t\t\t\t\t\t\t\tprojectId: id.projectId, platform: id.platform as 'claude' | 'openai', id: ack.id,\n\t\t\t\t\t\t\t\tfilename: member.file.name,\n\t\t\t\t\t\t\t\tstoragePath: member.storagePath,\n\t\t\t\t\t\t\t\tisReindex: hadExists,\n\t\t\t\t\t\t\t\tmime: mime || undefined,\n\t\t\t\t\t\t\t\tsize: member.file.size,\n\t\t\t\t\t\t\t\tstatus: ack.status === 'running' ? 'running' : 'pending',\n\t\t\t\t\t\t\t\tpoll: ack.poll,\n\t\t\t\t\t\t\t\t// Puts this file's row directly above the chat turn it was\n\t\t\t\t\t\t\t\t// attached to (drainBgTaskQueue). Undefined for an\n\t\t\t\t\t\t\t\t// attachment-only send, which appends.\n\t\t\t\t\t\t\t\tstageId: stageId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tself.drainBgTaskQueue(); // surface \"Indexing: <file>\" as soon as THIS file uploads\n\t\t\t\t\t\t}\n\t\t\t\t\t}, function (e: any) {\n\t\t\t\t\t\tconsole.error('[chat-engine] indexing request failed', e);\n\t\t\t\t\t\t// Nothing was queued, so hand the slot back: the retry (a later\n\t\t\t\t\t\t// send of the same chip) must not be refused by this client's own\n\t\t\t\t\t\t// claim. See claimIndexRun.\n\t\t\t\t\t\tself.releaseIndexRun(member.storagePath);\n\t\t\t\t\t\tanyIndexFailed = true; // uploaded but not indexed → yellow\n\t\t\t\t\t\t// Record the first index error's code/message for the report dialog.\n\t\t\t\t\t\tif (!att.errorCode && !att.errorDetail) {\n\t\t\t\t\t\t\tatt.errorCode = (e && (e.code || (e.body && e.body.code))) || '';\n\t\t\t\t\t\t\tatt.errorDetail = (e && (e.message || (e.body && e.body.message))) || (typeof e === 'string' ? e : '');\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t\treturn chain.then(function () {\n\t\t\tatt._abort = null; att.progress = 100;\n\t\t\tif (att.kind === 'folder') att.uploadedUrls = urls.map(function (u) { return { path: u.name, url: u.url, storagePath: u.storagePath }; });\n\t\t\tatt.status = anyIndexFailed ? 'indexError' : 'done';\n\t\t\tif (att.status === 'indexError') att.errorMessage = 'File indexing failed';\n\t\t\tself.host.renderAttachmentChips();\n\t\t\treturn urls;\n\t\t});\n\t}\n\n\t// Upload all not-yet-done attachments sequentially. Resolves to the full\n\t// list of { name, url, storagePath } for composing the chat message.\n\t//\n\t// `batchId` scopes the run to the chips stamped with it at Send time. The\n\t// composer stays live during an upload, so by the time this runs the\n\t// attachment list can already hold chips the user picked for the NEXT\n\t// message — uploading those here would attach them to the wrong turn, and\n\t// collecting the previous batch's finished urls would attach files the user\n\t// already sent. Omitted (no batch) means every chip, the old behavior.\n\t//\n\t// `stageId` is the turn these chips were attached to, carried onto every indexing\n\t// task so its collapsed row renders directly ABOVE that turn's bubble (see\n\t// BgTaskEntry.stageId). Omitted for an attachment-only send, which has no turn.\n\tuploadPendingAttachments(batchId?: string, stageId?: string): Promise<Array<{ name: string; url: string; storagePath?: string }>> {\n\t\tvar self = this;\n\t\tthis.host.resetOverwriteBatch();\n\t\tthis._uploadBatches += 1;\n\t\tthis.state.uploadingAttachments = true;\n\t\tthis.host.updateComposerControls();\n\t\tthis.host.renderAttachmentChips();\n\t\tvar collected: Array<{ name: string; url: string; storagePath?: string }> = [];\n\t\tvar snapshot = this.state.attachments.filter(function (a: any) {\n\t\t\treturn batchId ? a._batchId === batchId : true;\n\t\t});\n\t\tvar chain: Promise<any> = Promise.resolve();\n\t\tsnapshot.forEach(function (att: any) {\n\t\t\tchain = chain.then(function () {\n\t\t\t\tif (!self.state.attachments.some(function (a: any) { return a.id === att.id; })) return; // removed\n\t\t\t\tif (att.status === 'done' || att.status === 'indexError') {\n\t\t\t\t\tif (att.kind === 'folder' && att.uploadedUrls) {\n\t\t\t\t\t\tatt.uploadedUrls.forEach(function (u: any) { collected.push({ name: u.path, url: u.url, storagePath: u.storagePath }); });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (att.uploadedUrl) { collected.push({ name: att.name, url: att.uploadedUrl, storagePath: att.storagePath }); return; }\n\t\t\t\t}\n\t\t\t\treturn self.uploadSingleAttachment(att, stageId).then(function (us) {\n\t\t\t\t\tcollected.push.apply(collected, us);\n\t\t\t\t}).catch(function (err: any) {\n\t\t\t\t\tvar removed = !self.state.attachments.some(function (a: any) { return a.id === att.id; });\n\t\t\t\t\tvar aborted = err && (err.message === 'Aborted' || err === 'Aborted');\n\t\t\t\t\tif (removed || aborted) return;\n\t\t\t\t\tatt.status = 'error';\n\t\t\t\t\tatt.errorMessage = 'File upload has failed';\n\t\t\t\t\t// Preserve the original error code/message for the report dialog.\n\t\t\t\t\tatt.errorCode = (err && (err.code || (err.body && err.body.code))) || '';\n\t\t\t\t\tatt.errorDetail = (err && (err.message || (err.body && err.body.message))) || (typeof err === 'string' ? err : '');\n\t\t\t\t\tself.host.renderAttachmentChips();\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t\tvar done = function () {\n\t\t\tself._uploadBatches = Math.max(0, self._uploadBatches - 1);\n\t\t\t// Only the LAST batch standing clears the flag — a second send made\n\t\t\t// while this one was uploading is still running.\n\t\t\tself.state.uploadingAttachments = self._uploadBatches > 0;\n\t\t\tself.host.updateComposerControls(); self.host.renderAttachmentChips();\n\t\t\treturn collected;\n\t\t};\n\t\treturn chain.then(done, done);\n\t}\n\n\t// Stop timers / abort the typewriter (view teardown).\n\tstop(): void {\n\t\tthis.state.typingAbort = true;\n\t}\n\n\t// Bump the gate token so any in-flight immediate-send result is dropped\n\t// (called by the view on a service/platform switch or history clear).\n\tbumpGate(): void {\n\t\tthis.state.gateRefreshToken += 1;\n\t}\n}\n","/**\n * Background file-indexing turns, collapsed into ONE row per file.\n *\n * A single upload can produce many chat turns: the first \"Indexing: <file>\" pass\n * plus up to MAX_INDEXING_RESUME_PASSES CONTINUE passes, each with its own\n * request AND response bubble. Rendered flat, that reads as the same task\n * repeating forever, and any real question the user asks in between gets buried.\n *\n * buildChatDisplayList turns the flat message array into a DISPLAY list in which\n * every message belonging to one run of one file (however far apart the passes\n * sit, and whatever else is interleaved between them) is represented by a single\n * group entry, rendered at the position of that run's FIRST loaded pass.\n *\n * First, not newest. The message array is ordered by request CREATION time, and\n * a run's later passes are created one at a time as the previous one resolves —\n * by the client for the paged text path, and by the WORKER itself for the\n * rendered-page (PDF) path, which the client only learns about on its next\n * first-page history fetch. So a pass is routinely created minutes after the\n * upload, on a queue that runs in parallel with the foreground chat. Anchoring\n * at the newest pass meant one such late pass dragged the whole run — every\n * earlier pass with it — below any question the user had asked in the meantime,\n * and made a run that had visibly finished before the question render after it.\n * Anchoring at the first pass puts the row where the run actually began, which\n * is a position no later pass can change:\n * - a new pass never relocates the row, so nothing under the reader shifts;\n * - a question asked after the upload always renders below the row, which is\n * the order it happened in.\n * The cost is that a long-running index does not follow the conversation to the\n * bottom: once the user has chatted past the upload, the spinner and the Stop\n * button sit above their newest turns. That is a scroll away, and the row no\n * longer lies about when the work started.\n *\n * Paging older history is the one thing that CAN move the row: an older page\n * carrying earlier passes of a run already on screen moves it up into that page.\n * That happens at most once per run, only for a run whose start was never\n * loaded (`mayHaveOlder`), and it is the same event that already re-derives\n * `runKey` — so the view treats it as a new row either way.\n *\n * The group deliberately reports no authoritative pass TOTAL. History is paged\n * newest-first, so any total computed from loaded messages is a lower bound that\n * a later scroll-up would contradict. It reports STATE (indexing / indexed /\n * failed), how many passes are currently loaded, and `mayHaveOlder` when the\n * file's first pass is not among them.\n *\n * For the same reason it also reports NOT KNOWING. A run whose start is still\n * being paged in, and a worker-driven run whose queue state has not been asked\n * for yet, are both rows whose state is a moving target — and on a chatbox that\n * was just opened, that is most of them. `resolving` marks those, so the view can\n * say which wait it is waiting on rather than committing to \"indexing\" or\n * \"indexed\" on a fraction of the evidence.\n *\n * Pure and view-agnostic: agent.vue and the BunnyQuery widget both render from\n * this, so the two stay identical.\n */\nimport type { ChatMessage, IndexingFileRef } from './host';\nimport { isPagedReadFile, isImageVisionFile } from './office';\nimport { windowedIndexingEnabled } from './config';\nimport { MAX_INDEXING_RESUME_PASSES } from './requests';\n\nexport type IndexingGroupStatus = 'active' | 'done' | 'error' | 'cancelled';\n\nexport type IndexingGroup = {\n\t/** The FILE this row is about: storage path when known (a file can be\n\t * re-uploaded under a name that already exists elsewhere), else name. Shared\n\t * by every run of that file, and what ChatSession.cancelIndexingGroup and\n\t * _indexKeyOf match on — never use it as a render key.\n\t *\n\t * It IS the key for persistent view state, above all the expansion state. That\n\t * used to be keyed by runKey, which is renamed the moment a run's true first\n\t * pass loads (see below) — so a row the user had opened silently closed itself\n\t * mid-indexing, every time a pass arrived ahead of the earlier ones. This never\n\t * changes for the life of a file. The cost is that two runs OF THE SAME FILE\n\t * (an index and a later re-index) open and close together, which is a fair\n\t * reading of \"show me this file's steps\" and is not a state the user can be\n\t * surprised out of. */\n\tkey: string;\n\t/** Identity of this ROW: one indexing RUN of that file. A file indexed on\n\t * Monday and re-indexed on Wednesday is two runs, and collapsing them into\n\t * one row erased Monday's from Monday's place in the conversation, claimed\n\t * its passes for Wednesday, and let Monday's failure be overwritten by\n\t * Wednesday's success. Named after the run's FIRST loaded pass (see where it\n\t * is assigned below), so passes appended to the run and other runs appearing\n\t * on either side of it never rename a row already on screen.\n\t *\n\t * This is the RENDER key, and only that. It is renamed when the run's true\n\t * first pass finally loads — routine while a worker-driven chain is running,\n\t * since a pass adopted from the queue can reach the client before the earlier\n\t * ones are paged in — and a rename is exactly right for a DOM key (the row did\n\t * change identity) but wrong for anything the USER set. Key that on `key`. */\n\trunKey: string;\n\tname: string;\n\tpath?: string;\n\tmime?: string;\n\tsize?: number;\n\t/** True when any loaded pass was a re-index of an already-stored file. */\n\tisReindex: boolean;\n\t/** Every message of this file, in chat order, with its index in the source\n\t * array (so cancel/typewriter paths keep addressing the real message). */\n\tmembers: { msg: ChatMessage; index: number }[];\n\t/** Indexing passes LOADED (request bubbles), never a server-side total. */\n\tpassCount: number;\n\tstatus: IndexingGroupStatus;\n\t/** Server item ids of the passes that are still queued/running, so the row can\n\t * offer a stop button (ChatSession.cancelIndexingGroup cancels each). Empty\n\t * when nothing is cancellable — a finished file, or a live pass whose server\n\t * id has not come back yet. */\n\tcancellableIds: string[];\n\t/** This row is in the middle of stopping: a cancel request is in flight for one\n\t * of its passes, or the user stopped the run and a pass is still running. Both\n\t * mean the same thing to a view — the Stop has been spent, so the button reads\n\t * \"Stopping...\" and is not offered again. */\n\tcancelling: boolean;\n\t/** The user stopped this run.\n\t *\n\t * NOT the same as `status === 'cancelled'`, and the difference is the whole\n\t * reason it exists: a stop landing on a pass that is already RUNNING cannot\n\t * un-run it, so the row stays `active` until that pass settles. `status` then\n\t * describes the work (something is still running) and this describes the user's\n\t * decision (no more of it will be started). */\n\tstopped: boolean;\n\t/** Why the last cancel attempt failed (e.g. the pass had already finished). */\n\tcancelError?: string;\n\t/** The file's first pass is not among the loaded messages, so earlier passes\n\t * exist in history that has not been paged in yet. */\n\tmayHaveOlder: boolean;\n\t/** Position in the source array this collapsed row renders at: the index of\n\t * the run's FIRST loaded pass (see the file docstring for why not the last). */\n\tanchorIndex: number;\n\t/** Identity of the turn at `anchorIndex` — its server item id, or its local id\n\t * while it has none, or `''` when it has neither. The views stamp this on the\n\t * row (`data-row-pos`) so the scroll anchor can tell a row that RELOCATED (an\n\t * older page moved the run's start) from one that merely gained a pass. They\n\t * must not re-derive it from `members`: which member the row renders at is\n\t * this module's decision, and the two silently disagreed once already. */\n\tanchorId: string;\n\t/** `members` minus the turns an EXPANDED row should not show: every CONTINUE\n\t * request, and the running pass's empty placeholder.\n\t *\n\t * A continuation's request bubble says \"Indexing (continuing) <file>\" and\n\t * nothing else — it repeats the row's own header once per pass, so a long file\n\t * read as the same line over and over with the actual findings buried between\n\t * them. The pass is still represented, by its RESPONSE. The placeholder goes\n\t * for a different reason: the row now carries one loader of its own for as long\n\t * as work remains, and two spinners in one open row is noise.\n\t *\n\t * Additive. `members` is untouched and is still what every count, status,\n\t * cancel and anchor decision reads — several of them are only correct on the\n\t * full list (a `mayHaveOlder` run's members[0] IS a continuation). */\n\tvisibleMembers: { msg: ChatMessage; index: number }[];\n\t/** Who advances this file's chain, which decides what can confirm it is over:\n\t * 'single' one pass and done; 'client' this client dispatches each CONTINUE\n\t * pass and stops on the model's completion marker; 'worker' the server advances\n\t * the loop off the renderer's page count and the client is only a spectator. */\n\tdriver: 'single' | 'client' | 'worker';\n\t/** Positively established that no further indexing work will happen for this\n\t * run. NOT \"the file was fully read\" — a cap-out, a failure and a stop are all\n\t * finished, and the row's own status says which.\n\t *\n\t * False means \"not established\", which includes \"still running\" AND \"we have\n\t * not been able to find out\". The view shows a loader for both, deliberately:\n\t * the alternative default is the failure this exists to prevent, a row that\n\t * reads \"Indexed\" between two passes of a file still being read. */\n\tfinished: boolean;\n\t/** This row cannot honestly claim a state yet, because something it is derived\n\t * FROM is still being fetched. Both `status` and `finished` are read off the\n\t * passes that happen to be LOADED, and on a freshly opened chatbox that is a\n\t * moving target: history pages newest-first, so a long run arrives as a tail\n\t * of CONTINUE passes while its beginning is still being paged in. The row was\n\t * picking a side through that window — a spinner reading \"Indexing\" for a file\n\t * that finished last week, or a green \"Indexed\" for one still being read — and\n\t * both are verdicts drawn from a fraction of the run.\n\t *\n\t * Only ever set from status 'done'. A loaded pending pass PROVES the run is\n\t * live, and an error or a stop is the newest pass's own outcome, which\n\t * newest-first paging always has in hand — none of those is a guess, and\n\t * hiding any of them behind a loader would lose something the user needs.\n\t *\n\t * For the 'history' reason this means \"a fetch is IN FLIGHT\", not \"the picture\n\t * is incomplete\". Older history is paged in by explicit triggers only (the\n\t * viewport fill, the user scrolling to the top) and nothing auto-fetches on a\n\t * row's behalf, so a run whose start is still unloaded once the paging stops\n\t * has to go back to reporting what it does know — `mayHaveOlder` and the `+` on\n\t * the pass count carry the rest. A \"loading...\" that never ends is the same lie\n\t * pointing the other way.\n\t *\n\t * The 'status' reason is weaker on purpose: \"the queue has not answered\", which\n\t * a permanently failing query never resolves. That is deliberate, because it is\n\t * the SAME question as what the row should say when it cannot find out, and\n\t * every alternative is worse: a grey clock reading \"checking\" claims less than\n\t * the yellow spinner reading \"Indexing\" that it replaced. It also self-heals in\n\t * practice — the answer is re-sought on every first-page history load and every\n\t * settling pass — and gating it on an in-flight query instead would mean\n\t * threading a second liveness flag through a retry ladder with nine exit\n\t * points, i.e. trading this for a flag that can stick in the other direction. */\n\tresolving: boolean;\n\t/** Which wait, so the row can name it instead of just spinning. 'history':\n\t * older pages are being fetched and this run's first pass is not among the\n\t * loaded ones. 'status': the queue has not yet said whether this file is still\n\t * being worked on, which is the only thing that can end a worker-driven run. */\n\tresolvingReason?: 'history' | 'status';\n\t/** Synthesized from a durable run:: record: none of the run's passes are\n\t * among the loaded messages (bg history still deferred, or the run is older\n\t * than the paging cap). Header-and-status only — members/visibleMembers are\n\t * empty and there is nothing to cancel; the row is replaced by the real\n\t * group the moment actual passes load (same `key`, so expansion state\n\t * carries over). */\n\tstub?: boolean;\n\t/** The run:: record's stored error text, for a stub row's meta line. */\n\tstubError?: string;\n};\n\nexport type DisplayEntry =\n\t| { kind: 'message'; msg: ChatMessage; index: number }\n\t| { kind: 'indexing'; group: IndexingGroup; index: number };\n\nexport type BuildDisplayListOptions = {\n\t/** True while older history remains unpaged, which is what makes a group\n\t * with no first pass genuinely incomplete rather than merely odd. */\n\thasMoreHistory?: boolean;\n\t/** An OLDER-history fetch is in flight right now — a single page, or the whole\n\t * viewport-fill loop (createHistoryFiller's onRunningChange, which spans the\n\t * pages between which a per-request flag keeps dropping to false).\n\t *\n\t * Older specifically. A first-page refresh cannot bring in a run's earlier\n\t * passes, so counting it here would flip every incomplete row to \"still\n\t * loading\" for the length of a poll that could never have answered it. */\n\tloadingOlderHistory?: boolean;\n\t/** Files the SERVER still has unresolved indexing work for, keyed exactly like\n\t * IndexingGroup.key (ChatSession.getLiveIndexState). */\n\tliveIndexKeys?: { [fileKey: string]: boolean };\n\t/** Whether `liveIndexKeys` has been answered at least once for this chat. False\n\t * is \"we do not know\", and a worker-driven run stays unfinished on it. */\n\tliveIndexChecked?: boolean;\n\t/** Files carrying the durable done:: completion marker (one prefix sweep),\n\t * keyed like IndexingGroup.key (storage path; the bare-name fallback keys\n\t * of very old prompts simply never match — they keep the queue inference).\n\t * A marker is PROOF the file was read to the end: it settles a worker-run\n\t * green without waiting for the queue answer, and it is never withheld by\n\t * the resolving logic. A live queue hit still outranks it (a re-index in\n\t * flight whose marker-cascade delete lagged). */\n\tdoneKeys?: { [fileKey: string]: boolean };\n\t/** Server item ids of passes that were on a row when the user STOPPED it\n\t * (ChatSession.state.stoppedIndexIds). A run holding any of them is a run the\n\t * user stopped — see the status derivation for why a stop usually leaves no\n\t * other trace in the messages. Ids rather than a file key on purpose: they name\n\t * one RUN, so a later re-index of the same file cannot inherit the stop. */\n\tstoppedIndexIds?: { [serverItemId: string]: boolean };\n\t/** Whether the WORKER drives the windowed text/grid loop (chatEngineConfig's\n\t * windowedIndexing). Passed in rather than read from config so this stays a\n\t * pure function of its inputs and can be exercised for both settings. */\n\twindowedIndexing?: boolean;\n\t/** Durable run:: records, keyed by STORAGE PATH (the consumer's marker\n\t * sweep). Each key with no real group in the loaded messages gets a\n\t * synthesized header-only row (see IndexingGroup.stub), placed by its\n\t * `started` timestamp. A real group for the same file — matched by key,\n\t * path, or name — always suppresses the stub: loaded passes are evidence,\n\t * the record is only a summary. */\n\trunStubs?: { [storagePath: string]: RunStubInfo };\n\t/** The platform whose chat this list is for. run:: records are per-FILE,\n\t * but a chat is per (project, platform): a run started under Claude has\n\t * its passes in the Claude conversation and is invisible to the\n\t * OpenAI-scoped queue probe, so its stub could never be covered and never\n\t * be confirmed — it just sat there, in a chat it did not belong to.\n\t * Records minted before this was stamped carry no platform and are shown\n\t * in both, which keeps the leak to the historical set. */\n\tstubPlatform?: 'claude' | 'openai';\n\t/** The chat's clear-history horizon (ms epoch). Run records are service-\n\t * wide and know nothing about a cleared chat, so without this every\n\t * \"Clear chat history\" resurrects one row per indexed file. A stub whose\n\t * run ended (or, unfinished, began) at or before this moment is dropped —\n\t * unless the queue says the file is live RIGHT NOW, which no horizon can\n\t * make untrue. */\n\tstubClearedAt?: number;\n\t/** Clock injection for tests; defaults to Date.now(). Only run-stub\n\t * staleness reads it. */\n\tnow?: number;\n};\n\n/** The display-relevant fields of a run:: record (see requests.ts\n * runIndexUniqueId for the record's contract). */\nexport type RunStubInfo = {\n\tstatus: 'working' | 'done' | 'error' | 'cancelled';\n\tfilename?: string;\n\tstarted?: number;\n\tfinished?: number;\n\terror?: string;\n\t/** Chat that owns this run. Absent on records minted before it was\n\t * stamped; see BuildDisplayListOptions.stubPlatform. */\n\tplatform?: 'claude' | 'openai';\n};\n\n/** A 'working' run record older than this with no live-queue confirmation is\n * treated as unknown rather than live: a chain that died without reaching any\n * error path leaves 'working' dangling, and a row must not spin forever on a\n * claim nothing can end. */\nexport const RUN_RECORD_WORKING_STALE_MS = 6 * 60 * 60 * 1000;\n\n// The indexing label is view-formatted (formatIndexingLabel), so parsing it is\n// the FALLBACK path only: it exists for bubbles restored from a history cache\n// written before `_indexFile` was stamped. Live and freshly-mapped bubbles carry\n// the structured ref and never reach this.\n//\n// Shapes produced by formatIndexingLabel:\n// \"Indexing: [name](path) · mime · 1.2 MB\"\n// \"Reindexing: name · mime\"\n// \"Indexing (continuing) [name](path)\"\nconst INDEXING_LABEL_RE = /^(Re)?[Ii]ndexing(\\s*\\(continuing\\))?\\s*:?\\s+(.+)$/;\nconst LEADING_MD_LINK_RE = /^\\[([^\\]]+)\\]\\(([^)]+)\\)/;\n\nexport function parseIndexingLabel(\n\tcontent: string,\n): { name: string; path?: string; continued: boolean; isReindex: boolean } | null {\n\tif (typeof content !== 'string' || !content) return null;\n\tvar firstLine = content.split('\\n')[0].trim();\n\tvar m = firstLine.match(INDEXING_LABEL_RE);\n\tif (!m) return null;\n\t// Only the first \" · \" segment is the file; the rest is mime/size trivia.\n\tvar head = m[3].split(' · ')[0].trim();\n\tvar link = head.match(LEADING_MD_LINK_RE);\n\tvar name = link ? link[1].trim() : head;\n\tif (!name) return null;\n\treturn {\n\t\tname: name,\n\t\tpath: link ? link[2].trim() : undefined,\n\t\tcontinued: !!m[2],\n\t\tisReindex: !!m[1],\n\t};\n}\n\n/** The file a background-indexing bubble belongs to, structured ref preferred. */\nfunction readFileRef(msg: ChatMessage): (IndexingFileRef & { continued: boolean }) | null {\n\tvar ref = msg && msg._indexFile;\n\tif (ref && (ref.path || ref.name)) {\n\t\treturn {\n\t\t\tname: ref.name || ref.path || '',\n\t\t\tpath: ref.path,\n\t\t\tmime: ref.mime,\n\t\t\tsize: ref.size,\n\t\t\tisReindex: ref.isReindex,\n\t\t\tcontinued: !!ref.continued,\n\t\t};\n\t}\n\tvar parsed = parseIndexingLabel(msg && msg.content);\n\tif (!parsed) return null;\n\treturn {\n\t\tname: parsed.name,\n\t\tpath: parsed.path,\n\t\tisReindex: parsed.isReindex,\n\t\tcontinued: parsed.continued,\n\t};\n}\n\nfunction isPendingMsg(m: ChatMessage): boolean {\n\treturn !!(m.isPending || m.isPendingInProcess || m.isPendingQueued || m.isSendingToServer);\n}\n\n/**\n * A member an EXPANDED row should not render. See IndexingGroup.visibleMembers.\n *\n * A CANCELLED continuation is an exception and stays: a cancelled item is given no\n * response bubble at all, so hiding its request would erase the only evidence that\n * the pass existed. A user bubble we cannot classify (it joined the run by server\n * id, not by a label we could parse) also stays — showing an unexpected turn is a\n * far smaller error than silently dropping one.\n */\nfunction isHiddenPass(m: ChatMessage): boolean {\n\tif (m.role === 'user') {\n\t\tif (m.isCancelled) return false;\n\t\tvar ref = readFileRef(m);\n\t\treturn !!(ref && ref.continued);\n\t}\n\treturn !!m.isPending;\n}\n\n/**\n * Collapse background-indexing turns into per-file groups.\n *\n * Messages that are not background-indexing pass through untouched, at their\n * original positions and with their original indices.\n */\nexport function buildChatDisplayList(\n\tmessages: ChatMessage[],\n\topts?: BuildDisplayListOptions,\n): DisplayEntry[] {\n\tvar list = Array.isArray(messages) ? messages : [];\n\tvar liveIndexKeys = (opts && opts.liveIndexKeys) || {};\n\tvar liveIndexChecked = !!(opts && opts.liveIndexChecked);\n\tvar doneKeys = (opts && opts.doneKeys) || {};\n\tvar stoppedIndexIds = (opts && opts.stoppedIndexIds) || {};\n\tvar windowedIndexing = opts && opts.windowedIndexing !== undefined\n\t\t? !!opts.windowedIndexing\n\t\t: windowedIndexingEnabled();\n\tvar hasMoreHistory = !!(opts && opts.hasMoreHistory);\n\tvar loadingOlderHistory = !!(opts && opts.loadingOlderHistory);\n\tvar stubPlatform = opts && opts.stubPlatform;\n\n\t// One entry per RUN (see IndexingGroup.runKey), addressed by an internal id\n\t// while the list is being walked; runKey is assigned at the end, once the\n\t// number of runs per file is known.\n\tvar groups: { [runId: string]: IndexingGroup } = {};\n\tvar order: string[] = [];\n\tvar runOfIndex: (string | undefined)[] = new Array(list.length);\n\t// A response bubble carries no file metadata of its own; it is tied to its\n\t// request by the server item id, with the immediately preceding request as\n\t// the fallback for locally-pushed bubbles that have no id yet.\n\tvar runByItemId: { [itemId: string]: string } = {};\n\t// Row already opened for a file NAME, so a pass that reports no storage path\n\t// joins it instead of opening a second row for the same file.\n\tvar keyByName: { [name: string]: string } = {};\n\t// The run currently being accumulated for each file, every run of it, and the\n\t// file each run belongs to (a run id is opaque — a file key can contain any\n\t// character, so it must never be parsed back out of one).\n\tvar openRunOfKey: { [key: string]: string } = {};\n\tvar runsOfKey: { [key: string]: string[] } = {};\n\tvar keyOfRun: { [runId: string]: string } = {};\n\tvar runSeq = 0;\n\n\tfor (var i = 0; i < list.length; i++) {\n\t\tvar msg = list[i];\n\t\tif (!msg || !msg.isBackgroundTask) continue;\n\n\t\tvar runId: string | undefined;\n\t\tvar ref = msg.role === 'user' ? readFileRef(msg) : null;\n\t\tif (ref) {\n\t\t\t// Path first — a file can be re-uploaded under a name that already\n\t\t\t// exists elsewhere. But a pass that supplied no path (a compact\n\t\t\t// continuation label recovered from an old history cache) is still the\n\t\t\t// same file as the path-bearing passes above it, so let it join them\n\t\t\t// rather than splitting one file across two collapsed rows.\n\t\t\tvar key = ref.path || keyByName[ref.name] || ref.name;\n\t\t\t// A FIRST pass (\"A new file has just been uploaded\") when this file\n\t\t\t// already has a run open starts a new one: it is a re-index, or a\n\t\t\t// re-upload over the same storage path. Continuations join the run.\n\t\t\tif (!ref.continued && openRunOfKey[key]) delete openRunOfKey[key];\n\t\t\trunId = openRunOfKey[key];\n\t\t\tif (!runId) {\n\t\t\t\trunId = 'run' + (runSeq++);\n\t\t\t\topenRunOfKey[key] = runId;\n\t\t\t\tkeyOfRun[runId] = key;\n\t\t\t\t(runsOfKey[key] || (runsOfKey[key] = [])).push(runId);\n\t\t\t}\n\t\t} else if (msg._serverItemId && runByItemId[msg._serverItemId]) {\n\t\t\trunId = runByItemId[msg._serverItemId];\n\t\t} else if (msg.role !== 'user') {\n\t\t\t// ADJACENT only. Both paths that create a pass emit its request and\n\t\t\t// response bubbles together, so an id-less response belongs to the\n\t\t\t// message right before it. Falling back to the last file seen ANYWHERE\n\t\t\t// above swallowed stray background bubbles — an indexing prompt whose\n\t\t\t// shape we could not parse, a response whose request is not loaded —\n\t\t\t// into whichever file happened to be indexed most recently, however\n\t\t\t// much unrelated conversation sat in between.\n\t\t\trunId = runOfIndex[i - 1];\n\t\t}\n\t\t// A background bubble we cannot attribute to a file (an unrecognised label,\n\t\t// or a response whose request is not loaded) stays an ordinary message\n\t\t// rather than being folded into whichever group happens to be nearest.\n\t\tif (!runId) continue;\n\n\t\tvar g = groups[runId];\n\t\tif (!g) {\n\t\t\tvar fileKey = keyOfRun[runId];\n\t\t\tg = groups[runId] = {\n\t\t\t\tkey: fileKey,\n\t\t\t\trunKey: runId, // provisional; renumbered newest-first below\n\t\t\t\tname: ref ? ref.name : fileKey,\n\t\t\t\tpath: ref ? ref.path : undefined,\n\t\t\t\tmime: ref ? ref.mime : undefined,\n\t\t\t\tsize: ref ? ref.size : undefined,\n\t\t\t\tisReindex: !!(ref && ref.isReindex),\n\t\t\t\tmembers: [],\n\t\t\t\tpassCount: 0,\n\t\t\t\tstatus: 'done',\n\t\t\t\tcancellableIds: [],\n\t\t\t\tcancelling: false,\n\t\t\t\tstopped: false,\n\t\t\t\tmayHaveOlder: false,\n\t\t\t\t// The run's first loaded pass, and never re-stamped: see the file\n\t\t\t\t// docstring. `anchorId` is filled in once every member is known.\n\t\t\t\tanchorIndex: i,\n\t\t\t\tanchorId: '',\n\t\t\t\t// All five are derived once every member is known, below.\n\t\t\t\tvisibleMembers: [],\n\t\t\t\tdriver: 'single',\n\t\t\t\tfinished: false,\n\t\t\t\tresolving: false,\n\t\t\t};\n\t\t\torder.push(runId);\n\t\t}\n\t\tif (ref) {\n\t\t\t// Later passes carry the compact continuation label with no mime/size,\n\t\t\t// so keep the richest values any pass supplied.\n\t\t\tif (ref.name) g.name = ref.name;\n\t\t\tif (ref.path) g.path = ref.path;\n\t\t\tif (ref.mime) g.mime = ref.mime;\n\t\t\tif (typeof ref.size === 'number') g.size = ref.size;\n\t\t\tif (ref.isReindex) g.isReindex = true;\n\t\t\tif (!ref.continued) g.mayHaveOlder = false;\n\t\t\tg.passCount++;\n\t\t}\n\t\tg.members.push({ msg: msg, index: i });\n\t\trunOfIndex[i] = runId;\n\t\tif (msg._serverItemId) runByItemId[msg._serverItemId] = runId;\n\t\tif (ref && ref.name) keyByName[ref.name] = g.key;\n\t}\n\n\t// Name each run after its FIRST loaded pass. That id survives everything the\n\t// list does around it: passes appended to this run, other runs of the same\n\t// file appearing before OR after it, and an older page prepending. (An\n\t// ordinal would not — numbering from either end renames existing rows as soon\n\t// as a run appears at that end, which silently moves the user's expansion to\n\t// a row they never opened.) The one thing that changes it is the run's own\n\t// true first pass finally paging in, which happens at most once per run.\n\t// Whether a run is the NEWEST of its file. Only that one can still be running:\n\t// `liveIndexKeys` is keyed by FILE, shared by every run of it, so without this a\n\t// re-index left last week's finished row spinning for the whole of this week's\n\t// run — one file, two rows, both claiming to be working.\n\tvar newestRunOfKey: { [runId: string]: boolean } = {};\n\tfor (var nk in runsOfKey) {\n\t\tvar nrs = runsOfKey[nk];\n\t\tif (nrs.length) newestRunOfKey[nrs[nrs.length - 1]] = true;\n\t}\n\tfor (var rk in runsOfKey) {\n\t\tvar runIds = runsOfKey[rk];\n\t\tfor (var ri = 0; ri < runIds.length; ri++) {\n\t\t\tvar grpR = groups[runIds[ri]];\n\t\t\tif (!grpR) continue;\n\t\t\tvar first = grpR.members[0];\n\t\t\tvar firstId = first && first.msg && (first.msg._serverItemId || first.msg._localId);\n\t\t\t// A run whose passes are all still local (no server id yet) falls back to\n\t\t\t// its position, which is all there is to go on.\n\t\t\tgrpR.runKey = rk + '#' + (firstId || 'n' + ri);\n\t\t}\n\t}\n\n\t// Status + completeness, once every member is known.\n\tfor (var oi = 0; oi < order.length; oi++) {\n\t\tvar grp = groups[order[oi]];\n\t\t// A file's passes run strictly one after another, so a pass still marked\n\t\t// queued/running with a SETTLED pass after it is stale history, not live\n\t\t// work — the server's row for it simply never left \"running\". Ignoring\n\t\t// those matters most for pages reached by scrolling up (or by the viewport\n\t\t// fill), which get no poll attached to resolve them: one stale row would\n\t\t// otherwise flip a long-finished file back to a spinner with a \"Stop\"\n\t\t// button aimed at a dead item id, permanently.\n\t\tvar lastSettled = -1;\n\t\tfor (var si = 0; si < grp.members.length; si++) {\n\t\t\tif (!isPendingMsg(grp.members[si].msg)) lastSettled = si;\n\t\t}\n\t\tvar active = false;\n\t\tfor (var mi = lastSettled + 1; mi < grp.members.length; mi++) {\n\t\t\tif (isPendingMsg(grp.members[mi].msg)) { active = true; break; }\n\t\t}\n\t\t// Did the user STOP this run? Asked of the WHOLE run, because a stop routinely\n\t\t// leaves nothing behind at the end of it:\n\t\t// - only a QUEUED pass can be removed from the queue, and that is the one\n\t\t// case that produces a cancelled bubble. The pass that is actually running\n\t\t// cannot be un-run — it is flagged cancelled server-side, which is what\n\t\t// stops the worker enqueueing the next window, and then finishes its own\n\t\t// provider call and writes an ordinary, successful answer;\n\t\t// - a PDF (or any worker-driven file) usually has exactly ONE pass live, so\n\t\t// that running pass is normally all a stop has to act on;\n\t\t// - continuations still sitting in bgTaskQueue are dropped by\n\t\t// _applyIndexCancellations before they are ever surfaced, so they leave no\n\t\t// bubble either.\n\t\t// The messages of a stopped run therefore END in a successful pass, and reading\n\t\t// the status off the last member alone reported the stop as a green \"Indexed\"\n\t\t// over a file that was only partly read — with the newest pass's own text still\n\t\t// saying \"More pages remain\" right underneath it.\n\t\t//\n\t\t// Two witnesses, both scoped to one RUN so a later re-index of the same file\n\t\t// can never inherit a stop: a cancelled member (durable — it comes back from\n\t\t// history), and the ids ChatSession recorded when the user hit Stop (this\n\t\t// page's memory only, which is what covers the run that has no cancelled\n\t\t// member at all).\n\t\tvar stopped = false;\n\t\tfor (var ki = 0; ki < grp.members.length; ki++) {\n\t\t\tvar km = grp.members[ki].msg;\n\t\t\tif (km.isCancelled) { stopped = true; break; }\n\t\t\tif (km._serverItemId && stoppedIndexIds[km._serverItemId]) { stopped = true; break; }\n\t\t}\n\t\tgrp.stopped = stopped;\n\t\t// What a stop button would act on: the REQUEST bubble of every pass that is\n\t\t// still queued or running server-side. The assistant placeholder shares its\n\t\t// pass's server id, so ids are de-duplicated. A pass mid-cancel is left out\n\t\t// (its request is already on its way) but keeps the row in a cancelling\n\t\t// state so the button does not flicker back to \"stop\".\n\t\tfor (var xi = 0; xi < grp.members.length; xi++) {\n\t\t\tif (grp.members[xi].msg._cancelling) { grp.cancelling = true; break; }\n\t\t}\n\t\tvar seenIds: { [id: string]: boolean } = {};\n\t\tfor (var ci = 0; ci < grp.members.length; ci++) {\n\t\t\tvar cm = grp.members[ci].msg;\n\t\t\t// Report a failed Stop only while the stop is still something the user\n\t\t\t// can act on. \"Could not remove from queue\" (the pass had just started)\n\t\t\t// stays on that bubble, so reporting it from ANY member meant a row that\n\t\t\t// went on to finish normally kept describing a one-off transient failure\n\t\t\t// as a permanent property of the file, until a full history refresh\n\t\t\t// rebuilt the bubbles.\n\t\t\t//\n\t\t\t// And never for a run that IS stopped, which is the case the message gets\n\t\t\t// wrong: the only thing that failed there is removing the pass already in\n\t\t\t// flight (it cannot be un-run — it finishes and answers), while the stop\n\t\t\t// itself holds. The row says \"Stopping...\" and then \"Indexing cancelled\",\n\t\t\t// which is the accurate account; \"Could not stop this file\" beside it is\n\t\t\t// not.\n\t\t\tif (cm._cancelError && !stopped && (active || grp.cancelling)) grp.cancelError = cm._cancelError;\n\t\t\tif (cm.role !== 'user' || !cm._serverItemId || cm._cancelling || cm.isSendingToServer) continue;\n\t\t\tif (!(cm.isPendingQueued || cm.isPendingInProcess)) continue;\n\t\t\t// Same staleness rule: never offer to stop a pass a later one outlived.\n\t\t\tif (ci < lastSettled) continue;\n\t\t\tif (seenIds[cm._serverItemId]) continue;\n\t\t\tseenIds[cm._serverItemId] = true;\n\t\t\tgrp.cancellableIds.push(cm._serverItemId);\n\t\t}\n\t\tif (active) {\n\t\t\t// A pass IS still running, and a row that claimed otherwise would hide work\n\t\t\t// the user can still see the effects of. The stop is reported as `cancelling`\n\t\t\t// instead — \"Stopping...\", Stop spent — and the row settles to 'cancelled'\n\t\t\t// when that last pass lands.\n\t\t\tgrp.status = 'active';\n\t\t\tif (stopped) grp.cancelling = true;\n\t\t} else if (stopped) {\n\t\t\tgrp.status = 'cancelled';\n\t\t} else {\n\t\t\t// The newest loaded outcome is the file's state: an early pass may have\n\t\t\t// errored and a later one succeeded.\n\t\t\tvar last = grp.members[grp.members.length - 1].msg;\n\t\t\tgrp.status = last.isError ? 'error' : 'done';\n\t\t}\n\t\t// A group whose passes are ALL continuations began before the loaded\n\t\t// window; its earlier passes arrive when older history is paged in.\n\t\tvar sawFirstPass = false;\n\t\tfor (var pi = 0; pi < grp.members.length; pi++) {\n\t\t\tvar pm = grp.members[pi].msg;\n\t\t\tif (pm.role !== 'user') continue;\n\t\t\tvar pref = readFileRef(pm);\n\t\t\tif (pref && !pref.continued) { sawFirstPass = true; break; }\n\t\t}\n\t\tgrp.mayHaveOlder = !sawFirstPass && hasMoreHistory;\n\t\t// Where the row renders, and WHICH turn that is. Derived from the same\n\t\t// member so the two can never drift apart; a group always has a member\n\t\t// (it is created by the first one).\n\t\tvar anchor = grp.members[0];\n\t\tgrp.anchorIndex = anchor.index;\n\t\tgrp.anchorId = anchor.msg._serverItemId || anchor.msg._localId || '';\n\n\t\t// --- what an expanded row renders, and whether the run is over -------------\n\t\tvar sawComplete = false;\n\t\tfor (var vi = 0; vi < grp.members.length; vi++) {\n\t\t\tvar vm = grp.members[vi];\n\t\t\tif (vm.msg._indexComplete) sawComplete = true;\n\t\t\tif (!isHiddenPass(vm.msg)) grp.visibleMembers.push(vm);\n\t\t}\n\t\t// Mirrors ChatSession.maybeResumeIndexing's own routing, which is what makes\n\t\t// the answer match who will actually dispatch the next pass.\n\t\tgrp.driver = !isPagedReadFile(grp.name, grp.mime) ? 'single'\n\t\t\t: isImageVisionFile(grp.name, grp.mime) ? 'worker'\n\t\t\t\t: (windowedIndexing ? 'worker' : 'client');\n\t\tif (grp.status === 'active') {\n\t\t\tgrp.finished = false;\n\t\t} else if (grp.status === 'cancelled') {\n\t\t\t// The user stopped it. Nothing more will run, by construction.\n\t\t\tgrp.finished = true;\n\t\t} else if (grp.driver === 'single') {\n\t\t\t// One pass is the whole job: nothing continues a file that is not a paged\n\t\t\t// read, so a settled pass IS the end. Exact, and survives a reload.\n\t\t\tgrp.finished = true;\n\t\t} else if (grp.driver === 'client') {\n\t\t\t// The three branches this client itself stops dispatching on. Using the\n\t\t\t// same rule means the row cannot disagree with the pipeline: if the client\n\t\t\t// will send no more passes, the run is over whether or not the file was\n\t\t\t// fully read.\n\t\t\tgrp.finished = sawComplete || grp.status === 'error' ||\n\t\t\t\tgrp.passCount >= MAX_INDEXING_RESUME_PASSES;\n\t\t} else {\n\t\t\t// WORKER-driven, and the interesting case. Nothing in the messages can\n\t\t\t// settle it: the loop is advanced inside the worker off the renderer's page\n\t\t\t// count, the client only ever sees passes appear and settle, and the prompt\n\t\t\t// for these paths deliberately never asks for a completion marker — a model\n\t\t\t// that volunteers one is guessing, which is how an 88-page file once\n\t\t\t// \"finished\" at page 15. So sawComplete is deliberately NOT consulted here.\n\t\t\t// Either the server said this was the last pass, or the queue has been\n\t\t\t// asked and holds nothing for this file.\n\t\t\t//\n\t\t\t// A run that is NOT the newest of its file is over by construction: a newer\n\t\t\t// run exists, so this one's chain ended when that one began, and the\n\t\t\t// file-keyed queue answer describes the newer run, not this one.\n\t\t\t//\n\t\t\t// There used to be a third disjunct here, a server-stamped \"this was the\n\t\t\t// run's last pass\" (`_indexFinal`, off an `index_final` field). Nothing ever\n\t\t\t// wrote that field — not the SDK's history mapper, not the worker — so it was\n\t\t\t// permanently false and the two tests below were already carrying the whole\n\t\t\t// decision. It is gone rather than left as a hook, so this reads as what it\n\t\t\t// actually is: for a worker-driven run, ONLY the queue can say it is over.\n\t\t\t// The done:: marker is the third — and strongest — disjunct: written\n\t\t\t// only at a chain's true end (backend worker, or a client's own\n\t\t\t// deterministic completion), it answers without any queue round\n\t\t\t// trip. Gated on the queue NOT claiming the file live, so a\n\t\t\t// re-index whose marker-cascade delete lagged still shows yellow.\n\t\t\tgrp.finished = !newestRunOfKey[order[oi]] ||\n\t\t\t\t(!!doneKeys[grp.key] && !liveIndexKeys[grp.key]) ||\n\t\t\t\t(liveIndexChecked && !liveIndexKeys[grp.key]);\n\t\t}\n\n\t\t// --- is any of that knowable YET? ------------------------------------------\n\t\t// See IndexingGroup.resolving. Both answers above are read off the passes\n\t\t// that happen to be loaded, and while a fetch that would change WHICH passes\n\t\t// those are is still running, the row states the wait instead of picking a\n\t\t// side. Two waits, checked in that order because the first subsumes the\n\t\t// second: a run whose start has not arrived cannot be judged by any queue\n\t\t// answer either.\n\t\tif (grp.status !== 'done') {\n\t\t\t// 'active' is proof the run is live; 'error' and 'cancelled' are the\n\t\t\t// newest pass's own outcome, and newest-first paging always has that pass.\n\t\t\tgrp.resolving = false;\n\t\t} else if (grp.mayHaveOlder && loadingOlderHistory &&\n\t\t\t!liveIndexKeys[grp.key] && !doneKeys[grp.key] && newestRunOfKey[order[oi]]) {\n\t\t\t// The line this draws, and it is the same line the 'status' branch draws:\n\t\t\t// withhold what is UNKNOWN, and what is only INFERRED settled. Never\n\t\t\t// withhold what is PROVEN, in either direction. Two proofs, and an older\n\t\t\t// page can revise neither:\n\t\t\t// liveIndexKeys hit — the server just said this file is on the queue RIGHT\n\t\t\t// NOW. Yellow and spinning, and no amount of older history makes that\n\t\t\t// untrue. (Survives an unanswered `checked` for the reason above: only\n\t\t\t// ABSENCE needs the truncation guard.)\n\t\t\t// not the newest run of this file — a LATER run exists in the loaded\n\t\t\t// messages, so this run's chain ended when that one began. Prepending\n\t\t\t// adds OLDER messages, so it can never add a run after this one.\n\t\t\t// (A third proof used to sit here, a server-stamped last-pass flag, but\n\t\t\t// nothing ever wrote the field it read — see `finished` above.)\n\t\t\t//\n\t\t\t// What is deliberately NOT proof here: `finished` as a whole. Its remaining\n\t\t\t// source is `liveIndexChecked && !liveIndexKeys[key]`, which is an inference\n\t\t\t// from ABSENCE and is exactly what the user asked to stop reading as a green\n\t\t\t// \"Indexed\" mid-fetch. And a blanket `!grp.finished` would be wrong for a\n\t\t\t// second reason: driver 'single' also yields finished, and THAT verdict an\n\t\t\t// older page really can revise — the first pass is what carries the mime, so\n\t\t\t// a page bringing it in re-classifies the file as paged and hands the\n\t\t\t// question back to the queue.\n\t\t\tgrp.resolving = true;\n\t\t\tgrp.resolvingReason = 'history';\n\t\t} else if (!grp.finished && grp.driver === 'worker' && !liveIndexChecked && !liveIndexKeys[grp.key]) {\n\t\t\t// Worker-driven and the queue has not answered. `finished` is already\n\t\t\t// false here and the row would spin \"Indexing\" on the strength of nothing\n\t\t\t// — the same false claim, one round trip long, on every chatbox open of a\n\t\t\t// file that finished days ago. A 'client' run in the same shape is NOT\n\t\t\t// resolving: no answer is being waited for, this client is the one that\n\t\t\t// dispatches the next pass, so \"Indexing\" is a statement about its own\n\t\t\t// intent and is true.\n\t\t\t//\n\t\t\t// A POSITIVE key survives `!liveIndexChecked`, and must. `checked` is set\n\t\t\t// from `!truncated`: a capped page suppresses the whole answer, which is\n\t\t\t// right for ABSENCE (an omitted file would otherwise read as finished) and\n\t\t\t// wrong for PRESENCE, because an item the query did return is proof the\n\t\t\t// file is live. Hiding that behind \"checking...\" would withhold the one\n\t\t\t// thing here that is actually known.\n\t\t\tgrp.resolving = true;\n\t\t\tgrp.resolvingReason = 'status';\n\t\t} else {\n\t\t\tgrp.resolving = false;\n\t\t}\n\t}\n\n\t// --- durable run:: stubs ---------------------------------------------------\n\t// A run record whose passes are not among the loaded messages still deserves\n\t// a row: on a fresh open the bg history is deferred, and a run older than the\n\t// paging cap never loads at all. Synthesized as header-only groups and placed\n\t// by `started` among the messages' own timestamps; a real group for the same\n\t// file always wins (see BuildDisplayListOptions.runStubs).\n\tvar stubList: { started: number; group: IndexingGroup }[] = [];\n\tvar runStubs = opts && opts.runStubs;\n\tif (runStubs) {\n\t\t// Two namespaces, deliberately NOT one map: storage paths are\n\t\t// project-relative and folder trees repeat basenames routinely, so a\n\t\t// flat map let a real group for \"2025/report.pdf\" delete the stub for\n\t\t// \"2026/report.pdf\" with nothing replacing it. A bare NAME only covers\n\t\t// a stub when the group itself has no path (the legacy compact-label\n\t\t// case) and the record has no filename of its own to disambiguate.\n\t\tvar coveredPaths: { [k: string]: boolean } = {};\n\t\tvar coveredPathlessNames: { [k: string]: boolean } = {};\n\t\tfor (var ci = 0; ci < order.length; ci++) {\n\t\t\tvar cg = groups[order[ci]];\n\t\t\tif (cg.path) { coveredPaths[cg.path] = true; if (cg.key) coveredPaths[cg.key] = true; }\n\t\t\telse if (cg.name) coveredPathlessNames[cg.name] = true;\n\t\t\telse if (cg.key) coveredPaths[cg.key] = true;\n\t\t}\n\t\tvar now = opts && typeof opts.now === 'number' ? opts.now : Date.now();\n\t\tvar stubClearedAt = (opts && typeof opts.stubClearedAt === 'number' && opts.stubClearedAt > 0)\n\t\t\t? opts.stubClearedAt : 0;\n\t\tfor (var sp in runStubs) {\n\t\t\tvar rec = runStubs[sp];\n\t\t\tif (!sp || !rec || !rec.status || coveredPaths[sp]) continue;\n\t\t\tvar fname = rec.filename || sp.split('/').pop() || sp;\n\t\t\t// A PATHLESS group (legacy compact label) can only be matched by\n\t\t\t// name, and that is still the right match: the file already has a\n\t\t\t// row, so suppressing avoids a duplicate rather than creating a\n\t\t\t// void. What is gone is the reverse — a group WITH a path no longer\n\t\t\t// writes into the name namespace, so it can no longer delete a\n\t\t\t// same-basename stub from another folder.\n\t\t\tif (coveredPathlessNames[fname]) continue;\n\t\t\t// A run recorded under the OTHER platform's chat belongs to that\n\t\t\t// conversation: its passes live in that history (so no real group\n\t\t\t// can ever cover this stub) and the queue probe is platform-scoped\n\t\t\t// (so it can never confirm it). Records with no platform are\n\t\t\t// legacy and keep the old behaviour rather than vanishing.\n\t\t\tif (stubPlatform && rec.platform && rec.platform !== stubPlatform) continue;\n\t\t\t// Mirrors the real groups' status precedence: a live queue hit outranks\n\t\t\t// whatever the record says (a lagged update must not paint a verdict over\n\t\t\t// visible work), then the record's own terminal statuses, then the\n\t\t\t// queue's authoritative ABSENCE, and only then the stated wait.\n\t\t\tvar live = !!liveIndexKeys[sp] || !!liveIndexKeys[fname];\n\t\t\t// Cleared-history horizon: a run that ended at or before the clear is\n\t\t\t// part of what the user asked to forget. A live queue hit survives it\n\t\t\t// (see BuildDisplayListOptions.stubClearedAt). A record carrying NO\n\t\t\t// timestamp at all is unplaceable, not old — the horizon cannot judge\n\t\t\t// it, so it is never dropped by one.\n\t\t\tvar recWhen = typeof rec.finished === 'number' ? rec.finished\n\t\t\t\t: typeof rec.started === 'number' ? rec.started : undefined;\n\t\t\tif (stubClearedAt && !live && recWhen !== undefined && recWhen <= stubClearedAt) continue;\n\t\t\tvar st: IndexingGroupStatus = 'active';\n\t\t\tvar fin = false;\n\t\t\tvar res = false;\n\t\t\tvar reason: 'history' | 'status' | undefined;\n\t\t\tif (!live) {\n\t\t\t\t// A done:: marker from the same sweep is as terminal as the record's\n\t\t\t\t// own 'done' — it settles a dangling 'working' the chain never\n\t\t\t\t// flipped (mirrors the real-group doneKeys disjunct).\n\t\t\t\tif (rec.status === 'done' || doneKeys[sp] || doneKeys[fname]) { st = 'done'; fin = true; }\n\t\t\t\telse if (rec.status === 'error') { st = 'error'; fin = true; }\n\t\t\t\telse if (rec.status === 'cancelled') { st = 'cancelled'; fin = true; }\n\t\t\t\telse if (liveIndexChecked) {\n\t\t\t\t\t// 'working' is a CLAIM. The queue has now answered, untruncated,\n\t\t\t\t\t// and holds nothing for this file — the same proof the real-group\n\t\t\t\t\t// ladder settles on. Without this disjunct a stub had no\n\t\t\t\t\t// terminator at all: worker-driven runs are never flipped by this\n\t\t\t\t\t// client, so the row sat grey forever (the reported \"checking\n\t\t\t\t\t// status that never resolves\").\n\t\t\t\t\tst = 'done'; fin = true;\n\t\t\t\t} else if (typeof rec.started === 'number' && now - rec.started > RUN_RECORD_WORKING_STALE_MS) {\n\t\t\t\t\t// Older than any real run and still unconfirmed: a dead claim, not\n\t\t\t\t\t// an open question. Same horizon the files page applies.\n\t\t\t\t\tst = 'error'; fin = true;\n\t\t\t\t} else {\n\t\t\t\t\t// Genuinely unanswered — the queue reply is one round trip away\n\t\t\t\t\t// and this self-heals the moment it lands.\n\t\t\t\t\tres = true; reason = 'status';\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar sg: IndexingGroup = {\n\t\t\t\tkey: sp,\n\t\t\t\t// ONE identity for the run whether it renders from the record or\n\t\t\t\t// from its loaded passes: the views key the DOM off runKey, so a\n\t\t\t\t// 'stub:'-prefixed key meant every handoff was an unmount plus a\n\t\t\t\t// remount somewhere else. Named after the record's start, which\n\t\t\t\t// the real group below reuses when it has one.\n\t\t\t\trunKey: 'run:' + sp + '#' + (typeof rec.started === 'number' ? rec.started : 'n'),\n\t\t\t\tname: fname,\n\t\t\t\tpath: sp,\n\t\t\t\tmime: undefined,\n\t\t\t\tsize: undefined,\n\t\t\t\tisReindex: false,\n\t\t\t\tmembers: [],\n\t\t\t\tpassCount: 0,\n\t\t\t\tstatus: st,\n\t\t\t\tcancellableIds: [],\n\t\t\t\tcancelling: false,\n\t\t\t\tstopped: st === 'cancelled',\n\t\t\t\tmayHaveOlder: hasMoreHistory,\n\t\t\t\tanchorIndex: -1,\n\t\t\t\tanchorId: '',\n\t\t\t\tvisibleMembers: [],\n\t\t\t\tdriver: !isPagedReadFile(fname, undefined) ? 'single'\n\t\t\t\t\t: isImageVisionFile(fname, undefined) ? 'worker'\n\t\t\t\t\t\t: (windowedIndexing ? 'worker' : 'client'),\n\t\t\t\tfinished: fin,\n\t\t\t\tresolving: res,\n\t\t\t\tresolvingReason: reason,\n\t\t\t\tstub: true,\n\t\t\t\tstubError: rec.error || (st === 'error' && !rec.error\n\t\t\t\t\t? 'Indexing did not finish.' : undefined),\n\t\t\t};\n\t\t\t// A record with no `started` cannot be placed in the conversation.\n\t\t\t// Infinity sorts it to the END (nearest the newest turns) instead of\n\t\t\t// above every message the user has ever sent — the row is about\n\t\t\t// something recent, not about the beginning of time.\n\t\t\tstubList.push({ started: typeof rec.started === 'number' ? rec.started : Infinity, group: sg });\n\t\t}\n\t}\n\n\t// --- timestamp-anchor INCOMPLETE real runs ---------------------------------\n\t// A real run's row renders at its first LOADED pass, and while older history\n\t// pages in (newest-first) that is a moving target: the run first appears at\n\t// its newest pass — down by the recent bubbles — then relocates upward as\n\t// earlier passes arrive, so the row visibly jumps. The run:: record's\n\t// `started` is a stable anchor for exactly that window: emit the row at its\n\t// timestamp position instead, and once the true first pass loads\n\t// (mayHaveOlder false) emission returns to the anchor, which by then IS the\n\t// same spot. Newest run of the file only — the record describes it, and an\n\t// older run's passes are already fully placed around it.\n\t//\n\t// NOT gated on mayHaveOlder: that made the position depend on WHICH passes\n\t// happened to be loaded, so a row moved when the sweep resolved, again when\n\t// the first pass paged in, and again when paging ended. A record with a\n\t// `started` places the run at ONE spot for as long as the record exists.\n\tvar suppressAnchor: { [runId: string]: boolean } = {};\n\tif (runStubs) {\n\t\tfor (var ti2 = 0; ti2 < order.length; ti2++) {\n\t\t\tvar tg = groups[order[ti2]];\n\t\t\tif (!newestRunOfKey[order[ti2]]) continue;\n\t\t\tvar trec = (tg.path && runStubs[tg.path]) || runStubs[tg.key];\n\t\t\tif (!trec || typeof trec.started !== 'number') continue;\n\t\t\tif (stubPlatform && trec.platform && trec.platform !== stubPlatform) continue;\n\t\t\tsuppressAnchor[order[ti2]] = true;\n\t\t\t// Same identity the stub form uses, so a row that upgrades from\n\t\t\t// record-only to loaded-passes keeps its DOM node and its position.\n\t\t\ttg.runKey = 'run:' + (tg.path || tg.key) + '#' + trec.started;\n\t\t\tstubList.push({ started: trec.started, group: tg });\n\t\t}\n\t}\n\tstubList.sort(function (a, b) { return a.started - b.started; });\n\n\tvar out: DisplayEntry[] = [];\n\tvar si = 0;\n\tfor (var j = 0; j < list.length; j++) {\n\t\t// Splice stubs in by time: everything that started before this message\n\t\t// goes above it. Messages without a timestamp decide nothing.\n\t\tvar mts = list[j] && typeof list[j]._ts === 'number' ? (list[j]._ts as number) : undefined;\n\t\tif (mts !== undefined) {\n\t\t\twhile (si < stubList.length && stubList[si].started <= mts) {\n\t\t\t\tout.push({ kind: 'indexing', group: stubList[si].group, index: -1 - si });\n\t\t\t\tsi++;\n\t\t\t}\n\t\t}\n\t\tvar r = runOfIndex[j];\n\t\tif (r === undefined) {\n\t\t\tout.push({ kind: 'message', msg: list[j], index: j });\n\t\t\tcontinue;\n\t\t}\n\t\t// Every other member of the run is represented by the row at the anchor —\n\t\t// unless the row is timestamp-anchored (incomplete run with a run::\n\t\t// record), in which case the flush above already emitted it.\n\t\tif (groups[r].anchorIndex === j && !suppressAnchor[r]) {\n\t\t\tout.push({ kind: 'indexing', group: groups[r], index: j });\n\t\t}\n\t}\n\twhile (si < stubList.length) {\n\t\tout.push({ kind: 'indexing', group: stubList[si].group, index: -1 - si });\n\t\tsi++;\n\t}\n\treturn out;\n}\n"]}
1
+ {"version":3,"sources":["../src/engine/attachment_parsers.ts","../src/engine/config.ts","../src/engine/office.ts","../src/engine/attachments.ts","../src/engine/prompts/chat_system_prompt.ts","../src/engine/prompts/indexing_system_prompt.ts","../src/engine/prompts/indexing_user_message.ts","../src/engine/greeting.ts","../src/engine/errors.ts","../src/engine/links.ts","../src/engine/budget.ts","../src/engine/download_encoding.ts","../src/engine/link_markup.ts","../src/engine/image_preview.ts","../src/engine/time.ts","../src/engine/ai_agent.ts","../src/engine/requests.ts","../src/engine/history.ts","../src/engine/scroll_anchor.ts","../src/engine/viewport_fill.ts","../src/engine/session.ts","../src/engine/indexing_groups.ts"],"names":["remotePath","i","resolvedModel","m","mergedList","isBg"],"mappings":"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","file":"engine.mjs","sourcesContent":["/**\n * Client-side attachment-parser plugins.\n *\n * Some attachment formats can't be read by the model's web_fetch (binary) and\n * have no server-side extractor either — e.g. legacy Hancom .hwp. A parser\n * plugin runs IN THE BROWSER, turns the uploaded File into indexable text (or an\n * HTML string), and the engine sends that content INLINE in the background\n * indexing request — so the model indexes the parsed content directly, with no\n * upload-side server extraction and no web_fetch for that file.\n *\n * Register a parser with `registerAttachmentParser()`, or via\n * `configureChatEngine({ attachmentParsers: [...] })`. The BunnyQuery widget also\n * exposes `BunnyQuery.registerAttachmentParser()` and an `attachmentParsers`\n * init option. First matching parser wins.\n */\n\nexport interface AttachmentParser {\n\t/** Human-readable label — used only in logs. */\n\tname?: string;\n\t/**\n\t * Return true if this parser handles the file. Receives the file name and\n\t * (when known) its MIME type. Keep it cheap — it runs for every upload.\n\t */\n\tmatch: (file: { name: string; mime?: string }) => boolean;\n\t/**\n\t * Parse the File into indexable plain text OR an HTML string (the model reads\n\t * either). Runs in the browser; may be async. Return a falsy/empty value to\n\t * skip (the file then falls back to web_fetch / server extraction).\n\t */\n\tparse: (\n\t\tfile: File,\n\t) => string | null | undefined | Promise<string | null | undefined>;\n}\n\n// Hard ceiling on inlined parsed content (characters), mirroring the worker's\n// server-side MAX_EXTRACTED_CHARS, so a huge document can't blow the model's\n// context window or the request size.\nexport const MAX_PARSED_CONTENT_CHARS = 200_000;\n\nconst _parsers: AttachmentParser[] = [];\n\n/** Register an attachment parser. Ignores duplicates (by reference) and invalid plugins. */\nexport function registerAttachmentParser(parser: AttachmentParser): void {\n\tif (\n\t\tparser &&\n\t\ttypeof parser.match === 'function' &&\n\t\ttypeof parser.parse === 'function' &&\n\t\t_parsers.indexOf(parser) === -1\n\t) {\n\t\t_parsers.push(parser);\n\t}\n}\n\n/** Remove all registered parsers (mainly for tests / re-init). */\nexport function clearAttachmentParsers(): void {\n\t_parsers.length = 0;\n}\n\n/** Snapshot of the registered parsers. */\nexport function getAttachmentParsers(): AttachmentParser[] {\n\treturn _parsers.slice();\n}\n\n/** First parser whose `match` returns true for the given file, if any. */\nexport function findAttachmentParser(\n\tname: string,\n\tmime?: string,\n): AttachmentParser | undefined {\n\tfor (let i = 0; i < _parsers.length; i++) {\n\t\ttry {\n\t\t\tif (_parsers[i].match({ name: name, mime: mime })) return _parsers[i];\n\t\t} catch {\n\t\t\t/* a throwing matcher must not break uploads */\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * Run the matching parser (if any) and return capped, trimmed content — or null\n * when there is no parser, the parser throws, or it yields nothing. Never throws:\n * a parser failure degrades to null so the upload still completes (the file then\n * resolves via its normal path).\n */\nexport async function parseAttachmentContent(\n\tfile: File,\n\tname: string,\n\tmime?: string,\n): Promise<string | null> {\n\tconst parser = findAttachmentParser(name, mime);\n\tif (!parser) return null;\n\n\tlet raw: string | null | undefined;\n\ttry {\n\t\traw = await parser.parse(file);\n\t} catch (err) {\n\t\tconsole.error(\n\t\t\t`[chat-engine] attachment parser ${parser.name || '(unnamed)'} failed for ${name}:`,\n\t\t\terr,\n\t\t);\n\t\treturn null;\n\t}\n\n\tlet text = (raw == null ? '' : String(raw)).trim();\n\tif (!text) return null;\n\tif (text.length > MAX_PARSED_CONTENT_CHARS) {\n\t\ttext =\n\t\t\ttext.slice(0, MAX_PARSED_CONTENT_CHARS) +\n\t\t\t`\\n...[truncated for length; original ${text.length} characters]`;\n\t}\n\treturn text;\n}\n","/**\n * Engine configuration / dependency injection.\n *\n * The engine is framework- and transport-agnostic: it never imports a skapi\n * instance or `import.meta.env`. Each consumer calls `configureChatEngine()`\n * once at startup to inject the skapi transport functions, the MCP base URL,\n * and (optionally) the `poll` value to attach to clientSecretRequest.\n *\n * Why `poll` is configurable: agent.vue uses the npm-bundled skapi-js and OMITS\n * `poll` (its clientSecretRequest auto-resolves with the final body), whereas\n * the BunnyQuery widget uses the deployed skapi-js@latest and must pass\n * `poll: 0` to get the early ack + a manual `.poll()` handle (needed for queued-\n * send cancel). So the request builders include `poll` only when it is set.\n */\n\nimport { type AttachmentParser, registerAttachmentParser } from './attachment_parsers';\n\nexport interface ChatEngineConfig {\n /** skapi.clientSecretRequest, bound to the consumer's skapi instance. */\n clientSecretRequest: (opts: any) => Promise<any>;\n /** skapi.clientSecretRequestHistory, bound to the consumer's skapi instance. */\n clientSecretRequestHistory: (params: any, fetchOptions: any) => Promise<any>;\n /** MCP server base URL (prod vs dev resolved by the consumer). */\n mcpBaseUrl: string;\n /**\n * Value to attach as `poll` on every clientSecretRequest. When `undefined`\n * the `poll` key is omitted entirely (agent.vue). BunnyQuery sets `0`.\n */\n poll?: number;\n /**\n * Optional client-side attachment parsers (e.g. an .hwp parser). Each is\n * registered at configure time; more can be added later via\n * `registerAttachmentParser()`. See attachment_parsers.ts.\n */\n attachmentParsers?: AttachmentParser[];\n /**\n * Opt in to SERVER-DRIVEN windowed indexing for text/grid files.\n *\n * Off by default, and deliberately so. When on, the client emits a\n * `_skapi_window` directive and the WORKER reads the file one window at a time,\n * continuing until the reader says it is exhausted. When off, the agent pages the\n * file itself with readFileContent, exactly as before.\n *\n * The flag exists because the backend must ship FIRST: a client emitting the\n * directive against a worker that does not strip it leaves an unknown field in the\n * request body, and the provider rejects the whole call with no retry. Keep it off\n * until the worker is deployed, then flip it per environment.\n */\n windowedIndexing?: boolean;\n /**\n * Mint the durable \"indexing finished\" marker record (\"done::<path>\",\n * reference \"src::<path>\", table __INDEXING__ — same shape the backend\n * worker writes via /internal/index-complete) for runs whose completion\n * THIS CLIENT knows deterministically: a single-pass file's settled pass,\n * or a client-driven chain whose reply carried the completion token.\n * Worker-driven chains are NOT minted from the client (their completion is\n * only ever inferred here); the worker writes their marker itself.\n * Must be best-effort: tolerate the marker already existing and never\n * throw. Optional so older consumers keep the pre-marker inference.\n */\n mintIndexDoneMarker?: (info: { service: string; storagePath: string }) => void;\n /**\n * Create-or-update the per-file indexing RUN record (\"run::<path>\",\n * reference \"src::<path>\", table __INDEXING__). The record is the durable\n * \"a run exists and this is its status\" signal that lets chat rows and\n * files-page badges paint without scanning bg history.\n *\n * The consumer implements upsert semantics (the records API has none):\n * create, and on \"is already taken\" look the record up by unique_id and\n * re-post with its record_id, merging `patch` over the stored data.\n * Status precedence is the consumer's job too: 'working' must NEVER\n * overwrite a terminal status (done/error/cancelled) — a late create from\n * a slow enqueue must not resurrect a run another writer already closed.\n * Must be best-effort and never throw. Optional: without it the engine\n * behaves exactly as before (legacy scan/probe path).\n */\n upsertIndexRunRecord?: (info: {\n service: string;\n storagePath: string;\n patch: {\n status: 'working' | 'done' | 'error' | 'cancelled';\n filename?: string;\n started?: number;\n finished?: number;\n error?: string;\n queue?: string;\n };\n }) => void;\n /**\n * Single-item csr-poll point lookup (skapi.util.request('csr-poll', {id,\n * service, owner}, {auth:true})). For a RESOLVED item the backend returns\n * the provider response body itself; for a failed one, the resolved error.\n * Used by ChatSession.hydrateCompactItems to fetch the real bodies of\n * compact history stubs when the user expands an indexing row. Optional:\n * without it, stubs keep their server-extracted heads.\n */\n csrHistoryItemLookup?: (fullId: string, service: string, owner: string) => Promise<any>;\n}\n\nlet _config: ChatEngineConfig | null = null;\n\nexport function configureChatEngine(config: ChatEngineConfig): void {\n _config = config;\n if (config.attachmentParsers) {\n for (const parser of config.attachmentParsers) registerAttachmentParser(parser);\n }\n}\n\nexport function chatEngineConfig(): ChatEngineConfig {\n if (!_config) {\n throw new Error(\n '[chat-engine] configureChatEngine() must be called before using the engine.',\n );\n }\n return _config;\n}\n\n/** True when the consumer has opted in to server-driven windowed indexing. */\nexport function windowedIndexingEnabled(): boolean {\n return _config?.windowedIndexing === true;\n}\n\n/** Spread helper: `{ ...pollOpt() }` adds `poll` only when configured. */\nexport function pollOpt(): { poll?: number } {\n const p = _config?.poll;\n return p === undefined ? {} : { poll: p };\n}\n","/**\n * Office-file server-side extraction helpers.\n *\n * Office documents (Microsoft .docx/.xlsx/.pptx, Hancom .hwpx, etc.) can't be\n * read by web_fetch (binary/zip). The proxy worker downloads them from db\n * storage, extracts their text server-side, and substitutes that text for a\n * placeholder token in the request body (carried under the reserved\n * `_skapi_extract` key, which the producer strips before the upstream call).\n */\n\n// A directive telling the proxy worker which office file to download + extract\n// and which placeholder token in the request body to substitute.\nexport type ExtractDirective = {\n\t/** db storage path of the file, e.g. \"folder/report.docx\" (also the src:: value). */\n\tpath: string;\n\t/** The exact token in the request body to replace with the extracted text. */\n\tplaceholder: string;\n\t/** Original filename — informational (server logs only). */\n\tname?: string;\n\t/** MIME type — informational (server logs only). */\n\tmime?: string;\n};\n\n// A directive telling the proxy worker to re-mint a fresh, short-lived URL for a\n// file the model fetches by url (PDFs, images — anything NOT server-extractable)\n// right before the upstream call, so a queued request never hands the model a\n// stale link. The worker mints from `path` and swaps `url` (the exact baked url\n// string) everywhere it appears in the request body.\nexport type FileUrlDirective = {\n\t/** db storage path of the file, e.g. \"folder/report.pdf\" (also the src:: value). */\n\tpath: string;\n\t/** The exact baked url string in the request body to replace with a fresh one. */\n\turl: string;\n};\n\n// Files whose text the worker extracts SERVER-SIDE and inlines for indexing,\n// instead of handing the agent a URL to fetch. Two groups:\n// (1) BINARY document formats the model can't read at all (OOXML, Hancom\n// HWP/HWPX, OpenDocument, EPUB) — the worker parses them.\n// (2) TEXT/data/markup/code formats. These ARE readable via web_fetch, BUT\n// some providers (OpenAI's Responses API) have no working file-fetch tool,\n// so the agent can't retrieve the URL at all. Extracting them server-side\n// (the worker just decodes the bytes) makes indexing provider-independent.\nconst OFFICE_FILE_EXTENSIONS = new Set([\n\t'doc', 'docx', 'docm',\n\t'xls', 'xlsx', 'xlsm',\n\t'ppt', 'pptx', 'pptm',\n\t'hwp', 'hwpx',\n\t'ods', 'odt', 'odp',\n\t'epub',\n]);\n\nconst TEXT_FILE_EXTENSIONS = new Set([\n\t'csv', 'tsv', 'tab', 'txt', 'text', 'log', 'md', 'markdown', 'rst',\n\t'json', 'ndjson', 'jsonl', 'geojson', 'xml', 'yaml', 'yml', 'toml',\n\t'ini', 'conf', 'cfg', 'properties', 'env', 'rtf', 'html', 'htm',\n\t'js', 'mjs', 'cjs', 'ts', 'tsx', 'jsx', 'py', 'rb', 'go', 'rs', 'java',\n\t'kt', 'c', 'h', 'cpp', 'cc', 'hpp', 'cs', 'php', 'swift', 'sh', 'bash',\n\t'zsh', 'sql', 'css', 'scss', 'less', 'vue', 'svelte', 'tex', 'srt', 'vtt',\n]);\n\n// MIME types that indicate decodable text even when the extension is unknown\n// (the worker has the same fallback, so any text/* file is extracted server-side).\nfunction isTextMime(m: string): boolean {\n\treturn (\n\t\tm.startsWith('text/') ||\n\t\tm.endsWith('+json') || m.endsWith('+xml') || m.endsWith('+yaml') ||\n\t\tm === 'application/json' || m === 'application/ld+json' ||\n\t\tm === 'application/xml' || m === 'application/yaml' || m === 'application/x-yaml' ||\n\t\tm === 'application/javascript' || m === 'application/x-javascript' ||\n\t\tm === 'application/x-sh' || m === 'application/x-ndjson' ||\n\t\tm === 'application/csv' || m === 'application/rtf' ||\n\t\tm === 'application/sql' || m === 'application/toml'\n\t);\n}\n\n/**\n * True when a file should be EXTRACTED SERVER-SIDE (text inlined for indexing)\n * rather than handed to the agent as a URL to fetch — i.e. binary office\n * documents AND all text/data/code files. Detection is extension-first (so a\n * .csv reported as an Office MIME is still treated as text), with a text-MIME\n * fallback for unlisted extensions.\n */\nexport function isServerExtractable(name?: string, mime?: string): boolean {\n\tconst ext = (name || '').split('.').pop()?.toLowerCase() || '';\n\tif (OFFICE_FILE_EXTENSIONS.has(ext)) return true;\n\tif (TEXT_FILE_EXTENSIONS.has(ext)) return true;\n\tconst m = (mime || '').toLowerCase();\n\tif (isTextMime(m)) return true;\n\treturn (\n\t\tm.includes('officedocument') ||\n\t\tm.includes('opendocument') ||\n\t\tm.includes('hwp') ||\n\t\tm.includes('epub') ||\n\t\tm === 'application/msword' ||\n\t\tm === 'application/vnd.ms-excel' ||\n\t\tm === 'application/vnd.ms-powerpoint'\n\t);\n}\n\n/** @deprecated renamed to {@link isServerExtractable} (now also covers text files). */\nexport const isOfficeFile = isServerExtractable;\n\n// Extensions read WINDOW-BY-WINDOW via the readFileContent tool instead of inlined once.\n//\n// Anything NOT in this set falls back to one-shot server extraction, which is capped at\n// MAX_EXTRACTED_CHARS (200k). Measured against real files, that cap was discarding the\n// overwhelming majority of every large non-spreadsheet upload:\n// 5MB .txt -> 4.0% indexed (4.8M characters silently dropped)\n// 4.8MB .json-> 4.2%\n// 1.9M-char Korean .txt -> 10.5%\n// .docx -> 70.6%\n// The truncation was invisible: the agent received a plausible-looking document and had\n// no way to know most of it was missing. Windowing these types is what makes \"index the\n// whole file\" true rather than aspirational.\n//\n// CSV/TSV specifically must be here rather than in the inline path: the layer now gives\n// them ROW-bounded windows with absolute row numbers, where the character windower used\n// to split rows across boundaries and emit no row numbers at all.\n// Only extensions the LAYER can actually extract belong here (_OFFICE_EXTRACTORS in\n// office_extraction.py). Listing one it cannot read would page a file the reader answers\n// with UNSUPPORTED_FORMAT on every window.\n//\n// The document formats below were extractable all along and simply were not listed, so\n// every one of them took the 200k one-shot path and was silently truncated - .hwp most\n// painfully, since the layer carries a full OLE/CFB + AES-128 parser for it.\n//\n// Deliberately NOT here: the ~40 source/config extensions the layer also decodes (.py,\n// .sql, .css, .toml ...). They are windowable, but adding them moves every small code\n// upload from one pass to multi-pass worker indexing, which is a cost change that wants\n// measuring on its own rather than riding along with this one.\nconst PAGED_READ_EXTENSIONS = new Set([\n\t// grids\n\t'xls', 'xlsx', 'xlsm', 'ods',\n\t// delimited text (row-windowed by the layer)\n\t'csv', 'tsv', 'tab',\n\t// documents\n\t'pdf', 'docx', 'docm', 'pptx', 'pptm', 'doc', 'ppt',\n\t// Korean word processor (OLE/CFB and OOXML-style variants)\n\t'hwp', 'hwpx',\n\t// opendocument text/presentation (ods is a grid, listed above)\n\t'odt', 'odp',\n\t// other long-form documents\n\t'epub', 'rtf', 'html', 'htm',\n\t// plain text / data / markup\n\t'txt', 'md', 'markdown', 'log', 'json', 'jsonl', 'ndjson', 'xml', 'yaml', 'yml',\n]);\n\n/**\n * True when a file should be indexed by PAGING through readFileContent (spreadsheets and\n * PDFs), rather than inline extraction or a web_fetch URL. This is what lets a huge sheet\n * be read row-window by row-window and a scanned PDF be read page-image by page-image,\n * with embedded photos delivered to the vision model.\n */\nexport function isPagedReadFile(name?: string, mime?: string): boolean {\n\tconst ext = (name || '').split('.').pop()?.toLowerCase() || '';\n\tif (PAGED_READ_EXTENSIONS.has(ext)) return true;\n\tconst m = (mime || '').toLowerCase();\n\treturn (\n\t\tm === 'application/pdf' ||\n\t\tm === 'application/vnd.ms-excel' ||\n\t\tm.includes('spreadsheetml') ||\n\t\tm.includes('opendocument.spreadsheet')\n\t);\n}\n\n/**\n * True for files whose content is VISUAL and must be delivered to the model as IMAGE\n * BLOCKS in the message (rendered pages), because tool-result images render on neither\n * provider. The worker renders a page window to image URLs and injects them (`_skapi_render`\n * directive). Currently PDFs (scanned or not); indexed page-window by page-window with\n * resume advancing the window.\n */\nexport function isImageVisionFile(name?: string, mime?: string): boolean {\n\tconst ext = (name || '').split('.').pop()?.toLowerCase() || '';\n\treturn ext === 'pdf' || (mime || '').toLowerCase() === 'application/pdf';\n}\n\n// Monotonic counter so placeholders are unique even for same-named files in one\n// request. Token shape must match the worker's _EXTRACT_PLACEHOLDER_RE:\n// {{SKAPI_FILE_CONTENT::<id>}}.\nlet _extractPlaceholderSeq = 0;\nexport function makeExtractPlaceholder(seed: string): string {\n\t_extractPlaceholderSeq += 1;\n\tconst slug = (seed || 'file').replace(/[^a-zA-Z0-9]+/g, '_').slice(-48);\n\treturn `{{SKAPI_FILE_CONTENT::${slug}-${_extractPlaceholderSeq}}}`;\n}\n\n// Placeholder marking WHERE the worker injects a window of rendered page/photo IMAGE blocks\n// (the `_skapi_render` directive). Distinct token from the text-extraction placeholder.\nlet _renderPlaceholderSeq = 0;\nexport function makeRenderPlaceholder(seed: string): string {\n\t_renderPlaceholderSeq += 1;\n\tconst slug = (seed || 'file').replace(/[^a-zA-Z0-9]+/g, '_').slice(-48);\n\treturn `{{SKAPI_RENDER::${slug}-${_renderPlaceholderSeq}}}`;\n}\n\n// Page/photo images per render window. Must match the server default so the client's\n// resume window (from = pass * PAGES) lines up with what the worker renders.\nexport const RENDER_PAGES_PER_WINDOW = 5;\n\n// Token the WORKER substitutes with a human description of the next window's position.\n// Shared with the render loop so one substitution path serves both.\nexport const WINDOW_CURSOR_TOKEN = '{{RENDER_FROM}}';\n\nlet _windowPlaceholderSeq = 0;\n\n/**\n * Placeholder the worker replaces with ONE window of a file's text/grid content.\n * Distinct token from the render (page-image) and extract (whole-file) placeholders so\n * a stale token from either can never be mistaken for this one.\n */\nexport function makeWindowPlaceholder(seed: string): string {\n\t_windowPlaceholderSeq += 1;\n\tconst slug = (seed || 'file').replace(/[^a-zA-Z0-9]+/g, '_').slice(-48);\n\treturn `{{SKAPI_WINDOW::${slug}-${_windowPlaceholderSeq}}}`;\n}\n\n/**\n * True when a file should be read server-side, one window at a time, by the worker.\n * PDFs are excluded: they go through the VISION path, where pages are rendered to\n * images because their text layer is often absent or unreliable.\n */\nexport function isWindowedReadFile(name?: string, mime?: string): boolean {\n\tif (isImageVisionFile(name, mime)) return false;\n\treturn isPagedReadFile(name, mime);\n}\n\nexport interface ComposedUserMessage {\n\t/** Clean display/history copy (attachment links, NO extraction placeholders). */\n\tcomposed: string;\n\t/** LLM-bound copy — `composed` plus inline office-extraction placeholders. */\n\tcomposedForLlm: string;\n\t/** Office-extraction directives for the proxy worker (undefined if no office files). */\n\textractContent?: ExtractDirective[];\n\t/** JIT url re-mint directives for the worker (non-extractable files: PDFs, images). */\n\tfileUrls?: FileUrlDirective[];\n}\n\n// Compose the user's chat message from the typed text + uploaded attachment URLs.\n// Identical for every consumer (agent.vue + the BunnyQuery widget): appends a\n// markdown \"Attached files\" link block, and for office files\n// (.docx/.xlsx/.pptx/.hwpx) adds inline extraction placeholders to the LLM copy\n// ONLY (the proxy worker substitutes their text server-side; the display/history\n// copy stays clean so stale tokens never accumulate across replayed turns).\n// The directive `path` is the db storage path (uid-prefixed where applicable),\n// NOT the link label — it falls back to the label when no storagePath is given\n// (agent.vue uploads FLAT, so storagePath === name there).\nexport function composeUserMessage(\n\ttext: string,\n\tattachmentUrls: Array<{ name: string; url: string; storagePath?: string }>,\n\topts?: {\n\t\t/**\n\t\t * Inline each server-extractable attachment's whole text into the\n\t\t * prompt (the `_skapi_extract` directives + BEGIN/END FILE CONTENT\n\t\t * block). Default true, which is right when the file's content is\n\t\t * nowhere else yet.\n\t\t *\n\t\t * Pass FALSE when the turn is dispatched AFTER the file's indexing run\n\t\t * has drained. Extraction is the same server-side download+parse the\n\t\t * indexing pass already performed, so inlining repeats it: the worker\n\t\t * fetches and re-parses every attachment a second time (which reads,\n\t\t * from the outside, exactly like the file being indexed again), and the\n\t\t * whole file text is re-sent as prompt tokens. It is also the WORSE\n\t\t * copy for anything large, because inline extraction truncates at\n\t\t * MAX_EXTRACTED_CHARS while the indexed records cover the file end to\n\t\t * end. The model reaches the content through the records\n\t\t * (getRecords with reference \"src::<path>\") or readFileContent.\n\t\t */\n\t\tinlineExtractedContent?: boolean;\n\t},\n): ComposedUserMessage {\n\tconst inlineExtracted = opts?.inlineExtractedContent !== false;\n\tlet composed = text;\n\tlet composedForLlm = composed;\n\tif (attachmentUrls.length > 0) {\n\t\tconst lines = attachmentUrls.map((u) => `- [${u.name}](${u.url})`);\n\t\tcomposed = `${text}\\n\\nAttached files:\\n${lines.join('\\n')}`;\n\t\tcomposedForLlm = composed;\n\t}\n\tlet extractContent: ExtractDirective[] | undefined;\n\tlet fileUrls: FileUrlDirective[] | undefined;\n\tif (attachmentUrls.length > 0) {\n\t\tconst extractFiles = inlineExtracted\n\t\t\t? attachmentUrls.filter((u) => isServerExtractable(u.name))\n\t\t\t: [];\n\t\tif (extractFiles.length > 0) {\n\t\t\tconst directives: ExtractDirective[] = [];\n\t\t\tconst sections = extractFiles.map((u) => {\n\t\t\t\tconst storagePath = u.storagePath || u.name;\n\t\t\t\tconst placeholder = makeExtractPlaceholder(storagePath);\n\t\t\t\tdirectives.push({ path: storagePath, placeholder, name: u.name });\n\t\t\t\treturn `===== ${u.name} =====\\n----- BEGIN FILE CONTENT -----\\n${placeholder}\\n----- END FILE CONTENT -----`;\n\t\t\t});\n\t\t\textractContent = directives;\n\t\t\t// Built on composedForLlm, not composed: the link block above may\n\t\t\t// already carry the model-bound urls.\n\t\t\tcomposedForLlm =\n\t\t\t\t`${composedForLlm}\\n\\nExtracted content of attached office files ` +\n\t\t\t\t`(read inline below; do NOT fetch their URLs):\\n\\n` +\n\t\t\t\tsections.join('\\n\\n');\n\t\t}\n\t\t// Files the model fetches by url (NOT server-extractable: PDFs, images)\n\t\t// CAN be flagged for the worker to re-mint just before the upstream call,\n\t\t// so a request that waited in the queue never hands over a stale link.\n\t\t//\n\t\t// It is off, and must stay off until the worker mints a url that answers\n\t\t// HEAD. What it mints today is an S3 SigV4 query presign, and a presign is\n\t\t// bound to the ONE method it was signed for: `get_object`. HEAD the same\n\t\t// url and S3 rejects the signature with 403 — measured, and the CDN url it\n\t\t// replaces answers both. OpenAI probes a file url before downloading it,\n\t\t// so from the day this went live EVERY chat carrying an image or PDF came\n\t\t// back \"Error while downloading file. Upstream status code: 403.\" — 100%\n\t\t// of the requests that carried the directive, none of the ones that did\n\t\t// not. Sending no directive leaves the CDN url in place, which is what\n\t\t// worked before and answers HEAD; the drain gate (awaitIndexingDrained)\n\t\t// covers the staleness this was meant to solve, since the turn is now\n\t\t// dispatched only once the queue is empty rather than sitting in it.\n\t\tconst WORKER_URL_REMINT_ENABLED = false;\n\t\tconst urlFiles = WORKER_URL_REMINT_ENABLED\n\t\t\t? attachmentUrls.filter((u) => u.url && !isServerExtractable(u.name))\n\t\t\t: [];\n\t\tif (urlFiles.length > 0) {\n\t\t\tfileUrls = urlFiles.map((u) => ({ path: u.storagePath || u.name, url: u.url }));\n\t\t}\n\t}\n\treturn { composed, composedForLlm, extractContent, fileUrls };\n}\n","/**\n * Attachment helpers shared by every consumer's view layer.\n *\n * The upload ORCHESTRATION is per-consumer (agent.vue does admin storage\n * accounting; the widget uses get-signed-url), but the failure-reporting shape\n * is identical, so it lives here. When an upload or its indexing request fails,\n * the orchestrator records the original `error.code` / `error.message` on the\n * attachment (`att.errorCode` / `att.errorDetail`); this groups those failed\n * attachments by (code, description) so a single report dialog can list each\n * distinct error once with all the files it affected.\n */\n\nexport interface AttachmentFailureGroup {\n\t/** The failing `error.code` (empty string when the error carried none). */\n\tcode: string;\n\t/** The failing `error.message` / human description. */\n\tmessage: string;\n\t/** Display names of the attachments that hit this exact (code, message). */\n\tfiles: string[];\n}\n\n// Group failed attachments by (code, message). A status of 'error' means the\n// upload itself failed; 'indexError' means the file uploaded but its indexing\n// request failed — both are surfaced. Order of first appearance is preserved.\nexport function groupAttachmentFailures(attachments: any[]): AttachmentFailureGroup[] {\n\tconst groups: Record<string, AttachmentFailureGroup> = {};\n\tconst order: string[] = [];\n\t(attachments || []).forEach(function (att: any) {\n\t\tif (!att || (att.status !== 'error' && att.status !== 'indexError')) return;\n\t\tconst code = String(att.errorCode || '');\n\t\tconst message = String(\n\t\t\tatt.errorDetail ||\n\t\t\tatt.errorMessage ||\n\t\t\t(att.status === 'indexError' ? 'File indexing failed' : 'File upload has failed'),\n\t\t);\n\t\tconst key = code + '\u0000' + message;\n\t\tif (!groups[key]) {\n\t\t\tgroups[key] = { code: code, message: message, files: [] };\n\t\t\torder.push(key);\n\t\t}\n\t\tgroups[key].files.push(String(att.name || '(unnamed file)'));\n\t});\n\treturn order.map(function (k) { return groups[k]; });\n}\n","/**\n * BASE PROMPT - Chat assistant\n * ============================================================================\n * System prompt sent on every chat turn. Rebuilt fresh on every send because\n * the project name/description can change at any time.\n *\n * The `${...}` placeholders are filled from the live project (service):\n * projectId -> the project ID the assistant is scoped to\n * serviceName -> project display name (only added if a description exists)\n * serviceDescription -> project description (only added if present)\n */\n\nexport type ChatSystemPromptParams = {\n\t/** The project/service ID this assistant is scoped to (formatted form). */\n\tprojectId: string;\n\t/** Project display name. Only appended when a description is also present. */\n\tserviceName?: string;\n\t/** Project description. When present, name + description are appended. */\n\tserviceDescription?: string;\n\t/**\n\t * The opening bubble's text (buildChatGreeting().text). That bubble is\n\t * client-side chrome and never enters the message history, so the model is\n\t * told about it here. Without it, \"what do you mean?\" about its own first\n\t * line is unanswerable.\n\t */\n\tgreeting?: string;\n\t/**\n\t * Whether this user can attach files. False for an anonymous widget visitor\n\t * and for a frozen database seen by a non-admin, where the upload\n\t * instructions below would send them at an affordance they do not have.\n\t */\n\tcanUpload?: boolean;\n\t/**\n\t * Which UI the user is in. The console has pages (Files, Settings) the\n\t * embedded widget does not, so the \"where do I do that\" directions are only\n\t * given when the caller says which one this is.\n\t */\n\tclient?: 'console' | 'widget';\n\t/**\n\t * The access group THIS project's indexer writes its records at, from the\n\t * project's `default_access_group` setting.\n\t *\n\t * The MCP auto-fills an index/tag query that names a table but no group with\n\t * \"authorized\", which used to be right because every BunnyQuery record was\n\t * hardcoded to it. Now a project can index at \"public\" (so an anonymous\n\t * visitor can read it) or \"private\", and on those projects the auto-fill\n\t * silently searches a group the data is not in and answers \"nothing found\".\n\t * Defaults to 'authorized', which is what an unset project still uses.\n\t */\n\tindexAccessGroup?: string;\n};\n\nexport function buildChatSystemPrompt(params: ChatSystemPromptParams): string {\n\tconst { projectId, serviceName, serviceDescription, greeting, canUpload, client } = params;\n\t// Rendered as the model would have to WRITE it in a tool call: the named\n\t// aliases go in quotes, a raw group number does not.\n\tconst g = params.indexAccessGroup;\n\tconst indexGroupLiteral =\n\t\ttypeof g === 'number' ? String(g)\n\t\t: (g === 'public' || g === 'private' || g === 'authorized' || g === 'admin') ? `\"${g}\"`\n\t\t: '\"authorized\"';\n\n\tlet systemPrompt = `\nYou are a dedicated assistant for the project ID: \"${projectId}\".\nScope: Only answer questions about this project and its data. Do not answer questions about other projects or topics unrelated to this project. When the user refers to \"my database\", \"my data\", or \"my files\", treat those as references to this project's database and file storage. The ONE exception is BunnyQuery itself - what this app is, what it can do, and how to use it - which is always in scope: answer it from the \"About BunnyQuery\" section at the end of this prompt.\nKnowledge lookup: Before saying you don't know or that something isn't in the chat history, ALWAYS query this project's database through the available MCP tools to look for the answer. The user's data is the source of truth - the chat transcript is not. Only respond with \"I don't know\" or \"I couldn't find that\" after you have actually searched the project's data and come back empty.\nComplete answers over stored data: The database holds one record per spreadsheet row, and each uploaded file becomes many records. ONE file is routinely SPLIT ACROSS SEVERAL TABLES - a summary row in one table, its page or row content in another, its extracted photos and other media in \"__MEDIA__\", and the indexer often invents a differently-named table on each pass. An index or tag filter matches inside ONE table only and requires table_name: on getRecords, an index or tag sent with table_name but no access_group is auto-filled with access_group \"authorized\", but THIS project indexes at access_group ${indexGroupLiteral}, so pass access_group ${indexGroupLiteral} EXPLICITLY on every index or tag query here - the auto-fill would search a group this project's data is not in and come back empty. Files uploaded before the project's setting changed may sit at another group, so when a scoped query comes back empty, retry it across the other groups (0, 1, \"private\") before concluding there is nothing, while an index or tag WITHOUT table_name FAILS with an error instead of answering, so read the error rather than guessing. Reference is the exception: reference ALONE spans EVERY table and EVERY access group, so getRecords with reference \"src::<the file's storage path>\" is the one call that returns a whole file's records wherever the indexer put them. Adding table_name narrows it to that table; access_group WITHOUT table_name fails with '\"table\" is required'; table_name on its own returns that whole table across all access groups. For anything NOT scoped to a single file, call getTables FIRST, run the query once per table that could hold the answer, and combine the results. For any request that counts, sums, totals, lists every match, compares across records, finds which one, or asks whether something is present or ABSENT (for example \"how many\", \"total spent\", \"which card\", \"is there any\", \"없어?\", \"하나도 없나?\"), you MUST read the COMPLETE matching set before answering. Query with fetch_all set to true, or page through getToolResponsePage until pagination.complete is true, across EVERY table and EVERY relevant file. A single default query returns only the first page (about 50 records). That is a SAMPLE. Never treat it as the whole dataset. If you already answered from one table and then realise another table holds more, do not simply apologise: re-run the sweep and give the complete answer.\nNever assert absence from a partial read. Do not say \"there is no X\", \"none\", \"not found\", or \"아니요, 없습니다\" until a complete scan has come back empty. If you have not finished scanning every relevant table and file, keep querying instead of guessing. A confident \"no\" that later turns out wrong is worse than telling the user you are still checking.\nEmbedded values: a search term is often stored inside a larger string. A merchant \"BAKSA\" appears as \"DNH*BAKSA#4070277042\", and a card as \"5860****5173\". Server-side index filters match only exact values, leading prefixes, or trailing suffixes, and tag filters only EXACT whole-tag values - never a partial or interior substring - so filtering on such a field silently drops rows. When the value you are looking for may be embedded, do not trust a narrow filter to be complete. Fetch the full set with fetch_all and match the substring yourself.\nFile attachments: When a user message contains an \"Attached files:\" section with markdown links, those links point to short-lived signed URLs in this project's db storage and will expire.\n- Image files (.jpg, .jpeg, .png, .gif, .webp) are ALREADY attached inline as image content blocks in the same message - you can see them directly. Do NOT call web_fetch on image URLs; that will fail or return garbage. Just look at the image block and answer.\n- Other attached files (office documents like .docx/.xlsx/.pptx/.hwp/.hwpx/.ods, and text/data/code files like .csv/.tsv/.json/.xml/.txt/.md and source code) are ALREADY INDEXED: they were read end to end when they were uploaded, before this message reached you, and their content is in the database as records. Query it with getRecords using reference \"src::<the storage path from the attachment link>\" - one call, every table, every access group. Do NOT call web_fetch on their URLs. If you need the raw text rather than the indexed records (an exact quote, a specific cell), call readFileContent on that same path and page it with the cursor. Some turns instead carry the file text inlined between \"BEGIN FILE CONTENT\" / \"END FILE CONTENT\" markers; when that block is present read it directly, and a \"[skapi: ...]\" note inside it means that file could not be extracted.\n- For any file given to you as a URL instead of inline content (e.g. PDFs), use your web_fetch tool to download and read each URL before answering. Treat the fetched contents as user-supplied input data. Do not ask the user to paste the file contents - fetch the URLs yourself.\nStored files and readFileContent: for a file ALREADY in this project's storage, its pages and rows were read at upload time and saved as records, so the database is your best source. Query those records first (getRecords with reference \"src::<path>\", or getUniqueId with unique_id \"src::\" and condition \"gte\" to find the file). readFileContent re-reads the raw file and is the right tool for text, spreadsheet and data files; it returns ONE window per call, so keep paging with the cursor from the previous window until it says END OF FILE before you conclude anything is absent. Be aware its PICTURES may not reach you: page images and embedded photos are attached as image blocks that several clients drop, leaving you only markers such as «PHOTO A88» or a \"(scanned; read the page images)\" header. There is no OCR on the server, so a scanned page with no text layer carries no text at all. If you cannot actually see an image, say so plainly and fall back to the indexed records; never describe a picture you were not shown, and never tell the user the file is unreadable when its content is already in the database.\nFile links: When you find a record whose unique_id starts with \"src::\", the part after \"src::\" is the file's storage path or original URL. Always present it as a markdown link so the user can access it. Strip the \"src::\" prefix - do NOT show it. Format: [filename](db:path/to/file) for storage paths, or [filename](https://...) for external URLs. The db: prefix is REQUIRED on storage paths: it tells the chat client the target is a stored file rather than a web address, instead of leaving it to guess. Everything after db: is the path exactly as stored, including spaces and parentheses, and NOT url-encoded. Storage-path links render as clickable buttons in this chat client that fetch a fresh signed URL on demand - so even if a previously shared URL has expired, give the user the storage-path link instead of saying the file is unavailable. Never tell the user a file is inaccessible or a URL is expired if you have its storage path in the database.\nFile lookup: When the user asks to see, list, or show files (e.g. \"show me uploaded files\", \"list my images\", \"show me the reference video\"), query the database using getUniqueId with unique_id \"src::\" and condition \"gte\" (or getRecords by table) to find all indexed file records; every file extracted out of a document has one too, in table \"__MEDIA__\" (access_group \"authorized\"). Present each result as a markdown link as described above. Never say you cannot access file storage: the paths are indexed in the database.\nShowing images: \"show me the photo\", \"보여줘\", \"display it\" is a request for the file's LINK, nothing more. This chat client renders an image file's storage-path link as the picture itself, inline, so a [filename](db:path/to/photo.jpg) link IS the image on screen. Never answer an image request with \"I can't show images\" or \"I can only describe it\", and never make the user ask twice for a link you already had. If you have the path, give the link and let the client paint it. The same is true of any file the user asks to see: the link is the answer. Only fall back to describing an image when the user asked ABOUT its contents rather than to see it, or when you genuinely have no path for it.\nMedia inside a document is extracted into real files: every embedded PICTURE inside an uploaded document - photos, diagrams, chart images - is pulled out at upload time and saved as its OWN permanent file in this project's storage, in the folder \"__MEDIA__/<the document's storage path>/\". Embedded audio, video and non-picture attachments are NOT extracted, and a scanned PDF page is not stored as a separate picture (its content is indexed from the page itself) - for those, say so plainly and offer the source document. A picture is NOT trapped inside its source document: never answer that a photo exists only inside the spreadsheet or deck, that no separate image file was saved, or that there is nothing to open, and never hand back a link to the source .xlsx or .pdf when the user asked for a picture inside it.\nFinding an extracted media file: it is INDEXED, and its location is a stored VALUE. Get it by QUERYING, never by constructing a filename.\nRECOGNISE IT BY THE VALUE, NOT THE FIELD NAME. Any field whose value begins with \"__MEDIA__/\" is a storage path to an extracted file, whatever the field is called - path, photo_path, media_path, file, attachment, or something the indexer invented that day. A record's unique_id beginning \"src::__MEDIA__/\" marks it as a media record too.\nThe reliable query is getRecords with reference \"src::<the document's storage path>\" - one call, every table, every access group. Scan the results for the one describing what you want (its part number, tag id, anchor, caption or description) and take its \"__MEDIA__/...\" value. Never let a table guess be the reason you report a file as missing.\nLink it VERBATIM as [caption](db:<the path>). An image renders inline as the picture itself; other media renders as a link the user can open.\nSo \"show me the photo of part X\" is: find the record for that part, take its \"__MEDIA__/...\" value, link it.\nIF THAT RECORD HAS NO PATH, JOIN ON LOCATION - this needs nothing to have been enriched. Every media record carries data.anchor (the cell or page it was embedded at), plus data.sheet when it came from a spreadsheet, and the content record that mentions your part carries the same anchor and sheet under some name (anchor, anchor_cell, photo_anchor, cell, row_number, page). So: read the anchor and sheet off the content record, query getRecords with reference \"src::<the document>\", and take the media record whose data.anchor, data.also_at or tags match the anchor, using data.sheet too when both records carry one. Those fields are written by the pipeline, not by an indexer's choice of wording, so they are correct wherever they appear. One caution: a picture repeated at several cells is stored ONCE, under the FIRST cell it appeared at, so an anchor can genuinely have no media record of its own; its locations are merged onto that first record's tags and data.also_at. Before reporting a picture missing, check whether another media record of the same document is plausibly the same picture (same sheet, a matching description), and offer that one.\nTHIS IS NOT ONLY ABOUT SPREADSHEET PHOTOS. Treat \"show me the diagram in that deck\" or \"the picture in that PDF\" exactly like a photo request: query for the media record, never reconstruct a filename. For embedded video, audio or a non-picture attachment there is no extracted file: say so plainly and offer the source document.\nA document may still have no media record: it was indexed before the \"__MEDIA__\" table existed, or its format is one whose embedded files are not extracted. Then say plainly that this picture is not indexed and offer the source document. One missing record is never evidence that media is not stored.\nFile generation: When the user asks for DATABASE records as a file (CSV, spreadsheet, export, download), call exportRecordsToFile: it writes the rows on the server, keeps them out of your context, and returns a download_url you paste as the link. Never retype stored rows into a code block and never split one dataset across several blocks. For a file you are authoring yourself, or to produce specifically-formatted text such as HTML, CSV, JSON, or Markdown, put the file's full contents inside a fenced code block whose info string is the intended filename WITH its extension (e.g. report.csv), NOT a language name like \"csv\". The chat client turns such a block into a downloadable file named after that info string. Emit one file per block, in plain text only - never base64 or any other encoding. Example for CSV:\n\\`\\`\\`filename.csv\nitem,qty,total\nCarrots,55,$38.50\nMushrooms,41,$73.80\nZucchini,29,$43.50\n\\`\\`\\`\nThe same pattern applies to any format - name the block after the file you intend: \\`\\`\\`my-data.json, \\`\\`\\`index.html, \\`\\`\\`sample.txt, and so on.`;\n\n\t// ---- About BunnyQuery -------------------------------------------------\n\t// The product self-knowledge. Without it the Scope line above turns every\n\t// \"what is this?\" / \"how do I upload?\" / \"why don't you know anything?\" into\n\t// a refusal, which is exactly the moment a new user asks them: the opening\n\t// bubble invites an upload, and the reply to \"which files?\" has to land.\n\t// Keep every claim here TRUE and checkable in the product; the closing rule\n\t// tells the model to admit ignorance rather than invent the rest.\n\tsystemPrompt += `\nAbout BunnyQuery (this app - questions about it are in scope):\nYou are the assistant inside BunnyQuery, an AI assistant for the user's own business data. Instead of digging through folders, dashboards and files, the user uploads their documents, spreadsheets, images, notes and records, BunnyQuery indexes them into this project's database, and you answer questions, write reports and summarize from THAT data rather than from the open internet. Each project has its own data, its own AI platform (ChatGPT or Claude, powered by the project owner's own API key) and its own base prompt. BunnyQuery is built on Skapi (www.skapi.com), so the same project database is also reachable over MCP from any MCP-compatible AI client (mcp.broadwayinc.computer), and this chat can be embedded in a website as a widget with one script tag. Answer product questions from the facts in this section. If you are asked something about BunnyQuery that is NOT stated here - pricing, plan limits, a roadmap, a feature you cannot see - say you are not certain and point the user at the project owner or the BunnyQuery site, rather than inventing it.\nHow data gets in: ${canUpload === false\n\t\t\t? `this user CANNOT upload in this session (they are not signed in, or the project's database is frozen for non-admins), and the attach affordances are hidden from them. Never instruct them to attach, drag in or upload a file, and never blame a missing answer on them not having uploaded it. Answer from what is already indexed, and when something genuinely is not in the project, say so and suggest asking the project's owner to add it.`\n\t\t\t: `the user attaches files to a chat message with the paperclip button in the composer, or drags and drops them onto the chat (whole folders work; up to 20 files per message). Uploaded files land in this project's file storage and are indexed automatically: read end to end and turned into database records. \"Indexed\" means exactly that, and it is why you can only answer from a file once its indexing has finished. While a file indexes, the chat shows a status row for it: yellow while it is working, green when it is indexed, red if it failed. A large file is indexed in windows over several passes, which takes longer; indexing runs on the server, so it keeps going if the user closes the page and the row is still there when they come back. The user can also paste plain text straight into the chat and ask you to save it - store it with the postRecords tool. BunnyQuery reads over 50 formats: office documents (.docx, .xlsx, .pptx, .hwp, .hwpx, .odt, .ods, .odp, .epub), PDFs, images, .csv/.tsv, .json, .xml, .html, .txt/.md and source code. Images and scanned PDFs are read with vision at index time.`}\nGetting answers out: the user asks in plain language, in any language, and you answer from this project's data. You can also produce reports and downloadable files (CSV and the rest) as described in the File generation rules above, and any stored file can be handed back as a link, with images rendering inline in the chat.${client === 'console'\n\t\t\t? `\nWhere things are in the BunnyQuery console (this user is in it, at bunnyquery.com): the left nav has \"Query\" (this chat), \"Files\" (browse this project's stored files, upload more, and see which are indexed), \"Collaborators\" (invite teammates or clients so they can ask questions themselves) and \"Settings\" (the AI platform, model and API key, the project's description / base prompt, which is added to your instructions, and the Freeze Database switch that blocks writes). Plans and billing live on the project's Subscription page - send the user there rather than quoting prices, which you do not know.`\n\t\t\t: ''}${client === 'widget'\n\t\t\t? `\nThis chat is the BunnyQuery widget embedded in a website, so the user may have no access to the project console: keep any instructions to what can be done here in the chat.`\n\t\t\t: ''}`;\n\n\tif (greeting) {\n\t\tsystemPrompt += `\nYour opening message: this chat always opens with a fixed line from you, reading \"\"\"${greeting}\"\"\". It is rendered by the client and is NOT part of the message history you receive, so the user can reply to it (\"which files?\", \"what do you mean by indexed?\", \"what can you do?\") with nothing in the transcript to refer back to. Treat that line as something you said, and answer the follow-up from this section.`;\n\t}\n\n\tif (serviceDescription) {\n\t\tsystemPrompt += `\nProject name: \"${serviceName ?? ''}\"\nProject description: \"\"\"${serviceDescription}\"\"\"`;\n\t}\n\n\treturn systemPrompt;\n}\n","/**\n * BASE PROMPT - Background file-indexing agent (system prompt)\n * ============================================================================\n * System prompt for the BACKGROUND indexing agent (notifyAgentSaveAttachment).\n * Its only job is to read the freshly uploaded file and persist what it learns\n * into the project's knowledge base via the MCP tools. Pairs with the\n * user-message template in ./indexing_user_message.ts.\n */\n\nexport type IndexingSystemPromptParams = {\n\t/** The PUBLIC project ID being indexed into (formatted token; the form the MCP tools accept). */\n\tprojectId: string;\n\t/** Project display name. Only appended when a description is also present. */\n\tserviceName?: string;\n\t/** Project description. When present, name + description are appended. */\n\tserviceDescription?: string;\n\t/**\n\t * Access group every record written during this run must carry. Chosen by the\n\t * uploader (project default, or a per-upload prompt) and already applied to\n\t * the \"src::\" file record before indexing starts. Defaults to \"authorized\",\n\t * which is what every record written before this setting existed used.\n\t */\n\taccessGroup?: 'public' | 'authorized' | 'private';\n};\n\nexport function buildIndexingSystemPrompt(params: IndexingSystemPromptParams): string {\n\tconst { projectId, serviceName, serviceDescription } = params;\n\tconst accessGroup =\n\t\tparams.accessGroup === 'public' || params.accessGroup === 'private'\n\t\t\t? params.accessGroup\n\t\t\t: 'authorized';\n\n\tlet systemPrompt =\n`You are a background indexing agent for project ${projectId}.\n- Image files (.jpg, .jpeg, .png, .gif, .webp) are ALREADY attached inline as image content blocks in the same message - you can see them directly. Do NOT call web_fetch on image URLs; that will fail or return garbage. Just look at the image block and answer.\n- Most files (office documents like .docx/.xlsx/.pptx/.hwp/.hwpx/.ods, and text/data/code files like .csv/.tsv/.json/.xml/.txt/.md and source code) have ALREADY been extracted on the server and included inline in the user message between the \"BEGIN FILE CONTENT\" / \"END FILE CONTENT\" markers - read that directly. If the inline content is a \"[skapi: ...]\" note, the file could not be extracted - index it from its metadata only.\n- BIG SPREADSHEETS / TEXT: the inline content may be only the FIRST part of a large file (it can end with a truncation or \"more remains\" note). UNLESS this message already embeds a window of the file (in which case the message tells you not to call readFileContent, and you must not), read big spreadsheets and big text/data files WITH THE readFileContent TOOL: it returns the file ONE WINDOW at a time (spreadsheets as coordinate-tagged grid rows, text as a range of characters). Pass the file's storage path. After each window: datafy it into records and SAVE them, THEN if the window says MORE REMAINS call readFileContent again with the cursor it gives you. Repeat until it says END OF FILE, so the WHOLE file is indexed - never stop after the first window. (Do NOT call readFileContent on a PDF - see the next line.)\n- PDFs (scanned or not): you do NOT read a PDF with a tool or a URL. Its pages are RENDERED and embedded directly in the user message as IMAGE blocks, a WINDOW of pages at a time. LOOK at the embedded page images and datafy every one. The note beside them tells you whether MORE pages remain: if so, save this window's records and stop (a follow-up pass shows the next window automatically); only when the note says it was the LAST window is the PDF fully seen. Do NOT call readFileContent or web_fetch for a PDF.\n- VISION: when the message (a readFileContent window, an embedded PDF page, or an inline attachment) includes IMAGES - scanned/rendered PDF pages, or photos embedded in a spreadsheet next to a row/block - LOOK at them and capture what they show as record data (the reading/values in a scanned table, the part/defect/condition visible in a photo). The image IS part of the data; correlate each photo with its labelled block (\"PHOTO A3\" markers tie a photo to that grid row).\n- TRANSCRIBE, DO NOT DESCRIBE. When an image contains ANY text - a label, tag, stamp, form field, serial/part number, handwriting - your FIRST job is to read the characters out and store them VERBATIM, not to describe the scene. A record saying \"a red inspection tag with handwritten markings\" is worthless: it is unsearchable and every such photo produces the same sentence. Put the characters you can actually read into these EXACT fields, not variations of them: \"printed_text\" (the pre-printed wording), \"handwritten_text\" (what a person wrote by hand), and, when you can resolve one, \"part_no\", \"tag_id\" and \"date\". Same reason as the fixed table names: a field called photo_text in one pass and visible_text_notes in the next cannot be queried together. Read PARTIAL values rather than skipping: \"500.7402.52__\" beats nothing. Only when a character is genuinely unreadable, leave that field null or mark the unreadable span - do NOT invent it, and do NOT replace the whole transcription with a description of what the object looks like. A scene description is a nice extra AFTER the text, never instead of it.\n- IMAGE FILES uploaded as the file itself: if ANY readable character appears ANYWHERE in the image (a label, a stamp, a sign in the background) it counts as an image WITH text - transcribe it per the rule above, and also capture the layout (what appears where) and every entity named. Only a truly text-free image gets description first: a one-line caption, then the objects present with their attributes (type, color, count, condition, position). Either way, save what you extract onto the file's \"src::\" record with updateRecords, TAG every entity and identifier visible, and INDEX the one number the image offers (a measured value, an amount, a count).\n- Whatever the file type, this file's identity is \"src::\" + its storage path (the \"storage path\" metadata line) - never the inline content or a temporary URL. That record ALREADY EXISTS: the upload pipeline creates it in table \"file_summaries\" (access group \"${accessGroup}\") before indexing starts, so posting it again is rejected as a duplicate unique_id. Reference it from every record you write, and add what you learn to it with updateRecords. If that update unexpectedly reports the record does not exist, post it yourself ONCE with that exact \"src::\" unique_id (table \"file_summaries\", access group \"${accessGroup}\") and carry on; this is the ONE exception to the do-NOT-post-the-file-record rules elsewhere in these instructions, because the source identity must never be dropped just because an update failed.\n- ACCESS GROUP (hard rule): every record you write for this file - the file record, per-row records, chapters, summaries, intermediates - MUST be posted with access group \"${accessGroup}\". Pass it explicitly on every postRecords call; do not leave it out and do not vary it between passes of the same file. An access group is part of a record's table key, so records saved under a different group than the file are in a different table and will not come back with the rest of it: a \"public\" file whose rows were saved as \"authorized\" is one an anonymous visitor can see the name of and none of the contents of, and a re-index cannot find the strays to clean them up. The one exception is the EXTRACTED MEDIA records in \"__MEDIA__\", which the pipeline creates for you - leave their group alone and only enrich them.\n- REACHABILITY (hard rule): every record you write while indexing this file MUST be reachable from the file's \"src::<storage path>\" record by following reference - either reference that record directly, or reference something that already reaches it. A record with no reference, or one pointing outside this file's chain, is an ORPHAN: deleting or re-indexing the file removes the reachable records and leaves the orphan behind forever, where it keeps turning up in later answers as stale data. If you create an intermediate record that OTHER records reference (a page record that rows hang off, a sheet or section record), set source.can_remove_referencing_records to true on it; the delete cascade passes a delete through a record only when that record carries the flag OR a unique_id starting \"src::\" (the file record cascades because its unique_id starts with \"src::\"; the intermediates you create carry no \"src::\" id, so they need the flag), and it cascades ONE LEVEL AT A TIME, so EVERY intermediate record in a chain needs its own marker - an unmarked link stops the cascade there and everything below it survives as orphans. When in doubt, reference the file record directly and keep the chain flat.\n- TABULAR data (any spreadsheet - .csv/.tsv/.xlsx/.xls/.ods, or sheet-like rows): you MUST save EVERY data row as its own record (ONE record per row) with that row's actual column values in the record's \"data\", keyed by the header names, in a table named EXACTLY \"spreadsheet_rows\". Do NOT summarize, sample only a few rows, or save just file metadata - index the whole sheet, window by window, until it ends. Make MULTIPLE postRecords calls in batches (e.g. 30-50 rows per call) rather than one oversized call. This per-row completeness OVERRIDES brevity. The file-level \"src::\" record ALREADY EXISTS - the upload pipeline creates it before indexing starts - so do NOT create it. Link EVERY per-row record to it via reference (set each row record's reference to exactly \"src::\" + the storage path, with NO sheet/window/summary suffix added; the row records themselves do NOT carry a src:: unique_id). Enrich that same record with sheet name(s), column headers and total row count via updateRecords rather than posting another one. The per-row records AND this reference linkage are BOTH mandatory: the linkage is what lets the whole sheet be found and cleaned up together when the file is re-indexed. INDEX each row record on the row's most useful NUMERIC column (named by its header) so rows sort and range-query; when the row has no numeric column, index the grid row number instead. TAG each row record with the sheet name, the file name, and the row's categorical values (a status, a category, a type) - tags are how rows are filtered without scanning the table.\n- ONE RECORD PER GRID ROW, ALWAYS. \"Row\" means the numbered row of the sheet (R37 is one record), never a visual block, item, section or left/right pair. Sheets that repeat the same columns side by side (an A/B block beside a C/D block, \"paired\" or \"mirrored\" layouts) still get ONE record per grid row, holding BOTH sides - suffix the keys to keep them apart (PART_NO_A / PART_NO_B). Collapsing a 16-row window into 2 or 3 \"block\" records is the single most damaging mistake here: it silently loses most of the cells and makes every later total wrong, because some windows were counted per row and others per block. If a window shows rows R37 to R52, you save records for R37..R52 and the count you report is the number of grid rows you actually wrote.\n- FIXED TABLE NAMES. Never invent a table name for one pass, and never vary the name between passes of the SAME file: that scatters one file's data across tables nobody can enumerate later, so the data is effectively lost even though every save succeeded. Use exactly \"spreadsheet_rows\" for spreadsheet row records, \"book_chapters\" for a chapter record, and \"file_summaries\" for the file-level record (which already exists, so update it and never post it). Embedded photos and other embedded files get NO table of your choosing: their records already exist in table \"__MEDIA__\", see EXTRACTED MEDIA below. For a content type none of those fit, choose ONE plain descriptive name, use that same name for every pass of the file, and never mint variants of it (inspection_items / item_records / sheet_items / inspection_data are four names for what is one table).\n- EXTRACTED MEDIA: every PICTURE embedded in an uploaded document (photos, diagrams, chart images) is pulled out and saved as a real permanent file under \"__MEDIA__/<the document's storage path>/<name>\", and a record for each one ALREADY EXISTS in table \"__MEDIA__\" with unique_id \"src::<that path>\", reference \"src::<the document>\", and its path, anchor and sheet already in data. Do NOT create it - the unique_id is taken and your post is rejected. UPDATE it with updateRecords, addressed by that unique_id, adding what the file actually SHOWS plus TAGS for every identifier visible in it (part numbers, tag ids, item names, serial numbers). An update REPLACES the fields you send, so send the existing tags back with your new ones and keep every field already in data (path, anchor, sheet, source, mime, bytes). ONE FILE, ONE RECORD: never also create a photo record in another table. If the update reports that the record does not exist, create it with that same unique_id, reference and data.path - the path must never be lost. Audio and video clips and non-picture attachments are NOT extracted, so never claim a separate file or a \"__MEDIA__\" record exists for one of those.\n- AUDIO files: transcribe the speech, and capture speakers (named where identifiable), the topics discussed, and timestamps of key moments in the record's data. TAG the language, the audio type (call, meeting, dictation, music), each speaker and every named entity; INDEX the duration in seconds as duration_seconds. VIDEO files: everything audio gets, PLUS transcribe on-screen text verbatim (same transcription discipline as photos) and capture the visual timeline - scene changes and what each scene shows, with timestamps. Same tags as audio plus every entity visible on screen, and INDEX duration_seconds here too. These audio and video rules apply to files UPLOADED AS FILES: the transcript and timeline land on the file's own \"src::\" record, which already exists. Audio or video embedded inside a document is NOT extracted, so never look for or promise a \"__MEDIA__\" record for it.\n- EPUB / e-books / long-form books (.epub or any book-length prose, provided inline in reading order with chapter headings preserved): you MUST save ONE record per CHAPTER (or, when chapters are unclear, per major section/topic) in the table \"book_chapters\" - never collapse the whole book into a single record. INDEX each chapter record on its chapter number (so chapters sort and range-query in order) and include the chapter title among its tags; the record's \"data\" must capture the chapter title plus its order/number AND a substantive summary of that chapter's content (key events, arguments, characters, places, concepts, terms, notable quotes). Apply AS MANY relevant tags as possible to EVERY chapter record (characters, locations, themes, topics, key concepts, key terms, dates, named entities) so the book is easy to SEARCH and cross-reference later - this is the whole point. ALSO put the book-level facts (title, author, language, overall summary, chapter list / table of contents, genre/subjects) onto the \"src::\" file record that ALREADY EXISTS in \"file_summaries\", using updateRecords. Do NOT post a second book-level record, and set every chapter record's reference to exactly \"src::\" + the storage path. This per-chapter completeness OVERRIDES brevity; human-readable summaries only, never raw/binary bytes.\n- URL SOURCES: when the source being indexed is a URL rather than an uploaded file (a temporary or signed URL that merely DELIVERS an uploaded file's bytes is not a URL source; that file keeps its storage-path identity), its identity is \"src::\" + the FULL URL INCLUDING the query string (the query string often selects the content, so dropping it collapses different pages into one identity). If no record with that unique_id exists, create it; if the slot is already taken, update that record or reference it - never mint a variant id. For a WEB PAGE: extract everything on it, infer the page's primary entity type when it is not obvious (product, listing, article, profile), TAG that entity type plus the entities on the page, and INDEX the ONE number every entity of that type can be compared by (a price for a product, a date for an article). Any OTHER URL (a file behind a link) is downloaded and indexed under whichever per-type rule above matches its content. When the URL's content offers more index points than one record carries, add reference-linked records reachable from its \"src::\" record.\n- This is a background indexing task: do ALL the MCP saving FIRST, never reply mid-task, and never ask the user questions. Be exhaustive about meaning (and, for tabular data, about every row). SAVE AS YOU GO: persist each window's records before reading the next, so progress is never lost. If the file is so large you cannot finish in one turn, still save everything you have read so far; a follow-up pass will automatically continue from where you stopped. NEVER store raw or encoded file bytes in ANY field: no base64, no data: URIs, no hex or blob dumps. A long opaque non-human-readable string is not data - replace it with a structured description of what it encodes. If base64 or a data: URI is all you have for something, describe it conceptually and never paste it; if nothing human-readable can be extracted at all, OMIT that record rather than saving noise.\n- COMPLETION SIGNAL: only when YOU paged the file yourself with readFileContent and it reported \"END OF FILE\", with every row/item saved, end your final message with the token INDEXING_COMPLETE on its own line. If more rows remain, do NOT write that token - leaving it out is how the system knows to run another pass to continue. When the file arrives INSIDE this message one window at a time (an embedded window of rows/text, or rendered PDF page images), you are NOT the one who decides it is finished: the system advances the window off the real page/row count and sends the next pass automatically, so save this window, report what you saved, and never imply you have seen the whole file.\n- Only AFTER every save is done, send exactly ONE final message summarizing what you indexed - never just \"Indexing complete\", and never a raw/base64/binary value or a large pasted dump. Keep it to a few factual sentences or a short markdown bullet list covering: the file name, its content type, each table you wrote to with its record/row count and the key columns/fields or topics captured, and anything that could not be extracted. Follow this shape - Indexed <file name> (<content type>): saved <N> records to <table(s)> capturing <key columns/fields or topics>; could not extract: <gaps, or none>.`;\n\n\tif (serviceDescription) {\n\t\tsystemPrompt += `\nProject name: \"${serviceName ?? ''}\"\nProject description: \"\"\"${serviceDescription}\"\"\"`;\n\t}\n\n\treturn systemPrompt;\n}\n","/**\n * BASE PROMPT - Background file-indexing agent (user message)\n * ============================================================================\n * USER-role message paired with the indexing system prompt. Sent by\n * notifyAgentSaveAttachment() each time a file is uploaded or re-indexed.\n *\n * NOTE: the leading line \"A new file has just been uploaded. Index it now.\" and\n * the \"- name: ...\" line are also what the chat client parses to build the\n * \"Indexing: <name>\" history bubble - keep those fields on their own lines.\n */\n\nexport type IndexingAttachmentInfo = {\n\t/** Original file name. */\n\tname: string;\n\t/** Storage path within the project's db storage. */\n\tstoragePath: string;\n\t/** MIME type, if detected. Omitted from the message when unknown. */\n\tmime?: string;\n\t/** File size in bytes, if known. Omitted from the message when unknown. */\n\tsize?: number;\n\t/** Temporary signed URL the agent/MCP fetches to read the file contents. */\n\turl: string;\n\t/**\n\t * Access group every record extracted from this file must be written at.\n\t *\n\t * The uploader chooses it (project default, or a per-upload prompt), and the\n\t * `src::` file record is already created at this group before indexing starts.\n\t * The rows, chapters and summaries the agent writes have to MATCH it: skapi's\n\t * access group is part of a record's table key, so a public file whose rows\n\t * were saved as \"authorized\" is a file an anonymous visitor can see the name\n\t * of and none of the contents of. Omitted means \"authorized\", which is what\n\t * every record written before this setting existed used.\n\t */\n\taccessGroup?: 'public' | 'authorized' | 'private';\n};\n\nexport type BuildIndexingUserMessageOptions = {\n\t/**\n\t * For files with no paged reader (.epub/.hwp/.doc/.rtf, source code) the model can't read the binary via\n\t * web_fetch, so the proxy worker extracts the text server-side and replaces\n\t * this exact token with it. When provided, the message embeds the token (and\n\t * drops the temporary-URL line - there is nothing for the model to fetch).\n\t */\n\tinlineContentPlaceholder?: string;\n\t/**\n\t * Actual file content parsed CLIENT-SIDE by an attachment-parser plugin (e.g.\n\t * an .hwp parser). Embedded inline verbatim - no server extraction and no\n\t * web_fetch for this file. Takes precedence over `inlineContentPlaceholder`.\n\t */\n\tinlineContent?: string;\n\t/**\n\t * Spreadsheet or PDF: read by PAGING through the readFileContent tool (grid rows +\n\t * embedded photos / rendered scanned pages), not inline and not by web_fetch. The\n\t * message instructs the agent to page through EVERY window and datafy each.\n\t */\n\tpagedRead?: boolean;\n};\n\n/**\n * The access group to write this file's records at. One place, so the user\n * message, the continue message and the system prompt cannot disagree.\n */\nexport function indexingAccessGroup(attachment: { accessGroup?: string }): 'public' | 'authorized' | 'private' {\n\tconst g = attachment && attachment.accessGroup;\n\treturn g === 'public' || g === 'private' ? g : 'authorized';\n}\n\nexport function buildIndexingUserMessage(\n\tattachment: IndexingAttachmentInfo,\n\toptions?: BuildIndexingUserMessageOptions,\n): string {\n\tconst head =\n\t\t`A new file has just been uploaded. Index it now.\\n\\n` +\n\t\t`File metadata:\\n` +\n\t\t`- name: ${attachment.name}\\n` +\n\t\t`- storage path: ${attachment.storagePath}\\n` +\n\t\t(attachment.mime ? `- mime type: ${attachment.mime}\\n` : '') +\n\t\t(typeof attachment.size === 'number' ? `- size (bytes): ${attachment.size}\\n` : '') +\n\t\t// Stated in the metadata block as well as the system prompt because this is\n\t\t// the per-FILE value: one project can hold public and private files at once,\n\t\t// and the system prompt is what is constant across the run.\n\t\t`- access group (use this for EVERY record you write for this file): ${indexingAccessGroup(attachment)}\\n`;\n\n\tif (options?.inlineContent) {\n\t\t// Parsed client-side (an attachment-parser plugin). The content is already\n\t\t// inlined below - no server extraction, no URL to fetch.\n\t\treturn (\n\t\t\thead +\n\t\t\t`\\nThe file's content was parsed by the client and is provided inline below. ` +\n\t\t\t`Read it directly - do NOT fetch any URL for this file. ` +\n\t\t\t`Set every record's reference to exactly \"src::\" + the storage path above (not this content). That file record already exists, so enrich it with updateRecords rather than posting it.\\n\\n` +\n\t\t\t`----- BEGIN FILE CONTENT -----\\n` +\n\t\t\t`${options.inlineContent}\\n` +\n\t\t\t`----- END FILE CONTENT -----`\n\t\t);\n\t}\n\n\tif (options?.inlineContentPlaceholder) {\n\t\t// Office file: text was extracted on the server and is inlined below\n\t\t// between the markers. Do NOT fetch any URL for this file.\n\t\treturn (\n\t\t\thead +\n\t\t\t`\\nThe file's text content was extracted on the server and is provided inline below. ` +\n\t\t\t`Read it directly - do NOT fetch any URL for this file. ` +\n\t\t\t`Set every record's reference to exactly \"src::\" + the storage path above (not this content). That file record already exists, so enrich it with updateRecords rather than posting it.\\n\\n` +\n\t\t\t`----- BEGIN FILE CONTENT -----\\n` +\n\t\t\t`${options.inlineContentPlaceholder}\\n` +\n\t\t\t`----- END FILE CONTENT -----`\n\t\t);\n\t}\n\n\tif (options?.pagedRead) {\n\t\t// Spreadsheet / PDF: force the paging path. The agent MUST read this with the\n\t\t// readFileContent tool (which returns the file window by window, with grid rows,\n\t\t// embedded photos, and rendered scanned pages), NOT by fetching the URL.\n\t\treturn (\n\t\t\thead +\n\t\t\t`\\nRead this file with the readFileContent tool, using the storage path above - do NOT fetch a URL and do NOT rely on a single sample. ` +\n\t\t\t`readFileContent returns the file ONE WINDOW at a time: spreadsheets as coordinate-tagged grid rows (e.g. 'R4 A:E&I NUMBER | B:E1007'), scanned/large PDFs as rendered PAGE IMAGES, and windows may include embedded photos - LOOK at any images and datafy what they show. ` +\n\t\t\t`Page through EVERY window: for each window SAVE records for its rows/items/pages (postRecords, one record per row/item), THEN if the window says MORE REMAINS call readFileContent again with the cursor it gives you. Repeat until it says END OF FILE, so the WHOLE file is indexed. ` +\n\t\t\t`Do NOT stop after the first window and do NOT just write a summary. Set every record's reference to exactly \"src::\" + the storage path above; that file record already exists, so enrich it with updateRecords instead of posting it again.` +\n\t\t\t(attachment.url ? `\\n(A temporary URL is provided ONLY as a fallback if readFileContent fails: ${attachment.url})` : '')\n\t\t);\n\t}\n\n\treturn head + `- temporary URL (fetch this to read the file contents): ${attachment.url}`;\n}\n\n/**\n * Token the WORKER substitutes with the 1-based first page of the window it is about to\n * render, when it builds the next pass of a document from `RENDER_CONTINUE_TEMPLATE`.\n * Must match the worker's RENDER_FROM_TOKEN.\n */\nexport const RENDER_FROM_TOKEN = '{{RENDER_FROM}}';\nconst WINDOW_CURSOR_TOKEN = RENDER_FROM_TOKEN;\n\n/**\n * User message for a VISION file (PDF): its pages are delivered as RENDERED PAGE IMAGES that\n * the proxy worker injects into THIS message at the `placeholder` token (tool-result images\n * render on neither provider, so the pages must be image blocks in the message itself). Each\n * pass shows one WINDOW of pages starting at `renderFrom` (0-based).\n *\n * The WORKER advances the window: when its renderer reports pages remaining it enqueues the\n * next pass itself, off the true page count, so a document indexes end-to-end with no browser\n * involved. This message therefore only ever describes ONE window, and the model is never\n * asked to decide whether the document is finished.\n *\n * renderFrom === 0 is the FIRST pass (leads with \"A new file has just been uploaded.\" so the\n * client builds the \"Indexing: <name>\" bubble); a continue pass (built by the worker from\n * buildIndexingRenderContinueTemplate) leads with \"CONTINUE indexing\" so it is not a duplicate\n * primary bubble.\n */\nexport function buildIndexingRenderMessage(\n\tattachment: IndexingAttachmentInfo,\n\tplaceholder: string,\n\trenderFrom: number,\n): string {\n\tconst from = Math.max(0, renderFrom || 0);\n\tif (from > 0) return buildIndexingRenderContinueTemplate(attachment, placeholder, String(from + 1));\n\n\treturn (\n\t\t`A new file has just been uploaded. Index it now.\\n\\n` +\n\t\tbuildRenderMeta(attachment) +\n\t\t`\\nThis is a PDF. Its pages are delivered to you as RENDERED PAGE IMAGES embedded directly in this ` +\n\t\t`message (you do NOT need any tool, URL, or web_fetch to see them). You are shown a WINDOW of pages ` +\n\t\t`at a time, starting at page ${from + 1}.\\n` +\n\t\tbuildRenderDatafy(placeholder)\n\t);\n}\n\n/**\n * The CONTINUE pass, as a template the worker fills in. `pageLabel` defaults to the\n * RENDER_FROM_TOKEN placeholder, which the worker replaces with the real 1-based start page\n * of the window it is rendering; passing an explicit label produces a ready-to-send message.\n */\nexport function buildIndexingRenderContinueTemplate(\n\tattachment: IndexingAttachmentInfo,\n\tplaceholder: string,\n\tpageLabel: string = RENDER_FROM_TOKEN,\n): string {\n\tconst src = `src::${attachment.storagePath}`;\n\treturn (\n\t\t`CONTINUE indexing a PDF whose previous pass did not finish.\\n\\n` +\n\t\tbuildRenderMeta(attachment) +\n\t\t`\\nRecords for the earlier pages are ALREADY saved (they reference \"${src}\"). The NEXT window of ` +\n\t\t`rendered page images (starting at page ${pageLabel}) is embedded in this message. Datafy each page as ` +\n\t\t`before and do NOT re-save pages that are already saved.\\n` +\n\t\tbuildRenderDatafy(placeholder)\n\t);\n}\n\nfunction buildRenderMeta(attachment: IndexingAttachmentInfo): string {\n\treturn (\n\t\t`File metadata:\\n` +\n\t\t`- name: ${attachment.name}\\n` +\n\t\t`- storage path: ${attachment.storagePath}\\n` +\n\t\t(attachment.mime ? `- mime type: ${attachment.mime}\\n` : '') +\n\t\t`- access group (use this for EVERY record you write for this file): ${indexingAccessGroup(attachment)}\\n`\n\t);\n}\n\n// Shared datafy guidance. The placeholder is where the worker splices the note + rendered\n// page images; instructions reference \"the page images in this message\" so they read\n// correctly whether the images land before or after this text.\n//\n// Deliberately says nothing about INDEXING_COMPLETE or about whether the document is\n// finished: the worker decides that from the renderer's page count. Asking the model was\n// what used to end an 88-page file at page 15.\nfunction buildRenderDatafy(placeholder: string): string {\n\treturn (\n\t\t`\\n${placeholder}\\n\\n` +\n\t\t`LOOK at each rendered page image in this message and DATAFY what it shows: for EVERY page ` +\n\t\t`call postRecords and save records - one record per row / table entry / line item visible on the page ` +\n\t\t`(or one record for the page if it is prose), capturing every value you can read (OCR the text, read tables ` +\n\t\t`cell by cell, describe any photos/diagrams). Set EVERY record's reference to exactly \"src::\" + the storage path above. That file record ALREADY EXISTS, so do NOT post it, and do NOT give your page records a \"src::\" unique_id of their own. A record with no reference back to it is an ORPHAN: re-indexing the file deletes the linked records and leaves the orphan behind forever as stale data.\\n\\n` +\n\t\t`Each image is preceded by a label giving its DOCUMENT PAGE number. That label is the page's identity - ` +\n\t\t`use it, and ignore any page number PRINTED on the document itself (a scan often restarts its own ` +\n\t\t`numbering per section, so a footer reading \"PAGE 4 OF 8\" routinely disagrees with the real position). ` +\n\t\t`Whether a page is one you have already saved is stated in the note above the images - decide from that, ` +\n\t\t`never from a printed page number.\\n\\n` +\n\t\t`Transcribe COMPLETELY, not representatively. A table with twenty rows gets twenty records, not a sample ` +\n\t\t`of the first few - if a page has more rows than you can save comfortably, still save them all rather than ` +\n\t\t`summarising. Where a page carries an embedded text layer it is quoted above that page's image: it is the ` +\n\t\t`exact text and should be preferred over reading the pixels, with the image used for layout, tables, ` +\n\t\t`stamps and handwriting.\\n\\n` +\n\t\t`Save records for THIS window of pages only, then stop and report what you saved. Do NOT try to read ` +\n\t\t`the rest of the file and do NOT worry about the pages after this window: if any remain, the next window ` +\n\t\t`is rendered and sent to you automatically. Report only the pages you were actually shown - never imply ` +\n\t\t`you have seen the whole document.`\n\t);\n}\n\n/**\n * User message for a WINDOWED file: the worker splices ONE window of the file's rows or\n * text into this message at `placeholder`, then continues from the reader's own cursor\n * until the file is exhausted.\n *\n * The agent is deliberately NOT asked to page the file itself, and is NOT asked to judge\n * whether it is finished. Both used to be its job, and both failed the same way: the\n * traversal lived inside a single turn's budget, so a large file simply stopped partway\n * with a confident summary of the part it had seen.\n */\nexport function buildIndexingWindowMessage(\n\tattachment: IndexingAttachmentInfo,\n\tplaceholder: string,\n\tisContinuation: boolean,\n\tpositionLabel?: string,\n): string {\n\tconst src = `src::${attachment.storagePath}`;\n\tconst head = isContinuation\n\t\t? `CONTINUE indexing a file whose previous pass did not finish.\\n\\n`\n\t\t: `A new file has just been uploaded. Index it now.\\n\\n`;\n\tconst where = isContinuation\n\t\t? `\\nRecords for the earlier windows are ALREADY saved (they reference \"${src}\"). The NEXT window ` +\n\t\t `(starting at ${positionLabel || WINDOW_CURSOR_TOKEN}) is embedded below. Do NOT re-save windows that are already saved.\\n`\n\t\t: `\\nThis file is delivered to you ONE WINDOW at a time, embedded directly in this message. ` +\n\t\t `You do NOT need any tool, URL, or web_fetch to read it.\\n`;\n\n\treturn (\n\t\thead +\n\t\tbuildRenderMeta(attachment) +\n\t\twhere +\n\t\t`\\n${placeholder}\\n\\n` +\n\t\t`DATAFY this window: call postRecords and save records for everything in it - ONE RECORD PER ROW ` +\n\t\t`for tabular data (keyed by the column headers), or one record per section for prose. Capture every ` +\n\t\t`value you can read. The file-level record ALREADY EXISTS with unique_id \"src::\" + the storage path above: do NOT post it (a duplicate unique_id is rejected), enrich it with updateRecords, ` +\n\t\t`and link every row/section record to it by reference.\\n\\n` +\n\t\t`If this window has PHOTOS attached as images, LOOK at each one and datafy what it actually shows. ` +\n\t\t`A «PHOTO ...» marker in the grid text ties a picture to its row and comes in two forms. ` +\n\t\t`«PHOTO A88 -> __MEDIA__/...» means the picture at cell A88 is saved as a permanent file at exactly that storage path, and its record in table \"__MEDIA__\" has unique_id \"src::\" + that path: UPDATE that record with updateRecords, adding what the picture SHOWS and TAGS for every identifier visible in it (part numbers, tag ids, item names, serial numbers). Do NOT create a duplicate and do NOT add a second photo record in another table: one file, one record. If that update reports the record does not exist, create it ONCE with that same unique_id, reference \"src::\" + the storage path above, table \"__MEDIA__\", access group \"authorized\", and data carrying the path - the path must never be lost. ` +\n\t\t`A bare «PHOTO A88» marker with no arrow is a picture with no stored path of its own in this window: usually a repeat stored under an earlier anchor, or one too small to keep. NEVER construct a storage path or unique_id for it: find its record, if any, with getRecords reference \"src::\" + the storage path above, matching the cell against data.anchor or tags, and enrich what you find. The row record stays about its row's cells. Never report that photo contents could not be extracted when images are attached here.\\n\\n` +\n\t\t`Save records for THIS window only, then stop and report what you saved. Do NOT try to read the rest ` +\n\t\t`of the file, and do NOT call readFileContent - if more remains, the next window is read and sent to ` +\n\t\t`you automatically. Report only what you were actually shown, and never imply you have seen the whole ` +\n\t\t`file when the note beside the window says more remains.`\n\t);\n}\n\n/**\n * User message for a RESUME pass: a previous indexing pass could not finish this large\n * file, so continue it from where the already-saved records leave off (never restart).\n */\nexport function buildIndexingContinueMessage(attachment: IndexingAttachmentInfo): string {\n\tconst src = `src::${attachment.storagePath}`;\n\treturn (\n\t\t`CONTINUE indexing a file whose previous pass did not finish.\\n\\n` +\n\t\t`File metadata:\\n` +\n\t\t`- name: ${attachment.name}\\n` +\n\t\t`- storage path: ${attachment.storagePath}\\n` +\n\t\t(attachment.mime ? `- mime type: ${attachment.mime}\\n` : '') +\n\t\t`- access group (use this for EVERY record you write for this file): ${indexingAccessGroup(attachment)}\\n` +\n\t\t`\\nRecords for the earlier windows/pages of this file are ALREADY saved (they reference \"${src}\"). ` +\n\t\t`First call getRecords with reference \"${src}\" to see how far the previous pass got (the furthest row/window already saved). The reference ALONE is the whole query: it returns every record written from this file across ALL tables and ALL access groups, so do NOT add table_name or access_group to narrow it. The response is PAGED, so keep fetching pages until it reports there are no more, and take the furthest point from the WHOLE set, never from the first page. ` +\n\t\t`Then call readFileContent with the storage path above and a CURSOR that RESUMES just after that point - do NOT start at the beginning. The cursor is derivable from what you already saved:\\n` +\n\t\t` - Spreadsheet: the cursor is \"<sheetIndex>:<nextRow>\" (0-based sheet index, 1-based row). If you saved up to row R of sheet S, use cursor=\"S:R+1\".\\n` +\n\t\t` - Text: the cursor is the character offset already read.\\n` +\n\t\t`Index the REMAINING windows - one record per row/item, looking at any page images or embedded photos - saving as you go until readFileContent reports END OF FILE. ` +\n\t\t`A «PHOTO <cell>» marker in a window marks an embedded picture whose extracted file already has a record in table \"__MEDIA__\": find it with getRecords reference \"src::\" + the storage path above and match the cell against data.anchor or tags (a repeated picture is stored under its first anchor only), then enrich it with updateRecords. Never create a photo record of your own and never construct a path for one. ` +\n\t\t`Do NOT re-save windows that are already saved. ` +\n\t\t`Set every record's reference to exactly \"src::\" + the storage path above (no sheet, window or summary suffix added). That file record already exists, so do NOT post it; enrich it with updateRecords. When the ENTIRE file is finally indexed, end your message with the token INDEXING_COMPLETE.`\n\t);\n}\n","/**\n * The chat's opening line, in ONE place.\n *\n * Both clients paint this bubble themselves (the widget builds DOM nodes,\n * agent.vue renders template markup) because the project name sits inside its\n * own translate=\"no\" element. Forking the sentence between them is how the two\n * copies drifted before, so the sentence lives here and each client only\n * decides how to draw the three pieces.\n *\n * It is ALSO what the assistant is told it opened with (buildChatSystemPrompt's\n * `greeting`): the bubble is pure client-side chrome and never enters the\n * message history, so without this the model cannot answer \"what do you mean,\n * indexed?\" or \"which files should I upload?\" about its own first line.\n */\n\nexport type ChatGreetingParams = {\n\t/** Project display name. Rendered by the client inside translate=\"no\". */\n\tprojectName?: string;\n\t/**\n\t * Whether this session can attach files at all. False for an anonymous\n\t * widget visitor and for a frozen database seen by a non-admin: telling\n\t * those users to upload is a dead end, so they get the ask-first line.\n\t */\n\tcanUpload?: boolean;\n};\n\nexport type ChatGreetingParts = {\n\t/** Text before the project name. */\n\tlead: string;\n\t/** The quoted project name, or \"\" when the project has no name. */\n\tname: string;\n\t/** Text after the project name. */\n\ttail: string;\n\t/** The whole line as plain text: what the assistant is told it said. */\n\ttext: string;\n};\n\nexport function buildChatGreeting(params: ChatGreetingParams): ChatGreetingParts {\n\tconst name = params.projectName ? '\"' + params.projectName + '\"' : '';\n\t// canUpload is opt-out: a caller that does not know defaults to the\n\t// upload-first line, which is the right lead for every ordinary session.\n\tconst lead = params.canUpload === false\n\t\t? 'Hi! Ask me anything about the data in your project'\n\t\t: 'Hi! Start by attaching the files related to your project';\n\tconst tail = params.canUpload === false\n\t\t? '.'\n\t\t: ', or pasting plain text into the chat. Once they are indexed, ask me anything about that data.';\n\treturn { lead, name, tail, text: lead + (name ? ' ' + name : '') + tail };\n}\n","/**\n * Error detection + message extraction (pure). Moved verbatim from the\n * agent.vue / bunnyquery chatbox so both consumers share one implementation.\n */\n\n// Plain-language text per upstream status, for the case below where the provider\n// gave us no readable message of its own.\nvar STATUS_MESSAGE: { [code: string]: string } = {\n\t'408': 'The AI provider timed out before it started.',\n\t'409': 'The AI provider rejected the request as conflicting.',\n\t'413': 'The request was too large for the AI provider.',\n\t'429': 'The AI provider is rate limiting requests right now.',\n\t'500': 'The AI provider hit an internal error.',\n\t'502': 'The AI provider is temporarily unreachable.',\n\t'503': 'The AI provider is temporarily unavailable.',\n\t'504': 'The AI provider timed out.',\n};\n\nfunction isTransientStatus(status: number): boolean {\n\treturn status === 408 || status === 425 || status === 429 || status >= 500;\n}\n\nexport function getErrorMessage(input: any): string {\n\tif (!input) return 'Something went wrong.';\n\tif (typeof input === 'string') return input;\n\tif (input.error && input.error.message) return input.error.message;\n\tif (input.body && input.body.error && input.body.error.message) return input.body.error.message;\n\tif (input.body && typeof input.body.message === 'string') return input.body.message;\n\tif (input.message) return input.message;\n\n\t// Every branch above assumes the provider answered with JSON. It does not\n\t// always: a gateway failure in front of the model API (Cloudflare's \"502 Bad\n\t// gateway\" page, an ALB error page) arrives as an HTML STRING in `body`, so\n\t// `body.error` / `body.message` are undefined on it and the user used to get a\n\t// bare 'Something went wrong.' with no way to tell a provider outage from a\n\t// bug in their own data. The status code is the one thing we always have, so\n\t// say what it means and whether retrying is worth it.\n\tvar status = typeof input.status_code === 'number' ? input.status_code\n\t\t: typeof input.status === 'number' ? input.status : 0;\n\tif (status) {\n\t\tvar text = STATUS_MESSAGE[String(status)]\n\t\t\t|| (status >= 500 ? 'The AI provider returned a server error.'\n\t\t\t\t: 'The AI provider rejected the request.');\n\t\treturn text + ' (error ' + status + ')'\n\t\t\t+ (isTransientStatus(status) ? ' This is usually temporary, please try again.' : '');\n\t}\n\treturn 'Something went wrong.';\n}\n\nexport function isErrorResponseBody(response: any): boolean {\n\tif (!response || typeof response !== 'object') return false;\n\tif (typeof response.status_code === 'number' && response.status_code >= 400) return true;\n\tif (response.type === 'error') return true;\n\tif (response.error && (response.error.message || response.error.type)) return true;\n\tvar body = response.body;\n\tif (body && typeof body === 'object') {\n\t\tif (body.type === 'error') return true;\n\t\tif (body.error && (body.error.message || body.error.type)) return true;\n\t}\n\tif (typeof response.message === 'string' && response.message.length) {\n\t\tvar hasClaude = Array.isArray(response.content);\n\t\tvar hasOpenAI =\n\t\t\ttypeof response.output_text === 'string' ||\n\t\t\tArray.isArray(response.output) ||\n\t\t\tArray.isArray(response.choices);\n\t\tif (!hasClaude && !hasOpenAI) return true;\n\t}\n\treturn false;\n}\n\n// A request that failed because the REQUEST ITSELF is malformed — an unknown or\n// rejected parameter on a 400/422 — will deterministically re-fail if resent\n// unchanged; no session refresh or retry can fix it. Detecting it lets the retry\n// gates refuse to auto-resend (otherwise a 400 whose param name merely contains\n// \"token\", e.g. `max_output_tokens`, trips the `invalid_request + token` branch\n// of isAuthExpiredError below and loops refresh->resend forever, burning tokens).\n// This is the `_skapi_extract` 400 class. Distinct from auth-expiry, which IS\n// retryable after a token refresh — so 401 (auth) and 429/5xx (transient) are\n// intentionally NOT treated as non-retryable here.\nexport function isNonRetryableRequestError(input: any): boolean {\n\tif (!input || typeof input !== 'object') return false;\n\n\tvar status = typeof input.status_code === 'number' ? input.status_code\n\t\t: typeof input.status === 'number' ? input.status : undefined;\n\n\t// Collect the error envelope wherever it lives (response, response.body, or a\n\t// thrown error), mirroring isErrorResponseBody / isAuthExpiredError.\n\tvar param: any = undefined;\n\tvar blobs: string[] = [];\n\tvar sources = [input.error, input.body && input.body.error, input.body, input];\n\tfor (var i = 0; i < sources.length; i++) {\n\t\tvar e = sources[i];\n\t\tif (!e) continue;\n\t\tif (typeof e === 'string') { blobs.push(e); continue; }\n\t\tif (typeof e !== 'object') continue;\n\t\tif (param === undefined && e.param != null) param = e.param;\n\t\tif (typeof e.code === 'string') blobs.push(e.code);\n\t\tif (typeof e.type === 'string') blobs.push(e.type);\n\t\tif (typeof e.message === 'string') blobs.push(e.message);\n\t}\n\tvar hay = blobs.join(' | ').toLowerCase();\n\n\t// Explicit \"unknown / unsupported parameter\" is always a malformed request.\n\tif (hay.indexOf('unknown_parameter') !== -1 || hay.indexOf('unknown parameter') !== -1 ||\n\t\thay.indexOf('unsupported_parameter') !== -1 || hay.indexOf('unsupported parameter') !== -1) {\n\t\treturn true;\n\t}\n\n\t// A 400/422 invalid_request that points at a specific rejected field: resending\n\t// the identical body re-fails. (401 -> isAuthExpiredError; 429/5xx -> transient.)\n\tvar isClientReqStatus = status === 400 || status === 422;\n\tif (isClientReqStatus && param != null && param !== '') return true;\n\tif (isClientReqStatus && hay.indexOf('invalid_request') !== -1 &&\n\t\t(hay.indexOf('parameter') !== -1 || hay.indexOf('param') !== -1)) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport function isAuthExpiredError(input: any): boolean {\n\tif (!input) return false;\n\tvar blobs: string[] = [];\n\tvar push = function (v: any) { if (typeof v === 'string' && v) blobs.push(v); };\n\tif (typeof input === 'string') push(input);\n\telse {\n\t\tpush(input.message); push(input.code);\n\t\tif (input.error) { push(input.error.message); push(input.error.code); push(input.error.type); }\n\t\tif (input.body) {\n\t\t\tpush(input.body.message);\n\t\t\tif (input.body.error) { push(input.body.error.message); push(input.body.error.code); push(input.body.error.type); }\n\t\t}\n\t\tif (typeof input.status === 'number' && input.status === 401) return true;\n\t\tif (typeof input.status_code === 'number' && input.status_code === 401) return true;\n\t}\n\tvar hay = blobs.join(' | ').toLowerCase();\n\tif (!hay) return false;\n\treturn hay.indexOf('token has expired') !== -1 || hay.indexOf('token is expired') !== -1 ||\n\t\thay.indexOf('expired_token') !== -1 || hay.indexOf('invalid_token') !== -1 ||\n\t\thay.indexOf('unauthorized') !== -1 || hay.indexOf('not authorized') !== -1 ||\n\t\t(hay.indexOf('invalid_request') !== -1 && hay.indexOf('token') !== -1);\n}\n\n/**\n * True when the AI PROVIDER rejected the project's own API key.\n *\n * Deliberately narrow, and deliberately NOT the same question as\n * isAuthExpiredError: that one is about OUR session/MCP bearer going stale,\n * which the client fixes by refreshing and resending. This one means the key\n * the project owner pasted is wrong or revoked, which only a human can fix.\n *\n * A bare 401 is NOT enough to conclude it (the MCP bearer expiring is also a\n * 401), so this matches only the provider's key-specific markers:\n * Anthropic -> `authentication_error`, \"invalid x-api-key\"\n * OpenAI -> `invalid_api_key`, \"Incorrect API key provided\"\n * Accepts a response object, a thrown error, or the message string those get\n * reduced to by getErrorMessage, because the view usually only keeps the text.\n */\nexport function isProviderApiKeyError(input: any): boolean {\n\tif (!input) return false;\n\tvar blobs: string[] = [];\n\tvar push = function (v: any) { if (typeof v === 'string' && v) blobs.push(v); };\n\tif (typeof input === 'string') push(input);\n\telse {\n\t\tpush(input.message); push(input.code); push(input.type);\n\t\tif (input.error) { push(input.error.message); push(input.error.code); push(input.error.type); }\n\t\tif (input.body) {\n\t\t\tpush(input.body.message); push(input.body.type);\n\t\t\tif (input.body.error) { push(input.body.error.message); push(input.body.error.code); push(input.body.error.type); }\n\t\t}\n\t}\n\tvar hay = blobs.join(' | ').toLowerCase();\n\tif (!hay) return false;\n\treturn hay.indexOf('authentication_error') !== -1 ||\n\t\thay.indexOf('invalid_api_key') !== -1 ||\n\t\thay.indexOf('invalid x-api-key') !== -1 ||\n\t\thay.indexOf('incorrect api key') !== -1 ||\n\t\thay.indexOf('invalid api key') !== -1 ||\n\t\thay.indexOf('no api key provided') !== -1;\n}\n","/**\n * Pure link/path helpers (no DOM, no marked). Moved verbatim from the chatbox.\n * `projectId` is passed as a PARAMETER (the original read it from a global) so\n * the engine stays consumer-agnostic. The HTML-emitting helpers\n * (buildLinkPartFromGroups, linkToAnchorHtml, fileToAnchorHtml, parseMsgParts*)\n * stay in each VIEW — only these pure pieces move here.\n */\n\nexport var EXPIRED_ATTACHMENT_URL_HOST = '_expired_.url';\nexport var EXPIRED_ATTACHMENT_URL_ORIGIN = 'https://' + EXPIRED_ATTACHMENT_URL_HOST;\nexport var LINK_LABEL_MAX_DISPLAY_CHARS = 32;\n\n/**\n * Lifetime of the url minted when a user clicks an expired attachment chip.\n *\n * Mint it as a PLAIN get-db presign, never with generate_temporary_cdn_url: the\n * cdn branch ignores `expires` entirely and hands back a url good for the rest of\n * the current UTC day plus the next one, so a \"20 minute\" link would in fact live\n * 24 to 48 hours. The dashboard has always done this correctly and the widget did\n * not, which is precisely the kind of divergence a shared constant exists to stop.\n */\nexport var EXPIRED_LINK_REFRESH_EXPIRES_SECONDS = 20 * 60;\n\n/**\n * Lifetime of the url minted for an inline image PREVIEW.\n *\n * Longer than the click url above, and for a different reason. A click hands the\n * user a url they may keep, so it stays short. A preview url is consumed by the\n * page itself and never leaves it, and it is the ONE lever on how long the\n * downloaded picture stays reusable: get_signed_url will not cache a mint for\n * longer than the credential inside it survives, so `browser_cache` cannot buy\n * local availability that `expires` has not paid for. Twenty minutes meant every\n * image re-downloaded three times an hour of ordinary reading.\n *\n * An hour, giving 55 minutes of cache once the server's five minute headroom is\n * taken off. Short enough that a leaked preview url is not a standing grant, long\n * enough that a conversation does not re-fetch its own pictures while the user is\n * still reading it.\n */\nexport var PREVIEW_URL_EXPIRES_SECONDS = 60 * 60;\n\n/**\n * Seconds the browser may reuse a minted preview url (`browser_cache`).\n *\n * A presigned url is a fresh SigV4 query string on every mint, so it can never\n * be a browser cache key on its own and every reload re-downloads every image.\n * Asking for the MINT with a cacheable GET fixes it from the other end: the same\n * url comes back out of the browser cache, so the body already on disk stays\n * addressable.\n *\n * A CEILING, not a promise. get_signed_url caps what it grants at the lifetime of\n * the url inside the response (expires minus headroom, so 15 minutes for the\n * platform's 20 minute url), because a mint cached for longer than its own\n * credential is a guaranteed 403 that the browser keeps serving from its own\n * store. Asking for the week is still right: it says what this client would\n * reuse if the url were stable by construction, and the server decides.\n *\n * What keeps an image painting is the cached BODY, not a live url. Once the\n * browser evicts that body it refetches with a url that has since expired, gets a\n * 403, and the error path re-mints with `refresh` and mintCacheBustStamp. That\n * path is load-bearing, not a rare fallback.\n *\n * A week is the platform default for reading a private file, not a number chosen\n * here: skapi-js reads every private record file with\n * PRIVATE_FILE_BROWSER_CACHE_SECONDS = 7 days against the same 20-minute url, and\n * get_signed_url caps the header at BROWSER_CACHE_MAX_SECONDS = 7 days. A chat\n * that asked for a day was re-downloading images the rest of the product would\n * have served from disk.\n *\n * Applies to previews only. A CLICK must open a live url, so the chip refresh\n * stays on an uncached POST mint.\n */\nexport var PREVIEW_BROWSER_CACHE_SECONDS = 7 * 24 * 60 * 60;\n\n/**\n * How long a client may keep serving an href it already minted before dropping\n * back to the placeholder and re-minting.\n *\n * DERIVED from the TTL above, with five minutes of headroom, because the\n * invariant \"the cache must expire before the url does\" used to be a comment\n * next to two independent literals. If it is ever violated a client serves a\n * dead url with no way to notice; deriving it makes that unrepresentable.\n */\nexport var LINK_REFRESH_WINDOW_MS = (EXPIRED_LINK_REFRESH_EXPIRES_SECONDS - 5 * 60) * 1000;\n\n/**\n * Cache generation for the mint request url. BUMP THIS to abandon every mint\n * response browsers are currently holding.\n *\n * Generation 2 retires the entries written before 2026-08-11. Those were stored\n * with `max-age=604800` around a presign that dies in twenty minutes, so from\n * minute 21 each one is a guaranteed 403 that the browser keeps serving from its\n * own store for the rest of the week. The server no longer grants a lifetime a\n * url cannot back (get_signed_url resolve_browser_cache), but that fixes what is\n * written from now on and cannot reach what is already stored on a user's\n * device. Changing the url is the only thing that can: an entry nobody requests\n * again is an entry that cannot answer again.\n */\nexport var MINT_CACHE_GENERATION = 2;\n\n/**\n * Window stamp for a REFRESH mint.\n *\n * WINDOWED, not Date.now(): a per-call stamp is a new cache key per image per\n * retry, which is what made the original `nocache` parameter worse than the\n * disease. One stamp per refresh window means every repair inside those minutes\n * shares a single entry, and it rotates before the url it carries can die.\n */\nexport function mintCacheBustStamp(now?: number): number {\n\treturn Math.floor((now == null ? Date.now() : now) / LINK_REFRESH_WINDOW_MS);\n}\n\n/**\n * The `nocache` value for a preview mint: the generation, plus a window stamp\n * when this mint is a repair.\n *\n * A repair MUST reach the origin, and the request header the clients used to\n * rely on cannot do it. `Cache-Control: no-cache` is not a CORS-safelisted\n * request header, and the record gateway's preflight answers\n * `Access-Control-Allow-Headers` WITHOUT it (verified against the live api on\n * 2026-08-11), so a mint carrying that header is rejected by the browser before\n * it is ever sent. Every repair therefore failed, in every browser, and the chip\n * went straight to \"(unavailable)\". Only a phone noticed, because only a phone\n * drops image bodies often enough to need the repair at all.\n *\n * A query parameter has no such problem: it is part of the url, so it needs no\n * preflight and no cooperation from the cache.\n */\nexport function previewMintCacheToken(refresh?: boolean): string {\n\tif (!refresh) return String(MINT_CACHE_GENERATION);\n\treturn MINT_CACHE_GENERATION + '.' + mintCacheBustStamp();\n}\n\n/**\n * How long before a presign dies we stop handing it out.\n *\n * A url served with one second left is a 403 with extra steps: the request still\n * has to reach S3, and an image body still has to start arriving.\n */\nexport var PRESIGN_SAFETY_MARGIN_MS = 60 * 1000;\n\n/**\n * When the url in hand actually dies, read out of the url itself, or null if it\n * carries no expiry we recognise.\n *\n * Every client-side cache here ages a url from the moment it ARRIVED, which is\n * only the same thing as its lifetime when the mint went to the network. Once\n * mint responses are cacheable that assumption breaks: a mint answered from the\n * browser's store can be nearly as old as its own max-age, and the client then\n * adds its own reuse window on top, so a 20 minute credential can be handed to an\n * <img> half an hour after it was signed. Asking the url when it dies removes the\n * stacking instead of trying to budget for it.\n *\n * Both signature versions, because the platform mints SigV2 through the host\n * bucket and SigV4 elsewhere.\n */\nexport function presignExpiryEpochMs(url: string): number | null {\n\tif (!url) return null;\n\tvar q = url.indexOf('?');\n\tif (q < 0) return null;\n\tvar params: URLSearchParams;\n\ttry { params = new URLSearchParams(url.slice(q + 1)); }\n\tcatch (e) { return null; }\n\n\t// SigV2: Expires is an absolute epoch in seconds.\n\tvar v2 = params.get('Expires');\n\tif (v2 && /^\\d+$/.test(v2)) return parseInt(v2, 10) * 1000;\n\n\t// SigV4: signing time plus a duration.\n\tvar signed = params.get('X-Amz-Date');\n\tvar lifetime = params.get('X-Amz-Expires');\n\tif (signed && lifetime && /^\\d+$/.test(lifetime)) {\n\t\tvar m = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(signed);\n\t\tif (m) {\n\t\t\tvar at = Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6]);\n\t\t\treturn at + parseInt(lifetime, 10) * 1000;\n\t\t}\n\t}\n\treturn null;\n}\n\n// The two \"balanced parens\" groups match ONE CHARACTER per step, never a `+`\n// run, so each position has exactly one way to be matched: `[^()\\n]` cannot\n// start with `(`, and the nested-paren alternative always does. That disjointness\n// is load-bearing, not style.\n//\n// The obvious spelling — `(?:[^()\\n]+|\\([^()\\n]*\\))+` — is a nested quantifier:\n// a run of N plain characters can be split across the outer `+` in 2^N ways, and\n// the engine tries EVERY one before it can conclude the branch failed. A branch\n// fails on ordinary input: a link whose url contains a space (the url branch\n// forbids spaces), a link broken across a newline, or a reply truncated\n// mid-link. Measured on the unfixed pattern: `[label](` plus 30 characters with\n// no closing paren took 62 SECONDS, 45 characters never finished. Since this\n// regex is scanned over the whole reply by the typewriter (session.ts) and by\n// every message render (parseMsgParts), that is a permanently frozen tab the\n// moment such a message arrives. Same matches either way, linear time.\nexport function createInlineLinkRegex(): RegExp {\n\treturn /src::(\\S+)|\\[([^\\]\\n]+)\\]\\((https?:\\/\\/(?:[^\\s()]|\\([^\\s()]*\\))+)\\)|\\[([^\\]\\n]+)\\]\\(((?:[^()\\n]|\\([^()\\n]*\\))+)\\)|(https?:\\/\\/[^\\s<>\"']+)/g;\n}\n\nexport function safeDecodeURIComponent(v: string): string {\n\ttry { return decodeURIComponent(v); } catch (e) { return v; }\n}\n\nexport function encodePathSegments(path: string): string {\n\treturn path.split('/').filter(Boolean).map(function (s) { return encodeURIComponent(s); }).join('/');\n}\n\nexport function normalizeAttachmentPathCandidate(value: string): string {\n\treturn safeDecodeURIComponent((value || '').trim()).replace(/\\\\/g, '/').replace(/^\\/+/, '').replace(/\\/+/g, '/');\n}\n\nexport function extractRemotePathFromAttachmentHref(href: string, projectId: string): string | null {\n\ttry {\n\t\tvar parsed = new URL(href);\n\t\tif (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return null;\n\t\tvar path = normalizeAttachmentPathCandidate(parsed.pathname || '');\n\t\tvar segs = path.split('/').filter(Boolean);\n\t\tif (!segs.length) return null;\n\t\tvar HEX = /^[a-f0-9]{32,}$/i;\n\t\tvar sid = projectId || '';\n\t\tvar start = 0;\n\t\twhile (start < segs.length) {\n\t\t\tvar seg = segs[start];\n\t\t\tif (seg === sid || HEX.test(seg)) { start++; continue; }\n\t\t\tbreak;\n\t\t}\n\t\tvar real = segs.slice(start).join('/');\n\t\treturn real || null;\n\t} catch (e) { return null; }\n}\n\nexport function getExpiredAttachmentVisiblePath(remotePath: string, fallback?: string): string {\n\tvar n = normalizeAttachmentPathCandidate(remotePath);\n\tif (n) return n;\n\treturn normalizeAttachmentPathCandidate(fallback || 'file') || 'file';\n}\n\nexport function buildDisplayExpiredAttachmentHref(remotePath: string, fallback?: string): string {\n\treturn EXPIRED_ATTACHMENT_URL_ORIGIN + '/' + encodePathSegments(getExpiredAttachmentVisiblePath(remotePath, fallback));\n}\n\n// Does `href` point at THIS service's db attachment storage? A db attachment URL's\n// path always begins with the projectId segment (…/<projectId>/<hash>/<path>). Used\n// to SAFELY sanitize assistant messages — where an arbitrary external citation URL\n// must never be rewritten, only the service's own volatile db links.\nexport function isServiceDbAttachmentHref(href: string, projectId: string): boolean {\n\tif (!projectId) return false;\n\ttry {\n\t\tvar parsed = new URL(href);\n\t\tif (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false;\n\t\tvar segs = normalizeAttachmentPathCandidate(parsed.pathname || '').split('/').filter(Boolean);\n\t\treturn segs.length > 0 && segs[0] === projectId;\n\t} catch (e) { return false; }\n}\n\n/**\n * Read the storage path back out of an `_expired_.url` placeholder.\n *\n * The placeholder is not a display detail: sanitizeAttachmentLinksForHistory\n * writes it into PERSISTED history, and buildBoundedChatMessages replays it into\n * the model's context. So it round-trips constantly and MUST be recognised on the\n * way back in. Returns null for anything that is not the carrier.\n */\nexport function readExpiredAttachmentHref(href: string): string | null {\n\tif (!href) return null;\n\ttry {\n\t\tvar parsed = new URL(href);\n\t\tif (parsed.hostname !== EXPIRED_ATTACHMENT_URL_HOST) return null;\n\t\treturn normalizeAttachmentPathCandidate(parsed.pathname || '') || null;\n\t} catch (e) { return null; }\n}\n\n// Replace volatile attachment URLs with their durable `_expired_.url/<path>`\n// placeholder so a stored/replayed copy re-mints on demand instead of going stale.\n//\n// Only THIS service's db urls are rewritten, whichever role wrote them. The user\n// branch used to rewrite every url in any message that carried an \"Attached\n// files:\" block, which quietly destroyed a third-party link the user happened to\n// paste in the same message: it became a placeholder for a storage path that\n// never existed. We can only re-mint what we host, so we only rewrite what we\n// host.\nexport function sanitizeAttachmentLinksForHistory(content: string, projectId: string, forAssistant?: boolean): string {\n\tif (!content) return content;\n\tif (!forAssistant && content.indexOf('Attached files:') === -1) return content;\n\treturn content.replace(/\\[([^\\]\\n]+)\\]\\((https?:\\/\\/[^\\s)]+)\\)/g, function (_m: string, label: string, href: string) {\n\t\tif (!isServiceDbAttachmentHref(href, projectId)) return _m;\n\t\tvar remotePath = extractRemotePathFromAttachmentHref(href, projectId);\n\t\tvar fullPath = remotePath || normalizeAttachmentPathCandidate(label);\n\t\tif (!fullPath) return _m;\n\t\treturn '[' + label + '](' + buildDisplayExpiredAttachmentHref(fullPath, label) + ')';\n\t});\n}\n\n/**\n * Is this markdown link target a URL rather than a db storage path?\n *\n * The inline-link regex decides that by whether the target contains whitespace:\n * its url branch forbids it, its bare-path branch allows it (a db path really can\n * contain spaces). So a url that picked up a stray space anywhere in transit\n * falls out of the url branch and is claimed by the path branch, and the view\n * renders it as an `_expired_.url/https%3A/…` attachment chip that resolves to\n * nothing. The view asks this FIRST, so what a link IS never depends on damage.\n */\nexport function isHttpUrlLike(target: string): boolean {\n\treturn /^https?:\\/\\//i.test((target || '').trim());\n}\n\n/**\n * Repair whitespace inside a url. RFC 3986 has no legal whitespace anywhere in a\n * URI, so a space in an href is always damage, never content.\n *\n * Two repairs, because the right one differs:\n * - Our own `/download/<id>` capability links (skapi-mcp file-download.js) are\n * base64url, optionally with a single `.` separating the payload and hmac of\n * the older self-describing token. That alphabet cannot contain whitespace,\n * so the spaces are purely damage and REMOVING them restores the exact link,\n * which is what makes an already-sent message clickable again. A model\n * reproducing one of these into its reply is exactly where the spaces come\n * from, which is also why the id is now short.\n * - Anything else keeps every character and only has the whitespace encoded,\n * the same thing a browser does with a space in an href. Stripping would be\n * wrong there: `…/exports/my report.csv` is a real file whose name has a\n * space in it, and deleting it points at a file that does not exist.\n */\nexport function repairUrlWhitespace(href: string): string {\n\tif (!href || !/\\s/.test(href)) return href;\n\tvar stripped = href.replace(/\\s+/g, '');\n\tif (/^https?:\\/\\/[^/\\s]+\\/download\\/[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)?$/i.test(stripped)) return stripped;\n\treturn href.trim().replace(/\\s/g, '%20');\n}\n\n/**\n * A model reproducing a URL sometimes HTML-escapes its `&` query separators as\n * `&amp;` (or the numeric `&#38;` / `&#x26;`). Left in the href that escaping\n * survives the client's own escapeAttr -> v-html/innerHTML decode round-trip and\n * reaches the browser LITERALLY, so a presigned S3 URL is navigated with its\n * parameters named `amp;Signature`, `amp;Expires`, `amp;response-content-type`,\n * ... — the real params vanish, the signature can't be located, and S3 rejects\n * it (the \"링크가 안되\" dead export link). Undo just that entity escaping.\n *\n * This is a no-op on a clean URL: a valid link carries a raw `&` between params\n * and percent-encodes (`%26`) any literal ampersand that is data, so a real URL\n * never contains `&amp;` to begin with. Mirrors repairUrlWhitespace: it repairs\n * model damage, not the URL. The loop collapses a doubly-escaped `&amp;amp;` too.\n */\nexport function repairUrlEntities(href: string): string {\n\tif (!href || href.indexOf('&') === -1) return href;\n\tvar out = href, prev = '';\n\twhile (out !== prev) {\n\t\tprev = out;\n\t\tout = out\n\t\t\t.replace(/&amp;/gi, '&')\n\t\t\t.replace(/&#0*38;/g, '&')\n\t\t\t.replace(/&#x0*26;/gi, '&');\n\t}\n\treturn out;\n}\n\n/**\n * Trim punctuation and unmatched wrappers that cling to a token in prose.\n * `src::a/b.pdf).` -> `src::a/b.pdf`, while a balanced `file (v2).pdf` is kept.\n */\nexport function normalizeTrailingInlineToken(value: string): string {\n\tif (!value) return value;\n\tvar out = value.replace(/[.,;:!?]+$/, '');\n\tvar trimUnmatched = function (openCh: string, closeCh: string) {\n\t\twhile (out.charAt(out.length - 1) === closeCh) {\n\t\t\tvar openCount = (out.match(new RegExp('\\\\' + openCh, 'g')) || []).length;\n\t\t\tvar closeCount = (out.match(new RegExp('\\\\' + closeCh, 'g')) || []).length;\n\t\t\tif (closeCount > openCount) out = out.slice(0, -1); else break;\n\t\t}\n\t};\n\ttrimUnmatched('(', ')');\n\ttrimUnmatched('[', ']');\n\ttrimUnmatched('{', '}');\n\tout = out.replace(/[`'\"*>]+$/, '');\n\treturn out;\n}\n\n/**\n * Extensions a BROWSER can paint in an <img>, mapped to the content type the\n * presign must declare.\n *\n * The content type is not optional here. get_signed_url only sets\n * ResponseContentType when the caller passes `contentType`, and otherwise falls\n * back to application/octet-stream, which a new tab DOWNLOADS instead of\n * displaying. Since the whole point of the preview is that clicking it shows the\n * picture, the mint has to name the real type.\n *\n * Deliberately narrower than the extraction/vision lists elsewhere in the repo:\n * heic/heif out: Safari paints them, Chrome and Firefox show a broken image,\n * and it is the format every iPhone photo arrives in, so the\n * failure would be common and would read as a bug.\n * tif/wmf/emf out: no mainstream browser paints them.\n * svg out: inside an <img> an SVG is script-disabled and safe, but this\n * feature's click target is a TOP-LEVEL navigation, where an\n * SVG executes its own <script> in the serving origin with that\n * origin's cookies, from user-uploaded content. A preview is an\n * invitation to click exactly that.\n */\nexport var PREVIEWABLE_IMAGE_CONTENT_TYPES: Record<string, string> = {\n\tpng: 'image/png',\n\tjpg: 'image/jpeg',\n\tjpeg: 'image/jpeg',\n\tgif: 'image/gif',\n\twebp: 'image/webp',\n\tavif: 'image/avif',\n\tbmp: 'image/bmp',\n};\n\n/** Extension of a path or url, query and fragment stripped, '' when none. */\nexport function previewableExtOf(nameOrPath: string | null | undefined): string {\n\tvar v = String(nameOrPath || '');\n\t// A storage path may legally contain '?', so this cannot reuse extOf().\n\tvar cut = v.search(/[?#]/);\n\tif (cut !== -1) v = v.slice(0, cut);\n\tv = v.replace(/[\\\\/]+$/, '');\n\tvar dot = v.lastIndexOf('.');\n\tif (dot <= 0) return '';\n\tvar ext = v.slice(dot + 1).trim().toLowerCase();\n\treturn /^[a-z0-9]+$/.test(ext) ? ext : '';\n}\n\nexport function isPreviewableImagePath(nameOrPath: string | null | undefined): boolean {\n\treturn !!PREVIEWABLE_IMAGE_CONTENT_TYPES[previewableExtOf(nameOrPath)];\n}\n\n/** Content type to hand the presign so a new tab displays rather than downloads. */\nexport function previewImageContentType(nameOrPath: string | null | undefined): string | null {\n\treturn PREVIEWABLE_IMAGE_CONTENT_TYPES[previewableExtOf(nameOrPath)] || null;\n}\n\n/** A link the view renders. `expired` means the href is the `_expired_.url`\n * placeholder and a click must mint a fresh one from `remotePath`. */\nexport interface InlineLinkPart {\n\ttype: 'link';\n\tlabel: string;\n\tfullLabel: string;\n\thref: string;\n\texpired: boolean;\n\texpiredHref?: string;\n\tremotePath?: string;\n\t/**\n\t * Set only for a file WE host whose PATH says a browser can paint it. Its\n\t * presence IS the \"render a preview\" decision, so a view never re-tests the\n\t * label and never tests `href` (which is the _expired_.url placeholder).\n\t */\n\timage?: { ext: string; contentType: string };\n}\n\nexport interface InlineLinkContext {\n\t/** Current project id: the leading segment to strip off a db url. */\n\tprojectId: string;\n\t/** `https://db.<hostDomain>` for this deployment. */\n\tdbHostPrefix: string;\n\t/** A fresh url already minted for this placeholder, if the view cached one. */\n\tresolveFreshHref?: (expiredHref: string) => string | undefined;\n}\n\n/**\n * Decide what ONE inline-link regex match actually is, and how to render it.\n *\n * This is the single place that answers \"is this an external url, this project's\n * db file, or a bare storage path\", for every consumer. It used to live twice,\n * once in agent.vue and once in the widget, and both copies had to be found and\n * corrected for each of the link bugs this file's history records. A view now\n * supplies its own context (project id, db host, cached-href lookup) and does\n * nothing but turn the returned part into markup.\n *\n * `groups` is [g1..g6] from createInlineLinkRegex, in that order:\n * g1 src::<token> g2/g3 [label](url) g4/g5 [label](path) g6 bare url\n */\nexport function classifyInlineLink(\n\tfull: string,\n\tgroups: Array<string | undefined>,\n\tctx: InlineLinkContext,\n): { part: InlineLinkPart; tail?: string } | null {\n\tvar g1 = groups[0], g2 = groups[1], g3 = groups[2], g4 = groups[3], g5 = groups[4], g6 = groups[5];\n\tvar dbHostPrefix = (ctx.dbHostPrefix || '').toLowerCase();\n\tvar fresh = function (expiredHref: string): string | undefined {\n\t\treturn ctx.resolveFreshHref ? ctx.resolveFreshHref(expiredHref) : undefined;\n\t};\n\tvar isDbHost = function (url: string): boolean {\n\t\treturn !!dbHostPrefix && url.toLowerCase().indexOf(dbHostPrefix) === 0;\n\t};\n\t// A db path rendered as the placeholder the click handler resolves.\n\tvar asStoredFile = function (remotePath: string, label: string): { part: InlineLinkPart } | null {\n\t\tif (!remotePath) return null;\n\t\tvar expiredHref = buildDisplayExpiredAttachmentHref(remotePath, label);\n\t\tvar cached = fresh(expiredHref);\n\t\tvar part: InlineLinkPart = {\n\t\t\ttype: 'link',\n\t\t\tlabel: truncateLabelForDisplay(label),\n\t\t\tfullLabel: label,\n\t\t\thref: cached || expiredHref,\n\t\t\texpired: !cached,\n\t\t\texpiredHref: expiredHref,\n\t\t\tremotePath: remotePath,\n\t\t};\n\t\t// The PATH decides, never the label. The file is fetched by path, so the\n\t\t// path is the only claim with consequences: a model-written label reading\n\t\t// \"chart.png\" on a .xlsx would otherwise mint a url and paint a broken box.\n\t\tvar ext = previewableExtOf(remotePath);\n\t\tvar ct = PREVIEWABLE_IMAGE_CONTENT_TYPES[ext];\n\t\tif (ct) part.image = { ext: ext, contentType: ct };\n\t\treturn { part: part };\n\t};\n\n\t// src::<token> — a path, or a url the model copied out of a record.\n\tif (g1) {\n\t\tvar rawPath = normalizeTrailingInlineToken(g1);\n\t\tvar tail = full.slice(('src::' + rawPath).length);\n\t\tvar srcIsUrl = isHttpUrlLike(rawPath);\n\t\t// `src::` values come straight out of a record's unique_id, and the prompt\n\t\t// says that may be \"the file's storage path or original URL\". http:// is as\n\t\t// much a url as https://; testing only for https sent every plain-http\n\t\t// source into the storage-path branch, where it became a chip pointing at\n\t\t// this project for someone else's file.\n\t\tif (srcIsUrl && !isDbHost(rawPath) && !readExpiredAttachmentHref(rawPath)) {\n\t\t\t// decode any model-introduced `&amp;` in the URL (tail stays keyed on\n\t\t\t// the raw match length, so it is left untouched)\n\t\t\tvar srcUrl = repairUrlEntities(rawPath);\n\t\t\treturn {\n\t\t\t\tpart: { type: 'link', label: truncateLabelForDisplay(srcUrl), fullLabel: srcUrl, href: srcUrl, expired: false },\n\t\t\t\ttail: tail,\n\t\t\t};\n\t\t}\n\t\tvar srcPath = readExpiredAttachmentHref(rawPath)\n\t\t\t|| (srcIsUrl\n\t\t\t\t? (extractRemotePathFromAttachmentHref(rawPath, ctx.projectId) || normalizeAttachmentPathCandidate(rawPath))\n\t\t\t\t// bare stored path: same NON-decoding normalize as the db: branch; only\n\t\t\t\t// URL-derived paths genuinely arrive percent-encoded.\n\t\t\t\t: rawPath.trim().replace(/\\\\/g, '/').replace(/^\\/+/, '').replace(/\\/+/g, '/'));\n\t\tvar srcBuilt = asStoredFile(srcPath, srcPath);\n\t\treturn srcBuilt ? { part: srcBuilt.part, tail: tail } : null;\n\t}\n\n\t// [label](target) where target is NOT a url by the regex's reckoning.\n\tif (g4 && g5) {\n\t\t// An EXPLICIT db target, `[label](db:folder/file.csv)`, says what it is\n\t\t// instead of leaving us to infer it from the absence of \"http\". That is the\n\t\t// only form here that cannot be confused with anything else, and it matches\n\t\t// the scheme the backend already uses internally (db:<service>/<key>).\n\t\t// Accepted now so the clients tolerate it everywhere before anything starts\n\t\t// EMITTING it; until then this branch simply never fires.\n\t\tvar dbTarget = /^db:(.+)$/i.exec(g5.trim());\n\t\tif (dbTarget) {\n\t\t\t// NON-decoding normalize: the prompt guarantees a db: target is the path exactly\n\t\t\t// as stored, NOT url-encoded, and the MCP's own key builder refuses to decode\n\t\t\t// bare paths for the same corruption: percent-decoding here turned a stored name\n\t\t\t// containing a literal \"%20\" into the wrong key.\n\t\t\tvar rawDbPath = dbTarget[1].trim().replace(/\\\\/g, '/').replace(/^\\/+/, '').replace(/\\/+/g, '/');\n\t\t\tvar declared = asStoredFile(rawDbPath, g4);\n\t\t\tif (!declared) return null;\n\t\t\tdeclared.part.label = truncateLabelForDisplay(g4);\n\t\t\tdeclared.part.fullLabel = g4;\n\t\t\treturn declared;\n\t\t}\n\t\t// ...except when it is one. It only lands here because it contains\n\t\t// whitespace, which the url branch forbids and this one allows, and\n\t\t// reading a damaged url as a storage path is how a download link became a\n\t\t// dead chip. Repair it and classify it as what it is.\n\t\tif (isHttpUrlLike(g5)) {\n\t\t\treturn classifyInlineLink(full, [undefined, g4, repairUrlWhitespace(g5), undefined, undefined, undefined], ctx);\n\t\t}\n\t\t// Any OTHER scheme, or a fragment, is a link the user wrote and not a file\n\t\t// we host. `mailto:`, `tel:` and `#section` were all being turned into\n\t\t// download chips for storage paths of that literal text, so clicking one\n\t\t// asked this project for a file called \"mailto:a@b.com\".\n\t\tvar trimmedTarget = g5.trim();\n\t\tif (/^[a-z][a-z0-9+.-]*:/i.test(trimmedTarget) || trimmedTarget.charAt(0) === '#') {\n\t\t\treturn {\n\t\t\t\tpart: { type: 'link', label: truncateLabelForDisplay(g4), fullLabel: g4, href: trimmedTarget, expired: false },\n\t\t\t};\n\t\t}\n\t\tvar built = asStoredFile(normalizeAttachmentPathCandidate(g5), g4);\n\t\tif (!built) return null;\n\t\t// The label is the model's, not the path: keep it verbatim.\n\t\tbuilt.part.label = truncateLabelForDisplay(g4);\n\t\tbuilt.part.fullLabel = g4;\n\t\treturn built;\n\t}\n\n\t// [label](url) and bare urls.\n\tvar originalHref = g3 || g6 || '';\n\tif (!originalHref) return null;\n\t// A model that reproduces the URL may have HTML-escaped its `&` separators;\n\t// decode them now so every downstream check and the final href see a clean\n\t// URL (otherwise a presigned link navigates with `&amp;` and 403s).\n\toriginalHref = repairUrlEntities(originalHref);\n\t// A bare url swallows the punctuation that ends the sentence it sits in, so\n\t// `see https://host/a.pdf.` linked to `a.pdf.` and 404'd. Trim it and hand the\n\t// trimmed text back as `tail`, exactly as the src:: branch does.\n\tvar urlTail: string | undefined;\n\tif (!g3 && g6) {\n\t\tvar trimmedUrl = normalizeTrailingInlineToken(originalHref);\n\t\tif (trimmedUrl !== originalHref) urlTail = originalHref.slice(trimmedUrl.length);\n\t\toriginalHref = trimmedUrl;\n\t}\n\tvar withTail = function (r: { part: InlineLinkPart }): { part: InlineLinkPart; tail?: string } {\n\t\treturn urlTail ? { part: r.part, tail: urlTail } : r;\n\t};\n\tvar urlLabel = g2 || originalHref;\n\n\t// THE PLACEHOLDER, read back. sanitizeAttachmentLinksForHistory writes this\n\t// form into stored history and buildBoundedChatMessages replays it to the\n\t// model, so it arrives here constantly: as a rebuilt bubble on every reload,\n\t// and as text the model copied out of its own context. It has to be checked\n\t// BEFORE the generic https branch, because it IS https and it is NOT the db\n\t// host, so that branch claimed it and rendered `expired: false` — a link to a\n\t// hostname that does not resolve, with no way to ever refresh it. Every stored\n\t// attachment link went dead on reload for exactly that reason.\n\tvar carried = readExpiredAttachmentHref(originalHref);\n\tif (carried) {\n\t\tvar carriedBuilt = asStoredFile(carried, g2 || carried);\n\t\tif (carriedBuilt) {\n\t\t\tif (g2) { carriedBuilt.part.label = truncateLabelForDisplay(g2); carriedBuilt.part.fullLabel = g2; }\n\t\t\treturn withTail(carriedBuilt);\n\t\t}\n\t}\n\n\t// This project's own db url: volatile, so render it re-mintable. A db url for\n\t// a DIFFERENT project is not ours to mint, so it stays an ordinary link rather\n\t// than a chip that would query this project for someone else's key.\n\tif (isServiceDbAttachmentHref(originalHref, ctx.projectId)) {\n\t\tvar remotePath = extractRemotePathFromAttachmentHref(originalHref, ctx.projectId);\n\t\tif (remotePath) {\n\t\t\tvar dbBuilt = asStoredFile(remotePath, getExpiredAttachmentVisiblePath(remotePath, urlLabel));\n\t\t\tif (dbBuilt) return withTail(dbBuilt);\n\t\t}\n\t}\n\n\t// Everything else is a link, not a path. The old rule tested for `https://`\n\t// specifically and treated ANY other target as db storage, so a plain\n\t// `http://` citation, a `mailto:`, a `#anchor` and a `/relative` link all\n\t// rendered as download chips for storage paths that never existed, and\n\t// clicking one raised \"failed to refresh\" on a file the user never had.\n\treturn withTail({\n\t\tpart: { type: 'link', label: truncateLabelForDisplay(urlLabel), fullLabel: urlLabel, href: originalHref, expired: false },\n\t});\n}\n\n/**\n * \"We asked for a url for this file and did not get one.\"\n *\n * A chip the client cannot mint a url for is not a link: the ↗ is a promise it\n * already knows it cannot keep, and clicking it opens a dead tab or nothing at\n * all. Both views therefore keep a map of failures and render those chips\n * unavailable (renderInlineLinkHtml's `unavailable` option): greyed, ✕ instead\n * of ↗, no href.\n *\n * The MAP lives in the view (agent.vue has to re-render when it changes, and\n * that means a ref), so only the keys are here. A failure is reported with\n * exactly one identifier (an image preview knows the storage path, a click knows\n * the placeholder href), so marking writes one key and the lookup tries all of\n * them.\n */\n/**\n * Unicode form is not stable across the places a storage path travels through.\n *\n * macOS hands the browser a DECOMPOSED (NFD) filename, so a Korean name like\n * 운전면허-김대현.jpg arrives as 24 codepoints where the composed (NFC) form is 12.\n * Nothing in this engine normalized either way, so the SAME file could be keyed under\n * two different strings depending on which path it travelled: a mark left by a failed\n * mint under one form would never be cleared by a successful load under the other, and\n * the chip stayed greyed out as \"(unavailable)\" forever.\n *\n * NFC is the canonical choice: it is what the Unicode standard recommends for\n * interchange, and it is the shorter, more common form on the wire.\n */\nexport function canonicalizePathForm(value: string): string {\n\tif (!value) return value;\n\ttry { return value.normalize('NFC'); } catch (e) { return value; }\n}\n\nexport function linkUnavailableKeyForPath(remotePath: string): string {\n\t// Canonicalized so the NFC and NFD spellings of one file share ONE key.\n\treturn 'path:' + canonicalizePathForm(remotePath || '');\n}\n\nexport function linkUnavailableKeyForHref(href: string): string {\n\t// An `_expired_.url` placeholder carries the storage path percent-encoded, so NFC and\n\t// NFD spellings of one file produce two different href strings and therefore two\n\t// different keys. Route those through the path key instead, so a file has ONE key\n\t// however it is spelled and whichever carrier it arrived on.\n\tvar carried = readExpiredAttachmentHref(href);\n\tif (carried) return linkUnavailableKeyForPath(carried);\n\treturn 'href:' + canonicalizePathForm(href || '');\n}\n\n/**\n * Every key a stored file can be marked under, given only its path.\n *\n * Marking writes ONE key (whichever identifier the failing call had) and the\n * lookup ORs all of them, which is fine in one direction and wrong in the other:\n * a view that later learns the file is reachable knows only the path, and\n * clearing `path:` alone leaves a chip greyed by a failed CLICK (which marks\n * `href:` too) exactly as dead as before. The placeholder href is derived from\n * the path, so both keys can be rebuilt from it.\n */\nexport function linkUnavailableKeysForPath(remotePath: string): string[] {\n\tif (!remotePath) return [];\n\tvar keys = [\n\t\tlinkUnavailableKeyForPath(remotePath),\n\t\tlinkUnavailableKeyForHref(buildDisplayExpiredAttachmentHref(remotePath)),\n\t];\n\t// Both now canonicalize to the same key for a placeholder href, so drop the duplicate\n\t// rather than marking and clearing the same entry twice.\n\treturn keys.filter(function (k, i) { return keys.indexOf(k) === i; });\n}\n\nexport function isLinkUnavailable(\n\tlink: { href?: string; expiredHref?: string; remotePath?: string } | null | undefined,\n\tmap: Record<string, boolean | undefined> | null | undefined,\n): boolean {\n\tif (!link || !map) return false;\n\tif (link.remotePath && map[linkUnavailableKeyForPath(link.remotePath)]) return true;\n\tif (link.expiredHref && map[linkUnavailableKeyForHref(link.expiredHref)]) return true;\n\tif (link.href && map[linkUnavailableKeyForHref(link.href)]) return true;\n\treturn false;\n}\n\nexport function truncateLabelForDisplay(label: string): string {\n\tif (!label) return label;\n\tif (label.length <= LINK_LABEL_MAX_DISPLAY_CHARS) return label;\n\treturn '…' + label.slice(label.length - (LINK_LABEL_MAX_DISPLAY_CHARS - 1));\n}\n","/**\n * Token-budgeting (pure). Moved verbatim from the chatbox. Constants are shared\n * module-level values (identical in both consumers); a config knob is premature.\n * buildBoundedChatMessages now takes `projectId` in its options so it can pass it\n * to sanitizeAttachmentLinksForHistory (which used to read a global).\n */\nimport { sanitizeAttachmentLinksForHistory } from './links';\n\nexport var CONTEXT_WINDOW_DEFAULT: Record<string, number> = { claude: 200000, openai: 128000 };\n// Exact model ids first, then family keys (see getModelContextWindow: a suffixed\n// id falls back to its family rather than to the platform default). Claude\n// figures come from Anthropic's published model table; `max_input_tokens` from\n// /v1/models overrides all of this at runtime when a listing has been seen.\n// OpenAI's /v1/models carries NO context field at all, so every gpt entry here\n// is hand-maintained and is the only source for those models.\n// These are TOTAL windows (input + output), which is what the published tables\n// report and what getInputTokenBudget assumes when it subtracts the output\n// reserve. The two readings reconcile: gpt-5.6-luna is 1,050,000 total with a\n// 128,000 output cap, i.e. the ~922,000 of usable input quoted for it elsewhere.\nexport var CONTEXT_WINDOW_BY_MODEL: Record<string, number> = {\n\t// claude, exact ids\n\t'claude-fable-5': 1000000, 'claude-opus-5': 1000000,\n\t'claude-opus-4-8': 1000000, 'claude-opus-4-7': 1000000,\n\t'claude-opus-4-6': 1000000, 'claude-opus-4-5': 200000,\n\t'claude-sonnet-5': 1000000, 'claude-sonnet-4-6': 1000000,\n\t'claude-sonnet-4-5': 1000000, 'claude-sonnet-4': 200000,\n\t'claude-haiku-4-5': 200000, 'claude-3-5-sonnet': 200000,\n\t// openai, exact ids\n\t'gpt-5.6-sol': 1050000, 'gpt-5.6-terra': 1050000, 'gpt-5.6-luna': 1050000,\n\t'gpt-5.5': 1000000, 'gpt-5.4': 1050000,\n\t'gpt-5.4-mini': 400000, 'gpt-5.4-nano': 400000,\n\t'gpt-4.1': 1040000, 'gpt-4o': 128000, 'o1': 200000, 'o1-pro': 200000,\n\t// family keys\n\t'claude-fable': 1000000, 'claude-opus': 1000000, 'claude-sonnet': 1000000,\n\t'claude-haiku': 200000, 'gpt-5.6': 1050000, 'gpt-5': 128000,\n};\n// Two rows above are load-bearing rather than redundant, both because the family\n// walk drops trailing segments:\n// 'claude-opus-4-5' — a dated id like 'claude-opus-4-5-20251101' would\n// otherwise walk past it to the 'claude-opus' family and resolve 1000000 for\n// a model whose real window is 200000.\n// 'gpt-5.4-mini' and 'gpt-5.4-nano' — would otherwise walk to 'gpt-5.4' and\n// resolve 1050000 instead of their actual 400000. nano is the one that\n// matters most in practice: the indexing path selects it by name.\n// The bare 'gpt-5' family stays deliberately low: it is the catch-all for gpt-5\n// variants not listed here, and a mini-class variant is the likelier unknown.\n//\n// One asymmetry these rows expose: a total minus our output reserve can exceed a\n// model's separately-published INPUT ceiling (gpt-5.4-nano is 400000 total but\n// caps input at 272000, where 400000 - 25000 - 4000 reads as 371000). Harmless\n// today because INPUT_CAP_RATIO binds far below either figure (59360 for nano),\n// but it is why the ratio is not something to remove.\n\n// Provider hard ceilings on output tokens per request. Only used to clamp what\n// we ask for (see getMaxOutputTokens) — we never request more than\n// MAX_OUTPUT_TOKENS anyway, so this matters exactly where a model's cap is\n// BELOW that: gpt-4o at 4000 and legacy 3.5 Sonnet at 8000 would reject the\n// flat 25000 the request builder used to send unconditionally.\nexport var MAX_OUTPUT_BY_MODEL: Record<string, number> = {\n\t// claude\n\t'claude-fable-5': 128000, 'claude-opus-5': 128000,\n\t'claude-opus-4-8': 128000, 'claude-sonnet-5': 128000,\n\t'claude-sonnet-4-6': 64000, 'claude-haiku-4-5': 64000,\n\t'claude-3-5-sonnet': 8000,\n\t// openai\n\t'gpt-5.6-sol': 128000, 'gpt-5.6-terra': 128000, 'gpt-5.6-luna': 128000,\n\t'gpt-5.5': 128000, 'gpt-5.4': 128000,\n\t'gpt-5.4-mini': 128000, 'gpt-5.4-nano': 128000,\n\t'gpt-4.1': 16000, 'gpt-4o': 4000, 'o1': 100000, 'o1-pro': 100000,\n\t// family keys\n\t'claude-fable': 128000, 'claude-opus': 128000, 'claude-sonnet': 64000,\n\t'claude-haiku': 64000, 'gpt-5.6': 128000, 'gpt-5': 128000,\n};\n\n// The window a project runs at when nobody has touched the setting, clamped per\n// model by getContextWindow. Deliberately BELOW every frontier ceiling it can\n// resolve against (1,000,000 on the Claude 5 line, 1,050,000 on gpt-5.6) because\n// the client-side budget covers only the FIRST request: after that the model\n// runs a server-side tool loop whose web_fetch and MCP results accumulate in the\n// same conversation and are not counted here. The gap (120k and 170k\n// respectively) is that loop's room. It matters because no compaction beta is\n// enabled, so overrunning the real window is a hard error, not a graceful\n// degrade.\nexport var DEFAULT_CONTEXT_WINDOW = 880000;\n\n// Context windows reported by a provider's own models listing, keyed by model id.\n// Anthropic's GET /v1/models returns `max_input_tokens` per model, which is the\n// authoritative context window; OpenAI's listing carries no equivalent field, so\n// OpenAI models resolve from the table above. Populated by\n// registerModelContextWindows() when a client fetches its model list.\nvar apiReportedContextWindows: Record<string, number> = {};\nvar apiReportedMaxOutput: Record<string, number> = {};\n\n/**\n * Record context windows and output caps from a provider models listing. Reads\n * `max_input_tokens` and `max_tokens` (Anthropic); items without them are\n * skipped, so passing an OpenAI listing is a no-op rather than an error.\n *\n * Note the asymmetry against the static table: Anthropic reports\n * `max_input_tokens` (input only) where CONTEXT_WINDOW_BY_MODEL holds totals, so\n * a registered Claude window is treated as a total and loses its output cap\n * worth of budget. That is deliberate — under-spending the window is safe, and\n * with no compaction beta enabled overrunning it is a hard error.\n */\nexport function registerModelContextWindows(\n\tmodels: Array<{ id?: string; max_input_tokens?: number; max_tokens?: number }> | null | undefined,\n): void {\n\tif (!Array.isArray(models)) return;\n\tfor (var i = 0; i < models.length; i++) {\n\t\tvar m = models[i];\n\t\tvar id = (m && m.id ? String(m.id) : '').trim().toLowerCase();\n\t\tif (!id) continue;\n\t\tvar reported = m ? Number(m.max_input_tokens) : NaN;\n\t\tif (Number.isFinite(reported) && reported > 0) {\n\t\t\tapiReportedContextWindows[id] = Math.floor(reported);\n\t\t}\n\t\tvar out = m ? Number(m.max_tokens) : NaN;\n\t\tif (Number.isFinite(out) && out > 0) {\n\t\t\tapiReportedMaxOutput[id] = Math.floor(out);\n\t\t}\n\t}\n}\n\n/** Per-project override, keyed by service id. Set from the project settings. */\nvar projectContextWindows: Record<string, number> = {};\n\nexport function setProjectContextWindow(projectId: string, tokens: number | null | undefined): void {\n\tvar key = (projectId || '').trim();\n\tif (!key) return;\n\tvar n = Number(tokens);\n\tif (Number.isFinite(n) && n > 0) projectContextWindows[key] = Math.floor(n);\n\telse delete projectContextWindows[key];\n}\n\nexport function getProjectContextWindow(projectId: string): number | null {\n\tvar key = (projectId || '').trim();\n\treturn key && projectContextWindows[key] ? projectContextWindows[key] : null;\n}\n// `max_tokens` sent on every chat request. Exported so the reserve below and the\n// actual request cannot drift: they were 22000 and 25000 respectively, which\n// under-reserved by 3k on a window spent to the last token.\nexport var MAX_OUTPUT_TOKENS = 25000;\nexport var OUTPUT_TOKEN_RESERVE = MAX_OUTPUT_TOKENS;\nexport var TOOL_AND_RESPONSE_BUFFER = 4000;\nexport var MIN_INPUT_TOKEN_BUDGET = 8000;\n// Floor under INPUT_CAP_RATIO. Anthropic's default tier enforces 30,000 input\n// tokens per MINUTE on Opus, which is where the number comes from; it is applied\n// on OpenAI too so a small-window model keeps a usable attachment budget instead\n// of collapsing to the ratio.\nexport var MIN_PER_REQUEST_INPUT_CAP = 28000;\n/** @deprecated renamed to {@link MIN_PER_REQUEST_INPUT_CAP} (no longer Claude-only). */\nexport var CLAUDE_PER_REQUEST_INPUT_CAP = MIN_PER_REQUEST_INPUT_CAP;\nexport var MAX_HISTORY_MESSAGES = 20;\nexport var HISTORY_TOKEN_BUDGET = 8000;\n// Ratios that scale the two ceilings above off the resolved context window.\n// Originally calibrated to reproduce the previous fixed values at the old\n// default windows (claude 200000 -> cap 27840, openai 128000 -> history 8160).\n// Both are floored at the old constants, so they can only ever raise a budget,\n// never lower one, which is what keeps a small-window model (claude-opus-4-5 at\n// 200000) behaving as it always did.\n//\n// INPUT_CAP_RATIO now applies to BOTH platforms. It was Claude-only because it\n// encoded a Claude rate limit, but at a 880000 default it does a second job that\n// matters just as much on OpenAI: it is the headroom. Uncapped, gpt-5.6-luna\n// resolved an input budget of 851000 against a 922000 ceiling, leaving 71000 for\n// the whole server-side tool loop, and ONE web_fetch result can be 200000.\nexport var INPUT_CAP_RATIO = 0.16;\n/** @deprecated renamed to {@link INPUT_CAP_RATIO} (no longer Claude-only). */\nexport var CLAUDE_INPUT_CAP_RATIO = INPUT_CAP_RATIO;\nexport var HISTORY_BUDGET_RATIO = 0.08;\n\nexport function estimateTextTokens(text: string): number {\n\treturn Math.ceil((text || '').length / 3);\n}\n\nexport function estimateMessageTokens(msg: { role: string; content: string }): number {\n\treturn estimateTextTokens(msg.content) + estimateTextTokens(msg.role) + 6;\n}\n\n/**\n * The model's own HARD ceiling: the largest window it can be asked for at all.\n * Resolved most specific source first:\n * 1. the provider's own models listing (Anthropic `max_input_tokens`)\n * 2. an exact entry in CONTEXT_WINDOW_BY_MODEL\n * 3. a family entry, by dropping trailing '-' segments off the id\n * 4. the platform default\n *\n * Step 3 is why a new or suffixed id no longer drops straight to the platform\n * default: 'gpt-5.6-luna' resolves via 'gpt-5.6', and a dated Claude snapshot\n * such as 'claude-opus-4-7-20260101' resolves via 'claude-opus-4-7'. The walk\n * stops at the first hit, so a more specific entry always wins over its family.\n *\n * This is what the settings UI offers presets against; it is NOT what a request\n * is budgeted at. For that see getContextWindow.\n */\n/**\n * Shared id resolution for both per-model tables: provider listing, then exact\n * table entry, then family entries by dropping trailing '-' segments. Returns 0\n * when nothing matches so callers can apply their own default.\n */\nfunction resolveByModelId(\n\tapiTable: Record<string, number>,\n\tstaticTable: Record<string, number>,\n\tmodel?: string,\n): number {\n\tvar normalized = (model || '').trim().toLowerCase();\n\tif (!normalized) return 0;\n\tif (apiTable[normalized]) return apiTable[normalized];\n\tif (staticTable[normalized]) return staticTable[normalized];\n\tvar parts = normalized.split('-');\n\tfor (var end = parts.length - 1; end > 0; end--) {\n\t\tvar family = parts.slice(0, end).join('-');\n\t\tif (staticTable[family]) return staticTable[family];\n\t}\n\treturn 0;\n}\n\nexport function getModelContextWindow(platform: string, model?: string): number {\n\treturn resolveByModelId(apiReportedContextWindows, CONTEXT_WINDOW_BY_MODEL, model)\n\t\t|| CONTEXT_WINDOW_DEFAULT[platform];\n}\n\n/**\n * How many output tokens to ask for. We never want more than MAX_OUTPUT_TOKENS,\n * but a model whose own cap is lower rejects the request outright, so clamp to\n * whichever is smaller. Models with no known cap keep MAX_OUTPUT_TOKENS.\n */\nexport function getMaxOutputTokens(platform: string, model?: string): number {\n\tvar cap = resolveByModelId(apiReportedMaxOutput, MAX_OUTPUT_BY_MODEL, model);\n\treturn cap ? Math.min(MAX_OUTPUT_TOKENS, cap) : MAX_OUTPUT_TOKENS;\n}\n\n/**\n * The window a request is actually budgeted at: the per-project override when\n * one is set, otherwise DEFAULT_CONTEXT_WINDOW. Both are clamped to the model's\n * hard ceiling, because a budget above the ceiling builds a request the provider\n * rejects, and a stored override outlives the model it was chosen under.\n */\nexport function getContextWindow(platform: string, model?: string, projectId?: string): number {\n\tvar ceiling = getModelContextWindow(platform, model);\n\tvar override = projectId ? getProjectContextWindow(projectId) : null;\n\treturn Math.min(override || DEFAULT_CONTEXT_WINDOW, ceiling);\n}\n\n/**\n * Per-request input-token budget, i.e. how much of the resolved window this turn\n * may spend on system prompt + history + the latest message. The single\n * implementation behind both buildBoundedChatMessages and the composer's\n * pre-send guard, which used to be separate copies that disagreed.\n */\n/**\n * The share of the resolved window left after reserving what this request may\n * emit. The reserve is per-model rather than the flat OUTPUT_TOKEN_RESERVE\n * because getMaxOutputTokens clamps small-cap models below it.\n */\nfunction contextBasedBudgetFor(platform: string, model?: string, projectId?: string): number {\n\tvar contextWindow = getContextWindow(platform, model, projectId);\n\treturn Math.max(MIN_INPUT_TOKEN_BUDGET,\n\t\tcontextWindow - getMaxOutputTokens(platform, model) - TOOL_AND_RESPONSE_BUFFER);\n}\n\nexport function getInputTokenBudget(platform: string, model?: string, projectId?: string): number {\n\tvar contextBasedBudget = contextBasedBudgetFor(platform, model, projectId);\n\treturn Math.min(contextBasedBudget,\n\t\tMath.max(MIN_PER_REQUEST_INPUT_CAP, Math.round(contextBasedBudget * INPUT_CAP_RATIO)));\n}\n\nexport function stripFileBlocksFromHistory(content: string): string {\n\tif (!content) return content;\n\treturn content.replace(/```([^\\n`]+?\\.[^\\s.`]+)\\n[\\s\\S]*?```/g, '[file previously attached: $1]');\n}\n\nexport type BoundedChatOptions = {\n\tplatform: string;\n\tmodel?: string;\n\tsystemPrompt: string;\n\thistory: Array<{ role: string; content: string }>;\n\t/** Used to strip/rewrite expired attachment links in older user turns. */\n\tprojectId: string;\n};\n\nexport function buildBoundedChatMessages(options: BoundedChatOptions) {\n\tvar contextBasedBudget = contextBasedBudgetFor(options.platform, options.model, options.projectId);\n\t// Scaling used to be gated on an EXPLICIT per-project override so that a\n\t// project nobody had configured kept the old fixed ceilings. That gate is\n\t// gone now that DEFAULT_CONTEXT_WINDOW is itself the default: leaving it in\n\t// would mean an unconfigured project resolved 880000 and then spent 28000 of\n\t// it, making the new default purely cosmetic, and would keep the trap where\n\t// \"Default (880K)\" and an explicit 880K behaved differently.\n\t// Both ceilings derive from contextBasedBudget (pre-Claude-cap) so the two\n\t// platforms scale symmetrically rather than the Claude cap compounding down.\n\tvar availableInputBudget = getInputTokenBudget(options.platform, options.model, options.projectId);\n\tvar systemCost = estimateTextTokens(options.systemPrompt) + 12;\n\tvar historyAllowance = Math.max(HISTORY_TOKEN_BUDGET,\n\t\tMath.round(contextBasedBudget * HISTORY_BUDGET_RATIO));\n\tvar budgetForHistory = Math.max(1000, Math.min(historyAllowance, availableInputBudget - systemCost));\n\t// The message count scales alongside the token budget; otherwise 20 messages\n\t// is a second ceiling that swallows the extra budget on a raised window.\n\tvar maxHistoryMessages = Math.max(MAX_HISTORY_MESSAGES,\n\t\tMath.round(MAX_HISTORY_MESSAGES * (budgetForHistory / HISTORY_TOKEN_BUDGET)));\n\tvar windowed = options.history.slice(-maxHistoryMessages);\n\tvar latestIndex = windowed.length - 1;\n\tvar trimmed = windowed.map(function (m, i) {\n\t\tif (i === latestIndex) return m;\n\t\tvar stripped = stripFileBlocksFromHistory(m.content);\n\t\t// Sanitize BOTH roles: user turns via the \"Attached files:\" block, assistant\n\t\t// turns via the safe db-only path (forAssistant=true) so a volatile db url the\n\t\t// model emitted doesn't get replayed into the LLM context as a dead link.\n\t\tvar sanitized = sanitizeAttachmentLinksForHistory(stripped, options.projectId, m.role !== 'user');\n\t\treturn Object.assign({}, m, { content: sanitized });\n\t});\n\tvar bounded: Array<{ role: string; content: string }> = [], used = 0;\n\tfor (var i = trimmed.length - 1; i >= 0; i--) {\n\t\tvar cost = estimateMessageTokens(trimmed[i]);\n\t\tif (used + cost > budgetForHistory && bounded.length > 0) break;\n\t\tbounded.unshift(trimmed[i]); used += cost;\n\t}\n\treturn {\n\t\tmessages: bounded.map(function (m) { return { role: m.role, content: m.content }; }),\n\t\tdroppedCount: Math.max(0, options.history.length - bounded.length),\n\t\testimatedInputTokens: used + systemCost,\n\t\testimatedBudget: availableInputBudget,\n\t};\n}\n","/**\n * How a text file the chat offers as a download is encoded and labelled, so that\n * whatever opens it reads the characters correctly, in any language.\n *\n * When the model answers with a fenced ```name.ext block, the client turns that\n * block into a Blob and an <a download>. We always write UTF-8, but several very\n * common consumers do not assume UTF-8 when nothing in the file says so, and fall\n * back to the reader's local ANSI codepage: CP949 in Korea, CP932 in Japan,\n * CP936/CP950 in China and Taiwan, CP1251 for Cyrillic. The file is valid and\n * every non-ASCII character still opens as mojibake.\n *\n * There is no single fix, because the way a file declares \"this is UTF-8\" is a\n * property of the FORMAT:\n *\n * - a spreadsheet (csv/tsv) and a Windows text editor read a BOM;\n * - HTML is opened from disk with no HTTP headers, so only an in-document\n * <meta charset> survives;\n * - XML carries its encoding in its declaration, and a WRONG declaration makes\n * a conforming parser fail outright;\n * - RTF is 7-bit, so non-ASCII has to be escaped into \\uNNNN?;\n * - JSON, JSONL and YAML are UTF-8 by specification, and a BOM BREAKS them.\n *\n * Anything unrecognised is left byte-for-byte alone: an unknown extension is far\n * more likely to be machine-parsed, where an uninvited BOM is a new bug, than to\n * be opened by a legacy editor.\n *\n * MIRROR of skapi-mcp/download-encoding.js, which does the same job for files the\n * server publishes (writeReport / exportRecordsToFile). A file the user gets from\n * a fenced block and the same file published as a download must behave\n * identically, so the two have to change together.\n */\n\nexport const BOM = '';\n\n/** Files a spreadsheet or a Windows text editor opens directly. */\nexport const BOM_EXTS = new Set(['csv', 'tsv', 'tab', 'txt', 'text', 'log']);\n\n/** Read from disk with no HTTP headers, so the declaration must be in the file. */\nexport const HTML_EXTS = new Set(['html', 'htm', 'xhtml']);\nexport const XML_EXTS = new Set(['xml', 'svg', 'rss', 'atom', 'xsl', 'xslt', 'plist', 'kml']);\nexport const RTF_EXTS = new Set(['rtf']);\n\n/** Content types by extension. Every text family carries an explicit charset. */\nexport const EXT_CONTENT_TYPES: Record<string, string> = {\n\tcsv: 'text/csv; charset=utf-8',\n\ttsv: 'text/tab-separated-values; charset=utf-8',\n\ttab: 'text/tab-separated-values; charset=utf-8',\n\ttxt: 'text/plain; charset=utf-8',\n\ttext: 'text/plain; charset=utf-8',\n\tlog: 'text/plain; charset=utf-8',\n\tmd: 'text/markdown; charset=utf-8',\n\tmarkdown: 'text/markdown; charset=utf-8',\n\tjson: 'application/json; charset=utf-8',\n\tjsonl: 'application/x-ndjson; charset=utf-8',\n\tndjson: 'application/x-ndjson; charset=utf-8',\n\tgeojson: 'application/geo+json; charset=utf-8',\n\tyaml: 'text/yaml; charset=utf-8',\n\tyml: 'text/yaml; charset=utf-8',\n\ttoml: 'text/plain; charset=utf-8',\n\tini: 'text/plain; charset=utf-8',\n\tsql: 'text/plain; charset=utf-8',\n\thtml: 'text/html; charset=utf-8',\n\thtm: 'text/html; charset=utf-8',\n\txhtml: 'application/xhtml+xml; charset=utf-8',\n\txml: 'application/xml; charset=utf-8',\n\tsvg: 'image/svg+xml; charset=utf-8',\n\tcss: 'text/css; charset=utf-8',\n\tjs: 'text/javascript; charset=utf-8',\n\tts: 'text/plain; charset=utf-8',\n\tpy: 'text/x-python; charset=utf-8',\n\tsh: 'text/x-shellscript; charset=utf-8',\n\tsrt: 'application/x-subrip; charset=utf-8',\n\tvtt: 'text/vtt; charset=utf-8',\n\tics: 'text/calendar; charset=utf-8',\n\tvcf: 'text/vcard; charset=utf-8',\n\t// RTF is 7-bit ASCII by specification, so it takes no charset parameter.\n\trtf: 'application/rtf',\n\t// Binary types the model can only ever REFERENCE, never author in a fence, but\n\t// which keep the type sensible if one ever shows up.\n\tpdf: 'application/pdf',\n\tpng: 'image/png',\n\tjpg: 'image/jpeg',\n\tjpeg: 'image/jpeg',\n\tgif: 'image/gif',\n\twebp: 'image/webp',\n};\n\nexport type EncodingClass = 'bom' | 'html' | 'xml' | 'rtf' | 'none';\n\nexport function normalizeExt(ext: string | null | undefined): string {\n\treturn String(ext || '').trim().replace(/^\\./, '').toLowerCase();\n}\n\n/** Extension of a filename, '' when it has none. */\nexport function extOf(filename: string | null | undefined): string {\n\tconst name = String(filename || '');\n\tconst dot = name.lastIndexOf('.');\n\treturn dot > 0 ? normalizeExt(name.slice(dot + 1)) : '';\n}\n\n/** Which encoding declaration this format understands. */\nexport function encodingClassForExt(ext: string | null | undefined): EncodingClass {\n\tconst e = normalizeExt(ext);\n\tif (BOM_EXTS.has(e)) return 'bom';\n\tif (HTML_EXTS.has(e)) return 'html';\n\tif (XML_EXTS.has(e)) return 'xml';\n\tif (RTF_EXTS.has(e)) return 'rtf';\n\treturn 'none';\n}\n\n/** True when a file with this extension must be written BOM-first. */\nexport function needsBomForExt(ext: string | null | undefined): boolean {\n\treturn encodingClassForExt(ext) === 'bom';\n}\n\n/**\n * Content type to declare. Everything textual carries an explicit charset:\n * without one the receiving end guesses, and it guesses the local codepage.\n */\nexport function contentTypeForExt(\n\text: string | null | undefined,\n\tfallback = 'text/plain; charset=utf-8',\n): string {\n\treturn EXT_CONTENT_TYPES[normalizeExt(ext)] || fallback;\n}\n\nexport function hasBom(text: string): boolean {\n\treturn typeof text === 'string' && text.charCodeAt(0) === 0xfeff;\n}\n\n// --- HTML -------------------------------------------------------------------\n// Only the document head is inspected. A charset written further down is not one\n// a browser would act on anyway (the spec only honours a declaration in the first\n// 1024 bytes), and scanning the whole body would start matching <meta> tags that\n// a document about HTML is merely quoting.\nexport const HTML_HEAD_WINDOW = 4096;\nconst META_CHARSET_RE = /<meta[^>]+charset\\s*=\\s*[\"']?\\s*([a-z0-9_-]+)/i;\nconst META_HTTP_EQUIV_RE = /<meta[^>]+http-equiv\\s*=\\s*[\"']?content-type[\"']?[^>]*>/i;\n\n/**\n * Make an HTML document state its own encoding. Downloaded HTML is opened from\n * disk, where the Content-Type we set no longer exists, so a document with no\n * <meta charset> is decoded with the browser's locale default.\n */\nexport function ensureHtmlCharset(text: string): string {\n\tconst src = String(text == null ? '' : text);\n\tconst head = src.slice(0, HTML_HEAD_WINDOW);\n\n\tconst declared = META_CHARSET_RE.exec(head);\n\tif (declared) {\n\t\t// A declaration naming anything other than UTF-8 is actively wrong: the\n\t\t// bytes underneath it are always UTF-8. Correct it in place rather than\n\t\t// adding a second, contradictory one.\n\t\tif (declared[1].toLowerCase().replace(/[^a-z0-9]/g, '') === 'utf8') return src;\n\t\tconst start = declared.index + declared[0].length - declared[1].length;\n\t\treturn src.slice(0, start) + 'utf-8' + src.slice(start + declared[1].length);\n\t}\n\t// An http-equiv Content-Type with no charset= is still a declaration the\n\t// browser will use; replace the whole tag with the modern short form.\n\tconst httpEquiv = META_HTTP_EQUIV_RE.exec(head);\n\tif (httpEquiv) {\n\t\treturn src.slice(0, httpEquiv.index)\n\t\t\t+ '<meta charset=\"utf-8\">'\n\t\t\t+ src.slice(httpEquiv.index + httpEquiv[0].length);\n\t}\n\n\tconst tag = '<meta charset=\"utf-8\">';\n\t// As early as the document allows: inside <head> if there is one, else right\n\t// after <html>, else at the very top (a fragment is still parsed head-first).\n\tconst headOpen = /<head[^>]*>/i.exec(head);\n\tif (headOpen) {\n\t\tconst at = headOpen.index + headOpen[0].length;\n\t\treturn src.slice(0, at) + '\\n' + tag + src.slice(at);\n\t}\n\tconst htmlOpen = /<html[^>]*>/i.exec(head);\n\tif (htmlOpen) {\n\t\tconst at = htmlOpen.index + htmlOpen[0].length;\n\t\treturn src.slice(0, at) + '\\n<head>' + tag + '</head>' + src.slice(at);\n\t}\n\tconst doctype = /<!doctype[^>]*>/i.exec(head);\n\tif (doctype) {\n\t\tconst at = doctype.index + doctype[0].length;\n\t\treturn src.slice(0, at) + '\\n' + tag + src.slice(at);\n\t}\n\treturn tag + '\\n' + src;\n}\n\n// --- XML ---------------------------------------------------------------------\nconst XML_DECL_RE = /^\\s*<\\?xml\\s[^?]*\\?>/i;\n\n/**\n * Correct an XML declaration that names the wrong encoding.\n *\n * A MISSING declaration is left alone on purpose: XML with none is UTF-8 by\n * specification, so every conforming parser already gets it right. A declaration\n * naming EUC-KR over UTF-8 bytes, on the other hand, makes a parser fail outright.\n */\nexport function ensureXmlEncoding(text: string): string {\n\tconst src = String(text == null ? '' : text);\n\tconst decl = XML_DECL_RE.exec(src);\n\tif (!decl) return src;\n\n\tconst found = /encoding\\s*=\\s*[\"']([^\"']*)[\"']/i.exec(decl[0]);\n\tif (!found) return src; // declaration without an encoding is UTF-8 by spec\n\tif (found[1].toLowerCase().replace(/[^a-z0-9]/g, '') === 'utf8') return src;\n\n\tconst fixedDecl = decl[0].slice(0, found.index)\n\t\t+ found[0].replace(found[1], 'UTF-8')\n\t\t+ decl[0].slice(found.index + found[0].length);\n\treturn fixedDecl + src.slice(decl[0].length);\n}\n\n// --- RTF ----------------------------------------------------------------------\nconst RTF_SIGNATURE_RE = /^[\\s]*\\{\\\\rtf/i;\n\n/** True when the body really is RTF rather than text merely named .rtf. */\nexport function looksLikeRtf(text: string): boolean {\n\treturn RTF_SIGNATURE_RE.test(String(text == null ? '' : text));\n}\n\n/**\n * Escape every non-ASCII character into RTF's \\uNNNN? form.\n *\n * RTF is 7-bit: a literal UTF-8 byte in the body is read through the codepage the\n * header declares, which is how Korean, Japanese and Cyrillic RTF turns to\n * mojibake in Word. \\uNNNN? is codepage-independent.\n *\n * ASCII is never touched, which matters: backslashes and braces in an RTF body\n * are control syntax, and \"escaping\" them would destroy the document. \\u takes a\n * SIGNED 16-bit value, so anything above 0x7FFF is emitted negative, and astral\n * characters are emitted as their two surrogates.\n */\nexport function escapeRtfNonAscii(text: string): string {\n\tconst src = String(text == null ? '' : text);\n\tlet out = '';\n\tlet plainFrom = 0;\n\tfor (let i = 0; i < src.length; i++) {\n\t\tconst code = src.charCodeAt(i); // UTF-16 unit: surrogates arrive separately\n\t\tif (code < 0x80) continue;\n\t\tout += src.slice(plainFrom, i);\n\t\tout += `\\\\u${code > 32767 ? code - 65536 : code}?`;\n\t\tplainFrom = i + 1;\n\t}\n\treturn plainFrom === 0 ? src : out + src.slice(plainFrom);\n}\n\n/** Apply the format's encoding declaration to a whole document. */\nexport function applyEncodingDeclaration(text: string, ext: string | null | undefined): string {\n\tconst src = String(text == null ? '' : text);\n\tswitch (encodingClassForExt(ext)) {\n\t\tcase 'bom':\n\t\t\t// Never a second BOM: two U+FEFF show as a visible in the first cell.\n\t\t\treturn hasBom(src) ? src : BOM + src;\n\t\tcase 'html':\n\t\t\treturn ensureHtmlCharset(src);\n\t\tcase 'xml':\n\t\t\treturn ensureXmlEncoding(src);\n\t\tcase 'rtf':\n\t\t\t// Text merely NAMED .rtf is opened by Word as plain text, where a BOM is\n\t\t\t// what makes it read UTF-8. Escaping it would show literal \\u escapes.\n\t\t\treturn looksLikeRtf(src) ? escapeRtfNonAscii(src) : (hasBom(src) ? src : BOM + src);\n\t\tdefault:\n\t\t\treturn src;\n\t}\n}\n\n/**\n * Everything a client needs to turn a fenced ```name.ext block into a download:\n * the exact text to put in the Blob and the type to give it.\n */\nexport function prepareDownloadText(\n\tfilename: string,\n\tbody: string,\n): { ext: string; text: string; contentType: string } {\n\tconst ext = extOf(filename);\n\treturn {\n\t\text,\n\t\ttext: applyEncodingDeclaration(body, ext),\n\t\tcontentType: contentTypeForExt(ext),\n\t};\n}\n","/**\n * The chip / preview markup for one classified inline link.\n *\n * `classifyInlineLink` was consolidated into the engine because deciding what a\n * link IS had drifted between the two clients and every link bug had to be found\n * and fixed twice. The EMITTER stayed forked, byte for byte identical in\n * agent.vue and the widget. The image preview is the first behaviour that would\n * have had to be written twice, so the emitter moves here too.\n *\n * Pure string in, pure string out: no DOM, no globals, nothing reactive. That is\n * what lets agent.vue keep memoizing parseMsgParts on the message text alone.\n */\n\n/** Neither client sanitizes bubble HTML (no DOMPurify, no marked sanitize), so\n * everything interpolated here is escaped at the point of interpolation. */\nexport function escapeInlineHtml(v: string | null | undefined): string {\n\treturn String(v == null ? '' : v).replace(/[&<>\"']/g, function (ch) {\n\t\treturn ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' } as Record<string, string>)[ch];\n\t});\n}\n\n/**\n * Previews per MESSAGE. Each one costs a presign call and an image download the\n * moment it is hydrated, and a reply listing a folder can name dozens. Past this\n * many the link renders as the ordinary text chip.\n */\nexport var IMAGE_PREVIEWS_PER_MESSAGE = 8;\n\n/**\n * The glyph IS the promise: ↗ says \"click this and the file opens\". When the\n * client could not get a url for the file, keeping that glyph on a chip it knows\n * is dead is the bug: the click either opens a tab on a 403/404 or, once the\n * href is gone, does nothing at all with no explanation. ✕ says what happened.\n */\nexport var INLINE_LINK_GLYPH = '↗';\nexport var INLINE_LINK_UNAVAILABLE_GLYPH = '✕';\nexport var INLINE_LINK_UNAVAILABLE_SUFFIX = ' (unavailable)';\n\n/** Widened so each client's local link-part type is assignable. */\nexport interface RenderableInlineLink {\n\tlabel: string;\n\tfullLabel?: string;\n\thref: string;\n\texpired: boolean;\n\texpiredHref?: string;\n\tremotePath?: string;\n\timage?: { ext: string; contentType: string };\n}\n\nexport interface InlineLinkMarkupOptions {\n\t/** The view's own \"a mint is in flight for this href\" flag. */\n\trefreshing?: boolean;\n\t/** False once the caller has spent its per-message preview budget. */\n\tallowImagePreview?: boolean;\n\t/**\n\t * The view already tried to get a url for this file and failed (see\n\t * isLinkUnavailable). Renders a dead chip: ✕, greyed, no href.\n\t */\n\tunavailable?: boolean;\n}\n\nexport function renderInlineLinkHtml(link: RenderableInlineLink, opts?: InlineLinkMarkupOptions): string {\n\tvar o = opts || {};\n\tvar unavailable = !!o.unavailable;\n\t// A dead chip is never also \"fetching...\": the mint that would have cleared\n\t// that state is the one that failed.\n\tvar refreshing = !unavailable && !!o.refreshing;\n\tvar full = link.fullLabel || link.label;\n\t// No preview either. The <img> hides itself when its url fails, but a\n\t// re-render emits a FRESH element with no state, so leaving the preview in\n\t// would re-mint and re-fail once per render for the rest of the session.\n\tvar preview = !!link.image && !!link.remotePath && o.allowImagePreview !== false && !unavailable;\n\n\tvar cls = ['bq-link-button'];\n\tif (link.expired) cls.push('is-expired');\n\tif (refreshing) cls.push('is-refreshing');\n\tif (unavailable) cls.push('is-unavailable');\n\tif (preview) cls.push('is-image-preview');\n\n\tvar labelText = (unavailable ? INLINE_LINK_UNAVAILABLE_GLYPH : INLINE_LINK_GLYPH) + ' ' + link.label\n\t\t+ (unavailable ? INLINE_LINK_UNAVAILABLE_SUFFIX : refreshing ? ' (fetching...)' : '');\n\tvar attrs = ['class=\"' + cls.join(' ') + '\"'];\n\t// NO href when the file is unavailable. That is what disables the click:\n\t// an anchor with no href does not navigate, is not a tab stop and takes the\n\t// default cursor, so nothing else has to remember to swallow the event.\n\tif (unavailable) attrs.push('aria-disabled=\"true\"', 'data-bq-unavailable=\"1\"');\n\telse attrs.push('href=\"' + escapeInlineHtml(link.href) + '\"', 'target=\"_blank\"', 'rel=\"noopener noreferrer\"');\n\tattrs.push('title=\"' + escapeInlineHtml(unavailable ? full + INLINE_LINK_UNAVAILABLE_SUFFIX : full) + '\"');\n\t// `download` is ignored cross-origin and forces a save same-origin. On a\n\t// preview it states the wrong intent: the user clicked a picture to LOOK at\n\t// it. Every other chip keeps the attribute exactly where it was.\n\tif (!preview && !unavailable) attrs.push('download=\"' + escapeInlineHtml(full) + '\"');\n\tattrs.push('data-bq-link=\"1\"');\n\t// Deliberately NOT marked expired: `data-bq-expired` is what tells the\n\t// delegated click handler to mint a fresh url, and this is the chip whose\n\t// mint just failed.\n\tif (link.expired && !unavailable) attrs.push('data-bq-expired=\"1\"');\n\tif (link.expiredHref) attrs.push('data-bq-expired-href=\"' + escapeInlineHtml(link.expiredHref) + '\"');\n\tif (link.remotePath) attrs.push('data-bq-remote-path=\"' + escapeInlineHtml(link.remotePath) + '\"');\n\tif (link.fullLabel) attrs.push('data-bq-full-label=\"' + escapeInlineHtml(link.fullLabel) + '\"');\n\n\tif (!preview) return '<a ' + attrs.join(' ') + '>' + escapeInlineHtml(labelText) + '</a>';\n\n\t// NO src attribute. A stored file always classifies as the _expired_.url\n\t// placeholder until something mints a real url, so a src written here would be\n\t// a guaranteed broken image on every reload. The element carries the PATH and\n\t// hydrateImagePreviews fills the src in a DOM pass that runs after render.\n\t//\n\t// The caption is not decoration, it is the FALLBACK: if the url dies or the\n\t// file is gone the <img> hides itself and what is left is exactly the text\n\t// chip this feature replaced, still clickable.\n\treturn '<a ' + attrs.join(' ') + '>' +\n\t\t'<img class=\"bq-img-preview\" alt=\"' + escapeInlineHtml(full) + '\"' +\n\t\t' data-bq-img-path=\"' + escapeInlineHtml(link.remotePath || '') + '\"' +\n\t\t' data-bq-img-type=\"' + escapeInlineHtml(link.image ? link.image.contentType : '') + '\"' +\n\t\t// decoding=\"async\" but NOT loading=\"lazy\". Lazy guarantees the bytes arrive\n\t\t// exactly when the image is near the viewport, which is the one case the\n\t\t// scroll anchor deliberately declines to compensate for (growth at or below\n\t\t// the fold happened on screen, under a line the reader is looking at) — so it\n\t\t// shoved up to 320px of text under their eyes on every scroll toward it. It\n\t\t// saved no mint either: hydration mints for every preview in the DOM\n\t\t// regardless of viewport. It was also what turned the widget's per-notify\n\t\t// teardown into a 13x amplifier (6224px vs 450px measured).\n\t\t' decoding=\"async\">' +\n\t\t// Minting the url is a network round trip before the image even starts\n\t\t// downloading, so the wait is real and needs a state. Inline load, so the\n\t\t// dot trail, never the jumping bunny. CSS hides it the moment the <img>\n\t\t// gains a src, so no JS removes DOM and nothing re-parses.\n\t\t'<span class=\"bq-loader\" data-bq-img-loader=\"1\"></span>' +\n\t\t'<span class=\"bq-img-preview-caption\" translate=\"no\">' + escapeInlineHtml(labelText) + '</span>' +\n\t\t'</a>';\n}\n","import { LINK_REFRESH_WINDOW_MS, PRESIGN_SAFETY_MARGIN_MS, presignExpiryEpochMs } from './links';\n\n/**\n * Give a rendered preview <img> a real src.\n *\n * Why this is not part of the parse: every stored file classifies as\n * `expired: true` with the _expired_.url placeholder as its href, so the url an\n * <img> needs does not exist until something mints it. agent.vue memoizes its\n * parse on the raw message text and drops that cache whenever its link maps\n * change, so minting THROUGH those maps would clear the whole cache once per\n * image and re-run marked over the entire conversation each time. The mint\n * therefore lives here, in a cache that is not reactive and is never read by the\n * parse, and the src is written straight onto the element after render.\n *\n * DOM-free like the rest of the engine: the element type is structural, so a\n * real HTMLImageElement satisfies it while this file imports nothing from\n * lib.dom and touches no global.\n */\n\nexport interface PreviewImageEl {\n\tgetAttribute(name: string): string | null;\n\tsetAttribute(name: string, value: string): void;\n\tremoveAttribute(name: string): void;\n\taddEventListener(type: string, cb: () => void): void;\n}\n\n\nexport interface ImagePreviewContext {\n\t/** Project id. Namespaces the cache, see clearImagePreviewCache. */\n\tscope: string;\n\t/**\n\t * Mint a directly loadable url for a storage path.\n\t *\n\t * `contentType` is not advisory. get_signed_url only sets\n\t * ResponseContentType when the caller passes one and otherwise falls back to\n\t * application/octet-stream, which a new tab DOWNLOADS instead of displaying.\n\t * An implementation that drops this argument still paints the preview (an\n\t * <img> sniffs the bytes) but silently breaks the click.\n\t *\n\t * `refresh` asks for a url the browser cache cannot answer. The mint request\n\t * itself is cacheable (that is what stops a reload re-downloading every\n\t * image), so a plain re-mint can hand back the very url that just failed;\n\t * refresh is how the caller escapes its own cache.\n\t */\n\tmint: (remotePath: string, contentType: string, refresh?: boolean) => Promise<string>;\n\t/** An image finished painting. Views use it to re-pin the scroll. */\n\tonLoad?: (remotePath: string) => void;\n\t/** A preview gave up. The caption chip is now the whole answer. */\n\tonError?: (remotePath: string, err: unknown) => void;\n\t/**\n\t * This element's box just changed size, and nothing asked it to.\n\t *\n\t * Fires at the points where a preview resizes with NO DOM event of its own to\n\t * announce it: the src lands (a src-less <img> is hidden, so this is where it\n\t * starts taking space), and the src is dropped for a retry, or a mint fails\n\t * outright, where an already-painted picture collapses back to nothing.\n\t * `load` and `error` are deliberately NOT routed through here — both views\n\t * listen for those on the message box itself, which is also how they cover the\n\t * images this module never sees, a markdown `![alt](url)` among them.\n\t *\n\t * Each of these slides everything below the element, and for a reader scrolled\n\t * up into history that is a jump in the middle of a sentence. onLoad cannot\n\t * stand in for it: both views answer that with a scroll-to-bottom-if-pinned,\n\t * which by definition does nothing for the reader this hurts.\n\t *\n\t * Views wire this to their scroll anchor's absorb(). Called SYNCHRONOUSLY, so\n\t * the measurement it takes is the one the reader is looking at.\n\t */\n\tonLayoutChange?: (img: PreviewImageEl, remotePath: string) => void;\n}\n\ninterface MintedPreview { url: string; at: number; }\n\nvar previewUrlCache: Record<string, MintedPreview> = Object.create(null);\nvar previewInFlight: Record<string, Promise<string>> = Object.create(null);\n\nfunction cacheKey(scope: string, path: string): string { return scope + '\u0000' + path; }\n\n/**\n * Drop cached preview urls, for one project or all of them.\n *\n * The key carries the project because an identity-blind cache is how one\n * project's content has reached another project's chat before. Call on project\n * switch and on sign-out.\n */\nexport function clearImagePreviewCache(scope?: string): void {\n\tif (!scope) {\n\t\tpreviewUrlCache = Object.create(null);\n\t\tpreviewInFlight = Object.create(null);\n\t\tstaleImagePreviews = Object.create(null);\n\t\treturn;\n\t}\n\tvar prefix = scope + '\u0000';\n\tfor (var k in previewUrlCache) if (k.indexOf(prefix) === 0) delete previewUrlCache[k];\n\tfor (var f in previewInFlight) if (f.indexOf(prefix) === 0) delete previewInFlight[f];\n\t// Marks are keyed the same way, so a project switch must drop them too or a\n\t// mark set for project A would fire a pointless refresh in project B.\n\tfor (var s in staleImagePreviews) if (s.indexOf(prefix) === 0) delete staleImagePreviews[s];\n}\n\n/**\n * A url we already hold that is still comfortably alive, or null.\n *\n * Synchronous on purpose. Both views rebuild bubble DOM constantly (the widget\n * tears down and re-creates every node in renderMessages; Vue re-patches v-html\n * whenever the string changes), so an async-only assignment would blank every\n * visible image for a frame on each re-render. Called before paint, this makes a\n * re-render invisible.\n */\nexport function peekImagePreviewUrl(ctx: ImagePreviewContext, remotePath: string): string | null {\n\tvar hit = previewUrlCache[cacheKey(ctx.scope, remotePath)];\n\tif (!hit) return null;\n\t// Same headroom the chip cache uses: drop the url before it dies, never after.\n\tif (Date.now() - hit.at >= LINK_REFRESH_WINDOW_MS) return null;\n\t// And ask the url itself, because the line above measures from ARRIVAL. Now\n\t// that the mint response is cacheable, an arrival is not a signing: a mint\n\t// answered from the browser's store can already be most of its own max-age\n\t// old, and this window would then add its full length on top of that,\n\t// handing an <img> a credential that died in between. Both bounds, so a\n\t// device whose clock is wrong can only be over-cautious.\n\tvar dies = presignExpiryEpochMs(hit.url);\n\tif (dies !== null && Date.now() >= dies - PRESIGN_SAFETY_MARGIN_MS) return null;\n\treturn hit.url;\n}\n\n/**\n * Deduped, TTL-bounded mint for one path.\n *\n * `refresh` skips every cache in the way: this module's in-memory one, and the\n * browser's cache of the mint request itself. It is what the error path uses to\n * replace a url that has expired, and what a view would call to pick up a file\n * that changed.\n */\nexport function resolveImagePreviewUrl(\n\tctx: ImagePreviewContext,\n\tremotePath: string,\n\tcontentType: string,\n\trefresh?: boolean,\n): Promise<string> {\n\tvar key = cacheKey(ctx.scope, remotePath);\n\n\t// A file marked stale by an upload has to go to the network exactly once,\n\t// then behave normally again. Consuming the mark here (rather than at the\n\t// upload) means the refresh lands on the mint that actually paints the new\n\t// bubble, not on one issued before the render.\n\tif (staleImagePreviews[key]) {\n\t\tdelete staleImagePreviews[key];\n\t\trefresh = true;\n\t}\n\n\tif (refresh) {\n\t\tdelete previewUrlCache[key];\n\t\tdelete previewInFlight[key];\n\t} else {\n\t\tvar warm = peekImagePreviewUrl(ctx, remotePath);\n\t\tif (warm) return Promise.resolve(warm);\n\t\tvar flight = previewInFlight[key];\n\t\tif (flight) return flight;\n\t}\n\tvar run: Promise<string> = ctx.mint(remotePath, contentType, refresh).then(function (url) {\n\t\t// Only the CURRENT flight may publish. A refresh started while a plain\n\t\t// mint was still outstanding replaces previewInFlight, and without this\n\t\t// guard whichever settles last wins: the older mint would overwrite the\n\t\t// fresh url with the stale one it was already holding, and delete the\n\t\t// newer flight's bookkeeping on its way out.\n\t\tif (previewInFlight[key] === run) {\n\t\t\tpreviewUrlCache[key] = { url: url, at: Date.now() };\n\t\t\tdelete previewInFlight[key];\n\t\t}\n\t\treturn url;\n\t}, function (e) {\n\t\tif (previewInFlight[key] === run) delete previewInFlight[key];\n\t\tthrow e;\n\t});\n\tpreviewInFlight[key] = run;\n\treturn run;\n}\n\n/**\n * Declare a stored file changed, so the next mint for it goes to the network.\n *\n * The mint request is browser-cached, which is what stops a reload re-downloading\n * every image, but it also means an OVERWRITE is invisible: the file is re-posted\n * to the same storage path, so the mint url is byte-identical, so the browser\n * replays the cached mint and hands back the same signed url and the same cached\n * body. The preview would keep painting the previous picture for a day.\n *\n * Upload paths call this because they are the one place that KNOWS the bytes\n * changed. It is a marker, not a fetch: the refresh happens on the next mint,\n * which is when the new bubble actually renders. In memory only, deliberately.\n */\nexport function markImagePreviewStale(scope: string, remotePath: string): void {\n\tif (!scope || !remotePath) return;\n\tstaleImagePreviews[cacheKey(scope, remotePath)] = true;\n\tdelete previewUrlCache[cacheKey(scope, remotePath)];\n}\n\nvar staleImagePreviews: Record<string, boolean> = Object.create(null);\n\n/**\n * Hydrate every un-claimed preview <img> in the given list.\n *\n * Idempotent: an element is claimed by its own data-bq-img-state, so a full\n * re-render, a Vue patch, or two calls in one frame cannot mint twice. The\n * caller decides WHICH elements to pass, so a view can move from\n * querySelectorAll to an IntersectionObserver without an engine change.\n */\nexport function hydrateImagePreviews(imgs: ArrayLike<PreviewImageEl>, ctx: ImagePreviewContext): void {\n\tfor (var i = 0; i < imgs.length; i++) hydrateOne(imgs[i], ctx);\n}\n\nfunction hydrateOne(img: PreviewImageEl, ctx: ImagePreviewContext): void {\n\tif (img.getAttribute('data-bq-img-state')) return; // already claimed\n\tvar path = img.getAttribute('data-bq-img-path');\n\tvar type = img.getAttribute('data-bq-img-type') || '';\n\tif (!path) { img.setAttribute('data-bq-img-state', 'error'); return; }\n\timg.setAttribute('data-bq-img-state', 'loading');\n\n\timg.addEventListener('load', function () {\n\t\timg.setAttribute('data-bq-img-state', 'ready');\n\t\t// One repair per FAILURE, not one per element for the life of the tab.\n\t\t// A bubble's DOM survives as long as its text does (the parse is memoized\n\t\t// on the message), so a preview that failed, repaired and painted kept a\n\t\t// spent retry flag for hours. The next time the browser dropped the body\n\t\t// and refetched with a url that had since expired, it went straight to\n\t\t// the dead chip with no attempt. On a phone that second eviction is\n\t\t// routine, which is why this only ever showed up on mobile.\n\t\timg.removeAttribute('data-bq-img-retry');\n\t\t// The picture growing into place is absorbed by the view's own `load`\n\t\t// listener on the message box, which sees this element and every other\n\t\t// image alike. onLoad is the other half of the same moment: it re-pins a\n\t\t// reader who is at the BOTTOM, where holding a row would be wrong.\n\t\tif (ctx.onLoad) ctx.onLoad(path as string);\n\t});\n\timg.addEventListener('error', function () { onImageError(img, ctx, path as string, type); });\n\n\tvar warm = peekImagePreviewUrl(ctx, path);\n\t// A warm url is assigned in the caller's own frame, before the reader has\n\t// been anywhere: the element goes from src-less (hidden) to displaying, which\n\t// is a height change of its own even before the bytes arrive.\n\tif (warm) { img.setAttribute('src', warm); notifyLayoutChange(img, ctx, path); return; }\n\n\tresolveImagePreviewUrl(ctx, path, type).then(function (url) {\n\t\t// The element may have been torn out and replaced while we waited.\n\t\tif (img.getAttribute('data-bq-img-state') !== 'loading') return;\n\t\timg.setAttribute('src', url);\n\t\tnotifyLayoutChange(img, ctx, path);\n\t}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tnotifyLayoutChange(img, ctx, path);\n\t\tif (ctx.onError) ctx.onError(path as string, e);\n\t});\n}\n\n/**\n * One retry, then the caption chip is the answer.\n *\n * This is the LOAD-BEARING repair, not a rare fallback. Because the mint request\n * is browser-cached for far longer than a signed url lives, the expected failure\n * is: the browser evicted the image body, refetched with the cached url, and got\n * a 403 because that url expired hours ago. Re-minting fixes it, but only\n * through `refresh`, since a plain re-mint would be answered from the same\n * browser cache with the same dead url. A deleted file or a wrong path is not\n * fixed by retrying, so the second failure is final and the image stays hidden.\n */\nfunction onImageError(img: PreviewImageEl, ctx: ImagePreviewContext, path: string, type: string): void {\n\tif (img.getAttribute('data-bq-img-retry') === '1') {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tnotifyLayoutChange(img, ctx, path);\n\t\tif (ctx.onError) ctx.onError(path, new Error('image preview failed to load'));\n\t\treturn;\n\t}\n\timg.setAttribute('data-bq-img-retry', '1');\n\t// Dropping the src hides the element again (the CSS keys on the MISSING src),\n\t// so the retry collapses the picture before it repaints it.\n\timg.removeAttribute('src');\n\tnotifyLayoutChange(img, ctx, path);\n\tresolveImagePreviewUrl(ctx, path, type, true).then(function (url) {\n\t\timg.setAttribute('src', url);\n\t\tnotifyLayoutChange(img, ctx, path);\n\t}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tnotifyLayoutChange(img, ctx, path);\n\t\tif (ctx.onError) ctx.onError(path, e);\n\t});\n}\n\n/**\n * Report the box that actually resized, which is the ANCHOR, not the <img>.\n *\n * The anchor IS the preview: picture on top, the dot-trail loader beside it, the\n * caption chip underneath. When a src lands the loader collapses (a CSS sibling\n * selector) while the img is still undecoded, so measuring the img alone reports\n * a ~2px GROWTH (its border) against a real ~18px shrink. Measuring the anchor\n * makes every transition equal to what the reader saw move.\n *\n * A markdown `![alt](url)` has no such ancestor and stands for itself. Both views\n * apply the same closest() before calling absorb, so the two paths key its\n * per-element memo on the same node and cannot pay for one change twice.\n */\nfunction notifyLayoutChange(img: PreviewImageEl, ctx: ImagePreviewContext, path: string): void {\n\tif (!ctx.onLayoutChange) return;\n\tctx.onLayoutChange(previewLayoutBox(img), path);\n}\n\nexport var PREVIEW_LAYOUT_BOX_SELECTOR = 'a.bq-link-button.is-image-preview';\n\n/** The element whose height a preview's own transitions actually change. */\nexport function previewLayoutBox<T extends PreviewImageEl>(img: T): T {\n\tvar closest = (img as any).closest;\n\tif (typeof closest !== 'function') return img;\n\treturn closest.call(img, PREVIEW_LAYOUT_BOX_SELECTOR) || img;\n}\n","/**\n * Chat timestamp formatting, shared so agent.vue and the widget render an\n * identical \"small text under the bubble\". Pure and locale-aware: it formats a\n * given epoch-ms value, it never reads the current time, so it stays testable and\n * DOM-free.\n */\n\n/** Wall-clock epoch ms. Separate from the engine's monotonic nowMs() (which is\n * performance.now() when available and therefore NOT epoch): a displayed\n * timestamp must be wall time. */\nexport function wallClockNow(): number {\n\treturn Date.now();\n}\n\n/**\n * \"Jul 24, 2026, 3:42:07 PM\" (locale-formatted). Empty string for a missing or\n * non-finite value, so a caller can gate rendering on the result being truthy and\n * a pending bubble (no timestamp yet) simply shows nothing.\n */\nexport function formatChatTimestamp(ms?: number): string {\n\tif (typeof ms !== 'number' || !isFinite(ms) || ms <= 0) return '';\n\ttry {\n\t\treturn new Date(ms).toLocaleString(undefined, {\n\t\t\tyear: 'numeric',\n\t\t\tmonth: 'short',\n\t\t\tday: 'numeric',\n\t\t\thour: 'numeric',\n\t\t\tminute: '2-digit',\n\t\t\tsecond: '2-digit',\n\t\t});\n\t} catch (e) {\n\t\treturn '';\n\t}\n}\n","/**\n * The `ai_agent` service option, parsed and serialized in ONE place.\n *\n * Stored on the skapi service record as up to three '#'-delimited segments:\n *\n * none AI chat disabled\n * claude platform chosen, no model saved yet\n * claude#claude-sonnet-4-6 platform + model\n * claude#claude-sonnet-4-6#400000 platform + model + context-window override\n *\n * The third segment is new and optional, so every value written before it\n * existed parses unchanged with `contextWindow: null`. Nothing writes a third\n * segment without a model, because the window is meaningless without one.\n *\n * This lived as four separate copies (agent.vue, dbfile.vue, service.vue, and\n * the widget's index.js), which is how the format drifts. New callers should\n * import from here rather than re-deriving the split.\n */\n\nexport type AiAgentPlatform = 'claude' | 'openai' | null;\n\nexport type ParsedAiAgent = {\n\t/** null when unset or explicitly 'none'. */\n\tplatform: AiAgentPlatform;\n\t/** '' when no model has been saved. */\n\tmodel: string;\n\t/** Per-project context-window override in tokens, or null to use the model's. */\n\tcontextWindow: number | null;\n\t/** True when a real platform is configured (i.e. not unset and not 'none'). */\n\thasPlatform: boolean;\n};\n\nfunction normalizePlatform(raw: string): AiAgentPlatform {\n\tvar p = (raw || '').trim().toLowerCase();\n\treturn p === 'claude' || p === 'openai' ? p : null;\n}\n\nexport function parseAiAgentValue(value: string | null | undefined): ParsedAiAgent {\n\tvar raw = (value || '').trim();\n\tif (!raw || raw.toLowerCase() === 'none') {\n\t\treturn { platform: null, model: '', contextWindow: null, hasPlatform: false };\n\t}\n\n\t// Split into at most three parts so a '#' inside a model id (none today, but\n\t// the delimiter should not be load-bearing on the tail) cannot shift fields.\n\tvar firstHash = raw.indexOf('#');\n\tif (firstHash === -1) {\n\t\tvar only = normalizePlatform(raw);\n\t\treturn { platform: only, model: '', contextWindow: null, hasPlatform: !!only };\n\t}\n\n\tvar platform = normalizePlatform(raw.slice(0, firstHash));\n\tvar rest = raw.slice(firstHash + 1);\n\tvar secondHash = rest.indexOf('#');\n\tvar model = (secondHash === -1 ? rest : rest.slice(0, secondHash)).trim();\n\tvar windowRaw = secondHash === -1 ? '' : rest.slice(secondHash + 1).trim();\n\n\tvar parsedWindow = windowRaw ? Number(windowRaw) : NaN;\n\tvar contextWindow = Number.isFinite(parsedWindow) && parsedWindow > 0\n\t\t? Math.floor(parsedWindow)\n\t\t: null;\n\n\treturn { platform: platform, model: model, contextWindow: contextWindow, hasPlatform: !!platform };\n}\n\nexport function buildAiAgentValue(\n\tplatform: string | null | undefined,\n\tmodel?: string | null,\n\tcontextWindow?: number | null,\n): string {\n\tvar p = (platform || '').trim().toLowerCase();\n\tif (!p || p === 'none') return 'none';\n\n\tvar m = (model || '').trim();\n\tif (!m) return p;\n\n\tvar n = Number(contextWindow);\n\tif (!Number.isFinite(n) || n <= 0) return p + '#' + m;\n\treturn p + '#' + m + '#' + Math.floor(n);\n}\n","/**\n * AI request builders + dispatch transport (framework-agnostic).\n *\n * Ported from www.skapi.com/src/code/ai_agent.ts. The only changes vs the\n * original are dependency-injection seams:\n * - `skapi.clientSecretRequest*` -> chatEngineConfig().clientSecretRequest*\n * - MCP endpoint URL -> chatEngineConfig().mcpBaseUrl\n * - `poll` on each request -> pollOpt() (set per consumer; see config.ts)\n * - Vue `reactive`/`ref` removed (bgTaskQueue/agentViewMounted are app-level\n * state that stays in the consumer, not here;\n * only the BgTaskEntry TYPE lives here)\n */\nimport { buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingContinueMessage, buildIndexingRenderMessage, buildIndexingRenderContinueTemplate, buildIndexingWindowMessage } from './prompts';\nimport { isServerExtractable, isPagedReadFile, isImageVisionFile, isWindowedReadFile, makeExtractPlaceholder, makeRenderPlaceholder, makeWindowPlaceholder, RENDER_PAGES_PER_WINDOW, type ExtractDirective, type FileUrlDirective } from './office';\nimport { chatEngineConfig, pollOpt, windowedIndexingEnabled } from './config';\n// Output sizing lives in budget.ts so the request cap and the reserve the input\n// budget subtracts cannot drift; getMaxOutputTokens also clamps per model.\nimport { getMaxOutputTokens } from './budget';\n\nexport const ANTHROPIC_MESSAGES_API_URL = 'https://api.anthropic.com/v1/messages';\nconst ANTHROPIC_MODELS_API_URL = 'https://api.anthropic.com/v1/models';\nconst ANTHROPIC_VERSION = '2023-06-01';\nconst ANTHROPIC_MCP_BETA = 'mcp-client-2025-11-20';\nconst ANTHROPIC_WEB_FETCH_BETA = 'web-fetch-2025-09-10';\nconst ANTHROPIC_PROMPT_CACHING_BETA = 'prompt-caching-2024-07-31';\nconst ANTHROPIC_BETA_HEADER = `${ANTHROPIC_MCP_BETA},${ANTHROPIC_WEB_FETCH_BETA},${ANTHROPIC_PROMPT_CACHING_BETA}`;\nconst WEB_FETCH_MAX_USES = 40;\nconst WEB_FETCH_MAX_CONTENT_TOKENS = 200000;\n\nexport const OPENAI_RESPONSES_API_URL = 'https://api.openai.com/v1/responses';\nconst OPENAI_MODELS_API_URL = 'https://api.openai.com/v1/models';\nconst DEFAULT_OPENAI_IMAGE_DETAIL = 'auto';\nconst OPENAI_WEB_SEARCH_ENABLED = true;\nconst OPENAI_WEB_SEARCH_EXTERNAL_WEB_ACCESS = true;\nexport const MCP_NAME = 'BunnyQuery';\n\nexport const DEFAULT_CLAUDE_MODEL = 'claude-sonnet-5';\nexport const DEFAULT_OPENAI_MODEL = 'gpt-5.6-luna';\n\nconst mcpUrl = () => chatEngineConfig().mcpBaseUrl;\n\n/**\n * Where a chat turn's MCP tools point, and what they authenticate with.\n *\n * A SIGNED-IN turn uses the server's root endpoint with the literal\n * '$ACCESS_TOKEN', which the backend substitutes from the caller's\n * `x-access-token` header before the request leaves for the provider.\n *\n * An ANONYMOUS turn has no such header, so that substitution yields an EMPTY\n * credential: `authorization_token: \"\"` for Claude, `Bearer ` for OpenAI. That is\n * worse than sending none. The MCP server cannot identify a project from an empty\n * token, so every tool call 401s — and a pass whose calls all 401 is exactly what\n * the polling worker classifies as an auth outage, which STOPS the chain. A\n * provider that validates the field would reject the whole request before that.\n *\n * So an anonymous turn points at the project-scoped endpoint `/p/<project id>`\n * and sends NO credential. That route is anonymous by construction: read-only,\n * one project, public records only, and a bearer on it is ignored rather than\n * honoured.\n *\n * The project id is the PUBLIC compound token, matching the route's own pattern\n * and the form the tools accept; the raw regional code would not match.\n */\nfunction mcpEndpointFor(\n\tanonymous: boolean | undefined,\n\tpublicProjectId: string | undefined,\n\tservice: string,\n): { url: string; token?: string } {\n\tif (!anonymous) return { url: mcpUrl(), token: '$ACCESS_TOKEN' };\n\tconst project = publicProjectId || service;\n\treturn { url: String(mcpUrl()).replace(/\\/+$/, '') + '/p/' + project };\n}\nconst clientSecretRequest = (opts: any) => chatEngineConfig().clientSecretRequest(opts);\n\n// Resolve the per-image `detail` for OpenAI. The version match tolerates a\n// trailing variant/date suffix (`gpt-5.4-nano`, `-mini`, `-2026-01-01`, …):\n// previously the pattern was anchored with no suffix allowed, so EVERY suffixed\n// model silently fell through to 'auto' — i.e. the cheap tiers that most need\n// resolution were the ones getting downsampled images.\n//\n// Variants used to resolve to 'high' rather than 'original' on the reasoning that\n// 'high' is universally supported and an unsupported value would fail the whole\n// request. The cost of that caution turned out to be real: 'high' downsamples to\n// a 512px grid, so the small tiers that most need resolution were reading dense\n// scans at the lower of the two settings, and gpt-5.4-nano reports it cannot make\n// out the text where gpt-5.4 (on 'original') can. Variants now get 'original' too.\n//\n// If a variant rejects 'original' the failure is loud and immediate (a terminal\n// 400 on the whole request, no retry), so flip VARIANT_IMAGE_DETAIL back to\n// 'high' and it is undone. That is the one word to change.\nconst VARIANT_IMAGE_DETAIL = 'original';\n\n// Extra Responses-API knobs for NANO models on INDEXING passes only.\n//\n// `detail` (above) governs what the model SEES; these govern how it thinks and how completely it\n// writes. Nano strips vision detail to hit its latency target and compresses layout when\n// transcribing, which is the documented reason to raise verbosity FOR IT SPECIFICALLY. mini and the\n// base/named models do not need it, so they are excluded rather than paying its output cost.\n//\n// Deliberately NOT applied to chat: high verbosity makes ordinary replies longer and worse, and the\n// chat path has no transcription job to justify it.\n//\n// Two things to keep in mind, both of which is why these are separate switches:\n// 1. An UNKNOWN body field is fatal here, not ignored. The engine already documents it for\n// `_skapi_window`: it \"reaches the provider as an unknown body field and the call fails\n// terminally with no retry\". If a field name is wrong, EVERY indexing pass dies. Set either\n// constant to null to remove the field entirely.\n// 2. Reasoning tokens are billed against max_output_tokens on this API. An indexing pass spends\n// its output budget emitting postRecords calls, so buying reasoning takes budget away from the\n// records themselves and can truncate them.\n//\n// Effort was OFF, and the measurement that turned it on: across one nano run's photo records, only\n// 5 of 28 image text fields carried a concrete identifier read off the tag (a part number, a tag id).\n// The other 23 held a generic scene description. Reading small handwriting off a photographed label\n// is exactly the kind of work a moment of deliberation buys, so it went on at the LOWEST setting.\n//\n// It stays 'low' for a nano that already transcribes correctly (5.6-nano), because effort is\n// billed against the same budget as the records and buying it where it is not needed can only\n// truncate them.\n//\n// OLDEST_NANO_REASONING_EFFORT raises it for gpt-5.4-nano and below ONLY, which is the tier that\n// actually reads dense scans badly. It is 'high', and what makes that affordable is not one change\n// but two:\n// - that tier's render window is SMALL_TIER_PAGES_PER_WINDOW pages, not five, so the same cap is\n// divided between far fewer pages to begin with; and\n// - the worker now DETECTS a pass that ran out of output budget (_output_truncation_reason) and\n// re-runs that window at half the page count instead of advancing past it.\n// Before the detector, over-buying reasoning was unsafe in a way that did not show up: a truncated\n// pass still returned 200, so the page loop moved on and the rest of that window's records were\n// lost silently. With it, spending too much on reasoning costs an extra pass instead of data.\n//\n// Still the first knob to lower if the logs start showing repeated truncation retries, and\n// re-measure that 5-of-28 ratio rather than assuming. null removes the field entirely.\nconst VARIANT_TEXT_VERBOSITY: string | null = 'high';\nconst VARIANT_REASONING_EFFORT: string | null = 'low';\nconst OLDEST_NANO_REASONING_EFFORT: string | null = 'high';\n\n/**\n * True only for a NANO model, including a dated nano snapshot. NOT mini, not a base model, and not\n * a named variant like gpt-5.6-luna: those transcribe faithfully on their own and do not need the\n * knob, so paying its output cost on them would be waste.\n */\nconst isOpenAINano = (model?: string) => {\n\tconst normalized = (model || DEFAULT_OPENAI_MODEL).trim().toLowerCase();\n\tif (!/(^|-)nano(-|$)/.test(normalized)) return false;\n\n\t// Family floor, same shape as getOpenAIImageDetail's. \"Contains nano\" alone also matches\n\t// gpt-4.1-nano and anything else a project might name, and these are body fields an older\n\t// model REJECTS rather than ignores: one 400 with no retry kills every indexing pass. Only\n\t// gpt-5.4 and newer are known to take `text.verbosity` and `reasoning.effort`.\n\tconst match = normalized.match(/^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/);\n\tif (!match) return false;\n\tconst major = Number(match[1]);\n\tconst minor = match[2] === undefined ? null : Number(match[2]);\n\treturn major > 5 || (major === 5 && minor !== null && minor >= 4);\n};\n\n/**\n * The indexing-only body knobs, for the ONE tier that needs them: gpt-5.4-nano.\n *\n * Both conditions are load-bearing and mean different things. isOpenAINano is the gpt-5.4\n * FLOOR - below it these fields are rejected rather than ignored, and one 400 kills every\n * indexing pass. isOldestNano is the CEILING - 5.5-nano and 5.6-nano transcribe correctly\n * on their own, so they are left on the provider's defaults exactly like mini and the base\n * models. Every other model gets an empty object, i.e. no `text` and no `reasoning` at all.\n */\nconst variantIndexingOptions = (model?: string) => {\n\tif (!isOpenAINano(model) || !isOldestNano(model)) return {};\n\treturn {\n\t\t...(VARIANT_TEXT_VERBOSITY ? { text: { verbosity: VARIANT_TEXT_VERBOSITY } } : {}),\n\t\t...(OLDEST_NANO_REASONING_EFFORT ? { reasoning: { effort: OLDEST_NANO_REASONING_EFFORT } } : {}),\n\t};\n};\nconst getOpenAIImageDetail = (model?: string) => {\n\tconst normalized = (model || DEFAULT_OPENAI_MODEL).trim().toLowerCase();\n\tconst match = normalized.match(/^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/);\n\tif (!match) {\n\t\treturn DEFAULT_OPENAI_IMAGE_DETAIL;\n\t}\n\n\tconst major = Number(match[1]);\n\tconst minor = match[2] === undefined ? null : Number(match[2]);\n\tconst isVariant = !!match[3];\n\n\tconst supportsOriginal = major > 5 || (major === 5 && minor !== null && minor >= 4);\n\tif (!supportsOriginal) {\n\t\treturn DEFAULT_OPENAI_IMAGE_DETAIL;\n\t}\n\n\treturn isVariant ? VARIANT_IMAGE_DETAIL : 'original';\n};\n\n// Per-image `detail` for WORKER-RENDERED document pages (the `_skapi_render`\n// path). Same resolution as above with one difference: these are dense scans\n// whose entire purpose is to be read, so 'auto' is never acceptable — it lets\n// the API downsample exactly the pixels the model needs to OCR. Floor it at\n// 'high'; models that support full-resolution 'original' still get it.\n//\n// Without this the worker falls back to its own model-blind default ('high'),\n// which silently denies the strongest models the 'original' detail they support.\nconst getRenderImageDetail = (model?: string) => {\n\tconst detail = getOpenAIImageDetail(model);\n\treturn detail === DEFAULT_OPENAI_IMAGE_DETAIL ? 'high' : detail;\n};\n\n/**\n * A nano at gpt-5.4 or OLDER.\n *\n * This is the observed quality boundary, not a guessed one: gpt-5.4-nano and below\n * transcribe dense scans poorly, while mini, the base models and every gpt-5.6 model\n * (5.6-nano included) read the same documents correctly. So only this tier gets\n * compensated, and everything above it is left exactly as it was — on 'original' detail\n * and a full window, because nothing about it needs fixing and every compensation costs\n * either passes or output budget.\n */\n/** The id parses as a gpt version we can reason about. An id that does NOT (o3,\n * chatgpt-4o-latest, any custom name) is left entirely alone: we cannot tell what it is,\n * and every compensation here is either a body field that can 400 or a change to how many\n * images it receives. Unknown means untouched. */\nconst OPENAI_VERSIONED_ID = /^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/;\nconst isRecognisedOpenAIVersion = (model?: string) =>\n\tOPENAI_VERSIONED_ID.test((model || DEFAULT_OPENAI_MODEL).trim().toLowerCase());\n\nconst isOldestNano = (model?: string) => {\n\tconst normalized = (model || DEFAULT_OPENAI_MODEL).trim().toLowerCase();\n\tif (!/(^|-)nano(-|$)/.test(normalized)) return false;\n\tconst match = normalized.match(/^gpt-(\\d+)(?:\\.(\\d+))?(-[a-z0-9.\\-]+)?$/);\n\t// Called \"nano\" but not a naming we recognise: treat it as the weak tier. It also\n\t// fails the 'original' gate, so it is caught by the downsampled branch first anyway.\n\tif (!match) return true;\n\tconst major = Number(match[1]);\n\tconst minor = match[2] === undefined ? null : Number(match[2]);\n\tif (major < 5) return true;\n\tif (major > 5) return false;\n\treturn minor === null || minor <= 4;\n};\n\n// Pages in one render window for a SMALL tier, against RENDER_PAGES_PER_WINDOW (5) for a\n// full one.\n//\n// This is the lever that does not risk a 400. The output budget is one number for the whole\n// pass (getMaxOutputTokens, and reasoning is billed against it), so a window of 5 dense pages leaves\n// a small model a couple of thousand tokens per page and it starts sampling rows instead of\n// transcribing them - which is exactly the \"saved 5 line items\" on a page holding twenty.\n// Halving the window does not raise the cap, it just stops dividing it so many ways, and the\n// worker's page loop already runs as many windows as a file needs.\nconst SMALL_TIER_PAGES_PER_WINDOW = 2;\n\n// Horizontal bands per page for a tier whose images the API DOWNSAMPLES before the model\n// sees them ('high' resamples onto a 512px tile grid). For those models the render DPI is\n// irrelevant - the pixels are thrown away upstream - so the only way to hand them more\n// readable text is to make each image cover less of the page. Two bands doubles the\n// resolution the model effectively gets, at the cost of one extra image per page.\n//\n// Bands are horizontal so a table row is never cut down its middle, and they overlap\n// slightly so a line landing on the seam appears whole in one of them.\nconst DOWNSAMPLED_TIER_TILE = 2;\n\n/** How a given model should be shown a rendered document. */\nexport type VisionProfile = {\n\t/** Per-image `detail` (OpenAI only). */\n\tdetail: string;\n\t/** Pages the worker renders into one window. */\n\tpagesPerWindow: number;\n\t/** Horizontal bands per page; 1 renders the whole page as one image. */\n\ttile: number;\n};\n\n/**\n * Resolve the render profile for a model.\n *\n * Three tiers, and they fail for different reasons, which is why one set of knobs cannot\n * serve all of them:\n * - full: everything ABOVE gpt-5.4-nano - the base models, mini, and every gpt-5.6\n * including 5.6-nano. These already transcribe dense scans correctly, so they get\n * 'original' detail and are otherwise untouched.\n * - gpt-5.4-nano: also gets 'original', so it sees exactly the SAME pixels as the full\n * tier. Its gap therefore is not resolution, and tiling would do nothing for it. What\n * it lacks is room: a smaller window leaves the same output budget divided between\n * fewer pages.\n * - downsampled (below the 'original' floor: gpt-5.3-nano, gpt-5-nano, gpt-4.1-nano):\n * capped at 'high', which resamples the page onto a 512px grid no matter what DPI it\n * was rendered at. Render resolution is wasted on these entirely; the only way to give\n * them readable text is to make each image cover less of the page, which is `tile`.\n */\nexport function getVisionProfile(model?: string): VisionProfile {\n\tconst detail = getRenderImageDetail(model);\n\t// An id we cannot parse is left exactly as it was: full window, no tiling. Treating\n\t// \"unknown\" as \"weak\" would quietly change how much work every custom or aliased model\n\t// does, on no evidence at all.\n\tif (!isRecognisedOpenAIVersion(model)) {\n\t\treturn { detail, pagesPerWindow: RENDER_PAGES_PER_WINDOW, tile: 1 };\n\t}\n\tif (detail !== 'original') {\n\t\treturn { detail, pagesPerWindow: SMALL_TIER_PAGES_PER_WINDOW, tile: DOWNSAMPLED_TIER_TILE };\n\t}\n\tif (isOldestNano(model)) {\n\t\treturn { detail, pagesPerWindow: SMALL_TIER_PAGES_PER_WINDOW, tile: 1 };\n\t}\n\treturn { detail, pagesPerWindow: RENDER_PAGES_PER_WINDOW, tile: 1 };\n}\n\nexport type ClaudeRole = 'user' | 'assistant';\n\nexport type ClaudeMessage = {\n\trole: ClaudeRole;\n\tcontent: string;\n};\n\nexport type OpenAIMessage = {\n\trole: ClaudeRole;\n\tcontent: string;\n};\n\nexport type ClaudeMcpToolConfig = {\n\tenabled?: boolean;\n\tdefer_loading?: boolean;\n};\n\nexport type ClaudeMcpServerRequest = {\n\tname: string;\n\turl: string;\n\tauthorizationToken?: string;\n\tdefaultConfig?: ClaudeMcpToolConfig;\n\tconfigs?: Record<string, ClaudeMcpToolConfig>;\n};\n\nconst IMAGE_URL_REGEX =\n\t/\\bhttps?:\\/\\/[^\\s<>\"'()\\[\\]]+?\\.(?:jpg|jpeg|png|gif|webp)(?:\\?[^\\s<>\"'()\\[\\]]*)?/gi;\n\nexport function transformContentWithImages(\n\tcontent: string,\n): string | Array<Record<string, any>> {\n\tif (typeof content !== 'string' || !content) {\n\t\treturn content;\n\t}\n\n\tconst matches = content.match(IMAGE_URL_REGEX);\n\n\tif (!matches || !matches.length) {\n\t\treturn content;\n\t}\n\n\tconst seen = new Set<string>();\n\tconst imageBlocks: Array<Record<string, any>> = [];\n\n\tfor (const url of matches) {\n\t\tif (seen.has(url)) continue;\n\t\tseen.add(url);\n\t\timageBlocks.push({\n\t\t\ttype: 'image',\n\t\t\tsource: { type: 'url', url },\n\t\t});\n\t}\n\n\treturn [...imageBlocks, { type: 'text', text: content }];\n}\n\nfunction prepareClaudeMessages(messages: ClaudeMessage[]) {\n\tif (!messages.length) return messages;\n\t// Only transform the most recent user message. Historical user messages\n\t// may reference image URLs that are now stale (deleted, moved, expired).\n\tconst lastIndex = messages.length - 1;\n\tconst last = messages[lastIndex];\n\tif (last.role !== 'user') return messages;\n\tconst content = transformContentWithImages(last.content);\n\tif (content === last.content) return messages;\n\tconst next = messages.slice();\n\tnext[lastIndex] = { role: last.role, content } as unknown as ClaudeMessage;\n\treturn next;\n}\n\nexport function transformContentWithOpenAIImages(\n\tcontent: string,\n\tdetail = DEFAULT_OPENAI_IMAGE_DETAIL,\n): string | Array<Record<string, any>> {\n\tif (typeof content !== 'string' || !content) {\n\t\treturn content;\n\t}\n\n\tconst matches = content.match(IMAGE_URL_REGEX);\n\n\tif (!matches || !matches.length) {\n\t\treturn content;\n\t}\n\n\tconst seen = new Set<string>();\n\tconst imageBlocks: Array<Record<string, any>> = [];\n\n\tfor (const url of matches) {\n\t\tif (seen.has(url)) continue;\n\t\tseen.add(url);\n\t\timageBlocks.push({\n\t\t\ttype: 'input_image',\n\t\t\timage_url: url,\n\t\t\tdetail,\n\t\t});\n\t}\n\n\treturn [{ type: 'input_text', text: content }, ...imageBlocks];\n}\n\nfunction prepareOpenAIMessages(\n\tmessages: OpenAIMessage[],\n\tdetail = DEFAULT_OPENAI_IMAGE_DETAIL,\n) {\n\tif (!messages.length) return messages;\n\tconst lastIndex = messages.length - 1;\n\tconst last = messages[lastIndex];\n\tif (last.role !== 'user') return messages;\n\tconst content = transformContentWithOpenAIImages(last.content, detail);\n\tif (content === last.content) return messages;\n\tconst next = messages.slice();\n\tnext[lastIndex] = { role: last.role, content } as unknown as OpenAIMessage;\n\treturn next;\n}\n\n// Attach a cache_control breakpoint to the last message of the stable history\n// prefix (everything except the final user turn) so Anthropic re-uses it at\n// ~10% input-token billing.\nfunction applyHistoryCacheBreakpoint(messages: any[]): any[] {\n\tif (messages.length < 2) return messages;\n\tconst breakpointIndex = messages.length - 2;\n\treturn messages.map((m, i) => {\n\t\tif (i !== breakpointIndex) return m;\n\t\tconst blocks = Array.isArray(m.content)\n\t\t\t? m.content.slice()\n\t\t\t: [{ type: 'text', text: m.content }];\n\t\tif (!blocks.length) return m;\n\t\tconst lastBlockIndex = blocks.length - 1;\n\t\tblocks[lastBlockIndex] = {\n\t\t\t...blocks[lastBlockIndex],\n\t\t\tcache_control: { type: 'ephemeral' },\n\t\t};\n\t\treturn { ...m, content: blocks };\n\t});\n}\n\nexport type CallClaudeWithMcpParams = {\n\tprompt: string;\n\tmessages?: ClaudeMessage[];\n\tservice: string;\n\towner: string;\n\tuserId?: string;\n\tmodel?: string;\n\tmaxTokens?: number;\n\tsystem?: string;\n\tmcpServer: ClaudeMcpServerRequest;\n\textractContent?: ExtractDirective[];\n\tfileUrls?: FileUrlDirective[];\n\tonResponse?: (res: any) => void;\n\tonError?: (err: any) => void;\n};\n// Poll cadence for every client-secret request the chat waits on. Shared by the\n// engine's own poll sites and imported by agent.vue; the widget carries its own\n// copy in src/index.js that must be kept in step.\nexport const POLL_INTERVAL = 3000;\n// Ceiling on how many BACKGROUND indexing polls may be attached at once, across\n// every poll site (the engine's drain, the engine's history load, and each\n// client's own fallback poller).\n//\n// Every unresolved bg item used to get its own poll, and a poll is a\n// POLL_INTERVAL setInterval firing one request per tick. A bulk upload from the\n// db-files page enqueues one indexing pass per FILE, so uploading 10,000 files\n// attached 10,000 concurrent intervals: ~3,300 requests/second against a browser\n// that opens six connections per host. The resulting request backlog starved the\n// uploads themselves, which is the \"frozen tab that eventually finishes\" users\n// reported.\n//\n// Capping costs nothing, because the server settles one queue's passes in FIFO\n// order (a single SQS MessageGroupId per `<user>-bg` queue). A pass cannot\n// finish before the ones ahead of it, so asking about the newest 9,994 is pure\n// waste. Each resolution frees a slot, which the next-OLDEST unpolled entry\n// takes on the drain that follows. Spending the budget oldest-first is\n// load-bearing: spend it on the newest and the batch wedges, since those cannot\n// settle until the ones ahead of them do and nothing ahead would hold a poll.\n//\n// FOREGROUND polls (a reply the user is actively waiting on) are never capped.\nexport const MAX_CONCURRENT_BG_POLLS = 6;\nexport async function callClaudeWithMcp({\n\tprompt,\n\tmessages,\n\tservice,\n\towner,\n\tuserId,\n\tmodel = DEFAULT_CLAUDE_MODEL,\n\tmaxTokens = 1000,\n\tsystem,\n\tmcpServer,\n\textractContent,\n\tfileUrls,\n}: CallClaudeWithMcpParams) {\n\tconst mcpServerDefinition: Record<string, any> = {\n\t\ttype: 'url',\n\t\tname: mcpServer.name,\n\t\turl: mcpServer.url,\n\t};\n\n\tif (mcpServer.authorizationToken) {\n\t\tmcpServerDefinition.authorization_token = mcpServer.authorizationToken;\n\t}\n\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'claude',\n\t\tqueue: userId || service,\n\t\tservice,\n\t\towner,\n\t\t...pollOpt(),\n\t\turl: ANTHROPIC_MESSAGES_API_URL,\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'content-type': 'application/json',\n\t\t\t'x-api-key': '$CLIENT_SECRET',\n\t\t\t'anthropic-version': ANTHROPIC_VERSION,\n\t\t\t'anthropic-beta': ANTHROPIC_BETA_HEADER,\n\t\t},\n\t\tdata: {\n\t\t\tmodel,\n\t\t\tmax_tokens: maxTokens,\n\t\t\t...(extractContent && extractContent.length\n\t\t\t\t? { _skapi_extract: extractContent }\n\t\t\t\t: {}),\n\t\t\t...(fileUrls && fileUrls.length\n\t\t\t\t? { _skapi_file_urls: fileUrls }\n\t\t\t\t: {}),\n\t\t\t...(system\n\t\t\t\t? {\n\t\t\t\t\t\tsystem: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\t\ttext: system,\n\t\t\t\t\t\t\t\tcache_control: { type: 'ephemeral' },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\tmessages: (() => {\n\t\t\t\tconst prepared =\n\t\t\t\t\tmessages && messages.length\n\t\t\t\t\t\t? prepareClaudeMessages(messages)\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\trole: 'user',\n\t\t\t\t\t\t\t\t\tcontent: transformContentWithImages(prompt),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t];\n\t\t\t\treturn applyHistoryCacheBreakpoint(prepared as any[]);\n\t\t\t})(),\n\t\t\tmcp_servers: [mcpServerDefinition],\n\t\t\ttools: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'mcp_toolset',\n\t\t\t\t\tmcp_server_name: mcpServer.name,\n\t\t\t\t\t...(mcpServer.defaultConfig\n\t\t\t\t\t\t? { default_config: mcpServer.defaultConfig }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(mcpServer.configs ? { configs: mcpServer.configs } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'web_fetch_20250910',\n\t\t\t\t\tname: 'web_fetch',\n\t\t\t\t\tmax_uses: WEB_FETCH_MAX_USES,\n\t\t\t\t\tcitations: { enabled: true },\n\t\t\t\t\tmax_content_tokens: WEB_FETCH_MAX_CONTENT_TOKENS,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t});\n}\n\nexport async function callClaudeWithPublicMcp(\n\tprompt: string,\n\tservice: string,\n\towner: string,\n\tmessages?: ClaudeMessage[],\n\tsystem?: string,\n\tmodel?: string,\n\tuserId?: string,\n\textractContent?: ExtractDirective[],\n\tfileUrls?: FileUrlDirective[],\n\tonResponse?: (res: any) => void,\n\tonError?: (err: any) => void,\n\tmcpScope?: { anonymous?: boolean; publicProjectId?: string },\n) {\n\tconst endpoint = mcpEndpointFor(mcpScope?.anonymous, mcpScope?.publicProjectId, service);\n\treturn callClaudeWithMcp({\n\t\tprompt,\n\t\tmessages,\n\t\tservice,\n\t\towner,\n\t\tuserId,\n\t\tmodel: model || DEFAULT_CLAUDE_MODEL,\n\t\tmaxTokens: getMaxOutputTokens('claude', model || DEFAULT_CLAUDE_MODEL),\n\t\tsystem,\n\t\textractContent,\n\t\tfileUrls,\n\t\tmcpServer: {\n\t\t\tname: MCP_NAME,\n\t\t\turl: endpoint.url,\n\t\t\t// Omitted entirely for an anonymous turn; the `if (mcpServer.authorizationToken)`\n\t\t\t// guard below drops the key rather than sending an empty one.\n\t\t\tauthorizationToken: endpoint.token,\n\t\t},\n\t\tonResponse,\n\t\tonError,\n\t});\n}\n\nexport async function callOpenAIWithPublicMcp(\n\tprompt: string,\n\tservice: string,\n\towner: string,\n\tmessages?: OpenAIMessage[],\n\tsystem?: string,\n\tmodel?: string,\n\tuserId?: string,\n\textractContent?: ExtractDirective[],\n\tfileUrls?: FileUrlDirective[],\n\tonResponse?: (res: any) => void,\n\tonError?: (err: any) => void,\n\tmcpScope?: { anonymous?: boolean; publicProjectId?: string },\n) {\n\tconst endpoint = mcpEndpointFor(mcpScope?.anonymous, mcpScope?.publicProjectId, service);\n\tconst resolvedModel = model || DEFAULT_OPENAI_MODEL;\n\tconst imageDetail = getOpenAIImageDetail(resolvedModel);\n\tconst messageList =\n\t\tmessages && messages.length\n\t\t\t? prepareOpenAIMessages(messages, imageDetail)\n\t\t\t: [\n\t\t\t\t{\n\t\t\t\t\trole: 'user' as const,\n\t\t\t\t\tcontent: transformContentWithOpenAIImages(prompt, imageDetail),\n\t\t\t\t},\n\t\t\t];\n\n\tconst responseInput = [\n\t\t...(system\n\t\t\t? [\n\t\t\t\t{\n\t\t\t\t\trole: 'system',\n\t\t\t\t\tcontent: system,\n\t\t\t\t},\n\t\t\t]\n\t\t\t: []),\n\t\t...messageList.map((m) => ({\n\t\t\trole: m.role,\n\t\t\tcontent: m.content,\n\t\t})),\n\t];\n\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'openai',\n\t\tqueue: userId || service,\n\t\tservice,\n\t\towner,\n\t\t...pollOpt(),\n\t\turl: OPENAI_RESPONSES_API_URL,\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'content-type': 'application/json',\n\t\t\tAuthorization: 'Bearer $CLIENT_SECRET',\n\t\t},\n\t\tdata: {\n\t\t\tmodel: resolvedModel,\n\t\t\tmax_output_tokens: getMaxOutputTokens('openai', resolvedModel),\n\t\t\t...(extractContent && extractContent.length\n\t\t\t\t? { _skapi_extract: extractContent }\n\t\t\t\t: {}),\n\t\t\t...(fileUrls && fileUrls.length\n\t\t\t\t? { _skapi_file_urls: fileUrls }\n\t\t\t\t: {}),\n\t\t\tinput: responseInput,\n\t\t\ttools: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'mcp',\n\t\t\t\t\tserver_label: MCP_NAME,\n\t\t\t\t\tserver_url: endpoint.url,\n\t\t\t\t\trequire_approval: 'never',\n\t\t\t\t\t// No `headers` at all for an anonymous turn: `Bearer ` with an\n\t\t\t\t\t// empty token is a credential the MCP server rejects, and the\n\t\t\t\t\t// project-scoped endpoint needs none.\n\t\t\t\t\t...(endpoint.token\n\t\t\t\t\t\t? { headers: { Authorization: 'Bearer ' + endpoint.token } }\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t\t...(OPENAI_WEB_SEARCH_ENABLED\n\t\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'web_search',\n\t\t\t\t\t\t\texternal_web_access: OPENAI_WEB_SEARCH_EXTERNAL_WEB_ACCESS,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t\t: []),\n\t\t\t],\n\t\t},\n\t});\n}\n\nexport type AttachmentSaveInfo = {\n\tplatform: 'claude' | 'openai';\n\tmodel?: string;\n\tservice: string;\n\t/** The PUBLIC project ID (formatted token, skapi.project_id). Shown to the model; falls back to `service`. */\n\tpublicProjectId?: string;\n\towner: string;\n\t/**\n\t * Queue base for this indexing pass: \"<userId>-bg\". REQUIRED, and it must be\n\t * the SAME value the chat turn uses (ChatSession.dispatchComposedMessage's\n\t * `id.userId || id.projectId`) — the backend serialises requests that share a\n\t * queue name and runs different ones IN PARALLEL, so a pass enqueued under a\n\t * different base does not hold the chat back at all. It was optional once,\n\t * defaulting to `service`; the chatbox omitted it, and its files were indexed\n\t * on \"<projectId>-bg\" while its question ran on \"<userId>-bg\" — the question\n\t * was answered from a file nothing had read yet. Pass `userId || projectId`.\n\t */\n\tuserId: string;\n\tserviceName?: string;\n\tserviceDescription?: string;\n\tattachment: {\n\t\tname: string;\n\t\tstoragePath: string;\n\t\tmime?: string;\n\t\tsize?: number;\n\t\turl: string;\n\t\t/**\n\t\t * Access group this file's records are written at (the uploader's choice,\n\t\t * already applied to the \"src::\" record). Threaded into the indexing\n\t\t * prompts so the agent's own records land in the same group; omitted\n\t\t * means \"authorized\", the group everything used before the setting existed.\n\t\t */\n\t\taccessGroup?: 'public' | 'authorized' | 'private';\n\t};\n\t/**\n\t * Content parsed CLIENT-SIDE by an attachment-parser plugin (e.g. an .hwp\n\t * parser). When set, it is inlined into the indexing message verbatim and\n\t * takes precedence over server-side office extraction / web_fetch.\n\t */\n\tparsedContent?: string;\n\t/**\n\t * True for a RESUME pass: a previous indexing pass could not finish this (large)\n\t * file, so continue it - always via readFileContent paging, with a \"continue\"\n\t * message telling the agent to resume from where the saved records leave off.\n\t */\n\tcontinueIndexing?: boolean;\n\t/**\n\t * For an image-vision file (PDF), the 0-based PAGE the render window should start at.\n\t * The worker renders [renderFrom, renderFrom+RENDER_PAGES_PER_WINDOW) and injects them\n\t * as image blocks; the resume loop advances this by a window each pass.\n\t */\n\trenderFrom?: number;\n};\n\n// RESUME pass: continue indexing a large file a previous pass could not finish. Same\n// dispatch as notifyAgentSaveAttachment, but forced onto the paging path with a\n// \"continue from where the saved records leave off\" message.\nexport async function notifyAgentContinueIndexing(info: AttachmentSaveInfo) {\n\treturn notifyAgentSaveAttachment({ ...info, continueIndexing: true });\n}\n\n// Background \"save into knowledge\" call (not a chat turn). A client-parsed file\n// (parser plugin) is inlined directly; otherwise office files get the\n// _skapi_extract directive + a placeholder, and everything else gets a URL.\nexport async function notifyAgentSaveAttachment(info: AttachmentSaveInfo) {\n\tconst { platform, service, owner, attachment, parsedContent } = info;\n\n\t// A CONTINUE pass resumes a large file that a previous pass could not finish.\n\tconst continuing = !!info.continueIndexing;\n\n\t// Durable run record, minted the moment a run's FIRST pass is enqueued (every\n\t// first-pass site funnels through this function, so one mint covers them all;\n\t// resume passes belong to the existing run and must not touch it). Ordering is\n\t// safe by construction: every caller runs its delete-then-repost + src:: mint\n\t// BEFORE calling here, so the record's `reference: src::<path>` resolves. The\n\t// dispatch promise is tapped below so an enqueue that never reached the queue\n\t// closes the record as an error instead of leaving 'working' dangling.\n\tif (!continuing) {\n\t\tupsertIndexRunRecordSafe(service, attachment.storagePath, {\n\t\t\tstatus: 'working',\n\t\t\tfilename: attachment.name,\n\t\t\tstarted: Date.now(),\n\t\t\tqueue: bgIndexingQueueName(info.userId, service),\n\t\t\tplatform: platform,\n\t\t});\n\t}\n\tconst tapDispatchFailure = (p: Promise<any>): Promise<any> => {\n\t\tif (continuing) return p;\n\t\treturn p.then(\n\t\t\t(ack: any) => ack,\n\t\t\t(err: any) => {\n\t\t\t\tupsertIndexRunRecordSafe(service, attachment.storagePath, {\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tfinished: Date.now(),\n\t\t\t\t\terror: (err && (err.message || String(err))) || 'The indexing request could not be enqueued.',\n\t\t\t\t});\n\t\t\t\tthrow err;\n\t\t\t},\n\t\t);\n\t};\n\n\t// VISION files (PDFs) are delivered as rendered page IMAGES injected into the message by\n\t// the worker (`_skapi_render`), because tool-result images render on neither provider.\n\t// Both the first pass and every resume pass use this; renderFrom advances the page window.\n\tconst visionFile = !parsedContent && isImageVisionFile(attachment.name, attachment.mime);\n\tconst renderFrom = Math.max(0, info.renderFrom || 0);\n\tconst renderPlaceholder = visionFile ? makeRenderPlaceholder(attachment.storagePath) : undefined;\n\t// Tell the worker what image `detail` to stamp on the injected page blocks.\n\t// The worker is model-blind, so without this it applies a one-size default and\n\t// the strongest models never get the 'original' detail they support. Only\n\t// meaningful for OpenAI — Claude has no per-image detail knob and the worker\n\t// ignores the field for it.\n\tconst renderDetail = platform === 'openai'\n\t\t? getRenderImageDetail(info.model || DEFAULT_OPENAI_MODEL)\n\t\t: undefined;\n\t// `auto_continue` + `continue_text` hand the page loop to the WORKER: when its renderer\n\t// reports pages left after this window, it builds the next pass from this template\n\t// (substituting the window's 1-based start page for RENDER_FROM_TOKEN) and enqueues it\n\t// itself. That is what makes a 500-page document index end-to-end — the loop no longer\n\t// depends on the tab staying open, nor on the model correctly declaring itself unfinished.\n\t// Window size and per-page tiling are resolved from the MODEL, not fixed: see\n\t// getVisionProfile. Claude keeps the full window (renderDetail is OpenAI-only, and its\n\t// own resizing behaviour is a separate question this does not try to answer).\n\tconst visionProfile: VisionProfile = platform === 'openai'\n\t\t? getVisionProfile(info.model || DEFAULT_OPENAI_MODEL)\n\t\t: { detail: '', pagesPerWindow: RENDER_PAGES_PER_WINDOW, tile: 1 };\n\tconst skapiRender = visionFile && renderPlaceholder\n\t\t? {\n\t\t\t_skapi_render: [\n\t\t\t\t{\n\t\t\t\t\tpath: attachment.storagePath, from: renderFrom, count: visionProfile.pagesPerWindow,\n\t\t\t\t\tplaceholder: renderPlaceholder, name: attachment.name, mime: attachment.mime, detail: renderDetail,\n\t\t\t\t\ttile: visionProfile.tile,\n\t\t\t\t\tauto_continue: true,\n\t\t\t\t\tcontinue_text: buildIndexingRenderContinueTemplate(attachment, renderPlaceholder),\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t\t: {};\n\n\t// SERVER-DRIVEN windowed read. When enabled, the worker reads one window of the file\n\t// per request and continues from the reader's own cursor until the file is exhausted,\n\t// so the traversal no longer lives inside the model's turn budget.\n\t//\n\t// Flag-gated because the BACKEND MUST SHIP FIRST: against a worker that does not strip\n\t// `_skapi_window`, the directive reaches the provider as an unknown body field and the\n\t// call fails terminally with no retry.\n\tconst windowedRead =\n\t\t!visionFile && !parsedContent && windowedIndexingEnabled() &&\n\t\tisWindowedReadFile(attachment.name, attachment.mime);\n\tconst windowPlaceholder = windowedRead ? makeWindowPlaceholder(attachment.storagePath) : undefined;\n\tconst skapiWindow = windowedRead && windowPlaceholder\n\t\t? {\n\t\t\t_skapi_window: [\n\t\t\t\t{\n\t\t\t\t\tpath: attachment.storagePath,\n\t\t\t\t\tcursor: null,\n\t\t\t\t\tplaceholder: windowPlaceholder,\n\t\t\t\t\tname: attachment.name,\n\t\t\t\t\tmime: attachment.mime,\n\t\t\t\t\tkind: 'window',\n\t\t\t\t\t// Same per-image `detail` the render path sends. Without it the worker falls\n\t\t\t\t\t// back to its model-blind default of 'high', so a spreadsheet's embedded\n\t\t\t\t\t// photos were tiled at lower resolution than the SAME model gets for a PDF\n\t\t\t\t\t// page or a chat attachment. That is why a model could describe an attached\n\t\t\t\t\t// photo but reported the pictures inside a sheet as only partly legible.\n\t\t\t\t\tdetail: renderDetail,\n\t\t\t\t\tauto_continue: true,\n\t\t\t\t\tcontinue_text: buildIndexingWindowMessage(attachment, windowPlaceholder, true),\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t\t: {};\n\n\t// Spreadsheets are read by PAGING through readFileContent (grid rows), NOT inlined - so\n\t// they skip the inline server-extract and the agent is told to page the whole file.\n\tconst pagedRead = !visionFile && !windowedRead && (continuing || (!parsedContent && isPagedReadFile(attachment.name, attachment.mime)));\n\n\t// Client-parsed content wins over server-side extraction.\n\tconst serverExtract = !visionFile && !windowedRead && !continuing && !parsedContent && !pagedRead && isServerExtractable(attachment.name, attachment.mime);\n\tconst placeholder = serverExtract ? makeExtractPlaceholder(attachment.storagePath) : undefined;\n\tconst extractContent: ExtractDirective[] | undefined =\n\t\tserverExtract && placeholder\n\t\t\t? [{ path: attachment.storagePath, placeholder, name: attachment.name, mime: attachment.mime }]\n\t\t\t: undefined;\n\tconst skapiExtract =\n\t\textractContent && extractContent.length\n\t\t\t? {\n\t\t\t\t_skapi_extract: extractContent.map((d) => ({\n\t\t\t\t\t...d,\n\t\t\t\t\t// FIRST pass of an INDEXING run only: tells the worker to also pull the\n\t\t\t\t\t// file's embedded pictures into __MEDIA__ and register their records.\n\t\t\t\t\t// Chat-turn extraction (callClaudeWithMcp / callOpenAIWithPublicMcp)\n\t\t\t\t\t// never sets this, so merely ATTACHING a file to a chat message cannot\n\t\t\t\t\t// write media records; a CONTINUE pass skips it because the first pass\n\t\t\t\t\t// already saved (the save is whole-file, not windowed).\n\t\t\t\t\tsave_media: !continuing,\n\t\t\t\t})),\n\t\t\t}\n\t\t\t: {};\n\n\t// Ask the worker to re-sign this file's url at EXECUTION time.\n\t//\n\t// The url below was minted when the file was uploaded. Indexing for a project\n\t// runs on ONE FIFO group, one pass at a time, so a row queued behind a bulk\n\t// upload can wait hours or days before it fires - by which point that url can\n\t// be dead, the provider's fetch returns nothing, and the file is recorded as\n\t// indexed with an empty index behind it. The worker rebuilds the body from the\n\t// row on every delivery, so re-signing there means the url only has to outlive\n\t// ONE invocation however long the wait was.\n\t//\n\t// Sent for every indexing pass, including CONTINUE passes: a chain spanning\n\t// days is exactly where the baked url is oldest. Harmless where the file's\n\t// content arrives another way (server-side extraction, rendered pages) - the\n\t// url still appears as the attachment link, and a dead link in front of the\n\t// model is worth avoiding either way.\n\tconst skapiFileUrls = attachment.url && attachment.storagePath\n\t\t? { _skapi_file_urls: [{ path: attachment.storagePath, url: attachment.url }] }\n\t\t: {};\n\n\tconst userMessage = (visionFile && renderPlaceholder)\n\t\t? buildIndexingRenderMessage(attachment, renderPlaceholder, renderFrom)\n\t\t: (windowedRead && windowPlaceholder)\n\t\t? buildIndexingWindowMessage(attachment, windowPlaceholder, false)\n\t\t: continuing\n\t\t\t? buildIndexingContinueMessage(attachment)\n\t\t\t: buildIndexingUserMessage(\n\t\t\t\tattachment,\n\t\t\t\tparsedContent\n\t\t\t\t\t? { inlineContent: parsedContent }\n\t\t\t\t\t: placeholder\n\t\t\t\t\t\t? { inlineContentPlaceholder: placeholder }\n\t\t\t\t\t\t: pagedRead\n\t\t\t\t\t\t\t? { pagedRead: true }\n\t\t\t\t\t\t\t: undefined,\n\t\t\t);\n\n\tconst systemPrompt = buildIndexingSystemPrompt({\n\t\t// The model copies this id verbatim into project_id tool calls, so it must be\n\t\t// the PUBLIC token whenever the host supplied one; the raw code is rejected\n\t\t// by the tools' schema pattern.\n\t\tprojectId: info.publicProjectId || service,\n\t\tserviceName: info.serviceName,\n\t\tserviceDescription: info.serviceDescription,\n\t\t// Per-FILE, not per-project: one project holds public and private files at\n\t\t// once, so this travels on the attachment rather than the identity.\n\t\taccessGroup: attachment.accessGroup,\n\t});\n\n\tif (platform === 'openai') {\n\t\tconst resolvedModel = info.model || DEFAULT_OPENAI_MODEL;\n\t\tconst imageDetail = getOpenAIImageDetail(resolvedModel);\n\t\treturn tapDispatchFailure(clientSecretRequest({\n\t\t\tclientSecretName: 'openai',\n\t\t\tqueue: bgIndexingQueueName(info.userId, service),\n\t\t\tservice,\n\t\t\towner,\n\t\t\t...pollOpt(),\n\t\t\turl: OPENAI_RESPONSES_API_URL,\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'content-type': 'application/json',\n\t\t\t\tAuthorization: 'Bearer $CLIENT_SECRET',\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tmodel: resolvedModel,\n\t\t\t\tmax_output_tokens: getMaxOutputTokens('openai', resolvedModel),\n\t\t\t\t// Nano-only transcription knobs. Indexing only; see variantIndexingOptions.\n\t\t\t\t...variantIndexingOptions(resolvedModel),\n\t\t\t\t...skapiExtract,\n\t\t\t\t...skapiRender,\n\t\t\t\t...skapiWindow,\n\t\t\t\t...skapiFileUrls,\n\t\t\t\tinput: [\n\t\t\t\t\t{ role: 'system', content: systemPrompt },\n\t\t\t\t\t{\n\t\t\t\t\t\trole: 'user',\n\t\t\t\t\t\tcontent: transformContentWithOpenAIImages(userMessage, imageDetail),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\ttools: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'mcp',\n\t\t\t\t\t\tserver_label: MCP_NAME,\n\t\t\t\t\t\tserver_url: mcpUrl(),\n\t\t\t\t\t\trequire_approval: 'never',\n\t\t\t\t\t\theaders: { Authorization: 'Bearer $ACCESS_TOKEN' },\n\t\t\t\t\t},\n\t\t\t\t\t...(OPENAI_WEB_SEARCH_ENABLED\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: 'web_search',\n\t\t\t\t\t\t\t\t\texternal_web_access: OPENAI_WEB_SEARCH_EXTERNAL_WEB_ACCESS,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t},\n\t\t}));\n\t}\n\n\tconst resolvedModel = info.model || DEFAULT_CLAUDE_MODEL;\n\treturn tapDispatchFailure(clientSecretRequest({\n\t\tclientSecretName: 'claude',\n\t\tqueue: bgIndexingQueueName(info.userId, service),\n\t\tservice,\n\t\towner,\n\t\t...pollOpt(),\n\t\turl: ANTHROPIC_MESSAGES_API_URL,\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'content-type': 'application/json',\n\t\t\t'x-api-key': '$CLIENT_SECRET',\n\t\t\t'anthropic-version': ANTHROPIC_VERSION,\n\t\t\t'anthropic-beta': ANTHROPIC_BETA_HEADER,\n\t\t},\n\t\tdata: {\n\t\t\tmodel: resolvedModel,\n\t\t\tmax_tokens: getMaxOutputTokens('claude', resolvedModel),\n\t\t\t...skapiExtract,\n\t\t\t...skapiRender,\n\t\t\t...skapiWindow,\n\t\t\t...skapiFileUrls,\n\t\t\tsystem: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\ttext: systemPrompt,\n\t\t\t\t\tcache_control: { type: 'ephemeral' },\n\t\t\t\t},\n\t\t\t],\n\t\t\tmessages: [\n\t\t\t\t{\n\t\t\t\t\trole: 'user',\n\t\t\t\t\tcontent: transformContentWithImages(userMessage),\n\t\t\t\t},\n\t\t\t],\n\t\t\tmcp_servers: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'url',\n\t\t\t\t\tname: MCP_NAME,\n\t\t\t\t\turl: mcpUrl(),\n\t\t\t\t\tauthorization_token: '$ACCESS_TOKEN',\n\t\t\t\t},\n\t\t\t],\n\t\t\ttools: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'mcp_toolset',\n\t\t\t\t\tmcp_server_name: MCP_NAME,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'web_fetch_20250910',\n\t\t\t\t\tname: 'web_fetch',\n\t\t\t\t\tmax_uses: WEB_FETCH_MAX_USES,\n\t\t\t\t\tcitations: { enabled: true },\n\t\t\t\t\tmax_content_tokens: WEB_FETCH_MAX_CONTENT_TOKENS,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t}));\n}\n\nexport function extractClaudeText(response: any) {\n\tif (!Array.isArray(response?.content)) {\n\t\treturn '';\n\t}\n\n\treturn response.content\n\t\t.filter((block: any) => block?.type === 'text')\n\t\t.map((block: any) => block.text)\n\t\t.join('\\n');\n}\n\nexport function extractOpenAIText(response: any) {\n\tif (\n\t\ttypeof response?.output_text === 'string' &&\n\t\tresponse.output_text.length\n\t) {\n\t\treturn response.output_text;\n\t}\n\n\tif (Array.isArray(response?.output)) {\n\t\tconst text = response.output\n\t\t\t.flatMap((item: any) => item?.content || [])\n\t\t\t.filter((part: any) => part?.type === 'output_text')\n\t\t\t.map((part: any) => part.text || '')\n\t\t\t.join('\\n')\n\t\t\t.trim();\n\n\t\tif (text) {\n\t\t\treturn text;\n\t\t}\n\t}\n\n\tconst content = response?.choices?.[0]?.message?.content;\n\n\tif (typeof content === 'string') {\n\t\treturn content;\n\t}\n\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.map((part: any) => {\n\t\t\t\tif (typeof part === 'string') {\n\t\t\t\t\treturn part;\n\t\t\t\t}\n\t\t\t\tif (part?.type === 'text') {\n\t\t\t\t\treturn part.text || '';\n\t\t\t\t}\n\t\t\t\treturn '';\n\t\t\t})\n\t\t\t.join('\\n');\n\t}\n\n\treturn '';\n}\n\nexport async function listClaudeModels(service: string, owner: string) {\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'claude',\n\t\tservice,\n\t\towner,\n\t\turl: ANTHROPIC_MODELS_API_URL,\n\t\tmethod: 'GET',\n\t\theaders: {\n\t\t\t'x-api-key': '$CLIENT_SECRET',\n\t\t\t'anthropic-version': ANTHROPIC_VERSION,\n\t\t},\n\t});\n}\n\nexport async function listOpenAIModels(service: string, owner: string) {\n\treturn clientSecretRequest({\n\t\tclientSecretName: 'openai',\n\t\tservice,\n\t\towner,\n\t\turl: OPENAI_MODELS_API_URL,\n\t\tmethod: 'GET',\n\t\theaders: {\n\t\t\tAuthorization: 'Bearer $CLIENT_SECRET',\n\t\t},\n\t});\n}\n\n// Suffix for the background-indexing queue. Must sort *before* ':' (ASCII 58)\n// so the chat-history BETWEEN query never includes bg-queue items. '-' (45) works.\nexport const BG_INDEXING_QUEUE_SUFFIX = '-bg';\n\n/**\n * unique_id of the durable \"indexing finished\" marker record for a stored file.\n *\n * Written by the BACKEND (the polling worker calls the MCP server's\n * /internal/index-complete at the end of an auto_continue chain whose final\n * window reported no more content) and, for completions a client knows\n * deterministically (single-pass settle, client-chain completion token), by the\n * consumer's mintIndexDoneMarker hook — never by the model.\n * The marker record carries `reference: \"src::<path>\"`, so the reindex flow's\n * delete of the src:: record cascades to it and a re-run starts unmarked.\n *\n * Existence semantics: present = the whole file was read to the end. Absent =\n * unknown (still running, failed partway, indexed before this marker existed,\n * or a single-pass run minted before the client hook existed) - callers must\n * fall back to the live-queue probe (fetchLiveIndexingKeys) before reading\n * absence as anything.\n */\nexport function indexDoneUniqueId(storagePath: string): string {\n\treturn 'done::' + storagePath;\n}\n\n/**\n * unique_id of the per-file indexing RUN record.\n *\n * One record per storage path, newest run wins (a reindex's delete-then-repost\n * of src:: cascade-deletes the old record first, exactly like done::). Minted\n * status='working' by the client the moment it enqueues a run's FIRST pass, and\n * closed (done/error/cancelled) by whichever side observes the ending: the\n * worker via the MCP internal routes for worker-driven chains, the client for\n * deterministic settles, cancels, and dispatch failures. It exists so chat rows\n * and files-page badges can answer \"which runs exist and how did they end\"\n * from ONE records query instead of scanning bg history.\n *\n * A 'working' record is a claim, not proof: a chain that dies without reaching\n * any error path leaves it dangling, so readers must treat a stale 'working'\n * (old `started`, no live-queue confirmation) as unknown, never as live.\n */\nexport function runIndexUniqueId(storagePath: string): string {\n\treturn 'run::' + storagePath;\n}\n\nexport type IndexRunStatus = 'working' | 'done' | 'error' | 'cancelled';\n\nexport type IndexRunPatch = {\n\tstatus: IndexRunStatus;\n\tfilename?: string;\n\tstarted?: number;\n\tfinished?: number;\n\terror?: string;\n\tqueue?: string;\n\t/** Chat that owns this run. A run:: record is keyed by storage path alone,\n\t * but a chat is per (project, platform) — without this the Claude chat's\n\t * runs surfaced as rows in the same project's ChatGPT chat, where their\n\t * passes can never load and the queue probe can never see them. */\n\tplatform?: 'claude' | 'openai';\n};\n\n/**\n * Fire-and-forget wrapper over the consumer's upsertIndexRunRecord hook.\n * Safe everywhere: missing hook, unconfigured engine, and consumer throws all\n * reduce to a no-op — a run record must never be able to break the run itself.\n */\nexport function upsertIndexRunRecordSafe(service: string, storagePath: string, patch: IndexRunPatch): void {\n\tif (!service || !storagePath) return;\n\ttry {\n\t\tconst hook = chatEngineConfig().upsertIndexRunRecord;\n\t\tif (typeof hook !== 'function') return;\n\t\thook({ service, storagePath, patch });\n\t} catch (e) {\n\t\t// best-effort by contract\n\t}\n}\n\n/**\n * The one place the background-indexing queue name is spelled out. The backend\n * serialises requests sharing a queue name and runs different names in PARALLEL,\n * so every indexing pass AND the chat turn that must wait behind them have to\n * resolve to the identical string — see AttachmentSaveInfo.userId for what\n * happens when they do not.\n */\nexport function bgIndexingQueueName(userId?: string, service?: string): string {\n\treturn (userId || service || '') + BG_INDEXING_QUEUE_SUFFIX;\n}\n\n/**\n * True when a request belongs to the background-indexing queue.\n *\n * Accepts BOTH shapes this value arrives in: the bare queue name the client sends\n * (\"<userId>-bg\"), and the server qid that comes back on history/poll responses\n * (\"<service>:<queue>|<seq>\"). Testing the tail of the raw value only works for the\n * first: a qid ends in \"|<seq>\", so `endsWith('-bg')` is always false for it — which\n * silently meant history items were NEVER recognised as background tasks.\n */\nexport function isBgIndexingQueue(queueName?: string): boolean {\n\tif (typeof queueName !== 'string' || !queueName) return false;\n\tconst prefix = queueName.split('|')[0];\n\tconst idx = prefix.lastIndexOf(':');\n\tconst name = idx === -1 ? prefix : prefix.slice(idx + 1);\n\treturn name.slice(-BG_INDEXING_QUEUE_SUFFIX.length) === BG_INDEXING_QUEUE_SUFFIX;\n}\n\n// Pending background-indexing task descriptor. NOTE: the live mutable queue\n// (a Vue `reactive([])` in agent.vue, a plain array in bunnyquery) is app-level\n// state owned by the consumer — only the TYPE lives in the engine.\nexport type BgTaskEntry = {\n\tprojectId: string;\n\tplatform: 'claude' | 'openai';\n\tid: string;\n\tfilename: string;\n\tstoragePath?: string;\n\tisReindex?: boolean;\n\tmime?: string;\n\tsize?: number;\n\tstatus: 'running' | 'pending';\n\tpoll: ((opts: { latency: number }) => Promise<any>) | undefined;\n\t/** How many CONTINUE passes have already run for this file (resume-across-passes). */\n\tresumePass?: number;\n\t/** The STAGED chat turn these files were attached to (ChatSession.stageOutgoingMessage).\n\t * drainBgTaskQueue inserts this pass's bubble directly ABOVE that turn's bubble, so the\n\t * collapsed row sits where the reader expects it — right before the message the files\n\t * came with — from the moment it appears, instead of the turn being moved down past it\n\t * once everything finishes. Absent for work with no chat turn behind it (the dbfile\n\t * page, an attachment-only send, a worker-adopted pass), which appends as before. */\n\tstageId?: string;\n};\n\n// Token the indexing agent appends to its final message ONLY when it has fully read and\n// saved the whole file. Its ABSENCE is what tells the client to run another CONTINUE pass.\n//\n// Applies to the TEXT/GRID paging path only. The vision path (rendered PDF pages) no longer\n// asks the model whether it is finished — the worker advances that loop off the renderer's\n// page count — so this marker has no say in whether a PDF keeps going.\nexport const INDEXING_COMPLETE_MARKER = 'INDEXING_COMPLETE';\n// What an indexing pass's bubble says when its ENTIRE answer was the completion\n// token and stripping it left nothing. Without a stand-in the history mappers emit\n// no bubble at all for that pass (their `else if (assistantText)` guard fails on the\n// empty string) while the live path emits one — so the same run read as finished\n// live and unfinished after a reload, and the row's loader came back.\nexport const EMPTY_INDEXING_REPLY = 'Finished reading this file.';\n// Cap on CONTINUE passes per file, so a file the agent can never mark complete (or a\n// pathological loop) stops instead of re-dispatching forever. The text/grid paging path\n// reads MANY windows within a single pass (the agent loops readFileContent in one turn), so\n// a small cap suffices.\nexport const MAX_INDEXING_RESUME_PASSES = 6;\n\n// Records per chat-history page. Bigger than skapi's own default so the first load\n// (and each scroll-up page) covers more of the conversation in one round-trip — a\n// short page leaves the box unfilled and forces the viewport-fill loop to page\n// again immediately. Callers that want a narrower page (the queue/status probes in\n// ChatSession) pass their own `limit`, which wins over this default.\n// 500, up from 100: an indexing run is dozens of rows that collapse into ONE visible\n// row, so a screenful of history behind a few indexed files took 5+ sequential\n// round trips to assemble (cursor paging cannot be parallelised - each page's\n// startKey comes from the previous response). The number is a CAP, not a payload\n// size: DynamoDB stops a page at 1MB regardless and hands back a cursor, and the\n// backend passes the limit through without looping, so heavy indexing rows page at\n// the same bytes per trip as before while light chat rows now arrive 500 at a time.\nexport const CHAT_HISTORY_PAGE_LIMIT = 500;\n\n/**\n * `queue` narrows the fetch to one processing chain; `status` narrows it to items\n * in one state. Passing both is how the client asks \"is there still unresolved\n * work on the background-indexing queue?\" without pulling a page of chat history\n * (see ChatSession._adoptWorkerIndexingPasses) — the server answers that from a\n * status-keyed index, so the reply carries only the live items, not the bodies of\n * everything already finished.\n */\nexport async function getChatHistory(\n\tparams: {\n\t\tservice?: string; owner?: string; platform: 'claude' | 'openai'; queue?: string;\n\t\tstatus?: 'pending' | 'running' | 'resolved' | 'failed';\n\t\t/** Exact-queue listing: without it the qid range is a PREFIX match, so\n\t\t * queue \"u1\" also returns \"u1-bg\" rows. Requires the updated polling\n\t\t * lambda; older backends ignore it (harmless, wider results). */\n\t\tqueue_exact?: boolean;\n\t\t/** Label/marker STUBS instead of full bodies (see the polling lambda).\n\t\t * Older backends ignore it and return full items. */\n\t\tcompact?: boolean;\n\t\t/** Drop one queue's rows from an id-prefix listing — how the surface\n\t\t * chat is fetched WITHOUT the bg-indexing queue while legacy items on\n\t\t * odd queue names survive. Older backends ignore it. */\n\t\tqueue_exclude?: string;\n\t},\n\tfetchOptions: Record<string, any>,\n) {\n\tconst url =\n\t\tparams.platform === 'claude'\n\t\t\t? ANTHROPIC_MESSAGES_API_URL\n\t\t\t: OPENAI_RESPONSES_API_URL;\n\tconst p = Object.assign(\n\t\t{\n\t\t\turl,\n\t\t\tmethod: 'POST',\n\t\t},\n\t\t{ service: params.service, owner: params.owner },\n\t\tparams.queue ? { queue: params.queue } : {},\n\t\tparams.status ? { status: params.status } : {},\n\t\tparams.queue_exact ? { queue_exact: true } : {},\n\t\tparams.compact ? { compact: true } : {},\n\t\tparams.queue_exclude ? { queue_exclude: params.queue_exclude } : {},\n\t);\n\n\treturn chatEngineConfig().clientSecretRequestHistory(\n\t\tp as { url: string; method: 'POST'; queue?: string; status?: string },\n\t\tObject.assign({ ascending: false, limit: CHAT_HISTORY_PAGE_LIMIT }, fetchOptions),\n\t);\n}\n\n/** Full server-side id of one history item, for a csr-poll POINT LOOKUP (the\n * single-item path returns the item WITH bodies — how an expanded row fetches\n * the passes a compact listing stubbed out). Mirrors the id the SDK builds:\n * `[METHOD]url#service:` + the item's own `stamp:entropy` id. */\nexport function buildHistoryItemFullId(platform: 'claude' | 'openai', service: string, itemId: string): string {\n\tconst url = platform === 'claude' ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;\n\treturn `[POST]${url.toLowerCase()}#${service}:${itemId}`;\n}\n","/**\n * History mapping (pure). Moved verbatim from the chatbox. The clear-horizon\n * timestamp and the \"Indexing: …\" display label are INJECTED (clearedAt param,\n * formatIndexingLabel callback) so the engine touches neither localStorage nor\n * view-specific display formatting. projectId is passed for link sanitization.\n */\nimport { extractClaudeText, extractOpenAIText, INDEXING_COMPLETE_MARKER, EMPTY_INDEXING_REPLY, getChatHistory, bgIndexingQueueName } from './requests';\nimport { isErrorResponseBody, getErrorMessage } from './errors';\nimport { sanitizeAttachmentLinksForHistory } from './links';\nimport type { ChatMessage } from './host';\n\nexport function filterListByClearHorizon(list: any[], clearedAt: number): any[] {\n\tif (!clearedAt) return list;\n\treturn list.filter(function (item) {\n\t\tvar updated = Number(item && item.updated);\n\t\treturn isFinite(updated) && updated > clearedAt;\n\t});\n}\n\nexport function normalizeTextContent(content: any): string {\n\tif (typeof content === 'string') return content;\n\tif (Array.isArray(content)) {\n\t\treturn content.map(function (part: any) {\n\t\t\tif (typeof part === 'string') return part;\n\t\t\tif (part && (part.type === 'text' || part.type === 'input_text' || part.type === 'output_text')) return part.text || '';\n\t\t\treturn '';\n\t\t}).join('\\n').trim();\n\t}\n\treturn '';\n}\n\nexport function extractLastUserTextFromRequest(requestBody: any): string {\n\tvar arr = requestBody && Array.isArray(requestBody.messages) ? requestBody.messages\n\t\t: (requestBody && Array.isArray(requestBody.input) ? requestBody.input : []);\n\tfor (var i = arr.length - 1; i >= 0; i--) {\n\t\tif (arr[i] && arr[i].role === 'user') {\n\t\t\tvar t = normalizeTextContent(arr[i].content);\n\t\t\tif (t) return t;\n\t\t}\n\t}\n\treturn '';\n}\n\n/** The two openings an indexing prompt can have. A bg-queue item that starts with\n * neither is an ordinary chat that happened to be routed onto that queue. */\nexport function isIndexingRequestText(userText: any): boolean {\n\tif (typeof userText !== 'string') return false;\n\treturn userText.indexOf('A new file has just been uploaded') === 0 || userText.indexOf('CONTINUE indexing') === 0;\n}\n\nexport type IndexingRequestRef = {\n\tname: string;\n\tpath?: string;\n\tmime?: string;\n\tsize?: number;\n\t/** A CONTINUE pass rather than the run's first. */\n\tcontinued: boolean;\n};\n\n/**\n * The file an indexing prompt is about, read back out of the prompt itself.\n *\n * The prompt is the only description of the pass that survives on the server, so\n * this is how BOTH a history rebuild and a worker-minted pass the client never\n * dispatched (ChatSession._adoptWorkerIndexingPasses) recover the file. Shared so\n * the two produce the same `_indexFile`, which is what makes them group together.\n */\nexport function parseIndexingRequestText(userText: any): IndexingRequestRef | null {\n\tif (typeof userText !== 'string' || !userText) return null;\n\tvar nameMatch = userText.match(/^- name: (.+)$/m);\n\tif (!nameMatch) return null;\n\tvar mimeMatch = userText.match(/^- mime type: (.+)$/m);\n\tvar sizeMatch = userText.match(/^- size \\(bytes\\): (\\d+)$/m);\n\tvar pathMatch = userText.match(/^- storage path: (.+)$/m);\n\treturn {\n\t\tname: nameMatch[1].trim(),\n\t\tpath: pathMatch ? pathMatch[1].trim() : undefined,\n\t\tmime: mimeMatch ? mimeMatch[1].trim() : undefined,\n\t\tsize: sizeMatch ? Number(sizeMatch[1]) : undefined,\n\t\tcontinued: userText.indexOf('CONTINUE indexing') === 0,\n\t};\n}\n\n// One page of the status probe below. Matches ChatSession's own\n// WORKER_PASS_ADOPT_LIMIT: the queue holds one live pass per file (plus a\n// handful pending), so a FULL page means the answer may be incomplete and the\n// probe reports checked=false rather than letting a miss read as \"finished\".\nconst LIVE_INDEX_PROBE_LIMIT = 20;\n\n// ─── Shared bg-queue probe (write-through memo) ──────────────────────────────\n// The SAME two queries — getChatHistory({queue, status: 'pending'|'running'})\n// — are fired by four independent callers: the session's live-index snapshot,\n// its worker-pass adoption ladder, its drain wait, and fetchLiveIndexingKeys\n// (the db-files page's badge probe). Navigating chat → files re-asked the queue\n// the chat had answered seconds earlier.\n//\n// This memo dedupes them WITHOUT weakening anyone's evidence:\n// • progress loops (adopt ladder, drain wait) call with maxAgeMs 0 — they\n// always fetch fresh, because their whole point is to observe a CHANGE —\n// but their answers write through into the memo;\n// • snapshot readers pass a maxAge and reuse a young answer.\n// Every entry carries `at`, the time the underlying fetch actually ran. A\n// caller that needs two INDEPENDENT looks (dbfile's green-confirm ladder) must\n// compare `at`, never its own receipt time: a memo re-serve has the same `at`\n// and therefore counts as the single look it really is.\nexport const BG_PROBE_TTL_MS = 4000;\ntype BgProbeEntry = { result: any; at: number };\nconst bgProbeCache: { [key: string]: BgProbeEntry } = {};\nconst bgProbeInflight: { [key: string]: Promise<BgProbeEntry> } = {};\n\nexport function probeBgQueue(\n\tparams: {\n\t\tservice: string;\n\t\towner: string;\n\t\tplatform: 'claude' | 'openai';\n\t\tqueue: string;\n\t\tstatus: 'pending' | 'running';\n\t\tlimit: number;\n\t},\n\topts?: { maxAgeMs?: number },\n): Promise<BgProbeEntry> {\n\tconst key = [params.service, params.owner, params.platform, params.queue, params.status, params.limit].join('|');\n\tconst maxAge = opts && typeof opts.maxAgeMs === 'number' ? opts.maxAgeMs : 0;\n\tconst cached = bgProbeCache[key];\n\tif (maxAge > 0 && cached && Date.now() - cached.at < maxAge) {\n\t\treturn Promise.resolve(cached);\n\t}\n\tconst inflight = bgProbeInflight[key];\n\tif (inflight) return inflight;\n\tconst p = Promise.resolve(getChatHistory(\n\t\t{ service: params.service, owner: params.owner, platform: params.platform, queue: params.queue, status: params.status },\n\t\t{ limit: params.limit, fetchMore: false },\n\t)).then(function (result: any) {\n\t\tconst entry: BgProbeEntry = { result: result, at: Date.now() };\n\t\tbgProbeCache[key] = entry;\n\t\treturn entry;\n\t});\n\tbgProbeInflight[key] = p;\n\t// Clear the in-flight slot on either outcome; failures are NOT cached.\n\tp.then(function () { delete bgProbeInflight[key]; }, function () { delete bgProbeInflight[key]; });\n\treturn p;\n}\n\n/**\n * One bounded look at the background-indexing queue: which files still have a\n * pass pending or running? This is the same negative signal ChatSession's\n * display layer relies on - for a worker-driven (auto_continue) run, only the\n * queue can say the run is over, because the worker enqueues continuation\n * passes the client never dispatched.\n *\n * Returns every storage path AND file name found on live passes (both, because\n * older prompts may lack the storage-path line), plus `checked`: false when a\n * page came back full, in which case absence from `keys` proves nothing and\n * the caller must keep whatever state it already had.\n *\n * SCOPE: the probed queue is \"<userId>-bg\" - THIS user's dispatches only. A\n * chain launched by another collaborator or a widget end-user lives on their\n * queue and is invisible here, so \"idle\" must never be read as \"nobody is\n * indexing this file\", only as \"this user's runs are over\". The durable done::\n * marker (indexDoneUniqueId) is the cross-user signal.\n */\nexport async function fetchLiveIndexingKeys(params: {\n\tservice: string;\n\towner: string;\n\tplatform: 'claude' | 'openai';\n\t/** Same value the dispatch used - see bgIndexingQueueName. */\n\tuserId?: string;\n}): Promise<{ keys: Set<string>; checked: boolean; at: number }> {\n\tconst queue = bgIndexingQueueName(params.userId, params.service);\n\tconst base = { service: params.service, owner: params.owner, platform: params.platform, queue };\n\tconst [pending, running] = await Promise.all([\n\t\tprobeBgQueue({ ...base, status: 'pending', limit: LIVE_INDEX_PROBE_LIMIT }, { maxAgeMs: BG_PROBE_TTL_MS }),\n\t\tprobeBgQueue({ ...base, status: 'running', limit: LIVE_INDEX_PROBE_LIMIT }, { maxAgeMs: BG_PROBE_TTL_MS }),\n\t]);\n\tconst keys = new Set<string>();\n\tlet truncated = false;\n\tfor (const entry of [pending, running]) {\n\t\tconst res = entry.result;\n\t\tconst list: any[] = (res && Array.isArray((res as any).list)) ? (res as any).list : [];\n\t\tif (list.length >= LIVE_INDEX_PROBE_LIMIT) truncated = true;\n\t\tfor (const item of list) {\n\t\t\tconst text = extractLastUserTextFromRequest(item && item.request_body);\n\t\t\tif (!text || !isIndexingRequestText(text)) continue;\n\t\t\tconst ref = parseIndexingRequestText(text);\n\t\t\tif (!ref) continue;\n\t\t\tif (ref.path) keys.add(ref.path);\n\t\t\tif (ref.name) keys.add(ref.name);\n\t\t}\n\t}\n\t// `at` = when the OLDER of the two underlying fetches ran. Consumers that\n\t// need two independent looks (dbfile's green ladder) key on this, so a\n\t// memo re-serve is correctly seen as the same single look.\n\treturn { keys, checked: !truncated, at: Math.min(pending.at, running.at) };\n}\n\n// ─── Split history fetch ─────────────────────────────────────────────────────\n// One conversation, two queues: ordinary chat lives on the user's queue (or a\n// legacy/random one), indexing passes on \"<userId>-bg\" — whose stored request\n// bodies carry whole file windows and dominated every history page. The split\n// fetches the SURFACE (id-prefix listing minus the bg queue, full bodies) and\n// the BG queue (exact, compact stubs — the lambda stubs ONLY indexing-shaped\n// items, ordinary chats deferred onto the bg queue keep full bodies) and\n// returns a getChatHistory-shaped page.\n//\n// This is v2, redesigned around the 2026-08-11 review findings:\n// • The SDK ignores explicit fetchOptions.startKeyHistory — paging rides its\n// internal per-params-hash cursors. So ALL split state lives HERE, module-\n// level, keyed by (service|owner|platform|userId): the bg overflow buffer,\n// the undelivered surface page, end flags. Callers keep echoing\n// startKeyHistory opaquely; it is bookkeeping only, on both sides.\n// • Pages TILE exactly: each page emits only items at-or-newer-than the\n// surface page's oldest item (the boundary); bg items older than that are\n// BUFFERED for the next page. Consumers' raw prepend, retainedOlder\n// pruning and clear-horizon early-end all rely on this invariant.\n// • Retry-safe: the fetched surface page is held as pendingSurface until the\n// merged page is actually returned, and every bg page lands in the buffer\n// the moment it arrives — a mid-call failure + caller retry resumes with\n// nothing skipped (the SDK's internal cursors have already advanced; the\n// state carries what they advanced past).\n// • Empty-but-not-end pages are eliminated SERVER-side (the lambda re-queries\n// past fully-filtered windows). A defensive client cap remains.\n//\n// Backwards-safe: an old backend ignores queue_exclude/compact — the surface\n// then includes bg items with bodies (exactly today's single fetch), the bg\n// call returns duplicates, and dedup-by-id (surface wins) degrades to current\n// behavior plus one redundant query, never to data loss.\n// Per-call bg fetches. Depth is LAZY: the consumers merge prepended pages by\n// timestamp, so older stubs can arrive on any later page and still land at\n// their true position — there is no need to drain the bg queue eagerly, and\n// doing so is exactly what made first paint slow (bg windows are ~1MB of RAW\n// rows, i.e. a handful of stubs per round trip). Two fetches keep the nearby\n// stubs in the same paint; scroll-up/viewport-fill pages pull the rest.\nconst BG_COVERAGE_MAX_PAGES = 2;\n\ntype SplitHistoryState = {\n\t/** Fetched bg items not yet emitted (older than the last page's boundary). */\n\tbgBuffer: any[];\n\tbgEnd: boolean;\n\t/** Whether the bg chain has fetched at least once (first call resets the\n\t * SDK's internal bg cursor with fetchMore:false; later calls continue). */\n\tbgStarted: boolean;\n\tsurfaceEnd: boolean;\n\t/** Surface page fetched but not yet delivered in a returned merged page —\n\t * reused on retry so the SDK's advanced cursor cannot skip it. Stamped\n\t * with the fetchMore mode it was fetched under: a page-1 fetch abandoned\n\t * mid-coverage must never be replayed as an OLDER page (or vice versa). */\n\tpendingSurface: { list: any[]; endOfList: boolean; startKeyHistory: any[]; forFetchMore: boolean } | null;\n\t/** Surface items fetched but HELD BACK because the bg coverage loop's hop\n\t * cap fired before the bg side reached this page's boundary: emitting\n\t * them would let the uncovered bg stubs land on a LATER page above\n\t * strictly-newer surface turns. Prepended to the next page's surface. */\n\tsurfaceCarry: any[];\n\tlastSurfaceKeys: any[];\n\t/** Newest bg item id this chain has ever seen. The head refresh compares it\n\t * against the fresh head page: a FULL head page that no longer contains it\n\t * means more than one page of bg rows landed while nobody was polling, and\n\t * the walk must reopen or the gap is unfetchable forever. */\n\tnewestBgId: string;\n};\nconst splitHistoryStates: { [key: string]: SplitHistoryState } = {};\n// Per-key serialization: a token-bumped reload can start a NEW split call\n// while an old one is mid-flight, and both would interleave on the SDK's\n// shared internal cursor chains (silently skipping pages). The newcomer waits\n// for the incumbent to settle; its stale result is discarded by the callers'\n// own token guards, and the newcomer's fetchMore:false reset then starts from\n// a clean chain.\nconst splitHistoryLocks: { [key: string]: Promise<void> } = {};\n\nfunction freshSplitState(): SplitHistoryState {\n\treturn { bgBuffer: [], bgEnd: false, bgStarted: false, surfaceEnd: false, pendingSurface: null, surfaceCarry: [], lastSurfaceKeys: [], newestBgId: '' };\n}\n\n/** Track the newest bg id the chain has seen (ids are creation-ordered). */\nfunction noteBgIds(state: SplitHistoryState, list: any[]): void {\n\tfor (const it of list) {\n\t\tconst id = it && typeof it.id === 'string' ? it.id : '';\n\t\tif (id && id > state.newestBgId) state.newestBgId = id;\n\t}\n}\n\n/** Test hook: drop split-fetch state (all keys, or one). */\nexport function __resetSplitHistoryState(key?: string): void {\n\tif (key !== undefined) { delete splitHistoryStates[key]; delete splitHistoryLocks[key]; return; }\n\tfor (const k in splitHistoryStates) delete splitHistoryStates[k];\n\tfor (const k in splitHistoryLocks) delete splitHistoryLocks[k];\n}\n\nconst createdOf = (it: any): number => {\n\tconst c = Number(it && it.created);\n\treturn isFinite(c) && c > 0 ? c : NaN;\n};\nconst oldestCreated = (lst: any[]): number => {\n\tlet m = Infinity;\n\tfor (const it of lst) {\n\t\tconst c = createdOf(it);\n\t\tif (!isNaN(c) && c < m) m = c;\n\t}\n\treturn m; // Infinity when no item carries a usable timestamp\n};\n\n// A pure-bg band can outlast the LAMBDA's own re-query cap (its raw windows\n// are 1MB and inline indexing bodies run to ~300KB, so one lambda call may\n// cross only a few dozen rows) — so the client must ALSO loop past\n// empty-but-not-end surface pages, or the fill loops upstream read them as\n// exhausted and strand older history (and an empty page 1 would blank the\n// chat). Each hop here is one more lambda call.\nconst SURFACE_EMPTY_MAX_PAGES = 10;\n\nexport type SplitHistoryResult = {\n\tlist: any[];\n\tendOfList: boolean;\n\tstartKeyHistory: any[];\n\t/** True when this chat had never been walked in this session — the first\n\t * paint. Consumers gate the \"Loading indexing history\" hint on it: a\n\t * mid-walk tab return restarts the walk for cursor safety but must stay\n\t * silent (flashing the hint on every return was the reported bug). */\n\tfirstLoad?: boolean;\n\t/** Present only when `deferBg` was requested AND bg work remains: resolves\n\t * with the stub batch fetched in the background (the per-key lock is held\n\t * until it settles, so no other history call can interleave). The caller\n\t * merges the batch by timestamp — the same path older pages use. */\n\tbgPending?: Promise<{ list: any[]; endOfList: boolean }>;\n};\n\nexport async function getSplitChatHistory(\n\tparams: { service: string; owner: string; platform: 'claude' | 'openai'; userId?: string },\n\tfetchOptions: Record<string, any>,\n\t/** Test seam: replaces getChatHistory. Not for production callers. */\n\t_fetchImpl?: typeof getChatHistory,\n): Promise<SplitHistoryResult> {\n\tconst key = [params.service, params.owner, params.platform, params.userId || ''].join('|');\n\tconst prev = splitHistoryLocks[key] || Promise.resolve();\n\t// The lock resolves when the WHOLE call — including a deferred bg batch —\n\t// has settled, so queued calls never interleave with background work. A\n\t// call that returns WITHOUT a bgPending (or throws) releases immediately;\n\t// a deferred call releases in the bg batch's own finally.\n\tlet releaseLock: () => void;\n\tconst lockTail = new Promise<void>((r) => { releaseLock = r; });\n\tconst run = () => _getSplitChatHistoryLocked(key, params, fetchOptions, releaseLock!, _fetchImpl);\n\tconst p = prev.then(run, run);\n\tp.then((res: any) => { if (!res || !res.bgPending) releaseLock(); }, () => releaseLock());\n\tsplitHistoryLocks[key] = p.then(() => lockTail, () => lockTail);\n\treturn p;\n}\n\nasync function _getSplitChatHistoryLocked(\n\tkey: string,\n\tparams: { service: string; owner: string; platform: 'claude' | 'openai'; userId?: string },\n\tfetchOptions: Record<string, any>,\n\treleaseLock: () => void,\n\t_fetchImpl?: typeof getChatHistory,\n): Promise<SplitHistoryResult> {\n\tconst fetch = _fetchImpl || getChatHistory;\n\tconst bgQueue = bgIndexingQueueName(params.userId, params.service);\n\tconst base = { service: params.service, owner: params.owner, platform: params.platform };\n\tconst fetchMore = !!(fetchOptions && fetchOptions.fetchMore);\n\tconst limit = fetchOptions && fetchOptions.limit;\n\n\t// HEAD refresh: a repeat first-page call on a chain that already walked BOTH\n\t// queues to their end (tab return, poll-side page-1 refresh). Page 1 must be\n\t// re-fetched for new settles, but what the chain LEARNED about the older\n\t// tail — \"all history fetched\" — survives. Wiping it here was the tab-return\n\t// bug: every return re-pulled the bg stub pages from scratch, reported\n\t// endOfList false, and that un-gated the viewport fill into re-walking every\n\t// older page the user had already exhausted. Only a FULLY-ended chain is\n\t// safe to preserve: its fetchMore path short-circuits without touching the\n\t// SDK cursors this page-1 refresh rewinds. A mid-walk chain still restarts.\n\t// True when this chat has never been walked in this session at all — the\n\t// consumers gate the \"Loading indexing history\" hint on it, so a mid-walk\n\t// tab return (which restarts the walk for cursor safety) stays SILENT.\n\tconst firstLoad = !splitHistoryStates[key];\n\tlet headRefresh = false;\n\tif (!splitHistoryStates[key]) {\n\t\tsplitHistoryStates[key] = freshSplitState();\n\t} else if (!fetchMore) {\n\t\tconst prev = splitHistoryStates[key];\n\t\tif (prev.surfaceEnd && prev.bgEnd) {\n\t\t\theadRefresh = true;\n\t\t\tprev.pendingSurface = null;\n\t\t\tprev.surfaceCarry = [];\n\t\t\tprev.bgBuffer = []; // fully drained by construction; defensive\n\t\t} else {\n\t\t\t// Mid-walk chain: the page-1 refresh genuinely restarts the walk\n\t\t\t// (the underlying fetchMore:false calls below reset the SDK's own\n\t\t\t// cursors to match), exactly as before.\n\t\t\tsplitHistoryStates[key] = freshSplitState();\n\t\t}\n\t}\n\tconst state = splitHistoryStates[key];\n\n\t// A held page fetched under the OTHER mode is not this call's page —\n\t// discard it rather than replay page 1 as an \"older\" page (or vice versa).\n\tif (state.pendingSurface && state.pendingSurface.forFetchMore !== fetchMore) {\n\t\tstate.pendingSurface = null;\n\t}\n\n\t// ── surface page ────────────────────────────────────────────────────────\n\tif (!state.pendingSurface) {\n\t\t// The ended-chain short-circuit serves FETCHMORE only: a head refresh\n\t\t// re-fetches page 1 for real (new settles live there), and the\n\t\t// preserved surfaceEnd keeps every later fetchMore off the wire.\n\t\tif (state.surfaceEnd && !headRefresh) {\n\t\t\tstate.pendingSurface = { list: [], endOfList: true, startKeyHistory: state.lastSurfaceKeys, forFetchMore: fetchMore };\n\t\t} else {\n\t\t\tconst sOpts: any = { fetchMore };\n\t\t\tif (limit) sOpts.limit = limit;\n\t\t\tlet s = await fetch({ ...base, queue_exclude: bgQueue }, sOpts);\n\t\t\t// Loop past empty-but-not-end pages (see SURFACE_EMPTY_MAX_PAGES).\n\t\t\tlet hops = 0;\n\t\t\twhile (s && !s.endOfList && !((s.list || []).length) && hops < SURFACE_EMPTY_MAX_PAGES) {\n\t\t\t\thops++;\n\t\t\t\tconst nOpts: any = { fetchMore: true };\n\t\t\t\tif (limit) nOpts.limit = limit;\n\t\t\t\ts = await fetch({ ...base, queue_exclude: bgQueue }, nOpts);\n\t\t\t}\n\t\t\tstate.pendingSurface = {\n\t\t\t\tlist: (s && Array.isArray(s.list)) ? s.list : [],\n\t\t\t\tendOfList: !!(s && s.endOfList),\n\t\t\t\tstartKeyHistory: (s && Array.isArray(s.startKeyHistory)) ? s.startKeyHistory : [],\n\t\t\t\tforFetchMore: fetchMore,\n\t\t\t};\n\t\t}\n\t}\n\tconst surface = state.pendingSurface;\n\n\t// ── deferred bg (first-paint mode) ──────────────────────────────────────\n\t// The caller paints the CONVERSATION from this return immediately; the\n\t// stub fetch happens behind the resolved promise, under the same lock.\n\t// Anything already buffered ships now (it costs nothing).\n\tif (fetchOptions && fetchOptions.deferBg && (!state.bgEnd || headRefresh)) {\n\t\tconst surfaceList0 = state.surfaceCarry.length ? state.surfaceCarry.concat(surface.list) : surface.list.slice();\n\t\tstate.surfaceCarry = [];\n\t\tconst emitNow: any[] = surfaceList0.concat(state.bgBuffer);\n\t\tstate.bgBuffer = [];\n\t\t// A head refresh must not let page 1's \"more pages exist\" clobber the\n\t\t// preserved end-knowledge: those pages are the tail already walked.\n\t\tif (!headRefresh) state.surfaceEnd = surface.endOfList;\n\t\tstate.lastSurfaceKeys = surface.startKeyHistory;\n\t\tstate.pendingSurface = null;\n\t\tconst bgPending = (async () => {\n\t\t\ttry {\n\t\t\t\tconst batch: any[] = [];\n\t\t\t\tif (headRefresh) {\n\t\t\t\t\t// One HEAD page only: the walked tail is complete; this\n\t\t\t\t\t// catches bg rows that settled/minted while nobody was\n\t\t\t\t\t// polling. bgEnd/bgStarted are normally left alone — the\n\t\t\t\t\t// end-knowledge survives, and the coverage loop (gated on\n\t\t\t\t\t// !bgEnd) never touches the cursor this rewinds. ONE\n\t\t\t\t\t// exception: a FULL head page that no longer contains the\n\t\t\t\t\t// newest bg id this chain had seen means more than a page\n\t\t\t\t\t// of bg rows landed while hidden — the gap is unreachable\n\t\t\t\t\t// unless the walk reopens (id-dedup makes re-walking the\n\t\t\t\t\t// tail harmless).\n\t\t\t\t\tconst bOpts: any = { fetchMore: false };\n\t\t\t\t\tif (limit) bOpts.limit = limit;\n\t\t\t\t\tconst b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);\n\t\t\t\t\tconst bList: any[] = (b && Array.isArray(b.list)) ? b.list : [];\n\t\t\t\t\tfor (const it of bList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; batch.push(it); }\n\t\t\t\t\tconst prevNewest = state.newestBgId;\n\t\t\t\t\tnoteBgIds(state, bList);\n\t\t\t\t\tif (prevNewest && !(b && b.endOfList) &&\n\t\t\t\t\t\t!bList.some((it: any) => it && it.id === prevNewest)) {\n\t\t\t\t\t\tstate.bgEnd = false;\n\t\t\t\t\t\tstate.bgStarted = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlet hops = 0;\n\t\t\t\t\twhile (!state.bgEnd && hops < BG_COVERAGE_MAX_PAGES) {\n\t\t\t\t\t\thops++;\n\t\t\t\t\t\tconst bOpts: any = { fetchMore: state.bgStarted };\n\t\t\t\t\t\tif (limit) bOpts.limit = limit;\n\t\t\t\t\t\tconst b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);\n\t\t\t\t\t\tstate.bgStarted = true;\n\t\t\t\t\t\tconst bList: any[] = (b && Array.isArray(b.list)) ? b.list : [];\n\t\t\t\t\t\tfor (const it of bList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; batch.push(it); }\n\t\t\t\t\t\tnoteBgIds(state, bList);\n\t\t\t\t\t\tstate.bgEnd = !!(b && b.endOfList);\n\t\t\t\t\t\tif (!bList.length && !state.bgEnd) break;\n\t\t\t\t\t\tif (state.bgEnd) break;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { list: batch, endOfList: state.surfaceEnd && state.bgEnd };\n\t\t\t} finally {\n\t\t\t\treleaseLock();\n\t\t\t}\n\t\t})();\n\t\treturn {\n\t\t\tlist: emitNow,\n\t\t\t// A head-refreshed ended chain KNOWS it is still ended — reporting\n\t\t\t// the hardcoded false here was what un-gated the fill loop on every\n\t\t\t// tab return. Mid-walk it computes to false exactly as before (this\n\t\t\t// branch is only entered with bgEnd false then); the bg batch still\n\t\t\t// carries the final word for that case.\n\t\t\tendOfList: state.surfaceEnd && state.bgEnd,\n\t\t\tstartKeyHistory: surface.startKeyHistory,\n\t\t\tfirstLoad,\n\t\t\tbgPending,\n\t\t};\n\t}\n\n\t// Carried-over surface items (held back by an uncovered boundary on the\n\t// previous page) lead this page's surface list.\n\tconst surfaceList = state.surfaceCarry.length ? state.surfaceCarry.concat(surface.list) : surface.list.slice();\n\n\t// The tiling line: everything at-or-newer than this is emitted now, older\n\t// bg items wait in the buffer. A finished surface (endOfList) opens the\n\t// line all the way (-Infinity) so the bg side drains over the next pages.\n\t// An empty surface page past the loop above (a pathological pure-bg band\n\t// beyond both the lambda's and our own hop caps) yields Infinity — no bg\n\t// drain, an empty page, and the consumers' empty-page guards take over.\n\tconst boundary = surface.endOfList ? -Infinity : oldestCreated(surfaceList);\n\n\t// ── bg coverage ─────────────────────────────────────────────────────────\n\tif (headRefresh) {\n\t\t// Non-deferred head refresh: the same single HEAD page the deferred\n\t\t// branch fetches, under the same rules — new settles are caught, the\n\t\t// end-knowledge (bgEnd/bgStarted) is left untouched, EXCEPT when a full\n\t\t// head page no longer contains the newest bg id this chain had seen:\n\t\t// more than a page landed while hidden, and the walk must reopen or the\n\t\t// gap is unfetchable (id-dedup makes re-walking the tail harmless).\n\t\tconst hOpts: any = { fetchMore: false };\n\t\tif (limit) hOpts.limit = limit;\n\t\tconst hb = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, hOpts);\n\t\tconst hbList: any[] = (hb && Array.isArray(hb.list)) ? hb.list : [];\n\t\tfor (const it of hbList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; state.bgBuffer.push(it); }\n\t\tconst prevNewestH = state.newestBgId;\n\t\tnoteBgIds(state, hbList);\n\t\tif (prevNewestH && !(hb && hb.endOfList) &&\n\t\t\t!hbList.some((it: any) => it && it.id === prevNewestH)) {\n\t\t\tstate.bgEnd = false;\n\t\t\tstate.bgStarted = true;\n\t\t}\n\t} else if (boundary !== Infinity || surface.endOfList) {\n\t\tlet hops = 0;\n\t\twhile (!state.bgEnd && hops < BG_COVERAGE_MAX_PAGES) {\n\t\t\tconst bufOldest = state.bgBuffer.length ? oldestCreated(state.bgBuffer) : Infinity;\n\t\t\tif (state.bgBuffer.length && bufOldest <= boundary) break;\n\t\t\thops++;\n\t\t\tconst bOpts: any = { fetchMore: state.bgStarted };\n\t\t\tif (limit) bOpts.limit = limit;\n\t\t\tconst b = await fetch({ ...base, queue: bgQueue, queue_exact: true, compact: true }, bOpts);\n\t\t\tstate.bgStarted = true;\n\t\t\tconst bList: any[] = (b && Array.isArray(b.list)) ? b.list : [];\n\t\t\t// Buffer IMMEDIATELY: the SDK cursor has advanced; this is what a\n\t\t\t// retry resumes from. Tagged as bg-chain items so the consumers'\n\t\t\t// surface-frontier logic (retention boundary, clear-horizon) can\n\t\t\t// tell deep stubs from the conversation's own paging frontier.\n\t\t\tfor (const it of bList) { if (it && typeof it === 'object') (it as any)._fromBgChain = true; state.bgBuffer.push(it); }\n\t\t\tnoteBgIds(state, bList);\n\t\t\tstate.bgEnd = !!(b && b.endOfList);\n\t\t\tif (!bList.length && !state.bgEnd) break; // defensive: server loops past empties\n\t\t\tif (state.bgEnd) break;\n\t\t}\n\t}\n\n\t// ── emit ────────────────────────────────────────────────────────────────\n\t// Everything fetched ships NOW — surface items are never withheld and the\n\t// bg buffer drains into every page. Ordering across pages is the\n\t// consumers' job (stable timestamp merge on prepend), which is what\n\t// removed the old tiling/withholding machinery: it delayed the\n\t// CONVERSATION behind a full bg drain on every first visit.\n\tconst emitSurface: any[] = surfaceList;\n\tstate.surfaceCarry = [];\n\tconst emitBg: any[] = state.bgBuffer;\n\tstate.bgBuffer = [];\n\n\t// Dedup by item id, surface copy (full bodies) winning — the old-backend\n\t// degradation path, and a guard against any range overlap.\n\tconst seen: { [id: string]: boolean } = {};\n\tfor (const it of emitSurface) { if (it && typeof it.id === 'string') seen[it.id] = true; }\n\tconst merged = emitSurface.concat(emitBg.filter((it: any) => !(it && typeof it.id === 'string' && seen[it.id])));\n\n\t// ── deliver ─────────────────────────────────────────────────────────────\n\t// Same head-refresh rule as the deferred branch: page 1's own \"more pages\n\t// exist\" must not clobber a preserved end-knowledge.\n\tif (!headRefresh) state.surfaceEnd = surface.endOfList;\n\tstate.lastSurfaceKeys = surface.startKeyHistory;\n\tstate.pendingSurface = null;\n\n\treturn {\n\t\tlist: merged,\n\t\tendOfList: state.surfaceEnd && state.bgEnd && state.bgBuffer.length === 0 && state.surfaceCarry.length === 0,\n\t\t// Bookkeeping only (both the consumers and the SDK treat it opaquely);\n\t\t// the real cursors are the SDK's internal ones plus this module's state.\n\t\tstartKeyHistory: surface.startKeyHistory,\n\t\tfirstLoad,\n\t};\n}\n\n\nexport type MapHistoryOptions = {\n\tclearedAt: number;\n\tprojectId: string;\n\t/** View-side display formatter for \"Indexing:/Reindexing: …\" bubbles. */\n\tformatIndexingLabel: (name: string, mime?: string, size?: number | null, storagePath?: string, reindex?: boolean, continued?: boolean) => string;\n};\n\nexport function mapHistoryListToMessages(list: any[], platform: 'claude' | 'openai', opts: MapHistoryOptions) {\n\tvar mapped: any[] = [], runningItemIds: string[] = [];\n\tvar extractAssistantText = platform === 'openai' ? extractOpenAIText : extractClaudeText;\n\tvar filtered = filterListByClearHorizon(list, opts.clearedAt);\n\tfiltered.slice().reverse().forEach(function (item) {\n\t\tvar requestBody = item && item.request_body;\n\t\tvar isInProcess = item && item.status === 'running';\n\t\tvar isQueued = item && item.status === 'pending';\n\t\tvar isCancelledItem = item && item.status === 'cancelled';\n\t\tvar isPending = isInProcess || isQueued;\n\t\tvar isFailed = item && item.status === 'failed';\n\t\tvar response = isFailed ? (item.error != null ? item.error : item.response_body)\n\t\t\t: (item && item.response_body != null ? item.response_body : item && item.error);\n\t\t// COMPACT listing stubs (bg-queue pages fetched with `compact: true`):\n\t\t// bodies never left the server; the label line, the response head, and\n\t\t// the completion-marker bit arrive as dedicated fields. Everything the\n\t\t// COLLAPSED row needs is here; expanding a row fetches the real bodies\n\t\t// per item (buildHistoryItemFullId point lookups) and remaps.\n\t\tvar isCompact = !!(item && item.compact);\n\t\tvar userText = isCompact\n\t\t\t? (typeof item.request_text === 'string' ? item.request_text : '')\n\t\t\t: extractLastUserTextFromRequest(requestBody);\n\t\tvar assistantText = isPending ? '' : (isCompact\n\t\t\t? ((typeof item.response_text === 'string' ? item.response_text : '').trim())\n\t\t\t: ((extractAssistantText(response) || '').trim() || ''));\n\t\tvar isErrorResponse = !isPending && (isFailed || (!isCompact && isErrorResponseBody(response)));\n\t\t// Record the completion marker, then STRIP it — both, and in that order.\n\t\t// Recording gives the display layer a structured signal instead of a substring\n\t\t// search over model prose. Stripping matches the live resolution path: without\n\t\t// it the literal token rendered inside the bubble on every history load, which\n\t\t// is not a post-reload curiosity — a first-page load REPLACES the live bubbles,\n\t\t// and those responses are now on screen far more often than they used to be.\n\t\t//\n\t\t// Gated on _isBgTask: only an INDEXING pass has a protocol token to hide. An\n\t\t// ordinary reply that merely mentions it keeps its own words.\n\t\tvar reportedComplete = !!(item && item._isBgTask) && !isErrorResponse && (isCompact\n\t\t\t? item.response_complete_marker === true\n\t\t\t: (!!assistantText && assistantText.indexOf(INDEXING_COMPLETE_MARKER) !== -1));\n\t\t// Still gated on the recorded marker (i.e. an INDEXING pass): an ordinary\n\t\t// reply that merely mentions the token keeps its own words. A compact\n\t\t// head can carry the literal token too, so the strip covers both forms.\n\t\tif (reportedComplete) assistantText = assistantText.split(INDEXING_COMPLETE_MARKER).join('').trim();\n\t\tvar serverItemId = item && typeof item.id === 'string' && item.id ? item.id : undefined;\n\t\t// A USER bubble shows when the request was made (`created`); an ASSISTANT\n\t\t// bubble shows when its response landed (`updated`). Fall back to the other\n\t\t// if one is missing (older records only carried `updated`).\n\t\tvar createdTs = Number(item && item.created);\n\t\tvar updatedTs = Number(item && item.updated);\n\t\tvar userTs = isFinite(createdTs) && createdTs > 0 ? createdTs : (isFinite(updatedTs) && updatedTs > 0 ? updatedTs : undefined);\n\t\tvar replyTs = isFinite(updatedTs) && updatedTs > 0 ? updatedTs : (isFinite(createdTs) && createdTs > 0 ? createdTs : undefined);\n\n\t\tif (userText) {\n\t\t\tvar displayContent;\n\t\t\t// Structured file ref for the display layer's per-file collapsing, kept\n\t\t\t// alongside the formatted label so grouping never has to parse it back.\n\t\t\tvar indexFile: any = undefined;\n\t\t\tif (item._isBgTask) {\n\t\t\t\tvar ref = parseIndexingRequestText(userText);\n\t\t\t\tif (ref) {\n\t\t\t\t\t// A CONTINUE pass (\"CONTINUE indexing …\") gets the compact\n\t\t\t\t\t// continuation label; a first pass (\"A new file …\") gets the full\n\t\t\t\t\t// one. Mirrors agent.vue's mapHistoryListToMessages so a big file's\n\t\t\t\t\t// windows read as progress, not the same task repeating.\n\t\t\t\t\tdisplayContent = opts.formatIndexingLabel(\n\t\t\t\t\t\tref.name,\n\t\t\t\t\t\tref.mime || '',\n\t\t\t\t\t\ttypeof ref.size === 'number' ? ref.size : null,\n\t\t\t\t\t\tref.path,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\tref.continued\n\t\t\t\t\t);\n\t\t\t\t\tindexFile = ref;\n\t\t\t\t} else {\n\t\t\t\t\tdisplayContent = userText;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdisplayContent = sanitizeAttachmentLinksForHistory(userText, opts.projectId);\n\t\t\t}\n\t\t\tvar userMsg: any = { role: 'user', content: displayContent };\n\t\t\tif (item._fromBgChain) userMsg._fromBgChain = true;\n\t\t\tif (isInProcess) userMsg.isPendingInProcess = true;\n\t\t\tif (isQueued) userMsg.isPendingQueued = true;\n\t\t\tif (isCancelledItem) userMsg.isCancelled = true;\n\t\t\tif (isCompact) userMsg._compact = true;\n\t\t\tif (item._isBgTask) userMsg.isBackgroundTask = true;\n\t\t\tif (indexFile) userMsg._indexFile = indexFile;\n\t\t\tif (item._isOnBgQueue) userMsg._useBgQueue = true;\n\t\t\tif (serverItemId !== undefined) userMsg._serverItemId = serverItemId;\n\t\t\tif (userTs !== undefined) userMsg._ts = userTs;\n\t\t\tmapped.push(userMsg);\n\t\t}\n\t\tif (isCancelledItem) { /* no assistant bubble */ }\n\t\telse if (isInProcess) {\n\t\t\tvar ph: any = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true };\n\t\t\t// _ts matters even on a placeholder: the consumers' merge and any\n\t\t\t// display fallback must be able to place it without its user bubble.\n\t\t\tif (userTs !== undefined) ph._ts = userTs;\n\t\t\tif (item._fromBgChain) ph._fromBgChain = true;\n\t\t\tif (item._isBgTask) ph.isBackgroundTask = true;\n\t\t\tif (serverItemId !== undefined) { ph._serverItemId = serverItemId; runningItemIds.push(serverItemId); }\n\t\t\tmapped.push(ph);\n\t\t} else if (isQueued) { /* no assistant placeholder */ }\n\t\telse if (isErrorResponse) {\n\t\t\tvar em: any = { role: 'assistant', content: getErrorMessage(response), isError: true };\n\t\t\tif (item._fromBgChain) em._fromBgChain = true;\n\t\t\tif (item._isBgTask) em.isBackgroundTask = true;\n\t\t\tif (serverItemId !== undefined) em._serverItemId = serverItemId;\n\t\t\tif (replyTs !== undefined) em._ts = replyTs;\n\t\t\tmapped.push(em);\n\t\t// `|| reportedComplete`: a pass whose ENTIRE answer was the completion token\n\t\t// strips down to an empty string, and the plain `assistantText` guard then\n\t\t// emitted no bubble at all — while the live path emitted one. The run read as\n\t\t// finished live and unfinished after a reload, so the row's loader came back.\n\t\t} else if (assistantText || reportedComplete) {\n\t\t\t// Safe db-only sanitize (forAssistant) so a volatile db url the model\n\t\t\t// emitted renders as a re-mintable `_expired_.url` link, not a dead one.\n\t\t\tvar okm: any = { role: 'assistant', content: sanitizeAttachmentLinksForHistory(assistantText, opts.projectId, true) || EMPTY_INDEXING_REPLY };\n\t\t\tif (item._fromBgChain) okm._fromBgChain = true;\n\t\t\tif (item._isBgTask) okm.isBackgroundTask = true;\n\t\t\tif (isCompact) okm._compact = true;\n\t\t\tif (serverItemId !== undefined) okm._serverItemId = serverItemId;\n\t\t\tif (replyTs !== undefined) okm._ts = replyTs;\n\t\t\tif (reportedComplete) okm._indexComplete = true;\n\t\t\tmapped.push(okm);\n\t\t}\n\t});\n\t// Stamp the CHAT every bubble belongs to. Every cross-project guard in the\n\t// consumers reads `_ownerKey` and is written \"undefined means unknown, keep\n\t// it\" — and the mapper never set it, so SERVER-history bubbles (which is all\n\t// of them, including every indexing row) passed every one of those filters\n\t// unchallenged. That is what let one project's transcript survive on screen\n\t// into another project and be persisted under its key.\n\tif (opts.projectId) {\n\t\tvar ownerKey = opts.projectId + '#' + platform;\n\t\tfor (var oi = 0; oi < mapped.length; oi++) mapped[oi]._ownerKey = ownerKey;\n\t}\n\treturn { messages: mapped, runningItemIds: runningItemIds };\n}\n\n/* ---- rescuing in-flight bubbles across a first-page refetch ---------------\n *\n * A first-page fetch REPLACES the message list, and the list may hold bubbles the\n * server does not know about yet: a turn whose request is still in flight, a\n * staged turn whose files are still uploading, a queued turn waiting for its ack.\n * Those have to survive the replace, and nothing else may.\n *\n * The rule lived twice — agent.vue's own fetchHistoryPage and the engine's\n * loadHistory — and the two had to be edited in lockstep to stay honest. It is one\n * function now, because the failure mode when they drift is a turn rendered twice\n * and then PERSISTED into the history cache, where it survives every later visit.\n */\n\nexport interface RescueDecisionContext {\n\t/** Is this `_serverItemId` in the page that was just fetched? */\n\thasServerId: (id: string) => boolean;\n\t/**\n\t * The fetched page already shows a non-background pending assistant.\n\t *\n\t * Only meaningful for a bubble with NO server id, where it is the sole\n\t * available answer to \"is this turn already represented?\". For a bubble that\n\t * HAS one, hasServerId answers exactly the same question exactly, and applying\n\t * this on top of it would drop an in-flight turn whose server copy simply is\n\t * not in the page that was fetched.\n\t */\n\tpageHasPendingAssistant: boolean;\n\t/** state.sending: an immediate send is in flight for this chat. */\n\tsending: boolean;\n\t/** The bubble directly after this one in the local list. */\n\tnext?: ChatMessage | null;\n\t/** The chat this fetch is FOR. A bubble stamped for another must not cross. */\n\tloadKey?: string;\n}\n\nexport function shouldRescueInFlightMessage(m: ChatMessage, ctx: RescueDecisionContext): boolean {\n\tif (!m) return false;\n\t// Background indexing bubbles come back through their own merge.\n\tif (m.isBackgroundTask) return false;\n\t// Never carry another project's (or another platform's) bubbles onto this chat.\n\tif (m._ownerKey !== undefined && ctx.loadKey !== undefined && m._ownerKey !== ctx.loadKey) return false;\n\t// The page carries a fresher copy of this exact turn.\n\tif (m._serverItemId && ctx.hasServerId(m._serverItemId)) return false;\n\t// A staged turn has no server request yet, so nothing in the page can stand for\n\t// it. Unconditional: applying the pending-assistant test here would delete the\n\t// user's message mid-upload whenever some other turn happened to be in flight.\n\tif (m._stageId) return true;\n\tif (!m._serverItemId && ctx.pageHasPendingAssistant) return false;\n\t// In flight by its own flags, id or no id. The immediate-send pair is stamped\n\t// with its server id as soon as the dispatch reports one, and that id is there\n\t// to let the check above recognise the server's copy — not to disqualify the\n\t// bubble from being kept when there is no such copy.\n\tif (m.isSendingToServer || m.isPendingQueued || m.isPendingInProcess || m.isPending) return true;\n\t// An immediate-send user bubble carries no flags of its own (its in-flight-ness\n\t// lives in state.sending); what identifies it is its own unanswered placeholder\n\t// directly below it.\n\tif (ctx.sending && m.role === 'user') {\n\t\tvar next = ctx.next;\n\t\tif (!next || next.isBackgroundTask || !next.isPending) return false;\n\t\treturn next._serverItemId === undefined || next._serverItemId === m._serverItemId;\n\t}\n\treturn false;\n}\n","/**\n * Hold the reader's place in the message list.\n *\n * A chat box mutates constantly WITHOUT the reader asking for it: an older page\n * prepends, a poll resolves, an indexing row splices in or changes label, a link\n * chip goes grey, an image preview finishes decoding, the \"Fetching history...\"\n * bar appears and disappears. Every one of those changes the height of something\n * that may sit ABOVE the viewport, and the browser answers by keeping scrollTop,\n * which slides the sentence the reader was on out from under them.\n *\n * THE ONE RULE: nothing here stores a position to be applied later. Every method\n * acts at the moment it is called, against the box as it is at that moment, and\n * is finished when it returns.\n *\n * That rule is the whole design, and it was learned the hard way. An earlier\n * version of this module also had a \"park the place they left, put them back when\n * they return\" half — parked/parkedStuck/returning/returnBudget/sawFrozen, a\n * frozen mode, a retry budget. Every one of those was a stored instruction that\n * some later event would carry out, and the reader's experience of a stored\n * instruction is that the chat throws them somewhere for no reason they can see:\n * they came back from another app, tapped the composer, the on-screen keyboard\n * fired a resize, the resize triggered a fetch, the fetch settled, and the settle\n * dutifully executed an instruction recorded before they ever left. Compensating\n * at the moment of the change needs no such instruction, and a return then needs\n * no handling at all, because nothing moved the reader in the first place.\n *\n * Two shapes, both immediate:\n *\n * preserve(fn) / capture() + restore(a)\n * A mutation you can bracket. Measures immediately before and immediately\n * after, so it is exact even when the mutation tears the list down.\n *\n * remember() + hold()\n * A layout change you CANNOT bracket: an image decoding, a font arriving, a\n * re-parse from a promise. remember() runs from the view's scroll handler,\n * so the anchor is always the reader's own last position.\n *\n * hold() is not an exception to the rule, and the staleness check is why. A height\n * change above the viewport does NOT change scrollTop; the browser preserves it,\n * which is precisely why the content appears to jump. So the remembered anchor is\n * valid exactly while `box.scrollTop` still equals the value it was captured at,\n * i.e. while nothing at all has moved the box. The instant that stops being true\n * it is re-measured, never replayed. hold() can therefore only ever undo a height\n * change that just happened, and can never carry out an old intention.\n *\n * Two more consequences worth stating, because both were once done the other way:\n *\n * NO FREEZE. Compensation runs whether or not the tab is visible. Layout and\n * getBoundingClientRect are live in a hidden tab; only painting and rAF stop.\n * Suspending compensation while hidden is what created the need to restore\n * something afterwards.\n *\n * A CLAMP IS ACCEPTED. If the content below the reader shrank, their line is\n * genuinely unreachable and the browser truncates the correction. Retrying that\n * later is how a correction turns into an ambush.\n *\n * DOM-free like the rest of the engine: the element shapes below are structural,\n * so real DOM nodes satisfy them while this file imports nothing from lib.dom.\n */\n\nexport interface AnchorRect {\n\ttop: number;\n}\n\nexport interface AnchorRowEl {\n\tgetAttribute(name: string): string | null;\n\tgetBoundingClientRect(): AnchorRect;\n\toffsetHeight: number;\n\tparentNode: unknown;\n}\n\n/** Anything inside the list that resizes on its own schedule. See absorb(). */\nexport interface AnchorGrowableEl {\n\tgetBoundingClientRect(): AnchorRect;\n\toffsetHeight: number;\n}\n\nexport interface AnchorBoxEl {\n\tchildren: ArrayLike<AnchorRowEl>;\n\tgetBoundingClientRect(): AnchorRect;\n\tscrollTop: number;\n\tscrollHeight: number;\n\tclientHeight: number;\n}\n\nexport interface RowAnchor {\n\t/** data-row-key of the anchored row, or null when nothing was anchorable. */\n\tkey: string | null;\n\t/** Offset of that row from the top of the viewport. Negative above the fold. */\n\ttop: number;\n\t/** data-row-pos, present only on rows that can RELOCATE (see below). */\n\tpos: string | null;\n\t/** scrollTop at capture time. The staleness check, and the raw fallback. */\n\tscrollTop: number;\n\t/**\n\t * scrollHeight at capture time. How much the list GREW is the best available\n\t * answer when the anchored row itself cannot be found again, and the bound on\n\t * how far a correction can legitimately be.\n\t */\n\tscrollHeight: number;\n\t/**\n\t * The anchored element itself. A view that patches in place (Vue) keeps the\n\t * same node across an update, so restore is one rect read instead of a scan;\n\t * a view that rebuilds the list (the widget) drops it and falls back to the\n\t * key. Never trusted without re-checking that it is still in the box.\n\t */\n\tel: AnchorRowEl | null;\n\t/**\n\t * The next few anchorable rows below the primary, each with its own offset.\n\t *\n\t * The primary row does not always survive: a refresh can drop it, a collapsed\n\t * indexing row can be re-identified, an expanded group can fold. Without a\n\t * fallback the only thing left is lost(), which guesses from the list's total\n\t * growth — and total growth includes everything added BELOW the reader, so a\n\t * merge that lands rows on both sides of them over-pays. A second row that is\n\t * still there beats any guess, and collecting them costs nothing: capture is\n\t * already walking these rows.\n\t */\n\talts?: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }>;\n}\n\nexport interface ScrollAnchorOptions {\n\t/** The scrolling message box, or null when it is not mounted. */\n\tgetBox: () => AnchorBoxEl | null;\n\t/**\n\t * The reader is pinned to the bottom. There the bottom IS the anchor and the\n\t * scrollToBottom* paths own the position, so every method here no-ops.\n\t */\n\tisStuck: () => boolean;\n\t/**\n\t * Fall back to the raw scrollTop when the anchored row cannot be found again.\n\t *\n\t * For a view that REBUILDS the list (the widget's renderMessages), detaching\n\t * every child collapses scrollHeight and the browser clamps scrollTop to 0,\n\t * so the raw offset is strictly better than the clamp it would otherwise be\n\t * left with. For a view that patches in place (Vue) the browser has already\n\t * kept a sane position and re-imposing a stale offset is worse than nothing.\n\t */\n\trawFallback?: boolean;\n}\n\nexport interface ScrollAnchor {\n\t/** Measure the reader's current place. Null while pinned to the bottom. */\n\tcapture: () => RowAnchor | null;\n\t/** Put a captured place back. Safe to call with null. */\n\trestore: (anchor: RowAnchor | null) => void;\n\t/** capture -> mutate -> restore, for a mutation you can bracket. */\n\tpreserve: <T>(mutate: () => T) => T;\n\t/** Record the reader's place. Call from the box's scroll handler. */\n\tremember: () => void;\n\t/** Put the remembered place back, if it is still the reader's own. */\n\thold: () => void;\n\t/** Pin to the bottom, instantly, recording the write. The ONLY way to pin. */\n\tpinBottom: () => void;\n\t/** Absorb one element's own resize. See below. */\n\tabsorb: (el: AnchorGrowableEl | null | undefined) => void;\n\t/** Drop the remembered place (chat switch, unmount). */\n\tforget: () => void;\n}\n\n/**\n * A row is anchorable when it carries data-row-key. The bars that are not rows —\n * \"Fetching history...\", the greeting, the drafting bubble, an expanded group's\n * trailing loader — deliberately carry none, so they are never anchored ON while\n * still being fully covered BY the anchor: they change height above a row that\n * is held in place, and holding it is what absorbs them.\n */\nvar ROW_KEY_ATTR = 'data-row-key';\n/**\n * A collapsed indexing row names the turn it currently renders at. It is a WEAK\n * anchor because it can RELOCATE — an older page carrying earlier passes of the\n * same run moves the row itself — and pinning a row while it moves is what would\n * drag the reader along with it. So an ordinary message row is always preferred,\n * and a group row is used only when nothing else is on screen, and then only if\n * it did not move.\n */\nvar ROW_POS_ATTR = 'data-row-pos';\n/** How many standby rows capture() records. Two is enough to survive a refresh\n * that drops the reader's own row without paying for a full-list guess. */\nvar MAX_ALTS = 2;\n/** How far past the anchor collectAlts will look for them. */\nvar ALT_SCAN_LIMIT = 64;\n/** data-row-pos is present but empty: the row cannot say where it is anchored. */\nvar UNKNOWN_ROW_POS = '\\u0000?';\n\nexport function createScrollAnchor(options: ScrollAnchorOptions): ScrollAnchor {\n\tvar held: RowAnchor | null = null;\n\t// Per-element height, so absorb() needs no \"before\" call from the caller.\n\t// Weak on purpose: a re-render throws every row away and a strong map would\n\t// hold the whole conversation's DOM alive behind it.\n\tvar seen: WeakMap<object, number> | null =\n\t\ttypeof WeakMap === 'function' ? new WeakMap<object, number>() : null;\n\n\tfunction capture(): RowAnchor | null {\n\t\tvar box = options.getBox();\n\t\tif (!box || options.isStuck()) return null;\n\t\tvar boxTop = box.getBoundingClientRect().top;\n\t\tvar kids = box.children;\n\t\tvar fallback: RowAnchor | null = null;\n\t\tvar fallbackAt = -1;\n\t\t// The last few rows passed on the way down, kept as standbys of last resort.\n\t\tvar behind: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }> = [];\n\t\tfor (var i = 0; i < kids.length; i++) {\n\t\t\tvar el = kids[i];\n\t\t\tif (!el || typeof el.getAttribute !== 'function') continue;\n\t\t\tvar key = el.getAttribute(ROW_KEY_ATTR);\n\t\t\tif (!key) continue;\n\t\t\tvar top = el.getBoundingClientRect().top - boxTop;\n\t\t\t// Rows still (partly) on screen. `top` is negative when a row starts\n\t\t\t// above the fold, which is exactly the offset to preserve.\n\t\t\tif (top + el.offsetHeight <= 0) {\n\t\t\t\t// Entirely above: not the reader's place, but a free standby. The rect\n\t\t\t\t// is already in hand, and a row ABOVE the anchor survives the batches\n\t\t\t\t// that rewrite the ones below it. Anything beats lost()'s guess.\n\t\t\t\tvar bpos = el.getAttribute(ROW_POS_ATTR);\n\t\t\t\tbehind.push({\n\t\t\t\t\tkey: key, top: top,\n\t\t\t\t\tpos: bpos === null ? null : (bpos || UNKNOWN_ROW_POS), el: el,\n\t\t\t\t});\n\t\t\t\tif (behind.length > MAX_ALTS) behind.shift();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// And STOP at the bottom of the viewport. Without this the preference\n\t\t\t// for an ordinary row walks straight past a screenful of collapsed\n\t\t\t// indexing rows and anchors on a message two screens down — which is\n\t\t\t// not the reader's place, and holds the wrong thing when a row between\n\t\t\t// the two changes height.\n\t\t\tif (top >= box.clientHeight) break;\n\t\t\t// An EMPTY data-row-pos means \"this row cannot say where it is anchored\n\t\t\t// yet\" — a run:: stub has no anchorId until its real group loads. Treating\n\t\t\t// \"\" as a position made every stub -> real-group handoff read as a\n\t\t\t// relocation and abort the anchor, which is a background resolution that\n\t\t\t// happens on every fresh open. Empty is normalised to null, which also\n\t\t\t// keeps such a row from being MISTAKEN for an ordinary one: the\n\t\t\t// ordinary/group split is the attribute's PRESENCE, tested first.\n\t\t\tvar rawPos = el.getAttribute(ROW_POS_ATTR);\n\t\t\tvar pos = rawPos === null ? null : (rawPos || UNKNOWN_ROW_POS);\n\t\t\tvar cand: RowAnchor = {\n\t\t\t\tkey: key, top: top, pos: pos,\n\t\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: el,\n\t\t\t};\n\t\t\tif (rawPos === null) {\n\t\t\t\t// An ordinary row: use it, and take standbys from the rows after it in\n\t\t\t\t// the same walk, then the ones already passed. Forward first — they are\n\t\t\t\t// nearer the reader — but a batch that rewrites everything below the\n\t\t\t\t// fold leaves the rows above it alone, so backward is the better last\n\t\t\t\t// measurement.\n\t\t\t\tcand.alts = withBehind(collectAlts(box, boxTop, i + 1), behind);\n\t\t\t\treturn cand;\n\t\t\t}\n\t\t\tif (!fallback) { fallback = cand; fallbackAt = i; } // group row: last resort\n\t\t}\n\t\t// The weak anchor needs standbys MORE than the strong one does, not less: a\n\t\t// screenful of collapsed indexing rows is exactly what a background sweep\n\t\t// re-keys and re-anchors, and without them it fell straight into lost()'s\n\t\t// whole-list guess. Ordinary rows are PREFERRED, because they are the ones a\n\t\t// background batch does not rewrite — but no standby at all means the guess,\n\t\t// and a neighbouring group row is a real measurement that restore() will\n\t\t// reject anyway if it relocated. So group rows are the last thing before the\n\t\t// guess, not something to hold out against.\n\t\tif (fallback) {\n\t\t\tfallback.alts = withBehind(\n\t\t\t\tcollectAlts(box, boxTop, fallbackAt + 1, true) || collectAlts(box, boxTop, fallbackAt + 1),\n\t\t\t\tbehind,\n\t\t\t);\n\t\t\treturn fallback;\n\t\t}\n\t\treturn {\n\t\t\tkey: null, top: 0, pos: null,\n\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: null,\n\t\t};\n\t}\n\n\t/** Up to MAX_ALTS anchorable rows starting at `from`, for restore's fallback. */\n\tfunction collectAlts(box: AnchorBoxEl, boxTop: number, from: number, ordinaryOnly?: boolean) {\n\t\tvar out: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }> = [];\n\t\tvar kids = box.children;\n\t\t// Bounded: a chat can carry hundreds of collapsed rows below the fold, and\n\t\t// this must not become a full-list walk for two standbys.\n\t\tvar stop = Math.min(kids.length, from + ALT_SCAN_LIMIT);\n\t\tfor (var i = from; i < stop && out.length < MAX_ALTS; i++) {\n\t\t\tvar el = kids[i];\n\t\t\tif (!el || typeof el.getAttribute !== 'function') continue;\n\t\t\tvar key = el.getAttribute(ROW_KEY_ATTR);\n\t\t\tif (!key) continue;\n\t\t\tvar rawPos = el.getAttribute(ROW_POS_ATTR);\n\t\t\tif (ordinaryOnly && rawPos !== null) continue;\n\t\t\tout.push({\n\t\t\t\tkey: key,\n\t\t\t\ttop: el.getBoundingClientRect().top - boxTop,\n\t\t\t\tpos: rawPos === null ? null : (rawPos || UNKNOWN_ROW_POS),\n\t\t\t\tel: el,\n\t\t\t});\n\t\t}\n\t\treturn out.length ? out : undefined;\n\t}\n\n\t/** Forward standbys first, then the rows already passed, newest-first. */\n\tfunction withBehind(\n\t\tforward: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }> | undefined,\n\t\tbehind: Array<{ key: string; top: number; pos: string | null; el: AnchorRowEl }>,\n\t) {\n\t\tvar out = (forward || []).concat(behind.slice().reverse());\n\t\treturn out.length ? out : undefined;\n\t}\n\n\tfunction findRow(box: AnchorBoxEl, anchor: RowAnchor): AnchorRowEl | null {\n\t\t// The same node, still in the box: one rect read instead of a scan. Vue\n\t\t// patches keyed rows in place, so this is the common path there, and it is\n\t\t// what keeps a per-update hold() cheap enough to run on every update.\n\t\tvar el = anchor.el;\n\t\tif (el && el.parentNode === (box as unknown)) return el;\n\t\tif (!anchor.key) return null;\n\t\tvar kids = box.children;\n\t\tfor (var i = 0; i < kids.length; i++) {\n\t\t\tvar kid = kids[i];\n\t\t\tif (!kid || typeof kid.getAttribute !== 'function') continue;\n\t\t\tif (kid.getAttribute(ROW_KEY_ATTR) === anchor.key) return kid;\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction restore(anchor: RowAnchor | null): void {\n\t\tvar box = options.getBox();\n\t\tif (!box || !anchor || options.isStuck()) return;\n\t\tvar el = findRow(box, anchor);\n\t\tif (el) {\n\t\t\t// A row that MOVED (an older page re-anchored a collapsed run to its true\n\t\t\t// first pass) must not be pinned: doing so would drag the reader along\n\t\t\t// with it, to wherever the run now starts. Only compare when BOTH sides\n\t\t\t// actually name a turn — a stub that has since learned its anchorId (or\n\t\t\t// lost it) has not moved, it has just started being able to answer.\n\t\t\t//\n\t\t\t// A relocation disqualifies the ROW, not the whole capture: fall through\n\t\t\t// to the standbys, which are a real measurement, rather than to lost()'s\n\t\t\t// whole-list guess.\n\t\t\tvar livePos = el.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;\n\t\t\tif (anchor.pos !== null && anchor.pos !== UNKNOWN_ROW_POS &&\n\t\t\t\tlivePos !== UNKNOWN_ROW_POS && livePos !== anchor.pos) el = null;\n\t\t}\n\t\tif (el) {\n\t\t\tvar boxTop = box.getBoundingClientRect().top;\n\t\t\tvar delta = (el.getBoundingClientRect().top - boxTop) - anchor.top;\n\t\t\t// A row can also be MOVED rather than resized: a background refetch that\n\t\t\t// merges a run's passes into the middle of page 1 relocates the bubble\n\t\t\t// this anchor is holding, and following it would carry the reader across\n\t\t\t// the conversation. A real prepend or in-place growth can only ever need a\n\t\t\t// correction on the order of what the list gained, so a delta a whole\n\t\t\t// screen beyond that is a relocation, not a resize.\n\t\t\tvar slack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;\n\t\t\t// Test the relocation in CONTENT coordinates. `delta` is measured in the\n\t\t\t// VIEWPORT, so it also contains however far the box itself moved since the\n\t\t\t// capture — and the widget's teardown clamps scrollTop to 0, which makes\n\t\t\t// delta enormous for a row that never went anywhere. Judging that as a\n\t\t\t// relocation dropped a perfectly good anchor into lost()'s whole-list\n\t\t\t// guess. Subtracting the box's own movement leaves what the ROW did.\n\t\t\tvar moved = delta - (anchor.scrollTop - box.scrollTop);\n\t\t\tif (moved > slack || moved < -slack) {\n\t\t\t\t// The row really did relocate. That disqualifies the ROW, not the\n\t\t\t\t// capture: fall through to the standbys, which are a real measurement.\n\t\t\t\tel = null;\n\t\t\t} else {\n\t\t\t\t// Sub-pixel noise is not a jump, and writing scrollTop for it costs a\n\t\t\t\t// scroll event (and a re-layout) on every settle.\n\t\t\t\tif (delta >= 1 || delta <= -1) box.scrollTop += delta;\n\t\t\t\theld = {\n\t\t\t\t\tkey: anchor.key, top: anchor.top, pos: anchor.pos,\n\t\t\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: el,\n\t\t\t\t\t// Carried, not dropped: one successful restore used to disarm the\n\t\t\t\t\t// standbys for every later hold.\n\t\t\t\t\talts: anchor.alts,\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// The anchor row is gone or it relocated: its group collapsed, the history was\n\t\t// replaced, a background sweep re-keyed it.\n\t\t// A standby row that IS still there beats lost()'s guess outright.\n\t\tvar alts = anchor.alts;\n\t\tfor (var ai = 0; alts && ai < alts.length; ai++) {\n\t\t\tvar alt = alts[ai];\n\t\t\tvar ael = findRow(box, {\n\t\t\t\tkey: alt.key, top: alt.top, pos: alt.pos,\n\t\t\t\tscrollTop: anchor.scrollTop, scrollHeight: anchor.scrollHeight, el: alt.el,\n\t\t\t});\n\t\t\tif (!ael) continue;\n\t\t\tif (alt.pos !== null && alt.pos !== UNKNOWN_ROW_POS) {\n\t\t\t\tvar altLive = ael.getAttribute(ROW_POS_ATTR) || UNKNOWN_ROW_POS;\n\t\t\t\tif (altLive !== UNKNOWN_ROW_POS && altLive !== alt.pos) continue;\n\t\t\t}\n\t\t\tvar aboxTop = box.getBoundingClientRect().top;\n\t\t\tvar adelta = (ael.getBoundingClientRect().top - aboxTop) - alt.top;\n\t\t\tvar aslack = Math.abs(box.scrollHeight - anchor.scrollHeight) + box.clientHeight;\n\t\t\tvar amoved = adelta - (anchor.scrollTop - box.scrollTop);\n\t\t\tif (amoved > aslack || amoved < -aslack) continue;\n\t\t\tif (adelta >= 1 || adelta <= -1) box.scrollTop += adelta;\n\t\t\theld = {\n\t\t\t\tkey: alt.key, top: alt.top, pos: alt.pos,\n\t\t\t\tscrollTop: box.scrollTop, scrollHeight: box.scrollHeight, el: ael,\n\t\t\t\talts: alts.slice(ai + 1),\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\t\tlost(box, anchor);\n\t}\n\n\t/**\n\t * Neither the anchored row nor any standby survived: it is gone, or it moved.\n\t *\n\t * What is still known is how much the list GREW, and in the case this branch\n\t * exists for — the pager, whose page can carry the very pass that re-anchors a\n\t * collapsed row — all of that growth is above the reader. So pay it. Missing it\n\t * costs a whole page of history in one jump.\n\t *\n\t * With nothing gained there is nothing to pay, and then the two views differ:\n\t * one REBUILDS the list (its teardown clamped scrollTop to 0, so the raw offset\n\t * beats the clamp) and one patches in place (the browser already kept a sane\n\t * position, so re-imposing a stale offset is worse than nothing).\n\t */\n\tfunction lost(box: AnchorBoxEl, anchor: RowAnchor): void {\n\t\theld = null;\n\t\tvar grew = box.scrollHeight - anchor.scrollHeight;\n\t\tif (grew > 0) { box.scrollTop = anchor.scrollTop + grew; return; }\n\t\tif (options.rawFallback) box.scrollTop = anchor.scrollTop;\n\t}\n\n\tfunction preserve<T>(mutate: () => T): T {\n\t\tvar anchor = capture();\n\t\tvar result = mutate();\n\t\trestore(anchor);\n\t\treturn result;\n\t}\n\n\t/** Record the reader's place. Call from the box's scroll handler. */\n\tfunction remember(): void {\n\t\theld = capture();\n\t}\n\n\t/**\n\t * Put the remembered place back, if it is still the reader's own.\n\t *\n\t * The staleness check is what keeps this immediate rather than a stored\n\t * intention: a height change above the viewport does NOT move scrollTop, so the\n\t * anchor is valid exactly while scrollTop is still the value it was captured\n\t * at. Anything else — the reader scrolled, a clamp fired, a pin ran — means the\n\t * box moved for a reason of its own, and the answer is to re-measure, never to\n\t * replay.\n\t */\n\tfunction hold(): void {\n\t\tvar box = options.getBox();\n\t\tif (!box || options.isStuck()) { held = null; return; }\n\t\tif (!held) { held = capture(); return; }\n\t\tif (box.scrollTop !== held.scrollTop) { held = capture(); return; }\n\t\t// restore() re-stamps `held` with the position it just pinned, so repeated\n\t\t// holds (one image after another finishing) each start from a valid anchor.\n\t\trestore(held);\n\t}\n\n\t/**\n\t * Absorb a resize made by ONE element, wherever it sits.\n\t *\n\t * The row anchor cannot see this case. A reader partway through an assistant\n\t * reply taller than the viewport is anchored ON that row, and a picture decoding\n\t * higher up INSIDE it moves every line they are reading without moving the row's\n\t * own top by a pixel. Rows above the fold have the same problem in reverse:\n\t * hold() would fix them, but it cannot be allowed to run for an image as well or\n\t * the two would each pay the same debt.\n\t *\n\t * So images go through here, and it is the more precise of the two: it\n\t * compensates by the element's own height delta, and only while the element's\n\t * TOP is above the fold, which is exactly the condition for \"everything the\n\t * reader can see just moved by this much\". An element starting at or below the\n\t * fold is left alone: it grew on screen, under a line the reader is looking at,\n\t * and moving them is what would be the jump.\n\t *\n\t * The height it last saw is remembered per element, so the caller does not have\n\t * to bracket anything. An element it has never seen counts as zero, which is\n\t * what an <img> measures before it has anything to paint — including the\n\t * markdown images that have no hydration hook at all.\n\t */\n\tfunction absorb(el: AnchorGrowableEl | null | undefined): void {\n\t\tif (!el) return;\n\t\tvar box = options.getBox();\n\t\tif (!box) return;\n\t\tvar h = el.offsetHeight;\n\t\tvar prev = seen ? seen.get(el) : undefined;\n\t\t// The baseline is recorded even while pinned to the bottom (where no write is\n\t\t// wanted): forgetting it would make the next change pay for this height too.\n\t\tif (seen) seen.set(el, h);\n\t\tif (options.isStuck()) return;\n\t\tif (prev === undefined) prev = 0;\n\t\tvar delta = h - prev;\n\t\tif (delta === 0) return;\n\t\t// The element's own TOP, which a resize never moves: everything BELOW it\n\t\t// slides by delta, everything above stays. So the reader's first visible line\n\t\t// moved exactly when that top is above the fold.\n\t\tif (el.getBoundingClientRect().top >= box.getBoundingClientRect().top) return;\n\t\tbox.scrollTop += delta;\n\t\t// Re-measure the remembered anchor, do not patch it. Its scrollTop is stale\n\t\t// after that write, and so is its offset whenever the element that resized\n\t\t// lives INSIDE the anchored row: there the row's own top never moved, so\n\t\t// scrolling by delta changed the row's offset by -delta and the next hold()\n\t\t// would faithfully undo this correction.\n\t\tif (held) held = capture();\n\t}\n\n\t/**\n\t * Pin to the bottom, instantly.\n\t *\n\t * The ONE way anything is allowed to pin, and it reads the bottom at the moment\n\t * it is called rather than aiming at a remembered one. Instant because a smooth\n\t * glide fires a scroll event per frame at positions that are not the bottom, and\n\t * the hosts clear stickToBottom on each of them, so any merge landing inside the\n\t * animation strands the reader off the bottom permanently, aiming at a target\n\t * that was already stale when the glide started.\n\t */\n\tfunction pinBottom(): void {\n\t\tvar box = options.getBox();\n\t\tif (!box) return;\n\t\tbox.scrollTop = box.scrollHeight;\n\t}\n\n\tfunction forget(): void {\n\t\theld = null;\n\t}\n\n\treturn {\n\t\tcapture: capture,\n\t\trestore: restore,\n\t\tpreserve: preserve,\n\t\tremember: remember,\n\t\thold: hold,\n\t\tpinBottom: pinBottom,\n\t\tabsorb: absorb,\n\t\tforget: forget,\n\t};\n}\n","/**\n * Keep older history REACHABLE by paging until the message box actually gains\n * something to scroll to.\n *\n * Older history is paged in by one trigger only: the user scrolling to the top\n * of the message box. That trigger has two ways to die, and collapsed indexing\n * rows cause both:\n *\n * 1. The box never scrolls. A file's every indexing pass (the first plus every\n * CONTINUE pass, request AND response bubble each) folds into ONE row, so a\n * full history page — twenty-plus messages — can render as a single line.\n * Content shorter than the viewport fires no scroll event, so page 2 is\n * never requested and any conversation the user had before that upload is\n * permanently out of reach.\n * 2. The fetched page adds no height. A page that is entirely the same file's\n * earlier passes joins the collapsed row already on screen and renders\n * nothing new. The user, sitting at scrollTop 0, scrolls up again — and\n * because the position never changed, no further scroll event fires.\n *\n * Both are the same shape: fetch, re-measure, and keep going until the user\n * genuinely gained reachable content, history ran out, or the pager stopped\n * advancing. `isSatisfied` is what differs between the two (can the box scroll\n * at all / did it grow), so the loop below takes it as a predicate.\n *\n * DOM-free like the rest of the engine — the caller supplies the measurement and\n * awaits its own render before measuring, so agent.vue and the widget run the\n * identical loop over their own pagers.\n */\n\n/** Overflow (px) that counts as \"the user can scroll here\". Comfortably more\n * than the 60px top threshold that triggers the next page, so a filled box has\n * real room to scroll rather than sitting one pixel from the trigger. */\nexport const HISTORY_FILL_SLACK_PX = 64;\n\n/** Pages one fill pass will request before giving up. Reached only by a chat\n * whose history really is dozens of pages of one file's indexing passes; the\n * cap exists so a pager that stops advancing can never spin forever. */\nexport const MAX_HISTORY_FILL_PAGES = 24;\n\nexport type FillHistoryViewportOptions = {\n\t/** The user has reachable content and paging can stop. Called AFTER the\n\t * caller's own render has settled (nextTick / rAF), since only the caller\n\t * knows when its view has painted — hence the allowance for a promise. */\n\tisSatisfied: () => boolean | Promise<boolean>;\n\t/** All history is loaded — nothing left to page in. */\n\tisEndOfList: () => boolean;\n\t/** A history request is already in flight. Waited out, not treated as a stop\n\t * condition: a background first-page refresh (the queue-detect tick fires one\n\t * every couple of seconds while a file is indexing) would otherwise swallow\n\t * the user's scroll-up entirely, and scrolling up again from scrollTop 0\n\t * produces no second event to retry with. */\n\tisLoading: () => boolean;\n\t/** Messages currently loaded. Used to detect a page that added nothing, which\n\t * means the pager is not advancing and looping would never terminate. */\n\tmessageCount: () => number;\n\t/** Fetch ONE older page (the caller's own fetchMore path, scroll-restore and\n\t * all). Return `false` when the request was NOT issued (the caller's own\n\t * single-flight guard swallowed it) so the loop retries instead of reading\n\t * the unchanged message count as an exhausted pager. Anything else, including\n\t * undefined, means it was attempted. */\n\tfetchOlder: () => Promise<boolean | void | any>;\n\t/** The chat this fill was started for is gone (project switched, view\n\t * unmounted, gate token bumped). Checked between pages so a stale fill can\n\t * never keep paging another chat's history. */\n\tisStale?: () => boolean;\n\tmaxPages?: number;\n};\n\n/** How long to wait out an in-flight history request before giving up on it. */\nconst IDLE_WAIT_STEP_MS = 120;\nconst IDLE_WAIT_MAX_MS = 15000;\n\n/** Resolve once no history request is in flight. False if the wait timed out or\n * the chat went stale, in which case the caller should stop. */\nasync function waitForIdle(\n\topts: FillHistoryViewportOptions,\n\tstale: () => boolean,\n): Promise<boolean> {\n\tvar waited = 0;\n\twhile (opts.isLoading()) {\n\t\tif (stale() || waited >= IDLE_WAIT_MAX_MS) return false;\n\t\tawait new Promise(function (r) { setTimeout(r, IDLE_WAIT_STEP_MS); });\n\t\twaited += IDLE_WAIT_STEP_MS;\n\t}\n\treturn !stale();\n}\n\n/**\n * Page older history until `isSatisfied`, until history runs out, or until the\n * pager stops advancing. Never throws: a failed page ends the fill, and the\n * user's own scrolling remains the fallback trigger.\n */\nexport async function fillHistoryViewport(opts: FillHistoryViewportOptions): Promise<void> {\n\tvar maxPages = typeof opts.maxPages === 'number' ? opts.maxPages : MAX_HISTORY_FILL_PAGES;\n\tvar stale = function () { return !!(opts.isStale && opts.isStale()); };\n\tvar swallowed = 0;\n\n\tfor (var page = 0; page < maxPages; page++) {\n\t\tif (stale() || opts.isEndOfList()) return;\n\t\tif (!(await waitForIdle(opts, stale))) return;\n\t\tvar satisfied = false;\n\t\ttry {\n\t\t\tsatisfied = !!(await opts.isSatisfied());\n\t\t} catch {\n\t\t\treturn; // cannot measure (view torn down mid-fill) — stop.\n\t\t}\n\t\tif (satisfied || stale()) return;\n\n\t\t// Re-check immediately before dispatching: measuring above yields for a\n\t\t// frame, and a background first-page refresh landing in that gap would make\n\t\t// the caller's own single-flight guard swallow this request. A swallowed\n\t\t// page adds no messages, which used to read as \"the pager is exhausted\" and\n\t\t// abandoned the fill for good.\n\t\tif (!(await waitForIdle(opts, stale))) return;\n\t\tvar before = opts.messageCount();\n\t\tvar attempted: boolean | void;\n\t\ttry {\n\t\t\tattempted = await opts.fetchOlder();\n\t\t} catch {\n\t\t\treturn; // history is optional; the scroll trigger stays as the fallback.\n\t\t}\n\t\tif (stale()) return;\n\t\tif (attempted === false) {\n\t\t\t// The caller reported it never issued the request. Retry it rather than\n\t\t\t// mistaking it for an exhausted pager, but not forever.\n\t\t\tif (++swallowed > 3) return;\n\t\t\tpage--;\n\t\t\tcontinue;\n\t\t}\n\t\t// The page came back with nothing new. Either the pager is exhausted (and\n\t\t// endOfList simply has not been set) or it is stuck; either way another\n\t\t// round would request the same page again.\n\t\tif (opts.messageCount() <= before) return;\n\t}\n}\n\n/**\n * One fill loop per view, with predicates COMBINED rather than dropped.\n *\n * Fills come from several places at once — a first page finishing, a window\n * resize, a row being collapsed, and the user's own scroll to the top — and a\n * plain \"one at a time, drop the rest\" guard picks the wrong winner: a resize\n * fill (satisfied the moment the box can scroll at all) would swallow the user's\n * scroll-up (which needs content specifically ABOVE them), and the scroll-up\n * cannot be retried, because a reader parked at scrollTop 0 produces no further\n * scroll event. Dropping the guard entirely is no better: every frame of a\n * window drag would start its own 24-page loop.\n *\n * So a request that arrives mid-loop ANDs its predicate into the running one:\n * the loop then keeps paging until EVERY caller is satisfied. Predicates that\n * come true are dropped as it goes, so the cost stays flat.\n */\nexport function createHistoryFiller(\n\tbase: Omit<FillHistoryViewportOptions, 'isSatisfied'> & {\n\t\t/** Fired when the loop starts FETCHING and when it stops, and only on a real\n\t\t * change.\n\t\t *\n\t\t * This — not the caller's own per-request `isLoading` — is what \"older\n\t\t * history is still coming in\" means to a view. A fill is many pages, and\n\t\t * `isLoading` drops to false between every one of them, so anything\n\t\t * rendered off it flickers once per page for the whole loop. A collapsed\n\t\t * indexing row whose run begins above the loaded window renders exactly\n\t\t * that (\"still loading this run\" vs a status it cannot know yet), which is\n\t\t * why the loop has to publish its own span.\n\t\t *\n\t\t * Fetching, NOT requested. Most fills fetch nothing: they are fired on every\n\t\t * window resize, every row a user collapses, and every first-page load, and\n\t\t * the overwhelmingly common outcome is `isSatisfied` returning true on the\n\t\t * first look. Announcing at request time published a true/false pair for\n\t\t * each of those, and the widget's own satisfied-check spans two animation\n\t\t * frames — long enough for the browser to PAINT the intermediate state. Every\n\t\t * collapsed row strobed through \"loading\" on every resize tick. So the span\n\t\t * opens at the first actual page request, which is also the first moment the\n\t\t * claim is true. */\n\t\tonRunningChange?: (running: boolean) => void;\n\t},\n): { fill: (isSatisfied: () => boolean | Promise<boolean>) => Promise<void>; isRunning: () => boolean } {\n\tvar pending: Array<() => boolean | Promise<boolean>> = [];\n\t// One loop at a time. Set the instant a fill is REQUESTED, whether or not that\n\t// fill goes on to fetch anything.\n\tvar running = false;\n\t// What the view is told: a page is actually being fetched. Deliberately a\n\t// different fact from `running` — see onRunningChange.\n\tvar fetching = false;\n\n\t// The callback can NEVER break the loop, and the swallow is the point. It is a\n\t// view render (the widget rebuilds its whole message list from here), so it is\n\t// the least trustworthy code this module touches, and it is invoked from two\n\t// places that must both survive it: inside the fetch wrapper, and inside `done`\n\t// — where a throw would reject the promise `fill()` returns and leave the\n\t// closing edge unsent, pinning every row that renders off this at \"loading\"\n\t// forever. A view that cannot paint is the view's problem, not the pager's.\n\tfunction announce(next: boolean): void {\n\t\tif (fetching === next) return;\n\t\tfetching = next;\n\t\tif (!base.onRunningChange) return;\n\t\ttry { base.onRunningChange(next); } catch (e) { /* never break the pager */ }\n\t}\n\n\tasync function allSatisfied(): Promise<boolean> {\n\t\tvar next: Array<() => boolean | Promise<boolean>> = [];\n\t\tfor (var i = 0; i < pending.length; i++) {\n\t\t\tif (!(await pending[i]())) next.push(pending[i]);\n\t\t}\n\t\tpending = next;\n\t\treturn pending.length === 0;\n\t}\n\n\treturn {\n\t\t// The published fact, so a view and `isRunning()` can never disagree about\n\t\t// what they are showing. A fill that never fetches is not something anyone\n\t\t// outside this module has any use for knowing about.\n\t\tisRunning: function () { return fetching; },\n\t\tfill: function (isSatisfied) {\n\t\t\tpending.push(isSatisfied);\n\t\t\tif (running) return Promise.resolve();\n\t\t\trunning = true;\n\t\t\tvar done = function () { pending = []; running = false; announce(false); };\n\t\t\treturn fillHistoryViewport({\n\t\t\t\tisSatisfied: allSatisfied,\n\t\t\t\tisEndOfList: base.isEndOfList,\n\t\t\t\tisLoading: base.isLoading,\n\t\t\t\tmessageCount: base.messageCount,\n\t\t\t\t// The span opens HERE, at the first real page request: past\n\t\t\t\t// isEndOfList, past isStale, past isSatisfied. Everything before this\n\t\t\t\t// point is a fill that concluded there was nothing to do.\n\t\t\t\tfetchOlder: function () { announce(true); return base.fetchOlder(); },\n\t\t\t\tisStale: base.isStale,\n\t\t\t\tmaxPages: base.maxPages,\n\t\t\t}).then(done, done);\n\t\t},\n\t};\n}\n","/**\n * ChatSession — framework-agnostic stateful chat orchestration.\n *\n * Ported verbatim from the bunnyquery widget's in-place state machine (which was\n * itself ported from agent.vue), with three mechanical substitutions:\n * CS.<field> -> this.state.<field>\n * renderMessages() -> this.host.notify()\n * S.<x> / skapi -> this.host.getIdentity().<x> / this.host.cancelRequest / refreshSession\n * scroll/refresh -> this.host.scrollToBottom(IfSticky) / refreshMessageBubble\n * Module-level singletons (bgTaskQueue, aiChatHistoryCache, pendingAgentRequests,\n * cancelledServerIds, historyItemPolls) become instance fields. The provider\n * request builders are reached through the engine (which already has the skapi\n * transport + poll injected via configureChatEngine), so cancel/poll behavior is\n * preserved.\n *\n * The view (per consumer) keeps: rendering, markdown PARSE, DOM refs + scroll\n * measurement, attachment chips, and the auth/account shell. It drives the\n * session via the public methods and re-renders in host.notify().\n */\nimport {\n\tcallClaudeWithPublicMcp,\n\tcallOpenAIWithPublicMcp,\n\tnotifyAgentSaveAttachment,\n\tnotifyAgentContinueIndexing,\n\tINDEXING_COMPLETE_MARKER,\n\tEMPTY_INDEXING_REPLY,\n\tMAX_INDEXING_RESUME_PASSES,\n\textractClaudeText,\n\textractOpenAIText,\n\tgetChatHistory,\n\tPOLL_INTERVAL,\n\tMAX_CONCURRENT_BG_POLLS,\n\tbgIndexingQueueName,\n\tisBgIndexingQueue,\n\tbuildHistoryItemFullId,\n\tANTHROPIC_MESSAGES_API_URL,\n\tOPENAI_RESPONSES_API_URL,\n\tupsertIndexRunRecordSafe,\n\ttype IndexRunStatus,\n\ttype IndexRunPatch,\n\ttype BgTaskEntry,\n} from './requests';\nimport { isPagedReadFile, isImageVisionFile, isWindowedReadFile } from './office';\nimport { windowedIndexingEnabled, chatEngineConfig } from './config';\nimport { isErrorResponseBody, isAuthExpiredError, isNonRetryableRequestError, getErrorMessage } from './errors';\nimport { buildBoundedChatMessages } from './budget';\nimport { createInlineLinkRegex, sanitizeAttachmentLinksForHistory } from './links';\nimport { markImagePreviewStale } from './image_preview';\nimport { mapHistoryListToMessages, extractLastUserTextFromRequest, isIndexingRequestText, parseIndexingRequestText, probeBgQueue, BG_PROBE_TTL_MS, getSplitChatHistory, shouldRescueInFlightMessage } from './history';\nimport { wallClockNow } from './time';\nimport { parseAttachmentContent } from './attachment_parsers';\nimport type { ChatHost, ChatState, ChatMessage, ChatIdentity, PinnedDispatchContext } from './host';\nimport type { IndexingGroup } from './indexing_groups';\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise(function (r) { setTimeout(r, ms); });\n}\n\n// How many live items one look at the background-indexing queue asks for. The\n// queue is FIFO per user, so a healthy chain has one running plus at most a\n// couple queued; the cap only bounds a pathological backlog.\nconst WORKER_PASS_ADOPT_LIMIT = 20;\n// How stale the \"which files are indexing\" snapshot may be when it is used to\n// refuse a DUPLICATE index dispatch. Short, because the answer decides whether a\n// file gets indexed at all; long enough that one upload batch asks once, not once\n// per file.\nconst LIVE_INDEX_SNAPSHOT_MAX_AGE_MS = 5000;\n// How long a client holds a file's indexing slot from the moment it decides to\n// dispatch. It only has to outlive the gap between that decision and the queue\n// admitting the pass (a request, plus the status index catching up); after that\n// the bgTaskQueue entry and the pass's own bubble carry the fact. Bounded so a\n// dispatch that died without releasing cannot lock a file out for the session.\nconst INDEX_DISPATCH_CLAIM_MS = 2 * 60 * 1000;\n// Delays before each look (the first is immediate). More than one because the\n// worker writes the next pass's row a few milliseconds AFTER it resolves the\n// current one, so a look that wins that race sees an empty queue for a chain\n// that is still alive. Fixed and finite: this must never become a poll.\nconst WORKER_PASS_ADOPT_ATTEMPTS = [0, 2000, 6000];\n\n// awaitIndexingDrained: how often it re-asks the background-indexing queue, and\n// how many consecutive empty answers it needs before believing the chains are\n// over. More than one for the same reason the adopt ladder above looks twice —\n// pass N+1 is written just after pass N resolves, so a single look lands in that\n// gap and reports an idle queue for a file that is still being read.\n//\n// Two cadences: while work is visibly running there is nothing to be gained by\n// asking often (an indexing pass takes tens of seconds, and a big file can hold\n// the queue for many minutes), but once the queue looks empty the confirming\n// look is all that stands between the user and their answer.\n// Early point-lookups for a foreground reply, before the flat POLL_INTERVAL tick lands.\n// Widening on purpose: the first two catch a short reply (a greeting, a one-line answer) that\n// would otherwise idle until 3s, and after ~1.7s a reply is long enough that the 3s interval is\n// no longer the dominant cost, so probing further would just add requests. Three probes is at\n// most three extra point lookups per turn, and none of them fire once the reply has landed.\nconst EARLY_PROBE_SCHEDULE_MS = [400, 900, 1700];\n\nconst INDEXING_DRAIN_BUSY_POLL_MS = 8000;\nconst INDEXING_DRAIN_CONFIRM_POLL_MS = 3000;\nconst INDEXING_DRAIN_IDLE_LOOKS = 2;\n// Floor on the whole wait. The status index is eventually consistent, so the\n// pass this turn's own upload just enqueued can be missing from the first looks —\n// releasing on those would send the chat ahead of the very files it is asking\n// about. Costs nothing in the normal case, where the queue reports work\n// immediately and the wait is far longer than this anyway.\nconst INDEXING_DRAIN_MIN_MS = 8000;\n\n// Ownership sequence for state.bgHistoryLoading (see the deferred-batch handler\n// in loadHistory): the latest minted batch owns the flag; older handlers\n// settling late must neither clear nor keep it.\nlet _bgHistoryBatchSeq = 0;\n// Ceiling on that wait. Past it the turn is sent regardless: an answer computed\n// against a partly-indexed file is a poor outcome, but a question that is never\n// asked at all because one chain wedged server-side is a worse one.\nconst INDEXING_DRAIN_TIMEOUT_MS = 15 * 60 * 1000;\n// A look that never comes back would hang the whole wait forever — there is no\n// pending timer to fall back on, so the turn is never sent and its bubble never\n// stops saying \"(Indexing files...)\". A look that outlives this is abandoned and\n// counted as UNKNOWN, i.e. as busy, which costs one more cycle and nothing else.\n//\n// Set well above any plausible slow answer rather than just above a fast one. An\n// abandoned look counts as busy and there is no way back: an index that reliably\n// answers slower than this can never produce two agreeing idle looks, so the turn\n// would sit at \"(Indexing files...)\" until the 15-minute ceiling. The cost of\n// being generous is one extra cycle in the case this is meant to catch, which by\n// definition never returns at all.\nconst INDEXING_DRAIN_LOOK_TIMEOUT_MS = 45000;\n// Closest a nudged look may follow the previous one. Bounds the extra request\n// rate when a bulk upload finishes many chains at once; the unnudged cadence is\n// one pair of requests per INDEXING_DRAIN_BUSY_POLL_MS.\nconst INDEXING_DRAIN_NUDGE_MIN_GAP_MS = 1500;\n\n// requestAnimationFrame / high-res clock, reached through globalThis so the\n// engine stays DOM-free at the type level (and degrades gracefully in non-DOM\n// / test environments where these globals are absent).\nvar _g: any = typeof globalThis !== 'undefined' ? globalThis : {};\nfunction nowMs(): number {\n\treturn (_g.performance && typeof _g.performance.now === 'function') ? _g.performance.now() : Date.now();\n}\nfunction nextFrame(cb: (t: number) => void): void {\n\tif (typeof _g.requestAnimationFrame === 'function') { _g.requestAnimationFrame(cb); return; }\n\tsetTimeout(function () { cb(nowMs()); }, 16);\n}\n\n/** A live poll registered in ChatSession.historyItemPolls. */\nexport type PollHandle = {\n\t/** 'bg' = background indexing, pausable. 'fg' = a reply the user is waiting on. */\n\tkind: 'fg' | 'bg';\n\t/** Absent on an older skapi-js that cannot stop an attached poll. */\n\tstop?: () => void;\n};\n\n/**\n * True when a poll result came from stopPolling rather than the server. Duck-typed on\n * purpose — see the note above about not importing skapi-js here.\n */\nfunction isPollStopped(res: any): boolean {\n\treturn !!res && typeof res === 'object' && res.status === 'stopped';\n}\n\nexport class ChatSession {\n\thost: ChatHost;\n\tstate: ChatState;\n\tbgTaskQueue: BgTaskEntry[];\n\tcancelledServerIds: Set<string>;\n\t/** Files whose indexing the user stopped, keyed exactly as buildChatDisplayList\n\t * keys a group (storage path, else filename). Cancelling one pass is not\n\t * enough on its own: the client dispatches CONTINUE passes for paged files, so\n\t * without this the next pass is enqueued the moment the cancelled one settles.\n\t * Cleared when a FIRST pass for the same file is queued again (a re-upload or a\n\t * Reindex from the file manager), so stopping a file never poisons it. */\n\tcancelledIndexKeys: Set<string>;\n\tpendingAgentRequests: Record<string, Promise<any>>;\n\taiChatHistoryCache: Record<string, { messages: ChatMessage[]; endOfList: boolean; startKeyHistory: string[] }>;\n\thistoryItemPolls: Map<string, PollHandle>;\n\t/** Non-empty while polling is paused; keyed by reason so overlapping causes\n\t * (view detached AND tab hidden) do not resume each other prematurely. */\n\tprivate _pauseReasons: Set<string>;\n\tprivate _resuming: boolean;\n\tprivate _lidSeq: number;\n\tprivate _stageSeq: number;\n\t/** How many attachment-upload batches are running. uploadingAttachments is a\n\t * single flag but batches overlap (the composer stays live, so the user can\n\t * send a second one while the first uploads), and a nested finish must not\n\t * clear the flag out from under the batch still running. */\n\tprivate _uploadBatches: number;\n\t/** Indexing requests whose ack has not come back yet. Until it does the item\n\t * is not on the server's queue, so awaitIndexingDrained cannot see it — and\n\t * would read the gap between \"pass N settled\" and \"pass N+1 accepted\" as the\n\t * file being finished. */\n\tprivate _indexDispatchesInFlight: number;\n\t/** Live awaitIndexingDrained waiters, one callback each. A nudge only pulls that\n\t * waiter's NEXT look forward; it can never make one conclude anything, so a\n\t * wrong nudge costs one pair of requests and the look reports busy. Overlapping\n\t * waiters are normal — the composer stays live, so a second send can be\n\t * uploading while the first waits. */\n\tprivate _drainNudges: Array<() => void>;\n\t/** Stages whose upload/dispatch chain is still running in THIS page. Lives and\n\t * dies with those chains, so it is what tells a staged bubble restored from the\n\t * history cache whether anything is still working on it (see\n\t * settleDeadStagedMessages). Today the cache dies with the page too and every\n\t * restored stage is live; this stays correct if that ever changes. */\n\tprivate _liveStages: { [stageId: string]: boolean };\n\t/** Files the SERVER currently has unresolved indexing work for, by the same key\n\t * a collapsed row uses (storage path, else filename), and whether we have asked\n\t * even once for this chat.\n\t *\n\t * This is the only thing that can tell a WORKER-driven run (a PDF's page loop, a\n\t * windowed read) that it is over. Those chains are advanced inside the worker off\n\t * the renderer's page count; the client sees passes appear and settle and can\n\t * never tell \"between passes\" from \"finished\" by looking at them. Asking the\n\t * queue is how it finds out. Until it has asked, `checked` is false and the view\n\t * says \"still working\", which is the honest reading of not knowing — and the one\n\t * that does not repeat the bug where a row claimed \"Indexed\" mid-run. */\n\t/** The chat the live-index snapshot (state.liveIndexKeys) was taken for, so a\n\t * project switch drops it. */\n\tprivate _liveIndexKey: string;\n\t/** When the snapshot was last published (wall clock ms), so a caller that needs\n\t * a CURRENT answer can tell whether to re-ask. 0 = never. */\n\tprivate _liveIndexAt: number;\n\t/** Files this client has an index dispatch in flight for, by scoped path ->\n\t * wall clock. See claimIndexRun. */\n\tprivate _indexClaims: { [scopedPath: string]: number };\n\n\tconstructor(host: ChatHost) {\n\t\tthis.host = host;\n\t\tthis.state = {\n\t\t\tmessages: [],\n\t\t\tattachments: [],\n\t\t\tuploadingAttachments: false,\n\t\t\tsending: false,\n\t\t\ttyping: false,\n\t\t\ttypingAbort: false,\n\t\t\tloadingHistory: false,\n\t\t\tloadingOlderHistory: false,\n\t\t\t// A deferred bg stub batch (first-paint split) is still in flight; the\n\t\t\t// views show a small 'loading indexing history' hint while true.\n\t\t\tbgHistoryLoading: false,\n\t\t\thistoryEndOfList: false,\n\t\t\thistoryStartKeyHistory: [],\n\t\t\thistoryRequestToken: 0,\n\t\t\tgateRefreshToken: 0,\n\t\t\tliveIndexKeys: {},\n\t\t\tliveIndexChecked: false,\n\t\t\tstoppedIndexIds: {},\n\t\t};\n\t\tthis.bgTaskQueue = [];\n\t\tthis.cancelledServerIds = new Set();\n\t\tthis.cancelledIndexKeys = new Set();\n\t\tthis.pendingAgentRequests = {};\n\t\tthis.aiChatHistoryCache = {};\n\t\tthis.historyItemPolls = new Map();\n\t\tthis._pauseReasons = new Set();\n\t\tthis._resuming = false;\n\t\tthis._lidSeq = 0;\n\t\tthis._stageSeq = 0;\n\t\tthis._uploadBatches = 0;\n\t\tthis._indexDispatchesInFlight = 0;\n\t\tthis._drainNudges = [];\n\t\tthis._liveStages = {};\n\t\tthis._liveIndexKey = '';\n\t\tthis._liveIndexAt = 0;\n\t\tthis._indexClaims = {};\n\t}\n\n\t/** What the display layer needs to decide whether a run is finished. `keys` holds\n\t * every file the server still has indexing work for; `checked` is false until the\n\t * first answer for this chat, and false means \"we do not know yet\". */\n\tgetLiveIndexState(): { keys: { [fileKey: string]: boolean }; checked: boolean } {\n\t\treturn { keys: this.state.liveIndexKeys, checked: this.state.liveIndexChecked };\n\t}\n\n\t/** Passes that were on a row when the user stopped it, so the display layer can\n\t * still tell that this run was stopped once the stop has left no other trace.\n\t * See cancelIndexingGroup, which fills it, and buildChatDisplayList, which is\n\t * the only reader. */\n\tgetStoppedIndexIds(): { [serverItemId: string]: boolean } {\n\t\treturn this.state.stoppedIndexIds;\n\t}\n\n\t/**\n\t * Is this file ALREADY being indexed by this client?\n\t *\n\t * One live run per file, and the reason is what a second one looks like: the\n\t * conversation grows a SECOND collapsed row for the same file (a run is opened\n\t * by every FIRST pass, so two of them are two rows), the same document is read\n\t * twice at full provider cost, and the two chains fight over the same records —\n\t * the delete-then-repost that starts run 2 wipes what run 1 has saved so far.\n\t *\n\t * Asked of this client's own live work, so it cannot be wrong in the dangerous\n\t * direction: a queued/running pass keeps its bgTaskQueue entry until its bubble\n\t * settles, and a settled run answers false, which is what a genuine later\n\t * re-index needs.\n\t *\n\t * The retry that made this necessary: a chip whose INDEX request failed is\n\t * handed back to the composer to be retried on the next send, and an index\n\t * request can fail from the client's side (a lost ack, an expired token on the\n\t * response) while the server has already queued the pass. The retry then indexes\n\t * a file that was never not being indexed.\n\t */\n\thasLiveIndexRun(storagePath?: string): boolean {\n\t\tif (!storagePath) return false;\n\t\t// A dispatch this client has STARTED but not yet heard back about. Nothing\n\t\t// else can see one: a bgTaskQueue entry exists only once the ack lands, the\n\t\t// bubble only once the drain runs after that, and the server's own status\n\t\t// index is eventually consistent — the adopt ladder retries at 0/2s/6s\n\t\t// precisely because a row created seconds ago can be missing from it. So\n\t\t// between deciding to index a file and the queue admitting it, EVERY source\n\t\t// of truth says \"not indexing\", and a second dispatch in that window is\n\t\t// exactly the duplicate this guard exists to stop. Observed live: two first\n\t\t// passes four seconds apart, two collapsed rows.\n\t\tvar claimed = this._indexClaims[this._indexClaimKey(storagePath)];\n\t\tif (claimed && nowMs() - claimed < INDEX_DISPATCH_CLAIM_MS) return true;\n\t\tvar id = this.host.getIdentity();\n\t\tfor (var i = 0; i < this.bgTaskQueue.length; i++) {\n\t\t\tvar e = this.bgTaskQueue[i];\n\t\t\tif (e && e.storagePath === storagePath && e.projectId === id.projectId && e.platform === id.platform) return true;\n\t\t}\n\t\treturn this.state.messages.some(function (m) {\n\t\t\tif (!m.isBackgroundTask || m.role !== 'user' || m.isCancelled) return false;\n\t\t\tif (!(m.isPendingQueued || m.isPendingInProcess || m.isSendingToServer)) return false;\n\t\t\treturn !!m._indexFile && m._indexFile.path === storagePath;\n\t\t});\n\t}\n\n\t/** Storage paths are project-relative, and one ChatSession serves every\n\t * project, so a claim has to be scoped the way a stop is (_indexKeyOf). */\n\tprivate _indexClaimKey(storagePath: string): string {\n\t\treturn this.getHistoryCacheKey() + '|' + storagePath;\n\t}\n\n\t/**\n\t * Take this file's indexing slot, or report that someone already has it.\n\t *\n\t * The check-and-CLAIM is what makes it safe against a second caller arriving\n\t * mid-flight: the claim is written SYNCHRONOUSLY, before the first await, so a\n\t * concurrent caller sees it even though no request has completed and no queue\n\t * has admitted anything. Ask-then-dispatch could not do that — every source it\n\t * consults only learns about a dispatch after the ack.\n\t *\n\t * Returns true when the caller owns the slot and should dispatch. A caller that\n\t * then fails to dispatch MUST releaseIndexRun, or the file waits out the claim\n\t * (a few minutes) before it can be retried.\n\t */\n\tclaimIndexRun(storagePath?: string): Promise<boolean> {\n\t\tvar self = this;\n\t\tif (!storagePath) return Promise.resolve(true);\n\t\tif (this.hasLiveIndexRun(storagePath)) return Promise.resolve(false);\n\t\tthis._indexClaims[this._indexClaimKey(storagePath)] = nowMs();\n\t\treturn this._refreshLiveIndexKeys(LIVE_INDEX_SNAPSHOT_MAX_AGE_MS)\n\t\t\t.then(function () {\n\t\t\t\tif (!self.state.liveIndexKeys[storagePath]) return true;\n\t\t\t\tself.releaseIndexRun(storagePath);\n\t\t\t\treturn false;\n\t\t\t})\n\t\t\t.catch(function () { return true; });\n\t}\n\n\t/** Give the slot back — the dispatch failed, or was abandoned. */\n\treleaseIndexRun(storagePath?: string): void {\n\t\tif (storagePath) delete this._indexClaims[this._indexClaimKey(storagePath)];\n\t}\n\n\t/**\n\t * The same question, asked of the SERVER when this page cannot answer it.\n\t *\n\t * hasLiveIndexRun only knows what this page did. That is not enough for the\n\t * case duplicates actually come from: the first run was started before a\n\t * reload, or in another tab, or its bubble has since been paged out of the\n\t * loaded window — and then the retry finds nothing locally and starts a second\n\t * run of a file that is still being indexed. The queue is the one place that\n\t * knows, and it is already asked for exactly this list.\n\t *\n\t * Only a POSITIVE answer is used. Absence proves nothing here (the query is\n\t * capped, and `liveIndexChecked` records that), so an unanswerable question\n\t * falls back to dispatching — the cost of a wrong \"no\" is the duplicate this\n\t * exists to prevent, and the cost of a wrong \"yes\" is a file that never gets\n\t * indexed at all. Only one of those is recoverable by the user.\n\t */\n\tisIndexRunLive(storagePath?: string): Promise<boolean> {\n\t\tvar self = this;\n\t\tif (!storagePath) return Promise.resolve(false);\n\t\tif (this.hasLiveIndexRun(storagePath)) return Promise.resolve(true);\n\t\treturn this._refreshLiveIndexKeys(LIVE_INDEX_SNAPSHOT_MAX_AGE_MS)\n\t\t\t.then(function () { return !!self.state.liveIndexKeys[storagePath]; })\n\t\t\t.catch(function () { return false; });\n\t}\n\n\t/** Re-ask the queue which files are still being indexed, unless the answer we\n\t * have is younger than `maxAgeMs`. Shared by every caller that needs a current\n\t * one; the display layer's own refresh path is the adopt ladder. */\n\tprivate _refreshLiveIndexKeys(maxAgeMs: number): Promise<void> {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\tvar platform = id.platform;\n\t\tif (!id.projectId || (platform !== 'claude' && platform !== 'openai')) return Promise.resolve();\n\t\t// The chat this query is FOR, snapshotted before the round trip. The record\n\t\t// below is gated on it still being the chat on screen: the adopt ladder makes\n\t\t// the same resolve-time identity check, and without it a project switch inside\n\t\t// this query's RTT published chat A's queue answer as chat B's snapshot —\n\t\t// where absence reads as a green \"Indexed\" for files B is indexing right now.\n\t\tvar askedKey = this.getHistoryCacheKey();\n\t\tif (this._liveIndexKey === askedKey && nowMs() - this._liveIndexAt < maxAgeMs) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tvar queue = bgIndexingQueueName(id.userId, id.projectId);\n\t\t// Snapshot reader: a young shared answer (this session's own adopt\n\t\t// ladder, or the db-files page's probe) is as good as a fresh one.\n\t\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(probeBgQueue(\n\t\t\t\t{ service: id.projectId, owner: id.owner, platform: platform as 'claude' | 'openai', queue: queue, status: status, limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t{ maxAgeMs: BG_PROBE_TTL_MS },\n\t\t\t)).then(function (entry) { return entry.result; }).catch(function () { return null; });\n\t\t};\n\t\treturn Promise.all([ask('pending'), ask('running')]).then(function (results) {\n\t\t\tif (results[0] === null || results[1] === null) return;\n\t\t\tif (self.getHistoryCacheKey() !== askedKey) return;\n\t\t\tself._liveIndexKey = askedKey;\n\t\t\tself._recordLiveIndexKeys(results);\n\t\t});\n\t}\n\n\t/**\n\t * Replace the live-index snapshot from a queue query's raw items.\n\t *\n\t * Whole-snapshot, never incremental: the query returns everything unresolved on\n\t * the queue, so a file MISSING from it is precisely the fact we are after. Merging\n\t * would make a finished file impossible to observe.\n\t */\n\tprivate _recordLiveIndexKeys(lists: any[]): void {\n\t\tvar next: { [k: string]: boolean } = {};\n\t\t// A page that came back FULL is not a whole-queue answer: the query is capped\n\t\t// and ordered newest-first, so a bulk upload of 40 files returns the 20 newest\n\t\t// and omits the 20 about to run. Absence would then read as \"finished\" for\n\t\t// exactly the files that have not been touched yet. Report not-knowing instead.\n\t\tvar truncated = false;\n\t\t// Locally settled already. The adopt path refuses these items for the same\n\t\t// reason and says why: the status index is eventually consistent, so the pass\n\t\t// that just finished can still come back as running. Counting it as live work\n\t\t// leaves a finished file spinning with nothing left to ever settle and correct\n\t\t// it — the two readings of one payload must not disagree.\n\t\tvar settledIds: { [id: string]: boolean } = {};\n\t\tthis.state.messages.forEach(function (m) {\n\t\t\tif (!m._serverItemId) return;\n\t\t\tif (m.isPending || m.isPendingInProcess || m.isPendingQueued) return;\n\t\t\tsettledIds[m._serverItemId] = true;\n\t\t});\n\t\tfor (var li = 0; li < lists.length; li++) {\n\t\t\tvar list = lists[li] && Array.isArray(lists[li].list) ? lists[li].list : [];\n\t\t\tif (list.length >= WORKER_PASS_ADOPT_LIMIT) truncated = true;\n\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\tvar item = list[i];\n\t\t\t\tif (!item || (item.status !== 'pending' && item.status !== 'running')) continue;\n\t\t\t\tif (item.id && settledIds[item.id]) continue;\n\t\t\t\tvar text = extractLastUserTextFromRequest(item.request_body);\n\t\t\t\tif (!isIndexingRequestText(text)) continue; // an ordinary chat on this queue\n\t\t\t\tvar ref = parseIndexingRequestText(text);\n\t\t\t\tif (!ref) continue;\n\t\t\t\t// BOTH, not `path || name`. A row's key is normally the storage path,\n\t\t\t\t// but buildChatDisplayList falls back to the filename when the pass it\n\t\t\t\t// opened the run with carried no path (an old cached bubble, a label\n\t\t\t\t// with no link). A key recorded one way and looked up the other misses,\n\t\t\t\t// and a miss reads as FINISHED — the one direction that must never\n\t\t\t\t// happen by accident. Recording both can only over-match, which shows a\n\t\t\t\t// loader on a file that is done: visibly cautious instead of silently\n\t\t\t\t// wrong.\n\t\t\t\tif (ref.path) next[ref.path] = true;\n\t\t\t\tif (ref.name) next[ref.name] = true;\n\t\t\t}\n\t\t}\n\t\tvar nowChecked = !truncated;\n\t\tvar was = this.state.liveIndexKeys, changed = this.state.liveIndexChecked !== nowChecked;\n\t\tif (!changed) {\n\t\t\tfor (var k in next) if (!was[k]) { changed = true; break; }\n\t\t\tif (!changed) for (var k2 in was) if (!next[k2]) { changed = true; break; }\n\t\t}\n\t\tthis.state.liveIndexKeys = next;\n\t\tthis.state.liveIndexChecked = nowChecked;\n\t\tthis._liveIndexAt = nowMs();\n\t\t// Claim the snapshot for the CURRENT chat. Both callers verify identity before\n\t\t// recording, so this is always true - but only _refreshLiveIndexKeys used to say\n\t\t// so, and the adopt ladder (the path every plain page load actually seeds\n\t\t// through) never did. _liveIndexKey then stayed '', and the first-page reset in\n\t\t// loadHistory ('loadKey !== _liveIndexKey') fired on EVERY load - including every\n\t\t// tab refocus - wiping checked/keys and flipping every settled indexing row back\n\t\t// to the grey \"checking status\" until the queue answered again. With the claim,\n\t\t// that reset fires only on a genuine project/platform switch; a refocus keeps\n\t\t// showing the last known state (green/yellow) and the re-poll that follows\n\t\t// replaces the snapshot atomically when its answer lands.\n\t\tthis._liveIndexKey = this.getHistoryCacheKey();\n\t\tif (changed) this.host.notify();\n\t}\n\n\t/** Forget the snapshot: it describes ONE chat's queue, and the answer for the\n\t * project the user just switched to is unknown until it is asked for again. */\n\tprivate _resetLiveIndexKeys(): void {\n\t\tthis.state.liveIndexKeys = {};\n\t\tthis.state.liveIndexChecked = false;\n\t\tthis._liveIndexAt = 0;\n\t}\n\n\t/**\n\t * Ask the queue what is still indexing, once, for the chat that is on screen.\n\t *\n\t * Seeds the snapshot on a history load. Without it a reloaded chat has no way to\n\t * learn that a run it can see is over: the adopt ladder that normally answers this\n\t * only fires when a pass SETTLES, and after a reload there is no pass left to\n\t * settle — so every finished worker-driven row would spin forever.\n\t *\n\t * Best-effort: a failure leaves `checked` false, which reads as \"still working\"\n\t * rather than as a false all-clear.\n\t *\n\t * Delegates to the adopt ladder rather than asking once. A single empty look is\n\t * exactly what that ladder exists to distrust — the worker writes pass N+1 a few\n\t * milliseconds AFTER flipping pass N to resolved, so a query landing in that gap\n\t * sees an empty queue for a chain that is very much alive. One look would turn\n\t * that into a confident \"Indexed\" with a green check, on the one scenario this\n\t * whole feature is for, and nothing would ever re-ask: the ladder is normally\n\t * triggered by a pass SETTLING, and after a reload there is no pass left to\n\t * settle. The ladder re-asks at 0/2s/6s, records each answer, and as a bonus\n\t * adopts and polls any live pass it finds, which makes the row genuinely active\n\t * instead of merely unconfirmed.\n\t */\n\trefreshLiveIndexState(): void {\n\t\t// PASSIVE: this is the first-page/resume refresh, not a settle. One\n\t\t// fresh look (two status queries) always happens; the 2s/6s ladder\n\t\t// climb is reserved for when there is EVIDENCE of live work — the\n\t\t// pass-boundary gap the ladder exists for presumes a chain was alive,\n\t\t// and on an idle tab return the climb was three round trips of asking\n\t\t// a question whose answer had not changed.\n\t\tthis._adoptWorkerIndexingPasses(0, true);\n\t}\n\n\t/** Forget what we know about which files are indexing — but ONLY when the\n\t * snapshot was taken for a different chat than the one on screen now. For a\n\t * consumer whose history loading is its own fork and so never reaches\n\t * loadHistory's reset — a snapshot describes ONE chat's queue, and carrying it\n\t * into another project would let a row there claim to be finished on someone\n\t * else's evidence.\n\t *\n\t * Conditional for the same reason loadHistory's own reset is (the\n\t * `loadKey !== _liveIndexKey` gate): the view calls this on every mount, and\n\t * an unconditional wipe turned every re-entry to the chat into a grey\n\t * \"Checking status:\" sweep across rows whose state was already known. A\n\t * RE-entry keeps showing the last answer (green/yellow) while the first-page\n\t * refresh re-asks quietly; only a genuine project/platform switch starts from\n\t * \"not known yet\". Claiming `_liveIndexKey` here (before any answer) is the\n\t * same fudge loadHistory makes: it marks WHOSE chat the empty snapshot is\n\t * for, so repeated calls do not re-wipe, and _recordLiveIndexKeys re-claims\n\t * it when the real answer lands. */\n\tresetLiveIndexState(): void {\n\t\tvar key = this.getHistoryCacheKey();\n\t\tif (key === this._liveIndexKey) return;\n\t\tthis._liveIndexKey = key;\n\t\tthis._resetLiveIndexKeys();\n\t}\n\n\t/** Wrap an indexing-request dispatch so awaitIndexingDrained counts it as\n\t * live work from the moment it is sent, not from the moment it is acked. */\n\ttrackIndexDispatch<T>(p: Promise<T>): Promise<T> {\n\t\tvar self = this;\n\t\tthis._indexDispatchesInFlight += 1;\n\t\t// Deliberately does NOT nudge the drain when the count reaches zero. That\n\t\t// moment is a pass being ACCEPTED — new work ENTERING the queue — not work\n\t\t// ending. Nudging there pulled a waiting turn's two confirming looks into a\n\t\t// fixed ~4.5s window after the ack, which is inside the several seconds a\n\t\t// worker-minted pass can take to show up in the status index (the same\n\t\t// staleness WORKER_PASS_ADOPT_ATTEMPTS exists for). It turned a rare unlucky\n\t\t// alignment into a reliable one: the turn dispatched ahead of its own file's\n\t\t// remaining passes and the model answered from a partly-read file. There was\n\t\t// nothing to gain either — the pass it signals is work, so the pulled-forward\n\t\t// look can only report busy, or lie.\n\t\tvar release = function () { self._indexDispatchesInFlight = Math.max(0, self._indexDispatchesInFlight - 1); };\n\t\treturn p.then(function (v) { release(); return v; }, function (e) { release(); throw e; });\n\t}\n\n\t/**\n\t * Something just happened that plausibly ENDED indexing work, so let any waiting\n\t * turn look now instead of sitting out the rest of its busy interval.\n\t *\n\t * A nudge changes only WHEN a look happens, never what it concludes: the two\n\t * agreeing idle looks, the confirm gap between them, \"a failed look counts as\n\t * busy\" and the minimum wait are all untouched. That is why it is safe to fire\n\t * from places that are merely good guesses.\n\t *\n\t * Fired from end-of-chain points ONLY: the adopt ladder giving up, a resume\n\t * declining to continue, a pass failing. Not from every settling pass (one nudge\n\t * per pass per file for the whole run), and not from an indexing request being\n\t * accepted — see the note in trackIndexDispatch for why that one is actively\n\t * harmful rather than merely wasteful.\n\t */\n\tprivate _nudgeIndexingDrain(): void {\n\t\tif (!this._drainNudges.length) return;\n\t\tvar list = this._drainNudges.slice(); // a nudge may de-register itself\n\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\ttry { list[i](); } catch (e) { /* best-effort: never break the caller */ }\n\t\t}\n\t}\n\n\t/**\n\t * Register a live poll so (a) a remount dedupes against it instead of stacking a\n\t * SECOND poll on the same item, and (b) pausePolling can stop it.\n\t *\n\t * `stop` comes from the SDK and may be absent on an older skapi-js, in which case the\n\t * poll simply cannot be stopped and is left running — see pausePolling.\n\t *\n\t * (This block documents _trackPoll, further down. The two methods below sit between it\n\t * and its subject.)\n\t */\n\t/**\n\t * Foreground poll with an early-probe race.\n\t *\n\t * skapi's poll() is a bare setInterval(fn, latency) with NO check at t=0, so the earliest a\n\t * reply can be observed is one full POLL_INTERVAL (3s) after dispatch. For a long generation\n\t * that granularity is free. For a SHORT one it is nearly pure dead time: a greeting that the\n\t * provider finishes in 1s still waits until the 3s tick, which measured as a large share of a\n\t * 5s \"yo\" round trip.\n\t *\n\t * So keep the 3s interval as the steady state, and additionally point-look-up the item a few\n\t * times early, on a widening schedule. Whichever answers first wins and the other is stopped.\n\t * The probe uses the csrHistoryItemLookup hook both clients already implement; without it this\n\t * degrades to exactly the old behaviour.\n\t *\n\t * FOREGROUND ONLY. Background indexing polls keep the flat cadence: nobody is watching them,\n\t * and they are the ones bounded by MAX_CONCURRENT_BG_POLLS, so adding probes there would spend\n\t * the request budget the cap exists to protect.\n\t */\n\tattachForegroundPoll(source: any, itemId: string, opts?: any): any {\n\t\treturn this._fgPollWithEarlyProbe(source, itemId, opts);\n\t}\n\n\tprivate _fgPollWithEarlyProbe(source: any, itemId: string, opts?: any): any {\n\t\tvar self = this;\n\t\t// Callbacks ride along on the interval path exactly as before; the probe path below\n\t\t// fires onResponse itself, because a caller that only reacts through the callback\n\t\t// (the history drain does) would otherwise never learn the probe won.\n\t\tvar base = source.poll(Object.assign({ latency: POLL_INTERVAL }, opts || {}));\n\n\t\tvar lookup = chatEngineConfig().csrHistoryItemLookup;\n\t\tvar ident = this.host.getIdentity();\n\t\tvar platform = ident && ident.platform;\n\t\tif (!lookup || !itemId || !ident || !ident.projectId\n\t\t\t|| (platform !== 'claude' && platform !== 'openai')) {\n\t\t\treturn base;\n\t\t}\n\n\t\tvar settled = false;\n\t\tvar timers: any[] = [];\n\t\tvar clearProbes = function () {\n\t\t\tfor (var i = 0; i < timers.length; i++) clearTimeout(timers[i]);\n\t\t\ttimers = [];\n\t\t};\n\t\tvar stopBase = base && typeof base.stop === 'function' ? base.stop.bind(base) : null;\n\n\t\tvar raced: any = new Promise(function (resolve, reject) {\n\t\t\tbase.then(function (res: any) {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true; clearProbes(); resolve(res);\n\t\t\t}, function (err: any) {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true; clearProbes(); reject(err);\n\t\t\t});\n\n\t\t\tvar fullId = buildHistoryItemFullId(platform as 'claude' | 'openai', ident.projectId, itemId);\n\t\t\tEARLY_PROBE_SCHEDULE_MS.forEach(function (delay) {\n\t\t\t\ttimers.push(setTimeout(function () {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tPromise.resolve(lookup!(fullId, ident.projectId, ident.owner)).then(function (body: any) {\n\t\t\t\t\t\tif (settled || !body || typeof body !== 'object') return;\n\t\t\t\t\t\t// Still working: leave it to the next probe or the interval.\n\t\t\t\t\t\tif (body.status === 'pending' || body.status === 'running') return;\n\t\t\t\t\t\t// A stop is not a result; the normal stop path handles that.\n\t\t\t\t\t\tif (isPollStopped(body)) return;\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tclearProbes();\n\t\t\t\t\t\t// The interval would otherwise keep firing against a finished item.\n\t\t\t\t\t\tif (stopBase) { try { stopBase(); } catch (e) { /* already gone */ } }\n\t\t\t\t\t\tif (opts && typeof opts.onResponse === 'function') {\n\t\t\t\t\t\t\ttry { opts.onResponse(body); } catch (e) { /* caller's problem, not the poll's */ }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve(body);\n\t\t\t\t\t}, function () { /* probe failures are not errors: the interval is the source of truth */ });\n\t\t\t\t}, delay));\n\t\t\t});\n\t\t});\n\n\t\t// _trackPoll and the cancel path both reach for .stop, so the wrapper has to carry it.\n\t\traced.stop = function () {\n\t\t\tsettled = true;\n\t\t\tclearProbes();\n\t\t\tif (stopBase) stopBase();\n\t\t};\n\t\treturn raced;\n\t}\n\n\tprivate _trackPoll(id: string, kind: 'fg' | 'bg', p: any): any {\n\t\tvar stop = p && typeof p.stop === 'function' ? p.stop.bind(p) : undefined;\n\t\tif (!stop) {\n\t\t\t// The SDK could not give us a handle. Almost always means an older skapi-js\n\t\t\t// is loaded (or a stale bundler dep cache) — the poll will be unstoppable.\n\t\t\tconsole.debug('[chat-engine] poll has no stop handle', { id: id, kind: kind });\n\t\t}\n\t\tthis.historyItemPolls.set(id, { kind: kind, stop: stop });\n\t\treturn p;\n\t}\n\n\t/** Background polls currently attached, for the MAX_CONCURRENT_BG_POLLS budget.\n\t * Counts the registry rather than a separate tally so it cannot drift: every\n\t * attach goes through _trackPoll and every detach deletes the entry. Note an\n\t * entry left behind by pausePolling on an older skapi-js (no stop handle)\n\t * still counts, which is correct — that poll really is still running. */\n\tprivate _countBgPolls(): number {\n\t\tvar n = 0;\n\t\tthis.historyItemPolls.forEach(function (handle) {\n\t\t\tif (handle && handle.kind === 'bg') n++;\n\t\t});\n\t\treturn n;\n\t}\n\n\t/**\n\t * Stop and forget one item's poll. Used after a cancel: the row is either gone\n\t * (cancelled while queued) or flagged cancelled (cancelled while running), so\n\t * asking about it again only burns requests. Safe when no poll is attached, and\n\t * safe on an older skapi-js with no stop handle (the entry is then LEFT in the\n\t * map so a later drain cannot stack a second, unstoppable poll on the id).\n\t */\n\tprivate _stopPoll(id: string): void {\n\t\tvar handle = this.historyItemPolls.get(id);\n\t\tif (!handle) return;\n\t\tif (typeof handle.stop !== 'function') return;\n\t\ttry { handle.stop(); } catch (e) { /* best effort */ }\n\t\tthis.historyItemPolls.delete(id);\n\t}\n\n\t/** True while any pause reason is active. */\n\tisPollingPaused(): boolean {\n\t\treturn this._pauseReasons.size > 0;\n\t}\n\n\t/**\n\t * Stop BACKGROUND polling until resumePolling. Foreground polls (a reply the user is\n\t * waiting on) keep running deliberately: their results must still land in the history\n\t * cache so resumePendingRequest can render them on return, otherwise a user who sends\n\t * a message then navigates away comes back to a permanently stuck \"Thinking...\".\n\t *\n\t * Server-side work is untouched; this only stops asking about it. That is safe for\n\t * document indexing because the worker drives that loop itself.\n\t */\n\tpausePolling(reason: string): void {\n\t\tthis._pauseReasons.add(reason || 'paused');\n\t\tvar self = this;\n\t\tvar stopped: string[] = [];\n\t\tthis.historyItemPolls.forEach(function (handle, id) {\n\t\t\tif (!handle || handle.kind !== 'bg') return;\n\t\t\t// No stop available (older SDK): LEAVE the entry in place. Deleting it would\n\t\t\t// let a later drain attach a second, uncancellable poll on the same item.\n\t\t\tif (typeof handle.stop !== 'function') return;\n\t\t\ttry { handle.stop(); } catch (e) { /* best effort */ }\n\t\t\tstopped.push(id);\n\t\t});\n\t\t// Delete only what we actually stopped, one at a time. NEVER clear() the map:\n\t\t// wholesale clearing is what previously let loadHistory attach a duplicate poll\n\t\t// on a live item, producing duplicate replies and stranded \"Thinking\" bubbles.\n\t\tstopped.forEach(function (id) { self.historyItemPolls.delete(id); });\n\n\t}\n\n\t/**\n\t * Lift a pause reason WITHOUT running the reconcile. For a caller that is about to\n\t * reload history anyway (a view remounting), letting resumePolling also reconcile\n\t * would race that load and can double-attach.\n\t */\n\tclearPauseReason(reason: string): void {\n\t\tthis._pauseReasons.delete(reason || 'paused');\n\t}\n\n\t/**\n\t * Clear a pause reason and, once none remain, re-attach polling and reconcile.\n\t * Deliberately does NOT touch gateRefreshToken: bumping it would silently discard\n\t * the results of anything still in flight across the pause.\n\t */\n\tresumePolling(reason: string): Promise<void> {\n\t\tthis._pauseReasons.delete(reason || 'paused');\n\t\tif (this._pauseReasons.size > 0 || this._resuming) return Promise.resolve();\n\t\tif (!this.host.isViewMounted || !this.host.isViewMounted()) return Promise.resolve();\n\t\tvar self = this;\n\t\tthis._resuming = true;\n\t\treturn Promise.resolve()\n\t\t\t.then(function () {\n\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\treturn self.loadHistory(false, self.state.gateRefreshToken);\n\t\t\t})\n\t\t\t.catch(function (e: any) { console.error('[chat-engine] resume polling failed', e); })\n\t\t\t.then(function () { self._resuming = false; });\n\t}\n\n\tprivate _newLocalId(): string {\n\t\tthis._lidSeq += 1;\n\t\treturn 'lid_' + this._lidSeq;\n\t}\n\n\t/**\n\t * The key every per-chat cache hangs off: the restored message cache, the\n\t * hydrated-body memo, the live-index key and the per-file storage-path key.\n\t *\n\t * It carries the IDENTITY as well as the project and platform. A single\n\t * browser can hold more than one conversation on one project without a\n\t * reload — an anonymous visitor who signs in, or a dashboard user who logs\n\t * out and back in as someone else — and with an identity-free key the\n\t * previous conversation stayed in the cache and was re-rendered, and written\n\t * back, as the new one's. `userId` is the same value the request queue is\n\t * named after, so two identities that share a queue share a cache, which is\n\t * exactly right.\n\t */\n\tgetHistoryCacheKey(): string {\n\t\tvar id = this.host.getIdentity();\n\t\tif (!id.projectId || id.platform === 'none') return '';\n\t\treturn id.projectId + '#' + id.platform + '#' + (id.userId || '');\n\t}\n\n\t// ─── compact-stub hydration ─────────────────────────────────────────────\n\t// Split-fetch bg pages arrive as label stubs (no bodies). When the user\n\t// expands a row, the real reply text is fetched per item (csr-poll point\n\t// lookup) and MEMOIZED per chat: every later remap (first-page refresh,\n\t// queue-detect tick, cache restore) re-applies the memo, so a hydrated\n\t// bubble can never silently revert to its 200-char head.\n\tprivate _hydratedBodies: { [chatKey: string]: { [itemId: string]: string } } = {};\n\tprivate _hydratingItems: { [key: string]: boolean } = {};\n\n\t/** Re-apply memoized hydrated texts onto freshly-mapped messages. Both\n\t * clients call this right after their mapper runs (loadHistory does it\n\t * internally); it mutates the given array's items in place. */\n\tapplyHydratedBodies(messages: ChatMessage[]): void {\n\t\tvar key = this.getHistoryCacheKey();\n\t\tvar memo = key ? this._hydratedBodies[key] : null;\n\t\tif (!memo) return;\n\t\tvar id = this.host.getIdentity();\n\t\tfor (var i = 0; i < messages.length; i++) {\n\t\t\tvar m: any = messages[i];\n\t\t\tif (!m || !m._compact || m.role !== 'assistant' || !m._serverItemId) continue;\n\t\t\tvar text = memo[m._serverItemId];\n\t\t\tif (typeof text !== 'string') continue;\n\t\t\tm.content = sanitizeAttachmentLinksForHistory(text, id.projectId, true) || EMPTY_INDEXING_REPLY;\n\t\t\tdelete m._compact;\n\t\t}\n\t}\n\n\t/** Fetch the real response bodies for compact history stubs (one csr-poll\n\t * point lookup per item id), memoize, and swap them into the live list.\n\t * Best-effort: a failed lookup leaves the stub (its head + fallback line\n\t * still render) and a later expand retries. */\n\thydrateCompactItems(itemIds: string[]): Promise<void> {\n\t\tvar self = this;\n\t\tvar lookup = chatEngineConfig().csrHistoryItemLookup;\n\t\tif (!lookup || !itemIds || !itemIds.length) return Promise.resolve();\n\t\tvar id = this.host.getIdentity();\n\t\tvar platform = id.platform;\n\t\tif (!id.projectId || (platform !== 'claude' && platform !== 'openai')) return Promise.resolve();\n\t\tvar chatKey = this.getHistoryCacheKey();\n\t\tif (!chatKey) return Promise.resolve();\n\t\tvar jobs = itemIds.map(function (itemId) {\n\t\t\tif (!itemId) return Promise.resolve();\n\t\t\tvar already = self._hydratedBodies[chatKey] && self._hydratedBodies[chatKey][itemId] !== undefined;\n\t\t\tvar inflightKey = chatKey + '|' + itemId;\n\t\t\tif (already || self._hydratingItems[inflightKey]) return Promise.resolve();\n\t\t\tself._hydratingItems[inflightKey] = true;\n\t\t\treturn Promise.resolve(lookup(buildHistoryItemFullId(platform as 'claude' | 'openai', id.projectId, itemId), id.projectId, id.owner)).then(function (body: any) {\n\t\t\t\t// Chat may have switched while the lookup flew; the memo is\n\t\t\t\t// per-chat so record under the key we started with, and only\n\t\t\t\t// touch the live list if it is still that chat's.\n\t\t\t\tvar text = ((platform === 'openai' ? extractOpenAIText(body) : extractClaudeText(body)) || '').trim();\n\t\t\t\tif (text.indexOf(INDEXING_COMPLETE_MARKER) !== -1) text = text.split(INDEXING_COMPLETE_MARKER).join('').trim();\n\t\t\t\tif (!self._hydratedBodies[chatKey]) self._hydratedBodies[chatKey] = {};\n\t\t\t\tself._hydratedBodies[chatKey][itemId] = text;\n\t\t\t\tif (self.getHistoryCacheKey() !== chatKey) return;\n\t\t\t\tfor (var i = 0; i < self.state.messages.length; i++) {\n\t\t\t\t\tvar m: any = self.state.messages[i];\n\t\t\t\t\tif (m && m._compact && m.role === 'assistant' && m._serverItemId === itemId) {\n\t\t\t\t\t\tm.content = sanitizeAttachmentLinksForHistory(text, id.projectId, true) || EMPTY_INDEXING_REPLY;\n\t\t\t\t\t\tdelete m._compact;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}).catch(function () { /* stub stays; expand retries */ }).then(function () {\n\t\t\t\tdelete self._hydratingItems[inflightKey];\n\t\t\t});\n\t\t});\n\t\treturn Promise.all(jobs).then(function () {\n\t\t\tif (self.getHistoryCacheKey() !== chatKey) return;\n\t\t\tself.host.notify();\n\t\t\tself.updateHistoryCache();\n\t\t});\n\t}\n\n\tupdateHistoryCache(): void {\n\t\tvar key = this.getHistoryCacheKey();\n\t\tif (!key) return;\n\t\t// Never persist another chat's in-flight bubbles under THIS key. The\n\t\t// dashboard shares one ChatSession across projects, so a turn dispatched\n\t\t// in project A can still be sitting in state.messages while the identity\n\t\t// (and therefore `key`) already points at project B — without this filter\n\t\t// A's user + \"Thinking...\" bubbles get written into B's cache entry and\n\t\t// replay on every later visit to B. Bubbles with no _ownerKey (server\n\t\t// history, bg tasks) are always kept. Single pass: this runs on the\n\t\t// typewriter hot path.\n\t\t//\n\t\t// Staged bubbles (_stageId) ARE cached, deliberately. They used to be dropped\n\t\t// on the theory that a reload kills the upload but not the cache, leaving a\n\t\t// message that uploads forever — but this cache is an in-memory field on a\n\t\t// singleton created at module load, so a reload takes it and the upload chain\n\t\t// together and that state is unreachable. What dropping them DID cost was\n\t\t// real: state.messages is shared across projects, so both clients filter it by\n\t\t// _ownerKey on every chat switch, and with no cached copy the bubble was\n\t\t// destroyed outright. A user who sent a question with a file and then looked at\n\t\t// another project lost the question for the whole indexing wait and got it back\n\t\t// at the bottom minutes later.\n\t\t//\n\t\t// isLiveStage + settleDeadStagedMessages keep the original concern honest if\n\t\t// this cache is ever persisted: a restored stage whose upload no longer exists\n\t\t// settles into a plain message instead of uploading forever.\n\t\tthis.aiChatHistoryCache[key] = {\n\t\t\tmessages: this.state.messages.filter(function (m) {\n\t\t\t\treturn m._ownerKey === undefined || m._ownerKey === key;\n\t\t\t}),\n\t\t\tendOfList: this.state.historyEndOfList,\n\t\t\tstartKeyHistory: this.state.historyStartKeyHistory.slice(),\n\t\t};\n\t}\n\n\t/**\n\t * Give the immediate-send pair the server's id for their turn, the moment the\n\t * dispatch learns it.\n\t *\n\t * WHY THIS EXISTS. An immediate send pushes its user bubble and its\n\t * \"Thinking...\" placeholder locally, and until now neither ever carried a\n\t * _serverItemId — only the QUEUED path stamped one, off its ack. So for the\n\t * whole life of the turn there was no way to tell the local copy and the\n\t * server's copy of the SAME turn apart, and the history merge fell back to a\n\t * heuristic: rescue the local pair unless the freshly-fetched page happens to\n\t * contain a pending assistant.\n\t *\n\t * That heuristic has a hole exactly one poll interval wide. The server settles\n\t * the request; for up to POLL_INTERVAL the client has not noticed, so\n\t * `state.sending` is still true and the local pair is still on screen — while a\n\t * history fetch issued in that window returns the turn ALREADY SETTLED, with no\n\t * pending assistant in it. The rescue then re-appends the local pair below the\n\t * server's copy (the question, twice), and when the poll finally resolves,\n\t * typewriteLatestReply writes the answer into the rescued placeholder because it\n\t * is the only pending assistant left (the answer, twice). updateHistoryCache\n\t * persists the result, so it survives every later visit.\n\t *\n\t * Navigating away while waiting and coming back is what lands a fetch in that\n\t * window: a remount runs refreshGate -> a fresh first page, at an arbitrary\n\t * moment relative to the 3s poll.\n\t *\n\t * With the id on the bubbles, both clients' rescue loops skip them through the\n\t * dedup they already have (`_serverItemId is in this page`), the reply the\n\t * dispatch caches inherits the id too, and nothing needs a new special case.\n\t *\n\t * Matched by _localId, never by index: a file's indexing rows are spliced in\n\t * above these bubbles while the request is in flight.\n\t */\n\tprivate _stampTurnWithItemId(key: string, userLid: string | undefined, placeholderLid: string | undefined, itemId: string): void {\n\t\t// placeholderLid is undefined for a QUEUED send: that path has no\n\t\t// \"Thinking...\" bubble of its own until promoteNextQueuedToRunning makes one,\n\t\t// and that copies the user bubble's id itself.\n\t\tif (!itemId) return;\n\t\tvar changed = false;\n\t\tvar stamp = function (list: ChatMessage[]) {\n\t\t\tvar hit = false;\n\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\tvar m = list[i];\n\t\t\t\tif (!m || !m._localId) continue;\n\t\t\t\tif (m._localId !== userLid && m._localId !== placeholderLid) continue;\n\t\t\t\tif (m._serverItemId === itemId) continue;\n\t\t\t\tlist[i] = Object.assign({}, m, { _serverItemId: itemId });\n\t\t\t\thit = true;\n\t\t\t}\n\t\t\treturn hit;\n\t\t};\n\t\tchanged = stamp(this.state.messages);\n\t\t// And in the cache, which is what a remount renders BEFORE the fetch lands.\n\t\t// A cached copy still missing the id would be rescued by the very merge this\n\t\t// is here to satisfy.\n\t\tvar cached = key ? this.aiChatHistoryCache[key] : undefined;\n\t\tif (cached) {\n\t\t\tvar msgs = cached.messages.slice();\n\t\t\tif (stamp(msgs)) {\n\t\t\t\tthis.aiChatHistoryCache[key] = {\n\t\t\t\t\tmessages: msgs, endOfList: cached.endOfList, startKeyHistory: cached.startKeyHistory,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tif (changed) this.host.notify();\n\t}\n\n\t/**\n\t * Land a resolved reply in the history cache of a chat that is NOT currently\n\t * visible, without touching state.messages. Mirrors the cache-only path in\n\t * dispatchAgentRequest: REPLACE the trailing pending \"Thinking...\" bubble\n\t * (append only when there is none), and settle the matching pending user\n\t * bubble, so the cached copy never keeps a stuck \"Thinking...\" that a later\n\t * cache-first load would re-render forever.\n\t */\n\tprivate _applyReplyToCache(key: string, reply: ChatMessage, serverId?: string): void {\n\t\tif (!key) return;\n\t\tvar existing = this.aiChatHistoryCache[key] || { messages: [], endOfList: false, startKeyHistory: [] };\n\t\tvar msgs = existing.messages.slice();\n\n\t\tvar thIdx = -1;\n\t\tfor (var i = msgs.length - 1; i >= 0; i--) {\n\t\t\tvar m = msgs[i];\n\t\t\tif (!m || !m.isPending || m.role !== 'assistant' || m.isBackgroundTask) continue;\n\t\t\tif (serverId && m._serverItemId && m._serverItemId !== serverId) continue;\n\t\t\tthIdx = i; break;\n\t\t}\n\t\tif (thIdx !== -1) {\n\t\t\tif (reply._serverItemId === undefined && msgs[thIdx]._serverItemId !== undefined) reply._serverItemId = msgs[thIdx]._serverItemId;\n\t\t\tmsgs[thIdx] = reply;\n\t\t} else {\n\t\t\t// No pending placeholder left to replace. Before appending, check whether\n\t\t\t// this turn is ALREADY in the cache — a history fetch may have mapped the\n\t\t\t// resolved turn in while the reply was in flight. Appending blindly is how\n\t\t\t// one turn ended up rendered twice (the duplicated question+answer): the\n\t\t\t// cache is restored verbatim on the next mount, so a duplicate written\n\t\t\t// here survives every later visit.\n\t\t\tvar dupIdx = -1;\n\t\t\tif (serverId) {\n\t\t\t\tfor (var d = msgs.length - 1; d >= 0; d--) {\n\t\t\t\t\tvar dm = msgs[d];\n\t\t\t\t\tif (dm && dm.role === 'assistant' && dm._serverItemId === serverId) { dupIdx = d; break; }\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (dupIdx !== -1) msgs[dupIdx] = reply;\n\t\t\telse msgs.push(reply);\n\t\t}\n\n\t\t// Settle the user bubble this turn belongs to (first pending one, or the\n\t\t// one carrying serverId) so it stops rendering as still in flight.\n\t\tfor (var j = 0; j < msgs.length; j++) {\n\t\t\tvar u = msgs[j];\n\t\t\tif (!u || u.role !== 'user' || u.isBackgroundTask) continue;\n\t\t\t// A STAGED bubble matches this shape exactly — pending, no server id, so the\n\t\t\t// id test below cannot rule it out — and sits EARLIER in the list than the\n\t\t\t// turn actually resolving. Settling it would strip its _stageId and its\n\t\t\t// upload state, silently killing a turn whose files are still going up.\n\t\t\tif (u._stageId) continue;\n\t\t\tif (!(u.isPendingQueued || u.isPendingInProcess || u.isSendingToServer)) continue;\n\t\t\tif (serverId && u._serverItemId && u._serverItemId !== serverId) continue;\n\t\t\tvar settled: ChatMessage = { role: 'user', content: u.content };\n\t\t\tif (u._serverItemId !== undefined) settled._serverItemId = u._serverItemId;\n\t\t\tif (u._ownerKey !== undefined) settled._ownerKey = u._ownerKey;\n\t\t\tmsgs[j] = settled;\n\t\t\tbreak;\n\t\t}\n\n\t\tthis.aiChatHistoryCache[key] = {\n\t\t\tmessages: msgs,\n\t\t\tendOfList: existing.endOfList,\n\t\t\tstartKeyHistory: existing.startKeyHistory,\n\t\t};\n\t}\n\n\t/**\n\t * projectId/owner are passed explicitly by every caller: a request can be\n\t * dispatched after the user moved to another project, and re-reading the live\n\t * identity here would silently send the turn to THAT project instead of the\n\t * one it was composed for. Falls back to the live read only when a caller\n\t * omits them.\n\t */\n\tprivate _callProviderFor(platform: string, prompt: string, messages: any, system: string, model: string | undefined, userId: string, extractContent: any, fileUrls?: any, projectId?: string, owner?: string) {\n\t\tif (projectId === undefined || owner === undefined) {\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (projectId === undefined) projectId = id.projectId;\n\t\t\tif (owner === undefined) owner = id.owner;\n\t\t}\n\t\t// Read LIVE, unlike projectId/owner above, and deliberately: this decides\n\t\t// which MCP endpoint the turn's tools point at, and a retry after the\n\t\t// visitor signed in should use the authenticated one rather than the\n\t\t// project-scoped anonymous route it was composed under. Getting it wrong\n\t\t// costs a failed turn, never a wider read: the anonymous route is\n\t\t// read-only and public-records-only whoever calls it.\n\t\tvar liveId = this.host.getIdentity();\n\t\tvar mcpScope = { anonymous: liveId.anonymous, publicProjectId: liveId.publicProjectId };\n\t\treturn platform === 'openai'\n\t\t\t? callOpenAIWithPublicMcp(prompt, projectId, owner, messages, system, model, userId, extractContent, fileUrls, undefined, undefined, mcpScope)\n\t\t\t: callClaudeWithPublicMcp(prompt, projectId, owner, messages, system, model, userId, extractContent, fileUrls, undefined, undefined, mcpScope);\n\t}\n\n\tdispatchAgentRequest(params: any) {\n\t\tvar self = this;\n\t\t// Id of the in-flight item this dispatch polls. Recorded in\n\t\t// historyItemPolls (set below, deleted when the dispatch settles) so a\n\t\t// remount / history refetch dedups against THIS poll instead of stacking\n\t\t// a duplicate history poll on the same item. (The cacheKey guard alone\n\t\t// stops covering an item once pendingAgentRequests clears — e.g. a queued\n\t\t// message still in flight after the immediate one resolved.)\n\t\tvar dispatchItemId: string | undefined;\n\t\tvar sendAndPoll = function () {\n\t\t\treturn Promise.resolve(\n\t\t\t\tself._callProviderFor(params.aiPlatform, params.text, params.boundedMessages, params.systemPrompt, params.aiModel, params.userId, params.extractContent, params.fileUrls, params.projectId, params.owner)\n\t\t\t).then(function (initial: any) {\n\t\t\t\tif (initial && initial.poll && (initial.status === 'pending' || initial.status === 'running')) {\n\t\t\t\t\tif (initial.id) {\n\t\t\t\t\t\tif (dispatchItemId && dispatchItemId !== initial.id) self.historyItemPolls.delete(dispatchItemId);\n\t\t\t\t\t\tdispatchItemId = initial.id;\n\t\t\t\t\t\t// Hand the id to the caller so the bubbles already on screen can\n\t\t\t\t\t\t// carry it. An auth-refresh retry re-enters here with a NEW id,\n\t\t\t\t\t\t// so this reports every time, not once.\n\t\t\t\t\t\tif (typeof params.onItemId === 'function') params.onItemId(initial.id);\n\t\t\t\t\t}\n\t\t\t\t\tvar dp = self._fgPollWithEarlyProbe(initial, initial.id);\n\t\t\t\t\tif (initial.id) self._trackPoll(initial.id, 'fg', dp);\n\t\t\t\t\treturn dp;\n\t\t\t\t}\n\t\t\t\treturn initial;\n\t\t\t});\n\t\t};\n\t\tvar run = sendAndPoll()\n\t\t\t.catch(function (err: any) {\n\t\t\t\t// Only auth-expiry is worth a refresh+resend; a malformed-request 400\n\t\t\t\t// (e.g. the `_skapi_extract`/unknown-parameter class) re-fails identically,\n\t\t\t\t// so never loop on it — guard against isAuthExpiredError's heuristic\n\t\t\t\t// misfiring on a param name that merely contains \"token\".\n\t\t\t\tif (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(sendAndPoll);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.then(function (response: any) {\n\t\t\t\tif (isErrorResponseBody(response) && isAuthExpiredError(response) && !isNonRetryableRequestError(response)) {\n\t\t\t\t\treturn self.host.refreshSession().then(sendAndPoll);\n\t\t\t\t}\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.then(function (response: any) {\n\t\t\t\tif (isErrorResponseBody(response)) return { content: getErrorMessage(response), isError: true };\n\t\t\t\tvar answer = (params.aiPlatform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response));\n\t\t\t\tanswer = (answer || '').trim();\n\t\t\t\treturn { content: answer || 'No text response received from AI provider.', isError: false };\n\t\t\t})\n\t\t\t.catch(function (err: any) { return { content: getErrorMessage(err), isError: true }; })\n\t\t\t.then(function (result: any) {\n\t\t\t\t// Land the resolved reply in the shared history cache. This runs\n\t\t\t\t// independently of the view lifecycle, so a reply is captured even\n\t\t\t\t// if the chatbox unmounted mid-request.\n\t\t\t\tdelete self.pendingAgentRequests[params.key];\n\t\t\t\tif (dispatchItemId) self.historyItemPolls.delete(dispatchItemId);\n\t\t\t\tvar reply: ChatMessage = { role: 'assistant', content: result.content, isError: result.isError };\n\t\t\t\tif (dispatchItemId) reply._serverItemId = dispatchItemId;\n\n\t\t\t\t// REPLACE the trailing pending \"Thinking...\" bubble in the cache with\n\t\t\t\t// the answer, regardless of whether this chat is the currently-visible\n\t\t\t\t// view. The cache must NEVER retain a pending \"Thinking...\" bubble: even\n\t\t\t\t// when the chatbox is showing this chat, typewriteLatestReply swaps the\n\t\t\t\t// bubble only in state.messages and NEVER re-snapshots the cache — so\n\t\t\t\t// leaving a pending copy here would have a later cache-first remount\n\t\t\t\t// re-render that \"Thinking...\" forever. typewriteLatestReply still finds\n\t\t\t\t// this reply (it reads the latest non-pending assistant from the cache),\n\t\t\t\t// so replacing is correct for the visible case too.\n\t\t\t\t//\n\t\t\t\t// _applyReplyToCache rather than an inline copy of it. This used to be\n\t\t\t\t// its own loop with the same replace-or-append shape MINUS the\n\t\t\t\t// dedup-before-append its twin already had, and the append is reachable:\n\t\t\t\t// once the local pair carries its server id (_stampTurnWithItemId), a\n\t\t\t\t// first-page fetch that lands after the server settles the item\n\t\t\t\t// correctly drops both local copies and re-snapshots a cache with no\n\t\t\t\t// pending placeholder left to replace. The blind push then wrote the\n\t\t\t\t// answer in a SECOND time, with no id on it, and the cache is rendered\n\t\t\t\t// verbatim on the next mount — so the fix that stopped the turn\n\t\t\t\t// duplicating on screen would have moved the duplicate into the cache.\n\t\t\t\tself._applyReplyToCache(params.key, reply, dispatchItemId);\n\t\t\t\treturn result;\n\t\t\t});\n\t\tthis.pendingAgentRequests[params.key] = run;\n\t\treturn run;\n\t}\n\n\t/**\n\t * Put a turn on screen the INSTANT the user hits Send, before its attachments\n\t * have finished uploading. Uploads run in the background now (the composer is\n\t * cleared and stays usable), so without a staged bubble the message would\n\t * appear only once its files were up — below anything the user sent in the\n\t * meantime, in an order that never matches what they typed.\n\t *\n\t * Staged bubbles carry _useBgQueue because that is where a turn with\n\t * attachments ultimately dispatches (behind its own indexing tasks). That flag\n\t * is also what keeps promoteNextQueuedToRunning / resolveQueuedUserBubble off\n\t * them: those advance the SERVER queue, and a staged turn has no server\n\t * request behind it yet.\n\t *\n\t * Returns the id to hand back as PinnedDispatchContext.stageId at dispatch.\n\t */\n\tstageOutgoingMessage(displayText: string): string {\n\t\tthis._stageSeq += 1;\n\t\tvar stageId = 'stg_' + this._stageSeq;\n\t\tvar key = this.getHistoryCacheKey();\n\t\tvar staged: ChatMessage = {\n\t\t\trole: 'user', content: displayText,\n\t\t\tisPendingQueued: true, isUploadingAttachments: true, isSendingToServer: true,\n\t\t\t_dimSending: true,\n\t\t\t// A staged bubble has no server id for minutes, and its indexing rows are\n\t\t\t// now inserted ABOVE it — so its array index moves. Both views fall back to\n\t\t\t// the index when a bubble has no id, which would re-key (and in Vue, remount)\n\t\t\t// this bubble on every file, restarting its transition and losing it as a\n\t\t\t// scroll anchor. A local id it keeps for its whole life fixes both.\n\t\t\t_localId: this._newLocalId(),\n\t\t\t_useBgQueue: true, _stageId: stageId, _ts: wallClockNow(),\n\t\t};\n\t\tif (key) staged._ownerKey = key;\n\t\tthis._liveStages[stageId] = true;\n\t\tthis.state.messages.push(staged);\n\t\tthis.host.notify(); this.host.scrollToBottom(true);\n\t\treturn stageId;\n\t}\n\n\t/** Is anything in this page still uploading/dispatching for this stage? */\n\tisLiveStage(stageId?: string): boolean {\n\t\treturn !!stageId && !!this._liveStages[stageId];\n\t}\n\n\t/**\n\t * Settle any staged bubble in `list` whose chain no longer exists, and return the\n\t * list (a new array only if something changed).\n\t *\n\t * The caller is a cache restore. A staged bubble is the one kind of message whose\n\t * resolution lives entirely in page memory — no server request stands behind it\n\t * yet — so a copy that outlives its upload would render \"(Uploading files...)\"\n\t * forever with nothing left to finish it. Today nothing can: this cache dies with\n\t * the page, so every restored stage is still live and this is a no-op. It exists\n\t * so that stops being a silent assumption.\n\t */\n\tsettleDeadStagedMessages(list: ChatMessage[]): ChatMessage[] {\n\t\tif (!Array.isArray(list)) return list;\n\t\tvar self = this;\n\t\tvar dead = false;\n\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\tvar m = list[i];\n\t\t\tif (m && m._stageId && !self._liveStages[m._stageId]) { dead = true; break; }\n\t\t}\n\t\tif (!dead) return list;\n\t\treturn list.map(function (m) {\n\t\t\tif (!m || !m._stageId || self._liveStages[m._stageId]) return m;\n\t\t\tvar settled: ChatMessage = { role: 'user', content: m.content };\n\t\t\tif (m._ownerKey !== undefined) settled._ownerKey = m._ownerKey;\n\t\t\tif (m._ts !== undefined) settled._ts = m._ts;\n\t\t\tif (m._localId !== undefined) settled._localId = m._localId;\n\t\t\treturn settled;\n\t\t});\n\t}\n\n\tprivate _stageIndex(list: ChatMessage[], stageId?: string): number {\n\t\tif (!stageId) return -1;\n\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\tif (list[i] && list[i]._stageId === stageId) return i;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Staged turn, phase 2: its files are up and it is now waiting for the whole\n\t * indexing chain behind them. Swaps \"(Uploading files...)\" for\n\t * \"(Indexing files...)\"; the bubble stays dimmed, because from the user's side\n\t * nothing has been handed over yet.\n\t *\n\t * It deliberately does NOT say \"(In queue)\" here. The turn is not queued behind\n\t * anything the server knows about yet — it is waiting on work that can run for\n\t * minutes — and claiming otherwise is what made the wait look like a stall.\n\t */\n\tmarkStagedMessageIndexing(stageId: string): void {\n\t\tvar idx = this._stageIndex(this.state.messages, stageId);\n\t\tif (idx === -1) return;\n\t\tvar ex = this.state.messages[idx];\n\t\tif (!ex.isUploadingAttachments) return;\n\t\tthis.state.messages[idx] = Object.assign({}, ex, {\n\t\t\tisUploadingAttachments: false, isAwaitingIndexing: true,\n\t\t});\n\t\tthis.host.notify();\n\t}\n\n\t/**\n\t * Staged turn, phase 3: the last of its files has finished indexing, so the turn\n\t * is genuinely just queued now. Full opacity + \"(In queue)\".\n\t *\n\t * Clears the PRESENTATIONAL _dimSending only; isSendingToServer stays set until\n\t * the server actually acks (it is the token that ack matches on). Called by the\n\t * clients the instant awaitIndexingDrained resolves, i.e. immediately before the\n\t * dispatch that replaces this bubble — dispatchComposedMessage carries the\n\t * cleared flag onto the replacement so the turn does not blink back to dimmed.\n\t */\n\tmarkStagedMessageReady(stageId: string): void {\n\t\tvar idx = this._stageIndex(this.state.messages, stageId);\n\t\tif (idx === -1) return;\n\t\tvar ex = this.state.messages[idx];\n\t\tif (!ex.isAwaitingIndexing && !ex._dimSending && !ex.isUploadingAttachments) return;\n\t\tthis.state.messages[idx] = Object.assign({}, ex, {\n\t\t\tisUploadingAttachments: false, isAwaitingIndexing: false, _dimSending: false,\n\t\t});\n\t\tthis.host.notify();\n\t}\n\n\t/**\n\t * Resolves once this project's background-indexing queue has nothing left to\n\t * run, so a chat enqueued right after it is genuinely last.\n\t *\n\t * Sending the chat as soon as the uploads finish is not enough, which is the\n\t * whole reason this exists: indexing a file is a CHAIN, and each pass is only\n\t * enqueued once the previous one lands (the client mints CONTINUE passes for\n\t * text/grid files, the worker mints them for PDFs and windowed reads). Every\n\t * one of those passes therefore queues up BEHIND a chat sent at upload time,\n\t * and the model answers from a file it has only partly read.\n\t *\n\t * The queue is read from the server's status index rather than from\n\t * bgTaskQueue: that mirror holds only what this client dispatched or adopted,\n\t * and it stops being maintained once the view unmounts. An empty answer has to\n\t * repeat before it is believed — see INDEXING_DRAIN_IDLE_LOOKS — and a look\n\t * that fails counts as busy, so a dropped request delays the turn instead of\n\t * releasing it early.\n\t *\n\t * Reads the identity PINNED at Send time, never a live one: the user may be in\n\t * another project by now, and this must keep asking about the one they sent\n\t * from.\n\t */\n\tawaitIndexingDrained(identity: ChatIdentity): Promise<'drained' | 'timedout' | 'skipped'> {\n\t\tvar self = this;\n\t\tvar svcId = identity && identity.projectId;\n\t\tvar platform = identity && identity.platform;\n\t\tif (!svcId || (platform !== 'claude' && platform !== 'openai')) return Promise.resolve('skipped' as const);\n\t\tvar owner = identity.owner;\n\t\tvar queue = bgIndexingQueueName(identity.userId, svcId);\n\t\tvar startedAt = nowMs();\n\t\tvar deadline = startedAt + INDEXING_DRAIN_TIMEOUT_MS;\n\t\tvar idleLooks = 0;\n\t\t// null = \"could not find out\", which the loop below counts as busy. The race\n\t\t// is what makes the timeout necessary rather than tidy: a getChatHistory that\n\t\t// never settles leaves no pending timer behind, so the whole wait — and the\n\t\t// turn, and its bubble — would hang on it indefinitely.\n\t\tvar ask = function (status: 'pending' | 'running') {\n\t\t\tvar answered = false;\n\t\t\treturn new Promise<any>(function (res) {\n\t\t\t\tvar bail: any = null;\n\t\t\t\tvar settle = function (v: any) {\n\t\t\t\t\tif (answered) return;\n\t\t\t\t\tanswered = true;\n\t\t\t\t\tif (bail) { clearTimeout(bail); bail = null; }\n\t\t\t\t\tres(v);\n\t\t\t\t};\n\t\t\t\tbail = setTimeout(function () { settle(null); }, INDEXING_DRAIN_LOOK_TIMEOUT_MS);\n\t\t\t\t// maxAgeMs 0: this loop is WAITING for the queue to change, so a\n\t\t\t\t// cached answer is useless to it — but its fresh answers write\n\t\t\t\t// through into the shared probe memo for the snapshot readers.\n\t\t\t\tPromise.resolve(probeBgQueue(\n\t\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status, limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t\t{ maxAgeMs: 0 },\n\t\t\t\t)).then(function (entry: any) { settle(entry.result); }, function () { settle(null); });\n\t\t\t});\n\t\t};\n\t\t// Ordinary chats are routed onto this queue too (_isOnBgQueue), and those\n\t\t// are not work this turn has to wait behind — the server runs the queue in\n\t\t// order, so being enqueued after them is enough.\n\t\tvar hasLiveIndexing = function (res: any): boolean {\n\t\t\tvar list = res && Array.isArray(res.list) ? res.list : [];\n\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\tvar item = list[i];\n\t\t\t\tif (!item || (item.status !== 'pending' && item.status !== 'running')) continue;\n\t\t\t\tif (isIndexingRequestText(extractLastUserTextFromRequest(item.request_body))) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t\treturn new Promise(function (resolve) {\n\t\t\tvar timer: any = null;\n\t\t\tvar lastLookAt = -Infinity;\n\t\t\tvar nudgedThisInterval = false;\n\t\t\t// A look's queries are OUT. Nothing may start a second one alongside it:\n\t\t\t// two overlapping looks share idleLooks, so both coming back idle would\n\t\t\t// count as the two agreeing looks WITHOUT the confirm gap between them —\n\t\t\t// the one guard that stands between the user and an answer computed from a\n\t\t\t// half-indexed file.\n\t\t\tvar inFlight = false;\n\t\t\tvar finish = function (v: 'drained' | 'timedout') {\n\t\t\t\tif (timer) { clearTimeout(timer); timer = null; }\n\t\t\t\t// De-register on BOTH exits or the waiter leaks a closure per send, and\n\t\t\t\t// a later settle re-arms a timer for a turn that has already gone out.\n\t\t\t\tvar ni = self._drainNudges.indexOf(nudge);\n\t\t\t\tif (ni !== -1) self._drainNudges.splice(ni, 1);\n\t\t\t\tresolve(v);\n\t\t\t};\n\t\t\tvar again = function (ms?: number) {\n\t\t\t\tif (timer) { clearTimeout(timer); timer = null; }\n\t\t\t\tvar wait = ms == null ? (idleLooks > 0 ? INDEXING_DRAIN_CONFIRM_POLL_MS : INDEXING_DRAIN_BUSY_POLL_MS) : ms;\n\t\t\t\ttimer = setTimeout(look, wait);\n\t\t\t};\n\t\t\t// Indexing just ended somewhere (see _nudgeIndexingDrain): ask now rather\n\t\t\t// than waiting out the rest of the busy interval, which is what made the\n\t\t\t// turn sit dimmed for another ten seconds after its files were visibly done.\n\t\t\tvar nudge = function () {\n\t\t\t\t// Already on the confirm cadence — the two agreeing looks and the gap\n\t\t\t\t// between them are the guard, and pulling the second one forward is\n\t\t\t\t// exactly what must not happen.\n\t\t\t\tif (idleLooks > 0) return;\n\t\t\t\tif (inFlight) return; // a look is already asking; nothing to pull forward\n\t\t\t\tif (nudgedThisInterval) return; // one pull-forward per interval\n\t\t\t\t// A look now would short-circuit on this anyway. Nothing re-fires when\n\t\t\t\t// the count reaches zero, deliberately (see trackIndexDispatch): the\n\t\t\t\t// cost is up to one busy interval of extra dim, and the alternative is\n\t\t\t\t// a nudge fired by work STARTING, which can release a turn early.\n\t\t\t\tif (self._indexDispatchesInFlight > 0) return;\n\t\t\t\tnudgedThisInterval = true;\n\t\t\t\tagain(Math.max(0, INDEXING_DRAIN_NUDGE_MIN_GAP_MS - (nowMs() - lastLookAt)));\n\t\t\t};\n\t\t\tvar look = function () {\n\t\t\t\ttimer = null;\n\t\t\t\t// Belt to the nudge's brace: never two sets of queries out at once.\n\t\t\t\tif (inFlight) return;\n\t\t\t\tlastLookAt = nowMs(); nudgedThisInterval = false;\n\t\t\t\tif (nowMs() >= deadline) { finish('timedout'); return; }\n\t\t\t\t// A pass whose ack is still in flight is not on the queue yet, so no\n\t\t\t\t// look can see it.\n\t\t\t\tif (self._indexDispatchesInFlight > 0) { idleLooks = 0; again(); return; }\n\t\t\t\tinFlight = true;\n\t\t\t\tPromise.all([ask('running'), ask('pending')]).then(function (res: any[]) {\n\t\t\t\t\tinFlight = false;\n\t\t\t\t\tvar unknown = res[0] === null || res[1] === null;\n\t\t\t\t\tif (unknown || hasLiveIndexing(res[0]) || hasLiveIndexing(res[1])) idleLooks = 0;\n\t\t\t\t\telse idleLooks += 1;\n\t\t\t\t\tif (idleLooks >= INDEXING_DRAIN_IDLE_LOOKS && nowMs() - startedAt >= INDEXING_DRAIN_MIN_MS) {\n\t\t\t\t\t\tfinish('drained'); return;\n\t\t\t\t\t}\n\t\t\t\t\tagain();\n\t\t\t\t}, function () { inFlight = false; idleLooks = 0; again(); });\n\t\t\t};\n\t\t\tself._drainNudges.push(nudge);\n\t\t\tlook();\n\t\t});\n\t}\n\n\t/**\n\t * Abandon a staged turn — its uploads failed outright, so nothing will be\n\t * dispatched. The bubble stays (the user's text is not silently thrown away)\n\t * but settles into a plain, non-pending message; the caller reports the\n\t * failure separately.\n\t */\n\tsettleStagedMessage(stageId: string): void {\n\t\t// Retired even when the bubble is not on screen (another project is): the\n\t\t// chain is over either way, and a cached copy must not read as still working.\n\t\tdelete this._liveStages[stageId];\n\t\tvar idx = this._stageIndex(this.state.messages, stageId);\n\t\tif (idx === -1) return;\n\t\tvar ex = this.state.messages[idx];\n\t\tvar settled: ChatMessage = { role: 'user', content: ex.content };\n\t\tif (ex._ownerKey !== undefined) settled._ownerKey = ex._ownerKey;\n\t\tif (ex._ts !== undefined) settled._ts = ex._ts;\n\t\t// Same key across the settle: it has no server id and never will.\n\t\tif (ex._localId !== undefined) settled._localId = ex._localId;\n\t\tthis.state.messages[idx] = settled;\n\t\tthis.host.notify(); this.updateHistoryCache();\n\t}\n\n\t// composed = clean display text; composedForLlm carries office-extraction\n\t// placeholders for the provider only. useBgQueue routes a post-attachment turn\n\t// onto the \"-bg\" queue so it runs after indexing.\n\tdispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any, pinned?: PinnedDispatchContext): void {\n\t\tvar self = this;\n\t\t// This turn may already have a bubble on screen, staged at Send time while\n\t\t// its attachments uploaded. Every exit from here has to account for it:\n\t\t// dispatching replaces it in place (so it keeps the position the user sent\n\t\t// it in), and bailing settles it (so it never sits uploading forever).\n\t\tvar stageId = pinned ? pinned.stageId : undefined;\n\t\tif (!composed) { if (stageId) this.settleStagedMessage(stageId); return; }\n\t\t// A send can be dispatched LONG after the user hit Send (attachment\n\t\t// uploads are awaited first), by which time the live identity may have\n\t\t// moved to another project. The caller pins the identity + system prompt\n\t\t// it captured at Send time so the request still goes to the project the\n\t\t// question was actually asked of. Falls back to the live read when the\n\t\t// caller doesn't pin (the widget, which has only one project anyway).\n\t\tvar id = pinned ? pinned.identity : this.host.getIdentity();\n\t\tif (id.platform === 'none') { if (stageId) this.settleStagedMessage(stageId); return; }\n\t\t// Past every bail: this turn is going out, so its stage is over whichever\n\t\t// branch below takes it, and whether or not the bubble is still on screen.\n\t\tif (stageId) delete this._liveStages[stageId];\n\n\t\tvar llmComposed = composedForLlm || composed;\n\n\t\t// Cache key of the chat this turn belongs to. Every locally-created\n\t\t// bubble is stamped with it so a project switch (which flips\n\t\t// getIdentity()/getHistoryCacheKey() to the new project) can't\n\t\t// misattribute this turn's bubbles to that project.\n\t\t// (platform === 'none' already returned above, so projectId is the only gate)\n\t\tvar key = !id.projectId ? '' : id.projectId + '#' + id.platform;\n\t\t// True when the pinned chat is NOT the one currently on screen. Then\n\t\t// state.messages belongs to a different project and MUST NOT be touched:\n\t\t// the turn is staged in the pinned chat's cache instead and shows up when\n\t\t// the user navigates back to it.\n\t\tvar offChat = !!key && key !== this.getHistoryCacheKey();\n\n\t\tvar isQueuedSend = !offChat && (useBgQueue || this.state.sending || this.state.messages.some(function (m) {\n\t\t\treturn (m.isPending || m.isPendingQueued) && !m.isBackgroundTask && !m._useBgQueue;\n\t\t}));\n\n\t\tvar aiPlatform = id.platform;\n\t\tvar aiModel = id.model || undefined;\n\t\tvar systemPrompt = pinned ? pinned.systemPrompt : this.host.buildSystemPrompt();\n\t\tvar userId = id.userId || id.projectId;\n\t\t// Same string the indexing passes are enqueued under (bgIndexingQueueName),\n\t\t// which is the whole reason this turn ends up behind them: the backend runs\n\t\t// different queue names in parallel and only serialises a shared one.\n\t\tvar chatQueue = useBgQueue ? bgIndexingQueueName(userId) : userId;\n\t\t// _stageIndex is -1 when nothing was staged, or when the staged bubble is\n\t\t// gone (a remount rebuilds the list from the cache, which never holds staged\n\t\t// bubbles); either way the branches below fall back to appending.\n\n\t\tif (offChat) {\n\t\t\t// Stage the turn in the pinned chat's cache and dispatch. The\n\t\t\t// client-side queue can't be consulted (its state is the other\n\t\t\t// project's), but the SERVER serializes per queue name, so ordering\n\t\t\t// within the pinned chat still holds. dispatchAgentRequest replaces\n\t\t\t// the pending bubble in this same cache entry when the reply lands.\n\t\t\tvar offHistory = (this.aiChatHistoryCache[key] ? this.aiChatHistoryCache[key].messages : []).filter(function (m) {\n\t\t\t\treturn !m.isPending && !m.isPendingQueued && !m.isPendingInProcess && !m.isPendingOlder &&\n\t\t\t\t\t!m.isCancelled && !m.isBackgroundTask && !m.isError;\n\t\t\t});\n\t\t\tvar offBounded = buildBoundedChatMessages({\n\t\t\t\tplatform: aiPlatform, model: aiModel, systemPrompt: systemPrompt, projectId: id.projectId,\n\t\t\t\thistory: offHistory.concat([{ role: 'user', content: llmComposed }]),\n\t\t\t});\n\t\t\tvar offExisting = this.aiChatHistoryCache[key] || { messages: [], endOfList: false, startKeyHistory: [] };\n\t\t\tvar offUser: ChatMessage = { role: 'user', content: composed, _ownerKey: key, _ts: wallClockNow() };\n\t\t\t// The user hit Send here, then navigated away before the uploads\n\t\t\t// finished. The staged bubble belongs to THAT chat, not the one now on\n\t\t\t// screen, and the turn it stood in for is being cached below — so drop\n\t\t\t// it from the live list instead of leaving a bubble that uploads\n\t\t\t// forever in a project it does not belong to.\n\t\t\tvar offStage = this._stageIndex(this.state.messages, stageId);\n\t\t\tif (offStage !== -1) {\n\t\t\t\tif (this.state.messages[offStage]._ts !== undefined) offUser._ts = this.state.messages[offStage]._ts;\n\t\t\t\tthis.state.messages.splice(offStage, 1);\n\t\t\t\tthis.host.notify();\n\t\t\t}\n\t\t\t// The cached copy of that same staged bubble has to go with it. offUser is\n\t\t\t// the turn it stood in for, appended just below; leaving both would show the\n\t\t\t// question twice on the next visit, permanently — the cache is restored\n\t\t\t// verbatim. (Its _ts is recovered above only when the live bubble is still\n\t\t\t// there; take it from the cached copy otherwise, so the turn keeps the time\n\t\t\t// the user sent it at rather than the upload's finish time.)\n\t\t\tvar offCached = offExisting.messages;\n\t\t\tif (stageId) {\n\t\t\t\toffCached = offCached.filter(function (m) {\n\t\t\t\t\tif (m._stageId !== stageId) return true;\n\t\t\t\t\tif (offStage === -1 && m._ts !== undefined) offUser._ts = m._ts;\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.aiChatHistoryCache[key] = {\n\t\t\t\tmessages: offCached.concat([\n\t\t\t\t\toffUser,\n\t\t\t\t\t{ role: 'assistant', content: '', isPending: true, isPendingInProcess: true, _ownerKey: key },\n\t\t\t\t]),\n\t\t\t\tendOfList: offExisting.endOfList,\n\t\t\t\tstartKeyHistory: offExisting.startKeyHistory,\n\t\t\t};\n\t\t\tthis.dispatchAgentRequest({\n\t\t\t\tkey: key, projectId: id.projectId, owner: id.owner, aiPlatform: aiPlatform, aiModel: aiModel,\n\t\t\t\tsystemPrompt: systemPrompt, text: composed, boundedMessages: offBounded.messages, userId: chatQueue,\n\t\t\t\textractContent: extractContent, fileUrls: fileUrls,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (isQueuedSend) {\n\t\t\tvar resolvedHistory = this.state.messages.filter(function (m) {\n\t\t\t\treturn !m.isPending && !m.isPendingQueued && !m.isPendingInProcess && !m.isPendingOlder &&\n\t\t\t\t\t!m.isCancelled && !m.isBackgroundTask && !m.isError;\n\t\t\t});\n\t\t\tvar boundedQ = buildBoundedChatMessages({\n\t\t\t\tplatform: aiPlatform, model: aiModel, systemPrompt: systemPrompt, projectId: id.projectId,\n\t\t\t\thistory: resolvedHistory.concat([{ role: 'user', content: llmComposed }]),\n\t\t\t});\n\t\t\t// _localId for the same reason as immediateUser below: a queued turn can be\n\t\t\t// renumbered by indexing rows spliced in above it, and an id-less bubble is\n\t\t\t// keyed by index. Overwritten by the staged bubble's own id when replacing one.\n\t\t\tvar queuedBubble: ChatMessage = { role: 'user', content: composed, isPendingQueued: true, isSendingToServer: true, _dimSending: true, _localId: this._newLocalId(), _ts: wallClockNow() };\n\t\t\tif (key) queuedBubble._ownerKey = key;\n\t\t\tif (useBgQueue) queuedBubble._useBgQueue = true;\n\t\t\tvar qStage = this._stageIndex(this.state.messages, stageId);\n\t\t\tif (qStage !== -1) {\n\t\t\t\t// Replace IN PLACE. The turn already sits below its own indexing rows —\n\t\t\t\t// drainBgTaskQueue inserted each of them directly above this bubble as\n\t\t\t\t// the file's pass started — so there is nothing left to reorder, and the\n\t\t\t\t// row order the reader has been looking at all along is the same one the\n\t\t\t\t// server will report on the next load.\n\t\t\t\tvar qEx = this.state.messages[qStage];\n\t\t\t\t// Keep the send time the user saw, not the upload's finish time.\n\t\t\t\tif (qEx._ts !== undefined) queuedBubble._ts = qEx._ts;\n\t\t\t\t// This turn waited out its uploads AND its whole indexing chain in full\n\t\t\t\t// view; markStagedMessageReady un-dimmed it when that finished. Re-dimming\n\t\t\t\t// it now for the one remaining request would read as the wait restarting.\n\t\t\t\tif (qEx._dimSending === false) queuedBubble._dimSending = false;\n\t\t\t\tif (qEx._localId) queuedBubble._localId = qEx._localId;\n\t\t\t\tthis.state.messages.splice(qStage, 1, queuedBubble);\n\t\t\t} else {\n\t\t\t\tthis.state.messages.push(queuedBubble);\n\t\t\t}\n\t\t\tthis.host.notify(); this.updateHistoryCache(); this.scrollForDispatch(stageId);\n\n\t\t\tvar capturedComposed = composed, capturedPlatform = aiPlatform, capturedKey = key;\n\t\t\tvar capturedQueuedLid = queuedBubble._localId;\n\t\t\tPromise.resolve(this._callProviderFor(aiPlatform, composed, boundedQ.messages, systemPrompt, aiModel, chatQueue, extractContent, fileUrls, id.projectId, id.owner))\n\t\t\t\t.then(function (result: any) {\n\t\t\t\t\t// Only ack a bubble that belongs to THIS chat — the search is\n\t\t\t\t\t// positional, so on another project it would stamp this turn's\n\t\t\t\t\t// _serverItemId onto that project's unrelated in-flight bubble.\n\t\t\t\t\t// Staged bubbles (_stageId) are skipped for the same reason: they\n\t\t\t\t\t// sit EARLIER in the list and match this shape exactly, so a turn\n\t\t\t\t\t// whose files are still uploading would take the ack — and the\n\t\t\t\t\t// server id — belonging to the turn that actually just sent.\n\t\t\t\t\tvar sendingIdx = self.getHistoryCacheKey() !== capturedKey ? -1 : self.state.messages.findIndex(function (m) {\n\t\t\t\t\t\treturn m.isSendingToServer && (m.isPendingQueued || m.isPendingInProcess) && m.role === 'user' &&\n\t\t\t\t\t\t\t!m._stageId && (m._ownerKey === undefined || m._ownerKey === capturedKey);\n\t\t\t\t\t});\n\t\t\t\t\tvar serverId = result && typeof result.id === 'string' ? result.id : undefined;\n\t\t\t\t\tif (sendingIdx >= 0) {\n\t\t\t\t\t\tvar upd = Object.assign({}, self.state.messages[sendingIdx], { isSendingToServer: false, _dimSending: false });\n\t\t\t\t\t\tif (serverId) upd._serverItemId = serverId;\n\t\t\t\t\t\tself.state.messages[sendingIdx] = upd; self.host.notify();\n\t\t\t\t\t}\n\t\t\t\t\t// And into the CACHE, which the block above never touched: a remount\n\t\t\t\t\t// renders the cache first, so an unstamped copy there is a bubble the\n\t\t\t\t\t// first-page merge cannot recognise as the turn the server just sent\n\t\t\t\t\t// back — which is how a queued turn came back doubled. Keyed to\n\t\t\t\t\t// capturedKey and matched by _localId, so it lands correctly even\n\t\t\t\t\t// when the user has already moved to another project (plain\n\t\t\t\t\t// updateHistoryCache writes under the LIVE key, which by then is a\n\t\t\t\t\t// different chat).\n\t\t\t\t\tif (serverId) self._stampTurnWithItemId(capturedKey, capturedQueuedLid, undefined, serverId);\n\t\t\t\t\tif (result && result.poll && (result.status === 'pending' || result.status === 'running')) {\n\t\t\t\t\t\t// Track this queued item's poll so a remount/refetch dedups\n\t\t\t\t\t\t// against it instead of attaching a duplicate history poll.\n\t\t\t\t\t\tvar qp = self._fgPollWithEarlyProbe(result, serverId);\n\t\t\t\t\t\tif (serverId) self._trackPoll(serverId, 'fg', qp);\n\t\t\t\t\t\treturn qp\n\t\t\t\t\t\t\t.then(function (res: any) { if (isPollStopped(res)) return; return self.onQueuedSendResponse(capturedComposed, res, capturedPlatform, serverId, capturedKey); })\n\t\t\t\t\t\t\t.catch(function (err: any) { return self.onQueuedSendError(capturedComposed, err, serverId, capturedKey); });\n\t\t\t\t\t}\n\t\t\t\t\treturn self.onQueuedSendResponse(capturedComposed, result, capturedPlatform, serverId, capturedKey);\n\t\t\t\t})\n\t\t\t\t.catch(function (err: any) { return self.onQueuedSendError(capturedComposed, err, undefined, capturedKey); });\n\t\t\treturn;\n\t\t}\n\n\t\t// immediate send — cache+resume model (mirrors agent.vue). The reply is\n\t\t// appended to aiChatHistoryCache by dispatchAgentRequest (so it survives a\n\t\t// view unmount), then rendered from the cache via typewriteLatestReply. A\n\t\t// later resumePendingRequest() re-renders it if the view remounted while the\n\t\t// request was still in flight.\n\t\t// _localId on the user bubble too, not just the staged one it may replace: an\n\t\t// ordinary turn sent while another is staged sits BELOW that turn, so every\n\t\t// indexing row spliced in above renumbers it — and a view that keys an id-less\n\t\t// bubble by index would tear it down and rebuild it on every uploaded file.\n\t\tvar immediateUser: ChatMessage = { role: 'user', content: composed, _localId: this._newLocalId(), _ts: wallClockNow(), ...(key ? { _ownerKey: key } : {}) };\n\t\t// _localId on the placeholder too. It is how the server item id finds these\n\t\t// two bubbles again once the dispatch reports it (see onItemId below), and\n\t\t// indexing rows spliced in above move both of them, so an index will not do.\n\t\tvar immediatePlaceholder: ChatMessage = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, _localId: this._newLocalId(), ...(key ? { _ownerKey: key } : {}) };\n\t\tvar iStage = this._stageIndex(this.state.messages, stageId);\n\t\tif (iStage !== -1) {\n\t\t\t// Replace IN PLACE — see the queued branch above for why nothing moves.\n\t\t\tvar iEx = this.state.messages[iStage];\n\t\t\t// Keep the send time the user saw, not the upload's finish time.\n\t\t\tif (iEx._ts !== undefined) immediateUser._ts = iEx._ts;\n\t\t\t// Same id across the swap, so the row is not re-keyed (and in Vue, remounted)\n\t\t\t// at the very moment the turn goes out.\n\t\t\tif (iEx._localId) immediateUser._localId = iEx._localId;\n\t\t\tthis.state.messages.splice(iStage, 1, immediateUser, immediatePlaceholder);\n\t\t} else {\n\t\t\tthis.state.messages.push(immediateUser);\n\t\t\tthis.state.messages.push(immediatePlaceholder);\n\t\t}\n\t\tthis.host.notify(); this.updateHistoryCache(); this.state.sending = true; this.scrollForDispatch(stageId);\n\n\t\t// Same filter as the offChat and isQueuedSend paths above. It must drop the\n\t\t// pending flags too: the `isPending` placeholder pushed two lines up is the\n\t\t// in-flight \"Thinking...\" bubble, and leaving it in sent a trailing\n\t\t// `{role:'assistant', content:''}` upstream on EVERY immediate send. That is\n\t\t// a last-assistant-turn prefill, which the Claude platform rejects outright,\n\t\t// and on both platforms it made the history end on an assistant turn, so\n\t\t// prepareOpenAIMessages / prepareClaudeMessages bailed at their\n\t\t// `last.role !== 'user'` guard and silently stopped converting attached\n\t\t// images into image blocks.\n\t\t//\n\t\t// `isError` is dropped in all three paths for a different reason: those\n\t\t// bubbles are written by THIS client, never by the model. Every site that\n\t\t// sets `isError: true` fills content from getErrorMessage() or the literal\n\t\t// 'Request was cancelled.', so filtering them discards no model-authored\n\t\t// text. Keeping them handed the model a turn it never produced (\"The AI\n\t\t// provider is temporarily unreachable...\"), attributed to itself, because the\n\t\t// flag is stripped when buildBoundedChatMessages maps down to {role,content}.\n\t\t// The cost is that a retry now follows an unanswered question with no stated\n\t\t// reason, which is a true account of what happened rather than a false one.\n\t\t//\n\t\t// The turn being sent is appended LAST rather than left wherever its bubble\n\t\t// sits. A staged turn keeps the position it was sent in, which is NOT the\n\t\t// end of the list once a message sent after it (while its files uploaded)\n\t\t// has already been answered — and a history that ends on an assistant turn\n\t\t// hits exactly the `last.role !== 'user'` bail described above.\n\t\tvar historyForLlm = this.state.messages.filter(function (m) {\n\t\t\tif (m === immediateUser) return false;\n\t\t\treturn !m.isPending && !m.isPendingQueued && !m.isPendingInProcess && !m.isPendingOlder &&\n\t\t\t\t!m.isCancelled && !m.isBackgroundTask && !m.isError;\n\t\t});\n\t\thistoryForLlm.push({ role: 'user', content: llmComposed });\n\t\tvar bounded = buildBoundedChatMessages({\n\t\t\tplatform: aiPlatform, model: aiModel, systemPrompt: systemPrompt, projectId: id.projectId,\n\t\t\thistory: historyForLlm,\n\t\t});\n\t\tvar immediateUserLid = immediateUser._localId, immediatePlaceholderLid = immediatePlaceholder._localId;\n\t\tvar run = this.dispatchAgentRequest({\n\t\t\tkey: key, projectId: id.projectId, owner: id.owner, aiPlatform: aiPlatform, aiModel: aiModel,\n\t\t\tsystemPrompt: systemPrompt, text: composed, boundedMessages: bounded.messages, userId: chatQueue,\n\t\t\textractContent: extractContent, fileUrls: fileUrls,\n\t\t\t// THE fix for a turn rendering twice after navigate-away-and-back. Until\n\t\t\t// this existed the immediate-send pair carried no server id for its whole\n\t\t\t// life (only the QUEUED path stamped one, off its ack), so nothing could\n\t\t\t// tell the local copy and the server's copy of the same turn apart. See\n\t\t\t// _stampTurnWithItemId.\n\t\t\tonItemId: function (itemId: string) { self._stampTurnWithItemId(key, immediateUserLid, immediatePlaceholderLid, itemId); },\n\t\t});\n\t\t// Render the reply into the \"Thinking...\" bubble whenever the chatbox is\n\t\t// CURRENTLY showing this chat — even after an unmount/remount. The old\n\t\t// guard bailed on `requestToken !== gateRefreshToken`, but EVERY remount\n\t\t// bumps gateRefreshToken (refreshGate), so a request that finished after\n\t\t// the user navigated away and back left a stuck \"Thinking...\" (no view\n\t\t// typewriter ever ran, and resumePendingRequest bails when a pending\n\t\t// bubble is already present). Gate on \"is this the visible chat\" instead.\n\t\t// When it ISN'T (unmounted / another project), dispatchAgentRequest has\n\t\t// already replaced the pending bubble with the answer IN THE CACHE, so a\n\t\t// later loadChatHistory renders it.\n\t\tPromise.resolve(run).catch(function () { }).then(function () {\n\t\t\t// Clear `sending` UNCONDITIONALLY. It is session-global (it gates\n\t\t\t// isQueuedSend above, plus the platform/model pickers in the view), so\n\t\t\t// leaving it set when the user navigated to another project wedged\n\t\t\t// every subsequent send in EVERY project onto the queued path and kept\n\t\t\t// the view's user-bubble rescue arm armed forever. Only the RENDER of\n\t\t\t// the reply stays gated on still showing this chat — when it isn't,\n\t\t\t// dispatchAgentRequest has already written the answer into the cache\n\t\t\t// under `key`, so a later loadChatHistory renders it.\n\t\t\tself.state.sending = false;\n\t\t\tif (!(self.host.isViewMounted() && self.getHistoryCacheKey() === key)) return;\n\t\t\treturn Promise.resolve(self.typewriteLatestReply(key)).then(function () { self.host.scrollToBottomIfSticky(true); });\n\t\t});\n\t}\n\n\t/**\n\t * Scroll for a dispatch that is going out NOW, but never for one arriving late.\n\t *\n\t * A turn with attachments does not dispatch when the user hits Send: it waits out\n\t * its uploads and then its whole indexing chain, which is minutes\n\t * (awaitIndexingDrained). By then the reader has very often scrolled up into\n\t * history to pass the time, and the forcing scrollToBottom yanked them out of it\n\t * — and worse, force-pinned stickToBottom, which no-ops every method on the\n\t * scroll anchor and re-arms the queue-detect poll whose only bail is\n\t * !stickToBottom.\n\t *\n\t * `stageId` is the exact marker for that case: only the attachment path ever\n\t * produces one. The gesture itself was already paid for at stage time, where\n\t * stageOutgoingMessage forces the scroll while the user is still looking at the\n\t * composer. Deliberately NOT gated on \"did we find the staged bubble\" — a remount\n\t * rebuilds from the cache and the turn is appended rather than replaced, which is\n\t * just as late and just as unrequested.\n\t */\n\tprivate scrollForDispatch(stageId?: string): void {\n\t\tif (stageId) this.host.scrollToBottomIfSticky(true);\n\t\telse this.host.scrollToBottom(true);\n\t}\n\n\tpromoteNextBgQueuedToRunning(): void {\n\t\tif (this.state.messages.some(function (m) { return m.isPending && m.role === 'assistant' && m.isBackgroundTask; })) return;\n\t\tvar nextIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.isPendingQueued && m.role === 'user' && m.isBackgroundTask;\n\t\t});\n\t\tif (nextIdx === -1) return;\n\t\tvar existing = this.state.messages[nextIdx];\n\t\tvar promoted: ChatMessage = { role: 'user', content: existing.content, isPendingInProcess: true, isBackgroundTask: true };\n\t\tif (existing._indexFile) promoted._indexFile = existing._indexFile;\n\t\tif (existing._ts !== undefined) promoted._ts = existing._ts;\n\t\tif (existing._serverItemId !== undefined) promoted._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) promoted._ownerKey = existing._ownerKey;\n\t\tthis.state.messages[nextIdx] = promoted;\n\t\tvar placeholder: ChatMessage = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, isBackgroundTask: true };\n\t\tif (existing._serverItemId !== undefined) placeholder._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) placeholder._ownerKey = existing._ownerKey;\n\t\tthis.state.messages.splice(nextIdx + 1, 0, placeholder);\n\t\tthis.host.notify();\n\t}\n\n\tpromoteNextQueuedToRunning(): void {\n\t\tif (this.state.messages.some(function (m) { return m.isPending && m.role === 'assistant' && !m.isBackgroundTask; })) return;\n\t\tvar nextIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.isPendingQueued && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue;\n\t\t});\n\t\tif (nextIdx === -1) return;\n\t\tvar existing = this.state.messages[nextIdx];\n\t\tvar promoted: ChatMessage = { role: 'user', content: existing.content, isPendingInProcess: true };\n\t\tif (existing.isBackgroundTask) promoted.isBackgroundTask = true;\n\t\tif (existing._indexFile) promoted._indexFile = existing._indexFile;\n\t\tif (existing._ts !== undefined) promoted._ts = existing._ts;\n\t\tif (existing._serverItemId !== undefined) promoted._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) promoted._ownerKey = existing._ownerKey;\n\t\tif (existing.isSendingToServer) promoted.isSendingToServer = true;\n\t\t// Carried alongside isSendingToServer, never derived from it: an attachment\n\t\t// turn promoted to running while its ack is still out was already un-dimmed\n\t\t// by markStagedMessageReady and must stay that way.\n\t\tif (existing._dimSending) promoted._dimSending = true;\n\t\t// A turn promoted BEFORE its ack has no server id, so this is the only stable\n\t\t// render key it has; dropping it here re-keyed the bubble by index and undid\n\t\t// the reason it was minted (rows spliced in above renumber it).\n\t\tif (existing._localId !== undefined) promoted._localId = existing._localId;\n\t\tthis.state.messages[nextIdx] = promoted;\n\t\t// Carry the promoted turn's _serverItemId onto the \"Thinking...\" placeholder\n\t\t// (mirrors promoteNextBgQueuedToRunning). Without it, when this promoted turn\n\t\t// is resolved via the history-poll path — applyHistoryItemResolution, which\n\t\t// matches the pending assistant by _serverItemId — the placeholder is not\n\t\t// found, so the reply is spliced in BESIDE it and the \"Thinking...\" is\n\t\t// stranded forever (e.g. after a reload, or when a cancel advances the queue).\n\t\t// onQueuedSendResponse still finds it by position, so the queued-send path is\n\t\t// unaffected.\n\t\tvar placeholder: ChatMessage = { role: 'assistant', content: '', isPending: true };\n\t\tif (existing._serverItemId !== undefined) placeholder._serverItemId = existing._serverItemId;\n\t\tif (existing._ownerKey !== undefined) placeholder._ownerKey = existing._ownerKey;\n\t\tthis.state.messages.splice(nextIdx + 1, 0, placeholder);\n\t\tthis.host.notify();\n\t}\n\n\t/**\n\t * The \"Thinking...\" placeholder belonging to the user bubble at `userIdx`, or -1.\n\t *\n\t * Every path that creates one puts it IMMEDIATELY after its user bubble\n\t * (promoteNextQueuedToRunning, the immediate-send pair, applyHistoryItemResolution),\n\t * so ownership is adjacency — modulo background bubbles, which get spliced in\n\t * around them. Taking the first pending assistant ANYWHERE below instead was a\n\t * hijack: a turn sent with attachments never gets a placeholder of its own\n\t * (promoteNextQueuedToRunning skips _useBgQueue turns) and now keeps the position\n\t * it was sent in, so an ordinary turn sent while its files indexed sits BELOW it\n\t * with a placeholder of its own — and the attachment turn's answer was rendered\n\t * as the answer to that unrelated question.\n\t */\n\tprivate _ownThinkingIndex(userIdx: number, serverId?: string): number {\n\t\tif (userIdx < 0) return -1;\n\t\tfor (var i = userIdx + 1; i < this.state.messages.length; i++) {\n\t\t\tvar m = this.state.messages[i];\n\t\t\tif (!m) return -1;\n\t\t\tif (m.isBackgroundTask) continue; // an indexing row spliced between the pair\n\t\t\tif (m.isPending && m.role === 'assistant') {\n\t\t\t\t// A placeholder stamped for a DIFFERENT request is not this turn's, even\n\t\t\t\t// adjacent: ids are authoritative wherever both sides have one.\n\t\t\t\tif (serverId && m._serverItemId && m._serverItemId !== serverId) return -1;\n\t\t\t\treturn i;\n\t\t\t}\n\t\t\treturn -1; // the next real turn starts here; this one has no placeholder\n\t\t}\n\t\treturn -1;\n\t}\n\n\tresolveQueuedUserBubble(serverId?: string): number | undefined {\n\t\t// The two fallbacks below match by POSITION, not identity, so they must\n\t\t// never consider a bubble stamped for a different chat.\n\t\tvar liveKey = this.getHistoryCacheKey();\n\t\tvar isLocal = function (m: ChatMessage) { return m._ownerKey === undefined || m._ownerKey === liveKey; };\n\t\tvar userIdx = -1;\n\t\tif (serverId) {\n\t\t\tuserIdx = this.state.messages.findIndex(function (m) {\n\t\t\t\treturn m._serverItemId === serverId && (m.isPendingInProcess || m.isPendingQueued) &&\n\t\t\t\t\tm.role === 'user' && !m.isBackgroundTask;\n\t\t\t});\n\t\t}\n\t\tif (userIdx === -1) {\n\t\t\tuserIdx = this.state.messages.findIndex(function (m) {\n\t\t\t\treturn m.isPendingInProcess && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue && isLocal(m);\n\t\t\t});\n\t\t}\n\t\tif (userIdx === -1) {\n\t\t\tuserIdx = this.state.messages.findIndex(function (m) {\n\t\t\t\treturn m.isPendingQueued && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue && isLocal(m);\n\t\t\t});\n\t\t}\n\t\tif (serverId && this.cancelledServerIds.has(serverId)) {\n\t\t\tthis.cancelledServerIds.delete(serverId);\n\t\t\tif (userIdx >= 0) {\n\t\t\t\tvar ex = this.state.messages[userIdx];\n\t\t\t\tthis.state.messages[userIdx] = { role: 'user', content: ex.content, isCancelled: true, _serverItemId: ex._serverItemId, ...(ex._ownerKey !== undefined ? { _ownerKey: ex._ownerKey } : {}) };\n\t\t\t\tvar thIdx = this._ownThinkingIndex(userIdx, serverId);\n\t\t\t\tif (thIdx !== -1) this.state.messages.splice(thIdx, 1);\n\t\t\t}\n\t\t\tthis.promoteNextQueuedToRunning();\n\t\t\treturn undefined;\n\t\t}\n\t\tif (userIdx >= 0) {\n\t\t\tvar exist = this.state.messages[userIdx];\n\t\t\tvar repl: ChatMessage = { role: 'user', content: exist.content };\n\t\t\tif (exist._serverItemId !== undefined) repl._serverItemId = exist._serverItemId;\n\t\t\tif (exist._ownerKey !== undefined) repl._ownerKey = exist._ownerKey;\n\t\t\tif (exist._ts !== undefined) repl._ts = exist._ts;\n\t\t\t// Kept so the bubble is not re-keyed (and in Vue, remounted) at the moment\n\t\t\t// its answer arrives; the views prefer _serverItemId, this is the fallback.\n\t\t\tif (exist._localId !== undefined) repl._localId = exist._localId;\n\t\t\tthis.state.messages[userIdx] = repl;\n\t\t}\n\t\tvar thinkingIdx = this._ownThinkingIndex(userIdx, serverId);\n\t\treturn thinkingIdx !== -1 ? thinkingIdx : (userIdx >= 0 ? userIdx + 1 : -1);\n\t}\n\n\tinsertAtTarget(msg: ChatMessage, targetIdx: number): void {\n\t\t// Error/direct replies land here rather than through the typewriter, so this\n\t\t// is where they pick up their display time.\n\t\tif (msg && msg.role === 'assistant' && msg._ts === undefined) msg._ts = wallClockNow();\n\t\t// Overwrite only a placeholder that genuinely belongs to the turn above it.\n\t\t// Two things now sit at this index that must never be replaced by a chat\n\t\t// answer: a background \"Indexing:\" placeholder (a file's rows are inserted\n\t\t// directly above the turn they belong to, so one can land here) — replacing it\n\t\t// deletes a live pass from its collapsed row — and another request's\n\t\t// placeholder, which resolveQueuedUserBubble deliberately declined to claim.\n\t\t// Anything else is spliced in beside it.\n\t\tvar tgt = targetIdx >= 0 ? this.state.messages[targetIdx] : undefined;\n\t\tvar replaceable = !!tgt && !!tgt.isPending && !tgt.isBackgroundTask &&\n\t\t\tthis._isOwnPlaceholderOf(targetIdx, this._owningUserIndex(targetIdx));\n\t\tif (replaceable) this.state.messages[targetIdx] = msg;\n\t\telse if (targetIdx >= 0) this.state.messages.splice(targetIdx, 0, msg);\n\t\telse this.state.messages.push(msg);\n\t}\n\n\t/**\n\t * The server's OWN copy of this turn is already on screen.\n\t *\n\t * A first-page fetch can land between the server settling the item and this\n\t * poll's tick, and now that the local bubbles carry the item id\n\t * (_stampTurnWithItemId) the rescue correctly drops them and renders the\n\t * server's settled pair instead. There is then nothing left to resolve: the\n\t * -1 fallback would push the answer in a SECOND time at the bottom of the list,\n\t * and the positional fallbacks would hijack some other turn's bubble.\n\t *\n\t * The USER bubble counts, not just a settled assistant: an item whose answer is\n\t * empty produces no assistant bubble at all in the mapper, and that variant\n\t * would otherwise still bottom-push \"No text response received...\". While a turn\n\t * is genuinely live its user bubble is always pending (the queued branch sets\n\t * isPendingQueued, promoteNextQueuedToRunning sets isPendingInProcess), so this\n\t * cannot fire early.\n\t */\n\tprivate _turnAlreadyRendered(serverId?: string): boolean {\n\t\tif (!serverId) return false;\n\t\treturn this.state.messages.some(function (m) {\n\t\t\treturn m._serverItemId === serverId &&\n\t\t\t\t!m.isPending && !m.isPendingQueued && !m.isPendingInProcess;\n\t\t});\n\t}\n\n\tonQueuedSendResponse(_composed: string, response: any, platform: string, serverId?: string, ownerKey?: string): void {\n\t\tif (serverId) this.historyItemPolls.delete(serverId);\n\t\t// This turn resolved while a DIFFERENT chat is on screen (the user moved to\n\t\t// another project mid-flight). state.messages now belongs to that chat, and\n\t\t// resolveQueuedUserBubble's positional fallbacks would happily hijack ITS\n\t\t// pending bubble — or, finding nothing, push this answer onto its list.\n\t\t// Settle in the owning chat's cache instead and leave the view untouched.\n\t\tif (ownerKey && this.getHistoryCacheKey() !== ownerKey) {\n\t\t\tvar offReply: ChatMessage = isErrorResponseBody(response)\n\t\t\t\t? { role: 'assistant', content: getErrorMessage(response), isError: true }\n\t\t\t\t: { role: 'assistant', content: ((platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '').trim() || 'No text response received from AI provider.' };\n\t\t\tthis._applyReplyToCache(ownerKey, offReply, serverId);\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\treturn;\n\t\t}\n\t\tif (this._turnAlreadyRendered(serverId)) {\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar targetIdx = this.resolveQueuedUserBubble(serverId);\n\t\tif (targetIdx === undefined) { this.host.notify(); this.updateHistoryCache(); return; }\n\t\tif (isErrorResponseBody(response)) {\n\t\t\tthis.insertAtTarget({ role: 'assistant', content: getErrorMessage(response), isError: true }, targetIdx);\n\t\t} else {\n\t\t\tvar answer = (platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response));\n\t\t\tanswer = (answer || '').trim() || 'No text response received from AI provider.';\n\t\t\tvar lid = this._newLocalId();\n\t\t\tif (targetIdx >= 0 && this.state.messages[targetIdx] && this.state.messages[targetIdx].isPending) {\n\t\t\t\tthis.state.messages[targetIdx] = { role: 'assistant', content: '', _localId: lid };\n\t\t\t\tthis.host.notify(); this.enqueueTypewrite(targetIdx, answer, lid);\n\t\t\t} else if (targetIdx >= 0) {\n\t\t\t\tthis.state.messages.splice(targetIdx, 0, { role: 'assistant', content: '', _localId: lid });\n\t\t\t\tthis.host.notify(); this.enqueueTypewrite(targetIdx, answer, lid);\n\t\t\t} else {\n\t\t\t\tvar aiIdx = this.state.messages.length;\n\t\t\t\tthis.state.messages.push({ role: 'assistant', content: '', _localId: lid });\n\t\t\t\tthis.host.notify(); this.enqueueTypewrite(aiIdx, answer, lid);\n\t\t\t}\n\t\t}\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.promoteNextQueuedToRunning();\n\t\tthis.updateHistoryCache();\n\t\tthis.host.notify();\n\t\t// ARRIVAL, not a user action: only follow if the user is still pinned to\n\t\t// the bottom. Scrolled-up readers keep their position.\n\t\tthis.host.scrollToBottomIfSticky(true);\n\t}\n\n\tonQueuedSendError(_composed: string, err: any, serverId?: string, ownerKey?: string): void {\n\t\tvar self = this;\n\t\tif (serverId) this.historyItemPolls.delete(serverId);\n\t\t// Off-chat resolution — see onQueuedSendResponse. Settle in the owning\n\t\t// chat's cache rather than mutating whatever chat is on screen now.\n\t\tif (ownerKey && this.getHistoryCacheKey() !== ownerKey) {\n\t\t\tvar isGone = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\t\tthis._applyReplyToCache(ownerKey, isGone\n\t\t\t\t? { role: 'assistant', content: 'Request was cancelled.', isError: true }\n\t\t\t\t: { role: 'assistant', content: getErrorMessage(err), isError: true }, serverId);\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\treturn;\n\t\t}\n\t\t// Same reason as onQueuedSendResponse: with the server's settled copy already\n\t\t// on screen there is no pending bubble left that belongs to this turn, and\n\t\t// every fallback below would write onto some other turn's — or push a second\n\t\t// bubble at the bottom.\n\t\tif (this._turnAlreadyRendered(serverId)) {\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar isNotExists = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\tif (isNotExists) {\n\t\t\tvar userIdx = serverId\n\t\t\t\t? this.state.messages.findIndex(function (m) { return m._serverItemId === serverId && (m.isPendingInProcess || m.isPendingQueued) && m.role === 'user' && !m.isBackgroundTask; })\n\t\t\t\t: this.state.messages.findIndex(function (m) { return m.isPendingInProcess && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue; });\n\t\t\tif (!serverId && userIdx === -1) {\n\t\t\t\tuserIdx = this.state.messages.findIndex(function (m) { return m.isPendingQueued && m.role === 'user' && !m.isBackgroundTask && !m._useBgQueue; });\n\t\t\t}\n\t\t\tif (userIdx >= 0) {\n\t\t\t\tvar ex = this.state.messages[userIdx];\n\t\t\t\tvar repl: ChatMessage = { role: 'user', content: ex.content, isCancelled: true };\n\t\t\t\tif (ex._serverItemId !== undefined) repl._serverItemId = ex._serverItemId;\n\t\t\t\tthis.state.messages[userIdx] = repl;\n\t\t\t}\n\t\t\tif (serverId) {\n\t\t\t\tvar thById = this.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.isPending && m.role === 'assistant' && !m.isBackgroundTask; });\n\t\t\t\tif (thById !== -1) this.state.messages.splice(thById, 1);\n\t\t\t\telse if (userIdx >= 0) {\n\t\t\t\t\tvar thPos = this.state.messages.findIndex(function (m, i) { return i > userIdx && m.isPending && m.role === 'assistant' && !m.isBackgroundTask; });\n\t\t\t\t\tif (thPos !== -1) this.state.messages.splice(thPos, 1);\n\t\t\t\t}\n\t\t\t} else if (userIdx >= 0) {\n\t\t\t\tvar thPos2 = this.state.messages.findIndex(function (m, i) { return i > userIdx && m.isPending && m.role === 'assistant' && !m.isBackgroundTask; });\n\t\t\t\tif (thPos2 !== -1) this.state.messages.splice(thPos2, 1);\n\t\t\t}\n\t\t\tif (serverId) this.cancelledServerIds.delete(serverId);\n\t\t\tthis._removeStrayPendingAssistants();\n\t\t\tthis.promoteNextQueuedToRunning(); this.updateHistoryCache(); this.host.notify(); this.host.scrollToBottomIfSticky(true);\n\t\t\treturn;\n\t\t}\n\t\tvar targetIdx = this.resolveQueuedUserBubble(serverId);\n\t\tif (targetIdx === undefined) { this.host.notify(); this.updateHistoryCache(); return; }\n\t\tthis.insertAtTarget({ role: 'assistant', content: getErrorMessage(err), isError: true }, targetIdx);\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.promoteNextQueuedToRunning(); this.updateHistoryCache(); this.host.notify(); this.host.scrollToBottomIfSticky(true);\n\t}\n\n\tcancelQueuedMessage(msg: ChatMessage, idx: number): void {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\tvar serverId = msg._serverItemId;\n\t\tif (!serverId || msg._cancelling) return;\n\t\tvar platform = id.platform;\n\t\tif (platform !== 'claude' && platform !== 'openai') return;\n\t\tvar url = platform === 'claude' ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;\n\t\tvar queueBase = id.userId || id.projectId;\n\t\tvar queue = (msg.isBackgroundTask || msg._useBgQueue) ? bgIndexingQueueName(queueBase) : queueBase;\n\t\t// `idx` is the index the VIEW rendered this bubble at, and the list can have\n\t\t// moved under it since: indexing rows are inserted above the turn they belong\n\t\t// to (drainBgTaskQueue), so a pass that starts between the last render and the\n\t\t// click shifts every bubble below it down. Writing blind at a stale index\n\t\t// overwrites an unrelated message with a copy of this one. The server id is the\n\t\t// identity — cancelQueuedMessage already refuses to run without one.\n\t\t// The role test belongs on BOTH arms: a request bubble and its reply share one\n\t\t// _serverItemId, so an id-only fast path would paint \"Stopping...\" on the\n\t\t// reply whenever the list shifted UP by one instead (a stray placeholder\n\t\t// swept, a sibling pass cancelled, a NOT_EXISTS splice).\n\t\tvar at = (this.state.messages[idx] && this.state.messages[idx]._serverItemId === serverId && this.state.messages[idx].role === msg.role)\n\t\t\t? idx\n\t\t\t: this.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.role === msg.role; });\n\t\t// Gone from the list entirely (a history refetch rebuilt it): skip the paint —\n\t\t// writing at the rendered index would clobber a stranger — but still SEND the\n\t\t// cancel. The user asked for it, and the server request is the part that matters.\n\t\tif (at !== -1) {\n\t\t\tthis.state.messages[at] = Object.assign({}, this.state.messages[at], { _cancelling: true, _cancelError: undefined });\n\t\t}\n\t\tthis.host.notify();\n\t\tPromise.resolve(this.host.cancelRequest({\n\t\t\turl: url, method: 'POST', id: serverId, queue: queue, service: id.projectId, owner: id.owner,\n\t\t})).then(function (result: any) {\n\t\t\tif (result && result.removed) {\n\t\t\t\tself.cancelledServerIds.add(serverId as string);\n\t\t\t\tself._stopPoll(serverId as string);\n\t\t\t\tvar qi = self.bgTaskQueue.findIndex(function (e) { return e.id === serverId; });\n\t\t\t\tif (qi !== -1) self.bgTaskQueue.splice(qi, 1);\n\t\t\t\tvar removeIdx = self.state.messages.findIndex(function (m) {\n\t\t\t\t\treturn m._serverItemId === serverId && (m.isPendingQueued || m.isPendingInProcess) && m.role === 'user';\n\t\t\t\t});\n\t\t\t\tif (removeIdx !== -1) {\n\t\t\t\t\t// Carry the background/file markers onto the rebuild. Dropping them\n\t\t\t\t\t// took a cancelled INDEXING pass out of its file's collapsed row\n\t\t\t\t\t// (buildChatDisplayList only groups isBackgroundTask bubbles), so the\n\t\t\t\t\t// row stayed \"Indexing…\" forever while a bare \"Indexing: file\" bubble\n\t\t\t\t\t// appeared beside it.\n\t\t\t\t\tvar wasMsg = self.state.messages[removeIdx];\n\t\t\t\t\tvar cancelledMsg: ChatMessage = { role: 'user', content: wasMsg.content, isCancelled: true, _serverItemId: serverId };\n\t\t\t\t\tif (wasMsg.isBackgroundTask) cancelledMsg.isBackgroundTask = true;\n\t\t\t\t\tif (wasMsg._indexFile) cancelledMsg._indexFile = wasMsg._indexFile;\n\t\t\t\t\tif (wasMsg._useBgQueue) cancelledMsg._useBgQueue = true;\n\t\t\t\t\tif (wasMsg._ownerKey !== undefined) cancelledMsg._ownerKey = wasMsg._ownerKey;\n\t\t\t\t\tself.state.messages[removeIdx] = cancelledMsg;\n\t\t\t\t\tvar thById = self.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.isPending && m.role === 'assistant'; });\n\t\t\t\t\tif (thById !== -1) self.state.messages.splice(thById, 1);\n\t\t\t\t\telse {\n\t\t\t\t\t\tvar thPos = self.state.messages.findIndex(function (m, i) {\n\t\t\t\t\t\t\treturn i > removeIdx && m.isPending && m.role === 'assistant' &&\n\t\t\t\t\t\t\t\t(msg.isBackgroundTask ? !!m.isBackgroundTask : !m.isBackgroundTask);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (thPos !== -1) self.state.messages.splice(thPos, 1);\n\t\t\t\t\t}\n\t\t\t\t\tif (msg.isBackgroundTask) self.promoteNextBgQueuedToRunning(); else self.promoteNextQueuedToRunning();\n\t\t\t\t\tself.updateHistoryCache();\n\t\t\t\t}\n\t\t\t\tself.host.notify();\n\t\t\t} else {\n\t\t\t\tvar errMsg = result && typeof result.message === 'string' && result.message ? result.message : 'Could not remove from queue.';\n\t\t\t\tvar ci = self.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.role === 'user'; });\n\t\t\t\tif (ci !== -1) { self.state.messages[ci] = Object.assign({}, self.state.messages[ci], { _cancelling: false, _cancelError: errMsg }); self.host.notify(); }\n\t\t\t}\n\t\t}).catch(function (err: any) {\n\t\t\tvar errMsg = err && typeof err.message === 'string' && err.message ? err.message : 'Could not remove from queue.';\n\t\t\tvar ci = self.state.messages.findIndex(function (m) { return m._serverItemId === serverId && m.role === 'user'; });\n\t\t\tif (ci !== -1) { self.state.messages[ci] = Object.assign({}, self.state.messages[ci], { _cancelling: false, _cancelError: errMsg }); self.host.notify(); }\n\t\t});\n\t}\n\n\t/**\n\t * Stop indexing a file, from its collapsed row — every pass at once, not just\n\t * the bubble the user happens to see.\n\t *\n\t * A big file is indexed as a CHAIN of passes, so cancelling only the live one\n\t * accomplishes nothing: the next pass is dispatched as soon as it settles.\n\t * Three things end the chain:\n\t * 1. every queued/running pass of this file is cancelled server-side\n\t * (csr-cancel deletes a queued row and flags a running one \"cancelled\",\n\t * which is also the worker's gate for NOT enqueueing the next window);\n\t * 2. the file is remembered in cancelledIndexKeys, so the client-driven\n\t * resume (maybeResumeIndexing) stops dispatching CONTINUE passes; and\n\t * 3. any of its passes still sitting in bgTaskQueue is dropped by the next\n\t * drain rather than surfacing a fresh \"Indexing…\" bubble; and\n\t * 4. the RUN is remembered (state.stoppedIndexIds), because none of the above\n\t * necessarily leaves a mark on the conversation — see below — and without\n\t * it the collapsed row reported the stopped file as finished.\n\t *\n\t * Records already written by the passes that DID run are kept — this stops the\n\t * work, it does not undo it.\n\t */\n\tcancelIndexingGroup(group: IndexingGroup): void {\n\t\tvar self = this;\n\t\tif (!group || !group.key) return;\n\t\t// The group belongs to the chat on screen, so scope its key the same way\n\t\t// _indexKeyOf scopes a queued task's.\n\t\tvar scoped = this.getHistoryCacheKey() + '|' + group.key;\n\t\tthis.cancelledIndexKeys.add(scoped);\n\t\t// Remember WHICH RUN was stopped, by the ids of the passes it is made of.\n\t\t// Everything else here stops the work without leaving any mark on the\n\t\t// conversation: a running pass cannot be un-run (it finishes and writes an\n\t\t// ordinary answer), and a queued continuation is dropped before it is ever\n\t\t// surfaced — so a stopped run's newest bubble is routinely a successful pass,\n\t\t// and the row read \"Indexed\" over a file the user had just stopped. Ids, not\n\t\t// the file key, so a re-upload or Reindex of the same path is a new run with\n\t\t// new ids and starts clean; and on the reactive state so the row updates the\n\t\t// moment this is recorded, since a stop with nothing left to cancel changes\n\t\t// no message at all.\n\t\t//\n\t\t// Not for a run that is already OVER, though — you cannot stop what has\n\t\t// finished, and marking it stopped would relabel a fully-indexed file as\n\t\t// cancelled on the strength of a click that arrived too late. (`finished` is\n\t\t// only ever positively established: \"still running\" and \"we have not found\n\t\t// out\" both read as false here, so the doubt goes to recording the stop.)\n\t\tif (!group.finished) {\n\t\t\tvar stoppedIds: { [id: string]: boolean } = {};\n\t\t\tfor (var sk in this.state.stoppedIndexIds) stoppedIds[sk] = true;\n\t\t\t(group.members || []).forEach(function (m) {\n\t\t\t\tvar sid = m && m.msg && m.msg._serverItemId;\n\t\t\t\tif (sid) stoppedIds[sid] = true;\n\t\t\t});\n\t\t\t// The queue's own view of this file, which is not always the row's: an\n\t\t\t// entry can be waiting for its bubble, and the FIRST pass's entry outlives\n\t\t\t// the moment its bubble settles. _applyIndexCancellations reads this to\n\t\t\t// tell a pass that existed when the user hit Stop from a genuinely new\n\t\t\t// indexing request, and only the latter is allowed to lift the stop.\n\t\t\tthis.bgTaskQueue.forEach(function (e) {\n\t\t\t\tif (e && e.id && self._indexKeyOf(e) === scoped) stoppedIds[e.id] = true;\n\t\t\t});\n\t\t\tthis.state.stoppedIndexIds = stoppedIds;\n\t\t\t// Close the durable run:: record too — inside this !finished guard on\n\t\t\t// purpose, for the same reason as stoppedIndexIds: a stop that landed\n\t\t\t// after the run was over must not relabel an indexed file as cancelled.\n\t\t\t// Path over key: `key` degrades to a bare filename for path-less compact\n\t\t\t// stubs, and run:: is keyed by storage path only — no derivable path\n\t\t\t// means no record to close (restored stubs of old runs), which is fine.\n\t\t\tvar runPath = group.path || '';\n\t\t\tif (!runPath) {\n\t\t\t\t(group.members || []).some(function (m) {\n\t\t\t\t\tvar p = m && m.msg && m.msg._indexFile && m.msg._indexFile.path;\n\t\t\t\t\tif (p) { runPath = p; return true; }\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!runPath) {\n\t\t\t\tthis.bgTaskQueue.some(function (e) {\n\t\t\t\t\tif (e && e.storagePath && self._indexKeyOf(e) === scoped) { runPath = e.storagePath; return true; }\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (runPath) {\n\t\t\t\tvar ident = this.host.getIdentity();\n\t\t\t\tif (ident && ident.projectId) {\n\t\t\t\t\tupsertIndexRunRecordSafe(ident.projectId, runPath, { status: 'cancelled', finished: Date.now() });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Ask the QUEUE what else is live for this file, and cancel that too.\n\t\t//\n\t\t// The ids above are the passes THIS client knows about, and for a\n\t\t// worker-driven file that is routinely none of them: the worker mints the\n\t\t// next window itself and the client only learns its id on a later look. A\n\t\t// stop that reaches no server row at all is a stop that dies with the tab —\n\t\t// the chain keeps running, and the only record of the stop is this page's\n\t\t// memory. The adopt ladder is the existing machinery for exactly this\n\t\t// question; anything it turns up for a stopped file is dropped and\n\t\t// server-cancelled by _applyIndexCancellations on the next drain, which is\n\t\t// also what makes the worker stop enqueueing windows.\n\t\tthis._adoptWorkerIndexingPasses(0);\n\t\tvar ids = group.cancellableIds || [];\n\t\tif (!ids.length) { this.host.notify(); return; }\n\t\tids.forEach(function (serverId) {\n\t\t\t// Address the message by IDENTITY, not by the index captured when the\n\t\t\t// display list was built: an earlier cancel in this same loop may already\n\t\t\t// have spliced the array (a group can have more than one live pass), and a\n\t\t\t// stale index would mark the WRONG bubble as cancelling.\n\t\t\tvar idx = self.state.messages.findIndex(function (m) {\n\t\t\t\treturn m._serverItemId === serverId && m.role === 'user' &&\n\t\t\t\t\t(m.isPendingQueued || m.isPendingInProcess);\n\t\t\t});\n\t\t\tif (idx === -1) return;\n\t\t\tself.cancelQueuedMessage(self.state.messages[idx], idx);\n\t\t});\n\t}\n\n\t// --- typewriter -------------------------------------------------------\n\t// Reveal `fullText` into a message bubble at a constant wall-clock RATE\n\t// (chars/second) driven by requestAnimationFrame, rather than a fixed number\n\t// of characters per fixed-delay tick. This is what keeps typing smooth and\n\t// cheap on slow machines:\n\t//\n\t// * Each frame reveals `elapsed_ms * CHARS_PER_SEC` characters, so the\n\t// visual speed is the same regardless of how long a frame actually took.\n\t// * As the bubble's markdown grows, each re-render gets more expensive, so\n\t// frames get longer — which makes each frame reveal MORE characters and\n\t// therefore do FEWER, larger renders. That converts the old O(n^2)\n\t// \"re-render the whole growing string once per 3 characters\" (which got\n\t// slower and slower and pegged the CPU) into roughly O(n): the number of\n\t// renders self-throttles to what the machine can actually paint.\n\t// * rAF paces us to the browser's paint cycle and pauses in background\n\t// tabs, so we never queue work faster than it can be drawn.\n\ttypewriteIntoIndex(idx: number, fullText: string, localId?: string): Promise<void> {\n\t\tvar self = this;\n\t\tif (!fullText) return Promise.resolve();\n\n\t\tvar CHARS_PER_SEC = 300; // reveal rate (was ~188 = 3 chars / 16ms) — a bit faster\n\t\tvar MIN_STEP = 1; // always make progress, even on a sub-ms frame\n\t\tvar MAX_FRAME_MS = 1000; // cap catch-up after a long stall / backgrounded tab\n\n\t\t// Atomic regions that must never be left half-revealed: file fences\n\t\t// (shown as a download chip / hidden as \"[generating …]\" while unclosed —\n\t\t// and potentially huge, so revealed in one jump) and inline links\n\t\t// (a partial link is broken markdown). If a frame's reveal boundary lands\n\t\t// inside one, snap it to the region end so the chip/link appears whole.\n\t\tvar regions: Array<{ start: number; end: number }> = [], m;\n\t\tvar fenceRegex = /```[^\\n`]+?\\.[^\\s.`]+\\n[\\s\\S]*?```/g;\n\t\twhile ((m = fenceRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });\n\t\tvar linkRegex = createInlineLinkRegex();\n\t\twhile ((m = linkRegex.exec(fullText)) !== null) regions.push({ start: m.index, end: m.index + m[0].length });\n\t\tregions.sort(function (a, b) { return a.start - b.start; });\n\n\t\tthis.state.typing = true; this.state.typingAbort = false;\n\t\tvar i = 0;\n\t\tvar last = nowMs();\n\n\t\treturn new Promise<void>(function (resolve) {\n\t\t\tvar done = false;\n\t\t\tvar doc: any = _g.document;\n\t\t\tfunction isHidden(): boolean { return !!(doc && doc.hidden); }\n\t\t\tfunction cleanup(): void {\n\t\t\t\tif (doc && doc.removeEventListener) doc.removeEventListener('visibilitychange', onVisibility);\n\t\t\t}\n\t\t\tfunction finish(): void {\n\t\t\t\tif (done) return;\n\t\t\t\tdone = true;\n\t\t\t\tcleanup();\n\t\t\t\tif (!self.state.typingAbort) {\n\t\t\t\t\t// Re-find the bubble by localId and, if it's gone, bail WITHOUT\n\t\t\t\t\t// writing — never fall back to the numeric idx, which a concurrent\n\t\t\t\t\t// array mutation may have repurposed for an unrelated message\n\t\t\t\t\t// (mirrors frame()'s currentIdx===-1 bail below).\n\t\t\t\t\tvar fi = localId ? self.state.messages.findIndex(function (mm) { return mm._localId === localId; }) : idx;\n\t\t\t\t\tif (fi !== -1) {\n\t\t\t\t\t\tvar t = self.state.messages[fi];\n\t\t\t\t\t\tif (t) { t.content = fullText; self.host.refreshMessageBubble(fi); }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tself.state.typing = false;\n\t\t\t\tresolve();\n\t\t\t}\n\t\t\t// requestAnimationFrame is PAUSED in a backgrounded tab (setTimeout only\n\t\t\t// throttles), so an rAF-driven reveal would freeze there — leaving a blank\n\t\t\t// bubble and stalling the sequential enqueueTypewrite queue until refocus.\n\t\t\t// When the page is (or becomes) hidden, skip the animation and show the\n\t\t\t// full text immediately so the queue keeps draining.\n\t\t\tfunction onVisibility(): void { if (isHidden()) finish(); }\n\t\t\tif (doc && doc.addEventListener) doc.addEventListener('visibilitychange', onVisibility);\n\t\t\tfunction frame(t: number): void {\n\t\t\t\tif (done) return;\n\t\t\t\tif (self.state.typingAbort || i >= fullText.length || isHidden()) { finish(); return; }\n\n\t\t\t\tvar dt = t - last; last = t;\n\t\t\t\tif (!(dt > 0)) dt = 16; // first frame / clock glitch\n\t\t\t\tif (dt > MAX_FRAME_MS) dt = MAX_FRAME_MS;\n\t\t\t\tvar step = Math.round(dt * CHARS_PER_SEC / 1000);\n\t\t\t\tif (step < MIN_STEP) step = MIN_STEP;\n\t\t\t\tvar next = Math.min(fullText.length, i + step);\n\n\t\t\t\t// Extend past any atomic region the newly-revealed span (i, next]\n\t\t\t\t// cuts into. Iterate to convergence so back-to-back regions (e.g. a\n\t\t\t\t// link right after a fence) are all revealed whole in one frame.\n\t\t\t\tfor (var changed = true; changed;) {\n\t\t\t\t\tchanged = false;\n\t\t\t\t\tfor (var k = 0; k < regions.length; k++) {\n\t\t\t\t\t\tvar r = regions[k];\n\t\t\t\t\t\tif (next > r.start && i < r.end && r.end > next) { next = r.end; changed = true; }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (next > fullText.length) next = fullText.length;\n\t\t\t\ti = next;\n\n\t\t\t\tvar currentIdx = localId ? self.state.messages.findIndex(function (mm) { return mm._localId === localId; }) : idx;\n\t\t\t\tif (currentIdx === -1) { finish(); return; }\n\t\t\t\tvar target = self.state.messages[currentIdx];\n\t\t\t\tif (!target) { finish(); return; }\n\t\t\t\ttarget.content = fullText.slice(0, i);\n\t\t\t\tself.host.refreshMessageBubble(currentIdx);\n\t\t\t\tself.host.scrollToBottomIfSticky();\n\t\t\t\tnextFrame(frame);\n\t\t\t}\n\t\t\tif (isHidden()) { finish(); return; }\n\t\t\tnextFrame(frame);\n\t\t});\n\t}\n\n\tprivate typewriterQueue: Promise<any> = Promise.resolve();\n\tenqueueTypewrite(idx: number, fullText: string, localId?: string): Promise<any> {\n\t\tvar self = this;\n\t\t// Stamp the reply bubble's display time as it starts revealing. This is the\n\t\t// single chokepoint every typed reply (immediate, queued, and bg-resolution)\n\t\t// passes through, so it is where a live reply gets its \"when it arrived\"\n\t\t// timestamp; a history reload later replaces it with the server `updated`.\n\t\tvar target = this.state.messages[idx];\n\t\tif (target && target._ts === undefined) target._ts = wallClockNow();\n\t\tthis.typewriterQueue = this.typewriterQueue.then(function () { return self.typewriteIntoIndex(idx, fullText, localId); });\n\t\treturn this.typewriterQueue;\n\t}\n\n\t// --- cache+resume immediate-send rendering -----------------------------\n\t// Render the just-resolved reply (read from aiChatHistoryCache) into the\n\t// pending assistant bubble, character-by-character. Runs AFTER the reply is\n\t// already in the cache (dispatchAgentRequest appended it); errors are shown\n\t// instantly (no typing). Promotes the next queued message immediately so its\n\t// \"Thinking…\" bubble appears without waiting for this typewriter to finish.\n\ttypewriteLatestReply(key: string): Promise<any> {\n\t\tvar cached = this.aiChatHistoryCache[key];\n\t\tif (!cached || !cached.messages.length) return Promise.resolve();\n\t\tvar latest: ChatMessage | undefined;\n\t\tfor (var i = cached.messages.length - 1; i >= 0; i--) {\n\t\t\tvar m = cached.messages[i];\n\t\t\tif (m.role === 'assistant' && !m.isPending) { latest = m; break; }\n\t\t}\n\t\tif (!latest) return Promise.resolve();\n\t\tvar pendingIdx = this.state.messages.findIndex(function (mm) {\n\t\t\treturn mm.isPending && mm.role === 'assistant' && !mm.isBackgroundTask;\n\t\t});\n\t\tif (pendingIdx === -1) return Promise.resolve();\n\t\tif (latest.isError || !latest.content) {\n\t\t\tthis.state.messages[pendingIdx] = { role: 'assistant', content: latest.content || '', isError: !!latest.isError };\n\t\t\tthis._removeStrayPendingAssistants();\n\t\t\tthis.host.notify();\n\t\t\tthis.promoteNextQueuedToRunning();\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tvar lid = this._newLocalId();\n\t\tthis.state.messages[pendingIdx] = { role: 'assistant', content: '', isPending: false, _localId: lid };\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.host.notify();\n\t\tthis.promoteNextQueuedToRunning();\n\t\treturn this.enqueueTypewrite(pendingIdx, latest.content, lid);\n\t}\n\n\t// Remove leftover non-background pending (\"Thinking…\") assistant bubbles: the\n\t// duplicate that appears when a concurrent history refetch re-maps the still-\n\t// \"running\" turn into a pending placeholder (with a real _serverItemId) while the\n\t// local pending bubble (no _serverItemId) is rescued and re-appended (see the\n\t// loadHistory rescue below), and the orphan a resolve leaves when it splices its\n\t// reply beside a placeholder instead of into it. Each resolve path only replaces\n\t// ONE pending bubble, so without this a stray \"Thinking…\" survives forever next to\n\t// the reply. MUST run AFTER the resolved bubble has been made non-pending and\n\t// BEFORE promoteNext*() (which only adds a Thinking once none remains).\n\t//\n\t// It used to take EVERY one, on the premise that there is at most one at a time\n\t// because promoteNext* refuses to add a second. That premise never covered the\n\t// immediate-send path, which creates its pair directly — and a turn sent with\n\t// attachments does not block the composer and resolves on its own queue, so an\n\t// ordinary question asked while files index is in flight, with a placeholder of\n\t// its own, exactly when the attachment turn resolves. Sweeping it left that\n\t// question with no spinner and, worse, nowhere for its answer to land:\n\t// typewriteLatestReply bails when there is no pending assistant, so the reply\n\t// reached the cache and never the screen.\n\t//\n\t// The discriminator is the owning USER bubble. A live immediate send's user bubble\n\t// carries NO pending flags (its in-flight-ness lives in state.sending), while every\n\t// duplicate this sweep is for belongs to a user bubble that is still pending — and\n\t// an orphan has no user bubble above it at all.\n\t_removeStrayPendingAssistants(): void {\n\t\tfor (var k = this.state.messages.length - 1; k >= 0; k--) {\n\t\t\tvar m = this.state.messages[k];\n\t\t\tif (!m || !m.isPending || m.role !== 'assistant' || m.isBackgroundTask) continue;\n\t\t\tif (this._isLiveImmediatePlaceholder(k)) continue;\n\t\t\tthis.state.messages.splice(k, 1);\n\t\t}\n\t}\n\n\t/** Index of the USER bubble the message at `idx` belongs to — the nearest one\n\t * above it, stepping over background bubbles (a file's indexing rows are\n\t * inserted between turns). -1 when the nearest thing above is not a user turn,\n\t * which for a placeholder means it is an orphan. */\n\tprivate _owningUserIndex(idx: number): number {\n\t\tfor (var j = idx - 1; j >= 0; j--) {\n\t\t\tvar p = this.state.messages[j];\n\t\t\tif (!p) return -1;\n\t\t\tif (p.isBackgroundTask) continue;\n\t\t\treturn p.role === 'user' ? j : -1;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/** The bubble at `idx` is the \"Thinking…\" of a DIFFERENT turn that is still\n\t * waiting for its answer, so the sweep above must leave it alone. */\n\tprivate _isLiveImmediatePlaceholder(idx: number): boolean {\n\t\tvar ui = this._owningUserIndex(idx);\n\t\tif (ui === -1) return false; // orphan\n\t\tvar p = this.state.messages[ui];\n\t\t// Its own turn, still unanswered and not one of the pending duplicates: a live\n\t\t// immediate send's user bubble carries no pending flags at all.\n\t\treturn !p.isPending && !p.isPendingQueued && !p.isPendingInProcess &&\n\t\t\t!p.isPendingOlder && !p.isSendingToServer && !p.isCancelled;\n\t}\n\n\t/** A pending assistant at `idx` is the placeholder OF the turn above it, so a\n\t * reply may take its slot. Every path that makes one copies the parent's\n\t * _serverItemId (or neither has one yet), so a mismatch means the slot belongs to\n\t * some other request and the reply must be spliced in beside it, not on top. */\n\tprivate _isOwnPlaceholderOf(idx: number, userIdx: number): boolean {\n\t\tif (userIdx === -1) return false;\n\t\tvar ph = this.state.messages[idx], u = this.state.messages[userIdx];\n\t\tif (!ph || !u) return false;\n\t\tif (ph._serverItemId === undefined || u._serverItemId === undefined) return true;\n\t\treturn ph._serverItemId === u._serverItemId;\n\t}\n\n\t// Drop the pending flags on the resolved turn's USER bubble (preserving its\n\t// content + background-task marker). Needed because a bg \"Indexing:\" turn's user\n\t// bubble carries isPendingInProcess; leaving it set keeps the bubble visually\n\t// stuck and keeps its bgTaskQueue entry alive forever.\n\t_clearPendingUserBubble(itemId: string): void {\n\t\tvar uIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.role === 'user' && m._serverItemId === itemId &&\n\t\t\t\t(m.isPendingInProcess || m.isPendingQueued || m.isSendingToServer);\n\t\t});\n\t\tif (uIdx === -1) return;\n\t\tvar u = this.state.messages[uIdx];\n\t\tvar cleaned: ChatMessage = { role: 'user', content: u.content, _serverItemId: itemId };\n\t\tif (u.isBackgroundTask) cleaned.isBackgroundTask = true;\n\t\tif (u._ts !== undefined) cleaned._ts = u._ts;\n\t\t// Carry the file ref: it is what keeps this pass in its file's collapsed\n\t\t// row (the label parser is only a fallback for older cached bubbles).\n\t\tif (u._indexFile) cleaned._indexFile = u._indexFile;\n\t\tthis.state.messages[uIdx] = cleaned;\n\t}\n\n\t// If an immediate-send request for the current cache key is still in flight\n\t// (e.g. the view unmounted then remounted mid-request), show the sending\n\t// state, await it, then render the reply from the cache. Skipped when the\n\t// list already has its own pending/queued bubbles (those resolve via their\n\t// own polls). The displayed reply also lands via dispatchComposedMessage's\n\t// own finally if the view never unmounted — this is the remount recovery.\n\tresumePendingRequest(token: number): Promise<void> {\n\t\tvar self = this;\n\t\tvar key = this.getHistoryCacheKey();\n\t\tvar pending = key ? this.pendingAgentRequests[key] : undefined;\n\t\tif (!pending) return Promise.resolve();\n\t\tif (this.state.messages.some(function (m) { return (m.isPending || m.isPendingQueued) && !m.isBackgroundTask && !m._useBgQueue; })) return Promise.resolve();\n\t\tthis.state.sending = true;\n\t\tthis.host.scrollToBottomIfSticky(true);\n\t\treturn Promise.resolve(pending).catch(function () { }).then(function () {\n\t\t\tif (token !== self.state.gateRefreshToken) return;\n\t\t\tself.state.sending = false;\n\t\t\treturn Promise.resolve(self.typewriteLatestReply(key)).then(function () { self.host.scrollToBottomIfSticky(true); });\n\t\t});\n\t}\n\n\t// --- background-task resolution + drain -------------------------------\n\thandleHistoryItemResolution(itemId: string, response: any, platform: string): void {\n\t\t// Which file this turn was indexing, read BEFORE the resolution rewrites the\n\t\t// bubbles. Every settling turn funnels through here — the bg drain's own\n\t\t// poll, the history poll, and agent.vue's forked history poll, which calls\n\t\t// straight into this method — so hooking the chain follow-up here is what\n\t\t// makes it work in both clients without either of them forking a call site.\n\t\tvar indexRef = this._indexRefOfItem(itemId);\n\t\tthis.applyHistoryItemResolution(itemId, response, platform);\n\t\tthis.promoteNextBgQueuedToRunning();\n\t\t// applyHistoryItemResolution just released this item's poll slot. Under\n\t\t// MAX_CONCURRENT_BG_POLLS that slot is what the next-oldest unpolled entry\n\t\t// is waiting for, and every settling turn funnels through here — including\n\t\t// the history poll, whose resolution has no other path back to the drain.\n\t\tthis.drainBgTaskQueue();\n\t\t// A worker-driven chain has no client-side record of its next pass, so a\n\t\t// settling pass is the only moment there is to go looking for one.\n\t\tif (indexRef) this._followWorkerIndexingChain(indexRef.name, indexRef.mime);\n\t}\n\n\t/** The file an already-rendered background pass is about, off its request\n\t * bubble. Null for an ordinary turn, which is most of them. */\n\tprivate _indexRefOfItem(itemId: string): { name?: string; mime?: string } | null {\n\t\tif (!itemId) return null;\n\t\tfor (var i = 0; i < this.state.messages.length; i++) {\n\t\t\tvar m = this.state.messages[i];\n\t\t\tif (m._serverItemId !== itemId || m.role !== 'user' || !m.isBackgroundTask) continue;\n\t\t\treturn m._indexFile || null;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Settle a turn the server reports as cancelled: the request bubble goes to its\n\t * cancelled form and the \"Thinking...\" placeholder goes away. The same shape\n\t * cancelQueuedMessage produces locally, so a cancel this client made and one it\n\t * merely found out about render identically — and an indexing pass keeps the\n\t * markers that hold it in its file's collapsed row.\n\t */\n\tprivate _settleCancelledItem(itemId: string): void {\n\t\tvar uIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.role === 'user' && m._serverItemId === itemId && !m.isCancelled;\n\t\t});\n\t\tif (uIdx !== -1) {\n\t\t\tvar u = this.state.messages[uIdx];\n\t\t\tvar cancelled: ChatMessage = { role: 'user', content: u.content, isCancelled: true, _serverItemId: itemId };\n\t\t\tif (u.isBackgroundTask) cancelled.isBackgroundTask = true;\n\t\t\tif (u._indexFile) cancelled._indexFile = u._indexFile;\n\t\t\tif (u._useBgQueue) cancelled._useBgQueue = true;\n\t\t\tif (u._ownerKey !== undefined) cancelled._ownerKey = u._ownerKey;\n\t\t\tif (u._ts !== undefined) cancelled._ts = u._ts;\n\t\t\tthis.state.messages[uIdx] = cancelled;\n\t\t}\n\t\tvar pIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.isPending && m.role === 'assistant' && m._serverItemId === itemId;\n\t\t});\n\t\tif (pIdx !== -1) this.state.messages.splice(pIdx, 1);\n\t\tthis.cancelledServerIds.delete(itemId);\n\t\tthis._removeStrayPendingAssistants();\n\t\tthis.host.notify();\n\t\tthis.updateHistoryCache();\n\t}\n\n\t/**\n\t * A poll that came back saying the request was CANCELLED, rather than with an\n\t * answer.\n\t *\n\t * The server keeps a cancelled request as a terminal row instead of deleting it\n\t * (that row is the durable record of the stop, and the chat history it belongs\n\t * to), so a poll still running when the cancel lands now RESOLVES on it. It used\n\t * to reject with NOT_EXISTS, and the resolution path below reads a status object\n\t * as an answer with no text — which would stamp \"No text response received from\n\t * AI provider\" over a turn the user had just stopped.\n\t *\n\t * Reachable whenever the poll was not stopped by whoever cancelled: another tab,\n\t * another device, or the row being cancelled server-side by the file's own stop.\n\t */\n\tprivate _isCancelledPollResult(response: any): boolean {\n\t\tif (!response || typeof response !== 'object' || response.status !== 'cancelled') return false;\n\t\t// The POLL's own shape (id + queue fields, no provider payload), not a\n\t\t// provider body that happens to carry a `status` — OpenAI's Responses API\n\t\t// has a \"cancelled\" status of its own, and that one is an answer to render,\n\t\t// not a row that was removed from the queue.\n\t\tif (response.content !== undefined || response.output !== undefined) return false;\n\t\treturn response.queue_name !== undefined || response.in_queue !== undefined;\n\t}\n\n\tapplyHistoryItemResolution(itemId: string, response: any, platform: string): void {\n\t\tthis.historyItemPolls.delete(itemId);\n\t\tif (this._isCancelledPollResult(response)) {\n\t\t\tthis._settleCancelledItem(itemId);\n\t\t\treturn;\n\t\t}\n\t\tvar isErr = isErrorResponseBody(response);\n\t\tvar answer = isErr ? getErrorMessage(response)\n\t\t\t: ((platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '').trim();\n\t\t// Record the marker BEFORE hiding it from the displayed summary: the display\n\t\t// layer needs it as a structured fact, and searching the shown text for it\n\t\t// afterwards would find nothing. Mirrors history.ts, so a run reads the same\n\t\t// live and after a reload.\n\t\t//\n\t\t// The STRIP happens in the background branches only, not here. It used to run\n\t\t// on every answer, so an ordinary chat reply that merely mentioned the token\n\t\t// had it silently cut out of the user's text (leaving a double space) — and\n\t\t// the history mappers never did that, so the same reply read differently\n\t\t// before and after a reload. Only an INDEXING pass has a protocol token to\n\t\t// hide.\n\t\tvar reportedComplete = !isErr && !!answer && answer.indexOf(INDEXING_COMPLETE_MARKER) !== -1;\n\t\tvar stripMarker = function (t: string): string {\n\t\t\treturn reportedComplete ? t.split(INDEXING_COMPLETE_MARKER).join('').trim() : t;\n\t\t};\n\t\tvar idx = this.state.messages.findIndex(function (m) { return m.isPending && m._serverItemId === itemId; });\n\t\tif (idx !== -1) {\n\t\t\t// A bg \"Indexing:\" turn pushes a user bubble (isPendingInProcess) ALONGSIDE\n\t\t\t// the assistant Thinking; replacing only the assistant leaves that user\n\t\t\t// bubble stuck pending — and drainBgTaskQueue then never clears its queue\n\t\t\t// entry (its stillPending check stays true). Un-pend it here too.\n\t\t\tthis._clearPendingUserBubble(itemId);\n\t\t\t// Carry isBackgroundTask onto the REPLACEMENT. These rebuilds are fresh\n\t\t\t// object literals, so anything not copied is lost — and dropping this flag\n\t\t\t// made a pass that resolved LIVE fall out of its file's collapsed row\n\t\t\t// (buildChatDisplayList only considers isBackgroundTask messages), while\n\t\t\t// the same pass rebuilt from history stayed grouped. That mismatch is the\n\t\t\t// \"new indexing response renders outside the group\" bug.\n\t\t\tvar wasBgTask = !!this.state.messages[idx].isBackgroundTask;\n\t\t\tif (isErr) {\n\t\t\t\tthis.state.messages[idx] = { role: 'assistant', content: answer, isError: true, _serverItemId: itemId };\n\t\t\t\tif (wasBgTask) this.state.messages[idx].isBackgroundTask = true;\n\t\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t\t}\n\t\t\tvar text = answer || 'No text response received from AI provider.';\n\t\t\t// A background-indexing reply is INSIDE a collapsed row: nothing of it is\n\t\t\t// on screen. Typewriting it anyway put it on the one shared, serial\n\t\t\t// typewriter queue, so the user's own next reply — which IS on screen —\n\t\t\t// lost its \"Thinking...\" spinner and sat as an EMPTY bubble for however\n\t\t\t// long the invisible indexing summary took to reveal (seconds per pass,\n\t\t\t// additive across files). It also held state.typing true for the whole\n\t\t\t// time, which disables the platform/model pickers and no-ops Clear\n\t\t\t// history, and ran a per-frame scroll for content nobody can see.\n\t\t\t// Write it straight in; expanding the row then shows it complete.\n\t\t\tif (wasBgTask) {\n\t\t\t\tthis.state.messages[idx] = { role: 'assistant', content: stripMarker(text) || EMPTY_INDEXING_REPLY, isBackgroundTask: true, _serverItemId: itemId, ...(reportedComplete ? { _indexComplete: true } : {}) };\n\t\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t\t}\n\t\t\tvar lid = this._newLocalId();\n\t\t\tthis.state.messages[idx] = { role: 'assistant', content: '', _localId: lid, _serverItemId: itemId };\n\t\t\tthis.host.notify(); this.enqueueTypewrite(idx, text, lid);\n\t\t\tthis.updateHistoryCache(); return;\n\t\t}\n\t\tvar userIdx = this.state.messages.findIndex(function (m) {\n\t\t\treturn m.role === 'user' && m._serverItemId === itemId && (m.isPendingQueued || m.isPendingInProcess);\n\t\t});\n\t\tif (userIdx === -1) return;\n\t\tvar ex = this.state.messages[userIdx];\n\t\t// Same carry-over as above, plus _indexFile / _useBgQueue: this rebuild is\n\t\t// what keeps an indexing REQUEST bubble in its file's collapsed row (and a\n\t\t// bg-queued chat cancelling against the right queue) once the pass settles.\n\t\tvar settledUser: ChatMessage = { role: 'user', content: ex.content, _serverItemId: itemId };\n\t\tif (ex.isBackgroundTask) settledUser.isBackgroundTask = true;\n\t\tif (ex._ts !== undefined) settledUser._ts = ex._ts;\n\t\tif (ex._indexFile) settledUser._indexFile = ex._indexFile;\n\t\tif (ex._useBgQueue) settledUser._useBgQueue = true;\n\t\tthis.state.messages[userIdx] = settledUser;\n\t\tif (isErr) {\n\t\t\tvar errReply: ChatMessage = { role: 'assistant', content: answer, isError: true, _serverItemId: itemId };\n\t\t\tif (ex.isBackgroundTask) errReply.isBackgroundTask = true;\n\t\t\tthis.state.messages.splice(userIdx + 1, 0, errReply);\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar text2 = answer || 'No text response received from AI provider.';\n\t\t// Same as above: a collapsed row's reply is not on screen, so revealing it\n\t\t// character by character only blocks the queue the visible reply needs.\n\t\tif (ex.isBackgroundTask) {\n\t\t\tthis.state.messages.splice(userIdx + 1, 0, { role: 'assistant', content: stripMarker(text2) || EMPTY_INDEXING_REPLY, isBackgroundTask: true, _serverItemId: itemId, ...(reportedComplete ? { _indexComplete: true } : {}) });\n\t\t\tthis.host.notify(); this.updateHistoryCache(); return;\n\t\t}\n\t\tvar lid2 = this._newLocalId();\n\t\tvar reply: ChatMessage = { role: 'assistant', content: '', _localId: lid2, _serverItemId: itemId };\n\t\tthis.state.messages.splice(userIdx + 1, 0, reply);\n\t\tthis.host.notify(); this.enqueueTypewrite(userIdx + 1, text2, lid2);\n\t\tthis.updateHistoryCache();\n\t}\n\n\t/** How a bg task maps onto a collapsed row: the row's own key (storage path\n\t * when known, else the filename), scoped to the chat it belongs to. A storage\n\t * path is project-relative (\"report.xlsx\"), and ONE ChatSession serves every\n\t * project — unscoped, stopping a file in one project would silently suppress\n\t * the same filename's continuations in another. */\n\tprivate _indexKeyOf(entry: BgTaskEntry): string {\n\t\tif (!entry) return '';\n\t\tvar file = entry.storagePath || entry.filename;\n\t\tif (!file) return '';\n\t\treturn entry.projectId + '#' + entry.platform + '|' + file;\n\t}\n\n\t/**\n\t * Reconcile the bg queue with the files the user has stopped.\n\t *\n\t * A FIRST pass (no resumePass) is a fresh indexing request — a re-upload, or a\n\t * Reindex from the file manager — so it LIFTS the stop: the key is a storage\n\t * path, and without this an earlier cancel would silently kill every future\n\t * index of the same path. A continuation of a stopped file is dropped instead,\n\t * covering the pass that was dispatched in the moment before the cancel landed.\n\t *\n\t * \"Fresh\" is the load-bearing word, and it used to be missing. A run's OWN first\n\t * pass sits in this queue for as long as it runs (entries are only dropped once\n\t * their bubble settles), so stopping a file during its first pass — which is\n\t * exactly when a user who has just uploaded it does — met that first-pass entry\n\t * on the very next drain and lifted the stop the user had just asked for. The\n\t * chain then carried on, one worker-minted window after another, with nothing\n\t * client-side left to suppress it. The ids recorded at stop time are what tells\n\t * the two apart: a pass that was already there when the user hit Stop cannot be\n\t * the new request that lifts it.\n\t */\n\tprivate _applyIndexCancellations(): void {\n\t\tif (!this.cancelledIndexKeys.size) return;\n\t\t// Passes already on screen. Dropping the queue entry for one of those kills\n\t\t// its poll and leaves the bubble pending forever — a row stuck on \"Indexing\"\n\t\t// with no way to ever settle. _sweepCancelledIndexing (which runs straight\n\t\t// after this, on the same drain) cancels those properly, rebuilding the bubble\n\t\t// as cancelled; the splice below is only right for an entry with no bubble yet.\n\t\tvar surfaced: { [id: string]: boolean } = {};\n\t\tthis.state.messages.forEach(function (m) {\n\t\t\tif (!m._serverItemId) return;\n\t\t\tif (m.isPending || m.isPendingQueued || m.isPendingInProcess) surfaced[m._serverItemId] = true;\n\t\t});\n\t\tfor (var i = this.bgTaskQueue.length - 1; i >= 0; i--) {\n\t\t\tvar entry = this.bgTaskQueue[i];\n\t\t\tvar key = this._indexKeyOf(entry);\n\t\t\tif (!key || !this.cancelledIndexKeys.has(key)) continue;\n\t\t\tif (!entry.resumePass && !this.state.stoppedIndexIds[entry.id]) {\n\t\t\t\tthis.cancelledIndexKeys.delete(key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (surfaced[entry.id]) continue;\n\t\t\tthis.bgTaskQueue.splice(i, 1);\n\t\t\tthis._stopPoll(entry.id);\n\t\t\tthis._cancelServerItem(entry.id);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel any live pass of a stopped file that turned up on its own.\n\t *\n\t * The client is not the only thing that continues a file: for PDFs and (when\n\t * windowed indexing is on) text/grid files the WORKER enqueues the next window\n\t * itself, and that pass reaches the chat through the history poll, never\n\t * through bgTaskQueue. The worker's own gate stops the chain when the running\n\t * row is cancelled — but if the row had already finished when the user hit\n\t * stop, the next window was queued a moment earlier and still arrives. Stop it\n\t * here rather than making the user hit stop again.\n\t *\n\t * Runs from drainBgTaskQueue, which both clients call after a history load.\n\t */\n\tprivate _sweepCancelledIndexing(): void {\n\t\tif (!this.cancelledIndexKeys.size) return;\n\t\tvar self = this;\n\t\tvar chatKey = this.getHistoryCacheKey();\n\t\tvar targets: { msg: ChatMessage; idx: number }[] = [];\n\t\tthis.state.messages.forEach(function (m, i) {\n\t\t\tif (!m.isBackgroundTask || m.role !== 'user' || !m._serverItemId) return;\n\t\t\tif (m._cancelling || m.isSendingToServer) return;\n\t\t\tif (!(m.isPendingQueued || m.isPendingInProcess)) return;\n\t\t\tvar ref = m._indexFile;\n\t\t\tvar file = ref && (ref.path || ref.name);\n\t\t\tif (!file || !self.cancelledIndexKeys.has(chatKey + '|' + file)) return;\n\t\t\ttargets.push({ msg: m, idx: i });\n\t\t});\n\t\ttargets.forEach(function (t) {\n\t\t\tvar idx = self.state.messages.indexOf(t.msg);\n\t\t\tself.cancelQueuedMessage(t.msg, idx === -1 ? t.idx : idx);\n\t\t});\n\t}\n\n\t/**\n\t * True when the WORKER, not this client, drives the rest of this file's chain.\n\t * The mirror image of the early returns in maybeResumeIndexing: whatever that\n\t * refuses to continue is exactly what nothing client-side is tracking.\n\t */\n\tprivate _isWorkerDrivenIndexing(filename?: string, mime?: string): boolean {\n\t\tif (!isPagedReadFile(filename, mime)) return false;\n\t\tif (isImageVisionFile(filename, mime)) return true;\n\t\treturn windowedIndexingEnabled() && isWindowedReadFile(filename, mime);\n\t}\n\n\t/**\n\t * Pick up indexing passes the WORKER minted, which no client ever dispatched.\n\t *\n\t * For a PDF (and for text/grid when windowed indexing is on) the worker writes\n\t * pass N+1's row itself, inside pass N's invocation, right after saving pass\n\t * N's result. That row reaches this client through nothing at all: it is not in\n\t * bgTaskQueue (the client never asked for it) and it is not in state.messages\n\t * (only a first-page history load maps it in, which happens on mount, project\n\t * switch or tab return). So between two worker passes every pass the client\n\t * knows about is settled, and the collapsed row renders \"Indexed N passes\"\n\t * with no spinner and no Stop, for a file that is still being read. A user who\n\t * believes that then asks questions against a half-indexed file — which is what\n\t * this exists to prevent.\n\t *\n\t * So when a background indexing pass settles, ask the bg queue what is still\n\t * unresolved on it and adopt anything unknown as an ordinary BgTaskEntry.\n\t * drainBgTaskQueue then treats it exactly like a pass this client dispatched:\n\t * same bubble, same `_indexFile` (so it joins the file's collapsed row), same\n\t * poll — and that poll settling runs this again, so the chain is followed to\n\t * its end. `status`-scoped so the reply carries the live items only, never a\n\t * page of finished ones with their bodies.\n\t *\n\t * Termination: the only trigger is a pass SETTLING, which happens once per\n\t * pass. An adopted item that is still running is not re-adopted (its id is\n\t * already polled), and when the queue holds nothing unknown the chain stops on\n\t * its own. Nothing here is periodic — a timer that re-reads history is the\n\t * shape that previously looped fetchHistoryPage after an already-DONE index.\n\t */\n\tprivate _adoptingWorkerPasses = false;\n\tprivate _adoptWorkerIndexingPasses(attempt: number, passive?: boolean): void {\n\t\tvar self = this;\n\t\t// One in flight at a time. The query is queue-WIDE, so a second file's pass\n\t\t// settling in the same moment is covered by the query already running.\n\t\tif (this._adoptingWorkerPasses) return;\n\t\tvar id = this.host.getIdentity();\n\t\tvar platform = id.platform;\n\t\tif (!id.projectId || (platform !== 'claude' && platform !== 'openai')) return;\n\t\tif (this.isPollingPaused() || !this.host.isViewMounted()) return;\n\t\tvar svcId = id.projectId, owner = id.owner;\n\t\tvar queue = bgIndexingQueueName(id.userId, id.projectId);\n\t\t// maxAgeMs 0: adoption exists to notice passes the worker JUST minted,\n\t\t// so it must always look fresh — but its answers write through into the\n\t\t// shared probe memo, which is what keeps the snapshot readers (and the\n\t\t// db-files page's badge probe) from re-asking seconds later.\n\t\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(probeBgQueue(\n\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status, limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t{ maxAgeMs: 0 },\n\t\t\t)).then(function (entry) { return entry.result; }).catch(function () { return null; });\n\t\t};\n\t\tthis._adoptingWorkerPasses = true;\n\t\tPromise.all([ask('running'), ask('pending')]).then(function (results: any[]) {\n\t\t\tself._adoptingWorkerPasses = false;\n\t\t\t// The chat may have changed under the query; adopting into another\n\t\t\t// project's session is the cross-project bubble leak all over again.\n\t\t\tvar now = self.host.getIdentity();\n\t\t\tif (now.projectId !== svcId || now.platform !== platform) return;\n\t\t\tif (!self.host.isViewMounted()) return;\n\t\t\t// Free: this is already the whole-queue snapshot the display layer needs to\n\t\t\t// tell a worker-driven run's \"between passes\" from its \"finished\".\n\t\t\t//\n\t\t\t// A null is a FAILED query, and the adoption loop below reads it as an empty\n\t\t\t// list — harmless there (nothing to adopt) but not here: recording it would\n\t\t\t// publish \"the queue holds nothing\" on the strength of a request that never\n\t\t\t// answered, which reads as finished. Not knowing is the honest state.\n\t\t\tif (results[0] !== null && results[1] !== null) self._recordLiveIndexKeys(results);\n\t\t\tvar adoptedIds: string[] = [];\n\t\t\tfor (var ri = 0; ri < results.length; ri++) {\n\t\t\t\tvar list = results[ri] && Array.isArray(results[ri].list) ? results[ri].list : [];\n\t\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\t\tif (self._adoptWorkerIndexingItem(list[i], svcId, platform as 'claude' | 'openai')) adoptedIds.push(list[i].id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (adoptedIds.length) {\n\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\t// Only an item the drain KEPT means the chain is still going. One it\n\t\t\t\t// threw straight back out is not progress and must not end the ladder:\n\t\t\t\t// the status index is eventually consistent, so a look taken the\n\t\t\t\t// instant a pass settles can still report that pass as running, and a\n\t\t\t\t// pass belonging to a file the user stopped is dropped on sight. Both\n\t\t\t\t// used to read as \"found the next pass\", which ended the search for a\n\t\t\t\t// pass that had not been written yet.\n\t\t\t\tif (self._isTrackingAny(adoptedIds)) return;\n\t\t\t}\n\t\t\t// Nothing yet. The worker writes pass N+1 a few milliseconds AFTER it\n\t\t\t// flips pass N to resolved, so a poll that lands in that gap sees an\n\t\t\t// empty queue for a chain that is very much alive — and with no pass\n\t\t\t// left to settle, nothing would ever ask again. Look once or twice more\n\t\t\t// before believing the file is finished.\n\t\t\t//\n\t\t\t// PASSIVE calls (first-page/resume refresh) climb only on EVIDENCE of\n\t\t\t// live work — a queued local entry for this project, a live key the\n\t\t\t// look above just recorded, or an attached poll. The gap rationale\n\t\t\t// presumes a chain was alive; with nothing suggesting one, the climb\n\t\t\t// re-asked an unchanged question three more times on every tab return.\n\t\t\t// (No nudge here either: a send waiting on indexing implies local\n\t\t\t// entries, which IS evidence, so the passive stop never starves it.)\n\t\t\tif (passive && !self._hasLiveIndexEvidence(svcId)) return;\n\t\t\tif (attempt + 1 >= WORKER_PASS_ADOPT_ATTEMPTS.length) {\n\t\t\t\t// The ladder is the only thing that can tell a worker-driven chain has\n\t\t\t\t// really ended, and it just did. This is the earliest honest moment to\n\t\t\t\t// let a turn waiting on these files stop waiting.\n\t\t\t\tself._nudgeIndexingDrain();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetTimeout(function () {\n\t\t\t\tvar later = self.host.getIdentity();\n\t\t\t\tif (later.projectId !== svcId || later.platform !== platform) return;\n\t\t\t\tif (self.isPollingPaused() || !self.host.isViewMounted()) return;\n\t\t\t\tself._adoptWorkerIndexingPasses(attempt + 1, passive);\n\t\t\t}, WORKER_PASS_ADOPT_ATTEMPTS[attempt + 1]);\n\t\t}, function () { self._adoptingWorkerPasses = false; });\n\t}\n\n\t/** Anything at all suggesting THIS project's indexing may be live: a queued\n\t * local entry, a recorded live key (the adopt look just wrote them), or an\n\t * attached poll. Gates the passive adopt ladder's climb. */\n\tprivate _hasLiveIndexEvidence(svcId: string): boolean {\n\t\tfor (var i = 0; i < this.bgTaskQueue.length; i++) {\n\t\t\tvar e = this.bgTaskQueue[i];\n\t\t\tif (e && e.projectId === svcId) return true;\n\t\t}\n\t\tvar keys = this.state.liveIndexKeys || {};\n\t\tfor (var k in keys) { if (keys[k]) return true; }\n\t\t// BG polls only: a pending ORDINARY chat turn also holds a poll, and\n\t\t// counting it made every tab return during a conversation climb the\n\t\t// full passive ladder for indexing that does not exist.\n\t\tvar found = false;\n\t\tthis.historyItemPolls.forEach(function (h: any) { if (h && h.kind === 'bg') found = true; });\n\t\treturn found;\n\t}\n\n\t/** Any of these ids still queued or still polled, i.e. surviving work. */\n\tprivate _isTrackingAny(ids: string[]): boolean {\n\t\tfor (var i = 0; i < ids.length; i++) {\n\t\t\tif (this.historyItemPolls.has(ids[i])) return true;\n\t\t\tfor (var q = 0; q < this.bgTaskQueue.length; q++) {\n\t\t\t\tif (this.bgTaskQueue[q].id === ids[i]) return true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** One live bg-queue item -> a BgTaskEntry, if it is an indexing pass this\n\t * client is not already tracking. Returns whether it was adopted. */\n\tprivate _adoptWorkerIndexingItem(item: any, svcId: string, platform: 'claude' | 'openai'): boolean {\n\t\tif (!item || typeof item.id !== 'string' || !item.id) return false;\n\t\tif (item.status !== 'pending' && item.status !== 'running') return false;\n\t\tif (typeof item.poll !== 'function') return false;\n\t\t// Already known: a pass this client dispatched, or one adopted earlier that\n\t\t// has not settled yet. Adopting twice would stack a second poll on one item.\n\t\tif (this.historyItemPolls.has(item.id)) return false;\n\t\tfor (var q = 0; q < this.bgTaskQueue.length; q++) {\n\t\t\tif (this.bgTaskQueue[q].id === item.id) return false;\n\t\t}\n\t\t// Already SETTLED here. The status index is eventually consistent, so the\n\t\t// pass that just finished can still come back as running; re-adopting it\n\t\t// would re-poll a dead item and, worse, read as the chain continuing.\n\t\tfor (var m = 0; m < this.state.messages.length; m++) {\n\t\t\tvar msg = this.state.messages[m];\n\t\t\tif (msg._serverItemId !== item.id) continue;\n\t\t\tif (!(msg.isPending || msg.isPendingInProcess || msg.isPendingQueued)) return false;\n\t\t}\n\t\t// The bg queue also carries ordinary chats routed onto it (_isOnBgQueue), and\n\t\t// both platforms share one queue name, so check the shape as well: a claude\n\t\t// request body has `messages`, an openai one has `input`. Adopting the other\n\t\t// platform's item would poll it against this platform's url.\n\t\tvar body = item.request_body;\n\t\tif (!body || typeof body !== 'object') return false;\n\t\tif (platform === 'claude' ? !Array.isArray((body as any).messages) : !Array.isArray((body as any).input)) return false;\n\t\tvar userText = extractLastUserTextFromRequest(body);\n\t\tif (!isIndexingRequestText(userText)) return false;\n\t\tvar ref = parseIndexingRequestText(userText);\n\t\tif (!ref || !ref.name) return false;\n\t\t// Only chains the worker drives. A client-driven file is already tracked by\n\t\t// the entry that dispatched it, and adopting a copy of it would hand\n\t\t// maybeResumeIndexing an entry whose resumePass no longer counts that\n\t\t// chain's passes — which is the cap that stops it running forever.\n\t\tif (!this._isWorkerDrivenIndexing(ref.name, ref.mime)) return false;\n\t\tthis.bgTaskQueue.push({\n\t\t\tprojectId: svcId,\n\t\t\tplatform: platform,\n\t\t\tid: item.id,\n\t\t\tfilename: ref.name,\n\t\t\tstoragePath: ref.path,\n\t\t\tmime: ref.mime,\n\t\t\tsize: ref.size,\n\t\t\tstatus: item.status === 'running' ? 'running' : 'pending',\n\t\t\tpoll: item.poll,\n\t\t\t// Drives the \"(continuing)\" label and marks this as a continuation for\n\t\t\t// _applyIndexCancellations, which must not read a CONTINUE pass as the\n\t\t\t// fresh first pass that lifts a stop.\n\t\t\tresumePass: ref.continued ? 1 : 0,\n\t\t});\n\t\treturn true;\n\t}\n\n\t/** Follow the chain on from a background indexing pass that just settled. */\n\tprivate _followWorkerIndexingChain(filename?: string, mime?: string): void {\n\t\tif (!this._isWorkerDrivenIndexing(filename, mime)) return;\n\t\tthis._adoptWorkerIndexingPasses(0);\n\t}\n\n\t/** Best-effort server-side cancel of a bg-queue item that has no bubble (so\n\t * cancelQueuedMessage, which drives one, has nothing to act on). */\n\tprivate _cancelServerItem(serverId: string): void {\n\t\tvar id = this.host.getIdentity();\n\t\tif (!serverId || (id.platform !== 'claude' && id.platform !== 'openai')) return;\n\t\tvar url = id.platform === 'claude' ? ANTHROPIC_MESSAGES_API_URL : OPENAI_RESPONSES_API_URL;\n\t\tPromise.resolve(this.host.cancelRequest({\n\t\t\turl: url, method: 'POST', id: serverId,\n\t\t\tqueue: bgIndexingQueueName(id.userId, id.projectId),\n\t\t\tservice: id.projectId, owner: id.owner,\n\t\t})).catch(function () { /* the pass may already have finished; nothing to do */ });\n\t}\n\n\t// Inject \"Indexing: <file>\" bubbles for queued bg tasks + attach their polls.\n\tdrainBgTaskQueue(): void {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\tvar svcId = id.projectId, plat = id.platform;\n\t\tif (!svcId || plat === 'none' || !this.host.isViewMounted()) return;\n\t\t// Before anything is surfaced: drop continuations of files the user stopped\n\t\t// (and let a fresh first pass lift the stop), then cancel any worker-queued\n\t\t// pass of a stopped file that reached the chat through history.\n\t\tthis._applyIndexCancellations();\n\t\tthis._sweepCancelledIndexing();\n\t\t// Index messages by _serverItemId ONCE, so the per-entry presence/pending\n\t\t// checks below are O(1) instead of a full messages.some() scan each. With a\n\t\t// large bg queue (bulk uploads) the old nested scan was O(queue x messages)\n\t\t// per drain, and the drain runs once per uploaded file (O(n^3) overall).\n\t\tvar presentIds: { [id: string]: boolean } = {};\n\t\tvar pendingIds: { [id: string]: boolean } = {};\n\t\tthis.state.messages.forEach(function (m) {\n\t\t\tvar sid = m._serverItemId;\n\t\t\tif (sid == null) return;\n\t\t\tpresentIds[sid] = true;\n\t\t\tif (m.isPending || m.isPendingInProcess || m.isPendingQueued) pendingIds[sid] = true;\n\t\t});\n\t\tfor (var i = this.bgTaskQueue.length - 1; i >= 0; i--) {\n\t\t\tvar e = this.bgTaskQueue[i];\n\t\t\tif (e.projectId !== svcId || e.platform !== plat) continue;\n\t\t\tif (presentIds[e.id] && !pendingIds[e.id]) {\n\t\t\t\t// Settled while nobody was polling (hidden tab, dead poll): the\n\t\t\t\t// answer reached the chat as HISTORY, so no settle handler ever\n\t\t\t\t// ran for this entry — maybeResumeIndexing's flips included. For\n\t\t\t\t// a single-pass file that settle IS the whole run; close its\n\t\t\t\t// records off the settled bubbles' own flags before the entry\n\t\t\t\t// goes. (8 of 10 files in a real batch hit exactly this.)\n\t\t\t\tthis._flipRunFromSettledEntry(e);\n\t\t\t\tthis.bgTaskQueue.splice(i, 1);\n\t\t\t}\n\t\t}\n\t\t// Poll budget for this drain (see MAX_CONCURRENT_BG_POLLS). bgTaskQueue is\n\t\t// in push order, i.e. oldest first, which is also the order the server\n\t\t// settles them in — so spending the budget from the front spends it on the\n\t\t// only entries that can resolve next. Bubbles are still injected for EVERY\n\t\t// entry; only the polling is rationed, and an unpolled entry picks up a\n\t\t// poll on the drain that follows the next resolution.\n\t\tvar bgPollBudget = MAX_CONCURRENT_BG_POLLS - this._countBgPolls();\n\t\t// Set by the injection branch; drives the single render/cache/scroll below.\n\t\tvar injectedAny = false;\n\t\tthis.bgTaskQueue.forEach(function (entry) {\n\t\t\tif (entry.projectId !== svcId || entry.platform !== plat) return;\n\t\t\t// Bubble injection and poll attachment are INDEPENDENT. An entry whose bubble\n\t\t\t// already exists may still need a poll — that is exactly the state a paused\n\t\t\t// drain leaves behind, and returning early here stranded it as a permanent\n\t\t\t// \"Thinking...\" once polling resumed.\n\t\t\tif (!presentIds[entry.id]) {\n\t\t\tvar isRunning = entry.status === 'running';\n\t\t\tvar userBubble: ChatMessage = {\n\t\t\t\trole: 'user',\n\t\t\t\tcontent: self.host.formatIndexingLabel(entry.filename, entry.mime, entry.size, entry.storagePath, entry.isReindex, !!entry.resumePass),\n\t\t\t\tisBackgroundTask: true,\n\t\t\t\t_serverItemId: entry.id,\n\t\t\t\t// Structured ref so this live pass groups with the same file's passes\n\t\t\t\t// rebuilt from history (see indexing_groups.buildChatDisplayList).\n\t\t\t\t_indexFile: {\n\t\t\t\t\tname: entry.filename,\n\t\t\t\t\tpath: entry.storagePath,\n\t\t\t\t\tmime: entry.mime,\n\t\t\t\t\tsize: entry.size,\n\t\t\t\t\tisReindex: !!entry.isReindex,\n\t\t\t\t\tcontinued: !!entry.resumePass,\n\t\t\t\t},\n\t\t\t};\n\t\t\tif (isRunning) userBubble.isPendingInProcess = true; else userBubble.isPendingQueued = true;\n\t\t\t// Directly ABOVE the chat turn these files were attached to, when that turn\n\t\t\t// is still on screen as a staged bubble. The row then appears where it\n\t\t\t// belongs from the start — right before the message the files came with,\n\t\t\t// which is also the order the server reports once the turn is sent (its\n\t\t\t// request id is newer than every pass it waits for). Appending instead put\n\t\t\t// the row BELOW the message and left the turn to be moved down past it at\n\t\t\t// dispatch, minutes later: a swap under the reader, at the one moment they\n\t\t\t// were watching for the turn to go out.\n\t\t\t//\n\t\t\t// -1 (no stage id, or a staged bubble already replaced/rebuilt away) appends,\n\t\t\t// which is the old behaviour and the right one for work with no chat turn\n\t\t\t// behind it: the dbfile page, an attachment-only send, a worker-adopted pass.\n\t\t\t// Resolved PER ENTRY: one drain can inject several passes, and a hoisted\n\t\t\t// index would insert each one before the last and reverse them.\n\t\t\tvar stageAt = self._stageIndex(self.state.messages, entry.stageId);\n\t\t\tvar runningBubble: ChatMessage | null = isRunning\n\t\t\t\t? { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, isBackgroundTask: true, _serverItemId: entry.id }\n\t\t\t\t: null;\n\t\t\tif (stageAt === -1) {\n\t\t\t\tself.state.messages.push(userBubble);\n\t\t\t\tif (runningBubble) self.state.messages.push(runningBubble);\n\t\t\t} else if (runningBubble) {\n\t\t\t\t// One splice, so the request and its placeholder stay ADJACENT: an\n\t\t\t\t// id-less response bubble is attributed to the message immediately\n\t\t\t\t// above it (indexing_groups) and replies are spliced at userIdx + 1.\n\t\t\t\tself.state.messages.splice(stageAt, 0, userBubble, runningBubble);\n\t\t\t} else {\n\t\t\t\t// AT the staged bubble, so this pass lands after any pass already\n\t\t\t\t// inserted for the same turn — files keep their upload order.\n\t\t\t\tself.state.messages.splice(stageAt, 0, userBubble);\n\t\t\t}\n\t\t\tpresentIds[entry.id] = true; // keep the index consistent with the pushed bubbles\n\t\t\t// Render/cache/scroll are hoisted OUT of this loop (see injectedAny below).\n\t\t\t// They used to run per injected entry, and updateHistoryCache filters the\n\t\t\t// whole of state.messages into a fresh array each call — so a bulk upload\n\t\t\t// injecting one bubble per file did O(files x messages) element visits and\n\t\t\t// left one throwaway array per file for the GC. In the widget it was worse\n\t\t\t// still: its notify() is a full DOM re-render of the message list. The end\n\t\t\t// state is identical either way; only the discarded intermediate renders\n\t\t\t// are gone.\n\t\t\tinjectedAny = true;\n\t\t\t}\n\t\t\tif (bgPollBudget > 0 && !self.isPollingPaused() && !self.historyItemPolls.has(entry.id) && typeof entry.poll === 'function') {\n\t\t\t\tbgPollBudget--;\n\t\t\t\tvar capturedId = entry.id, capturedPlat = plat;\n\t\t\t\tvar capturedEntry = entry;\n\t\t\t\tvar wasStopped = false;\n\t\t\t\tvar bp = entry.poll({ latency: POLL_INTERVAL });\n\t\t\t\tself._trackPoll(entry.id, 'bg', bp);\n\t\t\t\tbp.then(function (response: any) {\n\t\t\t\t\t// A stopped poll is not a result: leave the bubble and the queue entry\n\t\t\t\t\t// exactly as they were so resumePolling can re-attach.\n\t\t\t\t\tif (isPollStopped(response)) { wasStopped = true; return; }\n\t\t\t\t\tself.handleHistoryItemResolution(capturedId, response, capturedPlat);\n\t\t\t\t\tself.maybeResumeIndexing(capturedEntry, response, capturedPlat);\n\t\t\t\t}).catch(function (err: any) {\n\t\t\t\t\tself.historyItemPolls.delete(capturedId);\n\t\t\t\t\tvar isNotExists = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\t\t\t\t// Settle the REQUEST bubble first, unconditionally. Only a RUNNING\n\t\t\t\t\t// pass gets an assistant placeholder, so for a queued one the lookup\n\t\t\t\t\t// below finds nothing and every branch was skipped — leaving the\n\t\t\t\t\t// request bubble isPendingQueued with its queue entry about to be\n\t\t\t\t\t// spliced away, i.e. no poll left to ever clear it. One such bubble\n\t\t\t\t\t// pins the whole collapsed row to \"active\": a spinner and a Stop\n\t\t\t\t\t// button against a dead id, until the page is reloaded.\n\t\t\t\t\tself._clearPendingUserBubble(capturedId);\n\t\t\t\t\tvar bi = self.state.messages.findIndex(function (m) { return m.isPending && m._serverItemId === capturedId; });\n\t\t\t\t\tif (bi !== -1) {\n\t\t\t\t\t\tif (isNotExists) self.state.messages.splice(bi, 1);\n\t\t\t\t\t\telse self.state.messages[bi] = { role: 'assistant', content: getErrorMessage(err), isError: true, isBackgroundTask: true, _serverItemId: capturedId };\n\t\t\t\t\t} else if (!isNotExists) {\n\t\t\t\t\t\t// No placeholder to turn into the error (a queued pass). Put one\n\t\t\t\t\t\t// after the request bubble so the row reports the failure instead\n\t\t\t\t\t\t// of quietly settling to \"Indexed\".\n\t\t\t\t\t\tvar ui = self.state.messages.findIndex(function (m) { return m.role === 'user' && m._serverItemId === capturedId; });\n\t\t\t\t\t\tif (ui !== -1) {\n\t\t\t\t\t\t\tself.state.messages.splice(ui + 1, 0, { role: 'assistant', content: getErrorMessage(err), isError: true, isBackgroundTask: true, _serverItemId: capturedId });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tself.host.notify(); self.updateHistoryCache();\n\t\t\t\t\t// A pass that FAILED dispatches no continuation on any path, so a\n\t\t\t\t\t// CLIENT-driven file is finished either way — let a turn waiting on it\n\t\t\t\t\t// look now. Not for a worker-driven one: this catch also fires on a\n\t\t\t\t\t// dropped poll, and the worker may have resolved that pass and written\n\t\t\t\t\t// the next one regardless. Nudging there would pull the two confirming\n\t\t\t\t\t// looks into the window where the new pass is not yet in the status\n\t\t\t\t\t// index, which is the same way a nudge on work STARTING went wrong.\n\t\t\t\t\tif (!self._isWorkerDrivenIndexing(capturedEntry.filename, capturedEntry.mime)) {\n\t\t\t\t\t\t// Also close the run record: for a CLIENT-driven file a failed\n\t\t\t\t\t\t// pass ends the chain on every path, and a removed row reads as\n\t\t\t\t\t\t// a cancel. Worker-driven files are excluded for the same reason\n\t\t\t\t\t\t// as the nudge — this catch fires on dropped polls too, and the\n\t\t\t\t\t\t// worker may be writing the next pass regardless.\n\t\t\t\t\t\tif (isNotExists) self._flipRunRecord(capturedEntry, 'cancelled');\n\t\t\t\t\t\telse self._flipRunRecord(capturedEntry, 'error', self._runErrorText(err));\n\t\t\t\t\t\tself._nudgeIndexingDrain();\n\t\t\t\t\t}\n\t\t\t\t}).then(function () {\n\t\t\t\t\t// Keep the queue entry when the poll was merely stopped, or resuming\n\t\t\t\t\t// would have nothing left to re-attach to.\n\t\t\t\t\tif (wasStopped) return;\n\t\t\t\t\tvar qi = self.bgTaskQueue.findIndex(function (q) { return q.id === capturedId; });\n\t\t\t\t\tif (qi !== -1) self.bgTaskQueue.splice(qi, 1);\n\t\t\t\t\t// This resolution freed a slot in the MAX_CONCURRENT_BG_POLLS budget,\n\t\t\t\t\t// so hand it to the next-oldest unpolled entry. Load-bearing under the\n\t\t\t\t\t// cap: with thousands of entries queued, only the handful holding\n\t\t\t\t\t// polls can ever settle, and without this re-drain the remaining\n\t\t\t\t\t// entries would sit unpolled forever. Not left to a host-side watcher\n\t\t\t\t\t// on bgTaskQueue — agent.vue has one, the widget does not.\n\t\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t// One render, one cache write, one scroll for the whole drain — however many\n\t\t// bubbles it injected. See the injectedAny comment above.\n\t\tif (injectedAny) {\n\t\t\tthis.host.notify();\n\t\t\tthis.updateHistoryCache();\n\t\t\tthis.host.scrollToBottomIfSticky(false);\n\t\t}\n\t\tthis.promoteNextBgQueuedToRunning();\n\t}\n\n\t// Resume-across-passes: if a background INDEXING task for a paged file (spreadsheet or\n\t// text) finished WITHOUT the completion marker, the agent ran out of room before reading\n\t// the whole file - dispatch a CONTINUE pass (up to a cap) that resumes from where the\n\t// already-saved records leave off. Additive + guarded so it never loops forever and\n\t// never breaks the resolution path.\n\t//\n\t// VISION files (PDFs rendered to page images) are NOT resumed here: the proxy worker\n\t// advances their page window itself, off the renderer's true page count. Driving them\n\t// from the browser is what used to lose pages on long documents - the chain lived in tab\n\t// memory (a reload or a closed tab ended it), and it stopped whenever the model claimed\n\t// completion, which on an 88-page file happened at page 15. Continuing to dispatch here\n\t// as well would now double-index every window.\n\t/** Fire the consumer's done::-marker hook for a run whose completion this\n\t * client knows DETERMINISTICALLY (see the two call sites in\n\t * maybeResumeIndexing). Best-effort by contract; identity-checked so a\n\t * project switch mid-settle cannot stamp the wrong service. */\n\t_mintDoneMarker(entry: BgTaskEntry): void {\n\t\ttry {\n\t\t\tvar mint = chatEngineConfig().mintIndexDoneMarker;\n\t\t\tif (!mint || !entry || !entry.storagePath || !entry.projectId) return;\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (!id || id.projectId !== entry.projectId) return;\n\t\t\tmint({ service: entry.projectId, storagePath: entry.storagePath });\n\t\t} catch (_e) { /* best-effort */ }\n\t}\n\n\t/** Short, storable form of an error body for the run:: record. */\n\t_runErrorText(response: any): string {\n\t\tvar msg = '';\n\t\ttry { msg = String(getErrorMessage(response) || ''); } catch (_e) { }\n\t\tmsg = msg.replace(/\\s+/g, ' ').trim();\n\t\treturn msg ? msg.slice(0, 300) : 'Indexing failed.';\n\t}\n\n\t/** Close the records of a run whose pass settled OFF-POLL — the answer came\n\t * back as history (hidden tab, dead poll, resume refetch), so none of the\n\t * poll-side settle handlers ran. Only for SINGLE-PASS files, where one\n\t * settled pass is deterministically the whole run (the same contract as\n\t * maybeResumeIndexing's single-pass branch); paged files stay with their\n\t * drivers. Outcome is read from the settled bubbles' own flags, which is\n\t * all the history mapping left us. Best-effort and idempotent throughout. */\n\t_flipRunFromSettledEntry(entry: BgTaskEntry): void {\n\t\ttry {\n\t\t\tif (!entry || !entry.storagePath || !entry.id || !entry.projectId) return;\n\t\t\tif (isPagedReadFile(entry.filename, entry.mime)) return;\n\t\t\t// A stopped run's verdict belongs to the stop funnel — never let a\n\t\t\t// late clean settle of its pass relabel 'cancelled' as 'done'.\n\t\t\tif (this.cancelledIndexKeys.has(this._indexKeyOf(entry))) return;\n\t\t\tif (this.state.stoppedIndexIds[entry.id]) return;\n\t\t\tvar userMsg: any = null, replyMsg: any = null;\n\t\t\tthis.state.messages.forEach(function (m: any) {\n\t\t\t\tif (m._serverItemId !== entry.id) return;\n\t\t\t\tif (m.role === 'user') { if (!userMsg) userMsg = m; }\n\t\t\t\telse if (!replyMsg) replyMsg = m;\n\t\t\t});\n\t\t\tif ((userMsg && userMsg.isCancelled) || (replyMsg && replyMsg.isCancelled)) {\n\t\t\t\tthis._flipRunRecord(entry, 'cancelled');\n\t\t\t} else if (replyMsg && replyMsg.isError) {\n\t\t\t\tvar errText = typeof replyMsg.content === 'string'\n\t\t\t\t\t? replyMsg.content.replace(/\\s+/g, ' ').trim().slice(0, 300) : '';\n\t\t\t\tthis._flipRunRecord(entry, 'error', errText || 'Indexing failed.');\n\t\t\t} else if (replyMsg) {\n\t\t\t\tthis._mintDoneMarker(entry);\n\t\t\t\tthis._flipRunRecord(entry, 'done');\n\t\t\t}\n\t\t\t// No reply bubble at all: nothing to judge from — leave the record.\n\t\t} catch (_e) { /* best-effort */ }\n\t}\n\n\t/** Close the durable run:: record for an ending THIS client observed.\n\t * service comes from the ENTRY, not the current identity: unlike the done::\n\t * mint above, a status flip must land even if the user switched projects\n\t * mid-settle — otherwise the record lies 'working' forever. Best-effort\n\t * through upsertIndexRunRecordSafe; the consumer's precedence guard keeps\n\t * repeats and races harmless. */\n\t_flipRunRecord(entry: BgTaskEntry, status: IndexRunStatus, error?: string): void {\n\t\tif (!entry || !entry.storagePath || !entry.projectId) return;\n\t\tvar patch: IndexRunPatch = { status: status, finished: Date.now() };\n\t\tif (error) patch.error = error;\n\t\tupsertIndexRunRecordSafe(entry.projectId, entry.storagePath, patch);\n\t}\n\n\tmaybeResumeIndexing(entry: BgTaskEntry, response: any, platform: string): void {\n\t\tvar self = this;\n\t\t// This client is the ONLY driver of the chains that reach the returns below,\n\t\t// so its decision not to continue one is authoritative and immediate — the\n\t\t// earliest honest \"these files are done\" a waiting turn can get. Used only to\n\t\t// make awaitIndexingDrained look sooner; it still has to agree twice.\n\t\t// NOT called for the worker-driven returns further down (the worker may be\n\t\t// about to write the next pass) or for a stopped file (its queued passes are\n\t\t// still being cancelled).\n\t\tvar endOfClientChain = function () { self._nudgeIndexingDrain(); };\n\t\ttry {\n\t\t\tif (!entry || !entry.storagePath) return;\n\t\t\t// The user stopped this file from its collapsed row. Dispatching the next\n\t\t\t// pass here is exactly what \"stop\" has to prevent — the cancelled pass\n\t\t\t// settles, and without this the chain simply carries on.\n\t\t\tif (this.cancelledIndexKeys.has(this._indexKeyOf(entry))) return;\n\t\t\tif (!isPagedReadFile(entry.filename, entry.mime)) {\n\t\t\t\t// Single-pass file: one settled pass IS the whole job. This is\n\t\t\t\t// deterministic knowledge (this client is the only dispatcher),\n\t\t\t\t// so record the durable done:: marker — single-pass runs never\n\t\t\t\t// get one from the worker. Errors don't count as completion\n\t\t\t\t// (this branch sits above the error check on purpose: the chain\n\t\t\t\t// is over either way, but only success gets a marker), and\n\t\t\t\t// neither does a CANCELLED poll shape — a row stopped from\n\t\t\t\t// another tab/device settles through here as {status:\n\t\t\t\t// 'cancelled', queue fields} with no provider payload, and\n\t\t\t\t// cancelledIndexKeys only records stops issued from THIS tab.\n\t\t\t\tif (!isErrorResponseBody(response) && !this._isCancelledPollResult(response)) {\n\t\t\t\t\tthis._mintDoneMarker(entry);\n\t\t\t\t\tthis._flipRunRecord(entry, 'done');\n\t\t\t\t} else if (this._isCancelledPollResult(response)) {\n\t\t\t\t\t// Stopped elsewhere (another tab/device): the stopping side\n\t\t\t\t\t// usually wrote 'cancelled' already; writing it again is a\n\t\t\t\t\t// same-value terminal update, and it closes the record when\n\t\t\t\t\t// the stopping tab died before its write landed.\n\t\t\t\t\tthis._flipRunRecord(entry, 'cancelled');\n\t\t\t\t} else {\n\t\t\t\t\tthis._flipRunRecord(entry, 'error', this._runErrorText(response));\n\t\t\t\t}\n\t\t\t\tendOfClientChain(); return;\n\t\t\t}\n\t\t\tif (isImageVisionFile(entry.filename, entry.mime)) return; // worker owns this loop (PDF vision)\n\t\t\t// When windowed indexing is on, the WORKER drives the text/grid loop too. The\n\t\t\t// client MUST NOT also resume, or two drivers each enqueue a continuation per\n\t\t\t// pass and the chain FORKS - duplicate records, runaway passes. Same reason\n\t\t\t// PDFs early-return above. Gated on the flag so the old client-driven path is\n\t\t\t// untouched when windowing is off.\n\t\t\tif (windowedIndexingEnabled() && isWindowedReadFile(entry.filename, entry.mime)) return;\n\t\t\tif (isErrorResponseBody(response)) {\n\t\t\t\t// A failed pass is not \"incomplete\" — the client-driven chain is over.\n\t\t\t\tthis._flipRunRecord(entry, 'error', this._runErrorText(response));\n\t\t\t\tendOfClientChain(); return;\n\t\t\t}\n\t\t\tvar answer = (platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '';\n\t\t\tif (answer.indexOf(INDEXING_COMPLETE_MARKER) !== -1) {\n\t\t\t\t// Client-driven chain, and the model's reply carried the\n\t\t\t\t// completion token — the same signal the worker requires before\n\t\t\t\t// minting for its own chains. Deterministic here: this client\n\t\t\t\t// is the only dispatcher and it is deciding, right now, that no\n\t\t\t\t// further pass will run.\n\t\t\t\tthis._mintDoneMarker(entry);\n\t\t\t\tthis._flipRunRecord(entry, 'done');\n\t\t\t\tendOfClientChain(); return; // fully indexed\n\t\t\t}\n\t\t\tvar pass = (entry.resumePass || 0) + 1;\n\t\t\tif (pass > MAX_INDEXING_RESUME_PASSES) {\n\t\t\t\t// Gave up after the cap: the file is only partially indexed, and no\n\t\t\t\t// further pass will ever run. 'error' rather than 'done' — the badge\n\t\t\t\t// must not claim a file the chain abandoned.\n\t\t\t\tthis._flipRunRecord(entry, 'error', 'Stopped after ' + MAX_INDEXING_RESUME_PASSES + ' passes without finishing.');\n\t\t\t\tendOfClientChain(); return;\n\t\t\t}\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (!id || id.platform === 'none' || id.projectId !== entry.projectId) {\n\t\t\t\t// This client is the only driver of this chain and it just declined\n\t\t\t\t// to dispatch the next pass — the chain is over, as an ending, not a\n\t\t\t\t// pause: the queue entry is spliced on settle and nothing revisits\n\t\t\t\t// it. Close the record (it writes with entry.projectId, so it lands\n\t\t\t\t// after a project switch) or it lies 'working' for the stale window.\n\t\t\t\tthis._flipRunRecord(entry, 'error', 'Indexing stopped: the session or project changed before the file finished.');\n\t\t\t\tendOfClientChain();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Counted as live work from here, not from the ack: awaitIndexingDrained\n\t\t\t// asks the SERVER what is queued, and this pass is not queued until the\n\t\t\t// call below returns. Without it a chat can slip in between two passes.\n\t\t\tthis.trackIndexDispatch(notifyAgentContinueIndexing({\n\t\t\t\tplatform: id.platform as 'claude' | 'openai',\n\t\t\t\tmodel: id.model,\n\t\t\t\tservice: id.projectId,\n\t\t\t\t// Without this the resume pass rebuilds its system prompt from the RAW\n\t\t\t\t// regional id (requests.ts falls back to `service`), and the model copies\n\t\t\t\t// that id verbatim into project_id tool calls, which the MCP schema\n\t\t\t\t// pattern rejects - the whole continue pass saves nothing.\n\t\t\t\tpublicProjectId: id.publicProjectId,\n\t\t\t\towner: id.owner,\n\t\t\t\tuserId: id.userId || id.projectId,\n\t\t\t\tserviceName: id.serviceName,\n\t\t\t\tserviceDescription: id.serviceDescription,\n\t\t\t\tattachment: {\n\t\t\t\t\tname: entry.filename,\n\t\t\t\t\tstoragePath: entry.storagePath,\n\t\t\t\t\tmime: entry.mime,\n\t\t\t\t\tsize: entry.size,\n\t\t\t\t\turl: '',\n\t\t\t\t},\n\t\t\t}).then(function (ack: any) {\n\t\t\t\tif (ack && typeof ack.id === 'string') {\n\t\t\t\t\tself.bgTaskQueue.push({\n\t\t\t\t\t\tprojectId: id.projectId, platform: id.platform as 'claude' | 'openai', id: ack.id,\n\t\t\t\t\t\tfilename: entry.filename, storagePath: entry.storagePath,\n\t\t\t\t\t\tisReindex: entry.isReindex, mime: entry.mime, size: entry.size,\n\t\t\t\t\t\tstatus: ack.status === 'running' ? 'running' : 'pending',\n\t\t\t\t\t\tpoll: ack.poll, resumePass: pass,\n\t\t\t\t\t\t// Deliberately NOT stamped with entry.stageId. Only a batch's FIRST\n\t\t\t\t\t\t// pass anchors to the turn; a continuation appends, which is the\n\t\t\t\t\t\t// order the server queued it in and therefore the order\n\t\t\t\t\t\t// promoteNextBgQueuedToRunning should spin it in. It costs nothing\n\t\t\t\t\t\t// on screen: a continuation is folded into the run whose row\n\t\t\t\t\t\t// already sits above the turn, and renders nothing at its own\n\t\t\t\t\t\t// index (indexing_groups anchors a run at its FIRST loaded pass).\n\t\t\t\t\t});\n\t\t\t\t\tself.drainBgTaskQueue();\n\t\t\t\t}\n\t\t\t}, function (e: any) { console.error('[chat-engine] resume-indexing dispatch failed', e); }));\n\t\t} catch (e) { /* best-effort: resume must never break bg-task resolution */ }\n\t}\n\n\t// --- history fetch + pagination --------------------------------------\n\t// Initial load (fetchMore=false) replaces the list (with in-flight rescue +\n\t// cancelled-merge) and attaches polls to running/pending items; pagination\n\t// (fetchMore=true) prepends older messages. The DOM scroll-restore for the\n\t// older-prepend is the VIEW's job (it captures the pre-prepend scroll position\n\t// and restores after this resolves) — the engine never measures the DOM.\n\tloadHistory(fetchMore?: boolean, token?: number): Promise<void> {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\t// Key this fetch is FOR, snapshotted from the same identity read the\n\t\t// request is built from. The rescue below compares against this rather\n\t\t// than a live getHistoryCacheKey(), so a project switch mid-fetch can't\n\t\t// make another chat's in-flight bubbles look local.\n\t\tvar loadKey = (!id.projectId || id.platform === 'none') ? '' : id.projectId + '#' + id.platform;\n\t\tif (token === undefined) token = this.state.gateRefreshToken;\n\t\tif ((this.state.loadingHistory && this.state.historyRequestToken === token) || id.platform === 'none' || !id.projectId) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tthis.state.historyRequestToken = token;\n\t\tthis.state.loadingHistory = true;\n\t\t// A first-page load is the one moment the chat may have changed under us. The\n\t\t// old snapshot describes the previous project's queue; keeping it would let a\n\t\t// row here claim it was finished on evidence from somewhere else. Re-seeded\n\t\t// when this load lands.\n\t\tif (!fetchMore && loadKey !== this._liveIndexKey) {\n\t\t\tthis._liveIndexKey = loadKey;\n\t\t\tthis._resetLiveIndexKeys();\n\t\t}\n\t\tif (fetchMore) this.state.loadingOlderHistory = true;\n\t\tthis.host.notify(); // surface \"Fetching history...\" while it loads\n\t\tvar platform = id.platform as 'claude' | 'openai';\n\t\tvar projectId = id.projectId, owner = id.owner;\n\t\tvar options: any = { fetchMore: fetchMore };\n\t\tif (fetchMore && this.state.historyStartKeyHistory.length) options.startKeyHistory = this.state.historyStartKeyHistory.slice();\n\t\t// First page: paint the CONVERSATION immediately and let the indexing\n\t\t// stubs arrive as a deferred batch (merged below when it lands).\n\t\tif (!fetchMore) options.deferBg = true;\n\n\t\t// Split fetch v2: surface (full bodies, bg queue excluded) + bg compact\n\t\t// stubs, tiled to the surface page's time window with module-level\n\t\t// state (buffering + retry safety) — see getSplitChatHistory. Returns\n\t\t// the exact single-fetch shape; startKeyHistory is bookkeeping only.\n\t\tvar fetchHistory = function () { return getSplitChatHistory({ service: projectId, owner: owner, platform: platform, userId: id.userId }, options); };\n\n\t\treturn Promise.resolve().then(fetchHistory).catch(function (err: any) {\n\t\t\tif (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);\n\t\t\tthrow err;\n\t\t}).then(function (history: any) {\n\t\t\tif (token !== self.state.gateRefreshToken) return;\n\t\t\tvar chatList = history && Array.isArray(history.list) ? history.list : [];\n\t\t\tchatList.forEach(function (item: any) {\n\t\t\t\tif (isBgIndexingQueue(item.queue_name)) {\n\t\t\t\t\t// Compact stubs carry the label as request_text — the body\n\t\t\t\t\t// never left the server — so classify from whichever form\n\t\t\t\t\t// this item arrived in.\n\t\t\t\t\tvar clsText = item.compact ? item.request_text : extractLastUserTextFromRequest(item.request_body);\n\t\t\t\t\tif (isIndexingRequestText(clsText)) item._isBgTask = true;\n\t\t\t\t\telse item._isOnBgQueue = true;\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar list = chatList.sort(function (a: any, b: any) {\n\t\t\t\tvar ai = typeof a.id === 'string' ? a.id : '', bi = typeof b.id === 'string' ? b.id : '';\n\t\t\t\treturn ai > bi ? -1 : (ai < bi ? 1 : 0);\n\t\t\t});\n\t\t\tvar mapped = mapHistoryListToMessages(list, platform, {\n\t\t\t\tclearedAt: self.host.getClearedAt(),\n\t\t\t\tprojectId: id.projectId,\n\t\t\t\tformatIndexingLabel: self.host.formatIndexingLabel,\n\t\t\t}).messages;\n\t\t\t// Re-apply any previously-hydrated compact bodies: a refresh maps\n\t\t\t// fresh stubs, and without this a bubble the user already expanded\n\t\t\t// would silently revert to its 200-char head.\n\t\t\tself.applyHydratedBodies(mapped);\n\n\t\t\t// Set when a first-page refresh re-prepended already-loaded older pages,\n\t\t\t// so the cursor reset below knows not to rewind to page 1's boundary.\n\t\t\tvar keptOlderPages = false;\n\t\t\t// The empty-page-1 keep below was taken ONLY on the strength of a\n\t\t\t// deferred batch still flying — if that batch then proves the chat\n\t\t\t// empty server-side, the kept screen must be let go (see the batch\n\t\t\t// handler), or an emptied transcript is indelible.\n\t\t\tvar keptScreenAwaitingBg = false;\n\n\t\t\tif (fetchMore) {\n\t\t\t\t// STRIP-THEN-MERGE keyed on SERVER ITEM ID. Incoming bubbles are\n\t\t\t\t// the fresher server state (queued→running→settled transitions),\n\t\t\t\t// so existing copies of incoming id|role bubbles are REMOVED first\n\t\t\t\t// (in-flight cancel flags carried over), then the page merges by\n\t\t\t\t// item id — ids are creation-ordered and BOTH lists are already\n\t\t\t\t// id-sorted, unlike _ts (assistant _ts is `updated`, which any\n\t\t\t\t// long-running turn makes non-monotonic and would misorder the\n\t\t\t\t// walk). Id-less bubbles on screen (staged/local, always the tail)\n\t\t\t\t// end the merge region; id-less incoming sorts first (oldest).\n\t\t\t\tvar incomingKeys: any = {};\n\t\t\t\tmapped.forEach(function (m: any) { if (m._serverItemId) incomingKeys[m._serverItemId + '|' + m.role] = m; });\n\t\t\t\tvar existing = self.state.messages.filter(function (m: any) {\n\t\t\t\t\tif (!m._serverItemId) return true;\n\t\t\t\t\tvar inc = incomingKeys[m._serverItemId + '|' + m.role];\n\t\t\t\t\tif (!inc) return true;\n\t\t\t\t\tif (m._cancelling) inc._cancelling = m._cancelling;\n\t\t\t\t\tif (m._cancelError) inc._cancelError = m._cancelError;\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t\tvar mergedList: ChatMessage[] = [];\n\t\t\t\tvar pi = 0, ei = 0;\n\t\t\t\twhile (pi < mapped.length && ei < existing.length) {\n\t\t\t\t\tvar pm: any = mapped[pi], em: any = existing[ei];\n\t\t\t\t\tvar eid = em._serverItemId;\n\t\t\t\t\tif (typeof eid !== 'string') break; // staged/local tail\n\t\t\t\t\tvar pid = pm._serverItemId;\n\t\t\t\t\tif (typeof pid !== 'string' || pid <= eid) { mergedList.push(pm); pi++; }\n\t\t\t\t\telse { mergedList.push(em); ei++; }\n\t\t\t\t}\n\t\t\t\twhile (pi < mapped.length) mergedList.push(mapped[pi++]);\n\t\t\t\twhile (ei < existing.length) mergedList.push(existing[ei++]);\n\t\t\t\tself.state.messages = mergedList;\n\t\t\t} else if (!mapped.length && history && (history.endOfList === false || (history as any).bgPending)\n\t\t\t\t&& self.state.messages.some(function (m: any) { return m._ownerKey === undefined || m._ownerKey === loadKey; })) {\n\t\t\t\t// Empty first page that cannot judge the chat empty: either\n\t\t\t\t// empty-but-not-end (a pure-bg band past every hop cap), or an\n\t\t\t\t// empty DEFERRED page whose bg batch is still flying — a chat\n\t\t\t\t// whose whole conversation rides the bg queue has a genuinely\n\t\t\t\t// empty surface (endOfList true on a head refresh), and the\n\t\t\t\t// batch carries everything. REPLACING with it would blank the\n\t\t\t\t// chat for the batch's flight time — the greeting flashed over\n\t\t\t\t// real messages on every tab return. Keep what is on screen.\n\t\t\t\t// Kept ONLY on the batch's word: the batch handler revisits.\n\t\t\t\tif (history.endOfList !== false) keptScreenAwaitingBg = true;\n\t\t\t} else {\n\t\t\t\tif (self.state.typing) self.state.typingAbort = true;\n\t\t\t\tvar serverIds: any = {};\n\t\t\t\tmapped.forEach(function (m: any) { if (m._serverItemId) serverIds[m._serverItemId] = 1; });\n\t\t\t\t// The retention boundary must be the SURFACE frontier: page 1 also\n\t\t\t\t// emits bg stubs reaching arbitrarily deep, and keying retention on\n\t\t\t\t// a weeks-old stub id would wipe (or gap) the scrolled-in pages.\n\t\t\t\tvar surfaceOldestId: string | undefined = undefined;\n\t\t\t\tmapped.forEach(function (m: any) {\n\t\t\t\t\tif (typeof m._serverItemId !== 'string' || m._fromBgChain) return;\n\t\t\t\t\tif (surfaceOldestId === undefined || m._serverItemId < surfaceOldestId) surfaceOldestId = m._serverItemId;\n\t\t\t\t});\n\t\t\t\tvar locallyCancelled: any = {};\n\t\t\t\tself.state.messages.forEach(function (m) { if (m.isCancelled && m._serverItemId) locallyCancelled[m._serverItemId] = m; });\n\t\t\t\t// A cancel the server has not acknowledged yet. Without carrying these\n\t\t\t\t// across the replace, a collapsed row mid-cancel drops its \"Stopping...\"\n\t\t\t\t// state and re-offers Stop; the second click cancels an id that is\n\t\t\t\t// already gone and writes a bogus \"Could not remove from queue.\" onto a\n\t\t\t\t// run that WAS stopped successfully.\n\t\t\t\tvar inFlightCancel: any = {};\n\t\t\t\tself.state.messages.forEach(function (m) {\n\t\t\t\t\tif (!m._serverItemId) return;\n\t\t\t\t\tif (m._cancelling || m._cancelError) inFlightCancel[m._serverItemId] = m;\n\t\t\t\t});\n\t\t\t\t// If the freshly-mapped server list ALREADY shows this in-flight turn\n\t\t\t\t// as a pending placeholder (a non-bg pending assistant, which carries\n\t\t\t\t// a real _serverItemId), re-pushing the local no-_serverItemId\n\t\t\t\t// user+Thinking would DUPLICATE it. Each resolve path only clears the\n\t\t\t\t// first pending bubble, so the duplicate strands a \"Thinking…\" beside\n\t\t\t\t// the reply/error. There is at most one in-flight regular turn, so a\n\t\t\t\t// mapped pending assistant IS this turn — skip the redundant local copy.\n\t\t\t\tvar mappedHasPendingAssistant = mapped.some(function (m: any) {\n\t\t\t\t\treturn m.isPending && m.role === 'assistant' && !m.isBackgroundTask;\n\t\t\t\t});\n\t\t\t\t// One rule, shared with agent.vue's own fetchHistoryPage — see\n\t\t\t\t// shouldRescueInFlightMessage for what it decides and why.\n\t\t\t\tvar rescued: ChatMessage[] = [];\n\t\t\t\tfor (var ri = 0; ri < self.state.messages.length; ri++) {\n\t\t\t\t\tvar mm = self.state.messages[ri];\n\t\t\t\t\tif (shouldRescueInFlightMessage(mm, {\n\t\t\t\t\t\thasServerId: function (sid) { return !!serverIds[sid]; },\n\t\t\t\t\t\tpageHasPendingAssistant: mappedHasPendingAssistant,\n\t\t\t\t\t\tsending: !!self.state.sending,\n\t\t\t\t\t\tnext: self.state.messages[ri + 1],\n\t\t\t\t\t\tloadKey: loadKey,\n\t\t\t\t\t})) rescued.push(mm);\n\t\t\t\t}\n\t\t\t\t// PRESERVE already-loaded older pages. `mapped` is only page 1, so a\n\t\t\t\t// blind replace threw away every page the user had scrolled in. This\n\t\t\t\t// path runs from resumePolling (visibilitychange), so merely leaving\n\t\t\t\t// the tab and coming back wiped the whole scrolled-in history.\n\t\t\t\t//\n\t\t\t\t// The list is oldest-first (fetchMore PREPENDS), and ids sort with\n\t\t\t\t// newest largest, so anything already in the list whose _serverItemId\n\t\t\t\t// sorts BELOW page 1's oldest id is an older page. Those are disjoint\n\t\t\t\t// from `mapped` (strict <), so re-prepending cannot duplicate.\n\t\t\t\tvar oldestInPage1: string | undefined = undefined;\n\t\t\t\tmapped.forEach(function (m: any) {\n\t\t\t\t\tvar sid = m._serverItemId;\n\t\t\t\t\tif (typeof sid !== 'string') return;\n\t\t\t\t\tif (oldestInPage1 === undefined || sid < (oldestInPage1 as string)) oldestInPage1 = sid;\n\t\t\t\t});\n\t\t\t\t// Only merge when the current list is genuinely a continuation of THIS\n\t\t\t\t// page 1 (shares at least one id with it). A project switch, a cleared\n\t\t\t\t// horizon, or a wholly-new page means the head is unrelated history and\n\t\t\t\t// must be replaced, not spliced.\n\t\t\t\tvar sharesPage1 = self.state.messages.some(function (m) {\n\t\t\t\t\treturn typeof m._serverItemId === 'string' && !!serverIds[m._serverItemId as string];\n\t\t\t\t});\n\t\t\t\tvar deferredBg = !!(history && (history as any).bgPending);\n\t\t\t\t// Boundary for retention: the SURFACE frontier when page 1 has any\n\t\t\t\t// surface item (bg stubs can reach weeks deeper and would otherwise\n\t\t\t\t// wipe or gap the scrolled-in pages); whole-page oldest only as the\n\t\t\t\t// fallback for a surface-empty page.\n\t\t\t\tvar retainBoundary: string | undefined = surfaceOldestId !== undefined ? surfaceOldestId : oldestInPage1;\n\t\t\t\tvar retainedOlder: ChatMessage[] = (!sharesPage1 || retainBoundary === undefined) ? [] : self.state.messages.filter(function (m) {\n\t\t\t\t\t// Settled server history only; in-flight bubbles are the rescue\n\t\t\t\t\t// loop's job below and would otherwise be kept twice.\n\t\t\t\t\tif (typeof m._serverItemId !== 'string') return false;\n\t\t\t\t\t// Same ownership predicate as the rescue loop: never carry another\n\t\t\t\t\t// project's bubbles onto this chat (the cross-project leak fix).\n\t\t\t\t\t// Compare against the snapshotted loadKey, never a live read.\n\t\t\t\t\tif (m._ownerKey !== undefined && m._ownerKey !== loadKey) return false;\n\t\t\t\t\t// While a deferred stub batch is in flight, KEEP already-loaded\n\t\t\t\t\t// indexing bubbles wherever they sit — the surface-only page has\n\t\t\t\t\t// none, and dropping them here would flicker every row until the\n\t\t\t\t\t// batch lands (its apply strips+re-merges them by id anyway).\n\t\t\t\t\tif (deferredBg && m.isBackgroundTask) return true;\n\t\t\t\t\t// Bg-chain bubbles already on screen stay put regardless of the\n\t\t\t\t\t// boundary — their ids interleave with deep history and the strip\n\t\t\t\t\t// in later merges replaces them when fresher copies arrive.\n\t\t\t\t\tif (m._fromBgChain) return true;\n\t\t\t\t\treturn (m._serverItemId as string) < (retainBoundary as string);\n\t\t\t\t});\n\t\t\t\t// Prepend only the STRICTLY-older bubbles. Retained bg bubbles whose\n\t\t\t\t// ids sit inside page 1's own range are ID-MERGED into it instead —\n\t\t\t\t// blanket prepending hoisted every indexing row above the whole\n\t\t\t\t// conversation, and after a head refresh the single-page batch\n\t\t\t\t// never re-placed the deep ones, so they sat hoisted for good.\n\t\t\t\tvar prependOlder: ChatMessage[] = [];\n\t\t\t\tvar interleave: ChatMessage[] = [];\n\t\t\t\tretainedOlder.forEach(function (m) {\n\t\t\t\t\tvar sid = m._serverItemId as string;\n\t\t\t\t\tif (serverIds[sid]) return; // page 1 carries a fresher copy\n\t\t\t\t\tif (retainBoundary !== undefined && sid < (retainBoundary as string)) prependOlder.push(m);\n\t\t\t\t\telse interleave.push(m);\n\t\t\t\t});\n\t\t\t\tvar page1: ChatMessage[] = mapped;\n\t\t\t\tif (interleave.length) {\n\t\t\t\t\t// Both sides are id-sorted oldest-first (retention preserves the\n\t\t\t\t\t// on-screen order; the mapper emits oldest-first).\n\t\t\t\t\tvar mergedP: ChatMessage[] = [];\n\t\t\t\t\tvar ii2 = 0, mi2 = 0;\n\t\t\t\t\twhile (ii2 < interleave.length && mi2 < mapped.length) {\n\t\t\t\t\t\tvar iv: any = interleave[ii2], mv: any = mapped[mi2];\n\t\t\t\t\t\tvar mid2 = typeof mv._serverItemId === 'string' ? mv._serverItemId : undefined;\n\t\t\t\t\t\tif (mid2 === undefined) break; // defensive: id-less tail\n\t\t\t\t\t\tif ((iv._serverItemId as string) <= mid2) { mergedP.push(iv); ii2++; }\n\t\t\t\t\t\telse { mergedP.push(mv); mi2++; }\n\t\t\t\t\t}\n\t\t\t\t\twhile (ii2 < interleave.length) mergedP.push(interleave[ii2++]);\n\t\t\t\t\twhile (mi2 < mapped.length) mergedP.push(mapped[mi2++]);\n\t\t\t\t\tpage1 = mergedP;\n\t\t\t\t}\n\t\t\t\tkeptOlderPages = prependOlder.length > 0 || interleave.length > 0;\n\t\t\t\tself.state.messages = prependOlder.length ? prependOlder.concat(page1) : page1;\n\t\t\t\trescued.forEach(function (m) {\n\t\t\t\t\t// Rescue can now carry a bubble that has a server id, and the\n\t\t\t\t\t// retained-older merge above carries ids too. One turn must not\n\t\t\t\t\t// arrive down both routes.\n\t\t\t\t\tif (m._serverItemId && self.state.messages.some(function (x) {\n\t\t\t\t\t\treturn x._serverItemId === m._serverItemId && x.role === m.role;\n\t\t\t\t\t})) return;\n\t\t\t\t\tself.state.messages.push(m);\n\t\t\t\t});\n\t\t\t\tif (Object.keys(locallyCancelled).length) {\n\t\t\t\t\tfor (var ci = 0; ci < self.state.messages.length; ci++) {\n\t\t\t\t\t\tvar c = self.state.messages[ci];\n\t\t\t\t\t\tif (!c._serverItemId || !locallyCancelled[c._serverItemId] || c.isCancelled) continue;\n\t\t\t\t\t\t// Rebuild FROM the mapped bubble rather than as a bare literal:\n\t\t\t\t\t\t// dropping isBackgroundTask / _indexFile here ejected a stopped\n\t\t\t\t\t\t// indexing pass from its file's collapsed row, where it then rendered\n\t\t\t\t\t\t// as a standalone \"Indexing: <file>\" chat bubble and left the row\n\t\t\t\t\t\t// recomputing its passes as if that one had never happened.\n\t\t\t\t\t\tself.state.messages[ci] = {\n\t\t\t\t\t\t\trole: 'user', content: c.content, isCancelled: true, _serverItemId: c._serverItemId,\n\t\t\t\t\t\t\tisBackgroundTask: c.isBackgroundTask, _indexFile: c._indexFile,\n\t\t\t\t\t\t\t_useBgQueue: c._useBgQueue, _ownerKey: c._ownerKey,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (ci + 1 < self.state.messages.length && self.state.messages[ci + 1].isPending && self.state.messages[ci + 1]._serverItemId === c._serverItemId) {\n\t\t\t\t\t\t\tself.state.messages.splice(ci + 1, 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Re-stamp a cancel that is still in flight (see inFlightCancel above).\n\t\t\t\t// Only onto a bubble the server still reports as pending — once it has\n\t\t\t\t// settled the flags describe nothing the user can act on.\n\t\t\t\tfor (var fi = 0; fi < self.state.messages.length; fi++) {\n\t\t\t\t\tvar fm = self.state.messages[fi];\n\t\t\t\t\tvar was = fm._serverItemId && inFlightCancel[fm._serverItemId];\n\t\t\t\t\tif (!was || fm.isCancelled) continue;\n\t\t\t\t\tif (!(fm.isPendingQueued || fm.isPendingInProcess || fm.isPending)) continue;\n\t\t\t\t\tif (was._cancelling) fm._cancelling = true;\n\t\t\t\t\tif (was._cancelError) fm._cancelError = was._cancelError;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Only adopt page 1's cursor when page 1 IS the whole list. If older pages\n\t\t\t// survived the merge, rewinding here would make the next scroll-up\n\t\t\t// re-fetch page 2 (already on screen) and duplicate it.\n\t\t\tif (!keptOlderPages) {\n\t\t\t\tself.state.historyEndOfList = !!(history && history.endOfList);\n\t\t\t\tself.state.historyStartKeyHistory = history && Array.isArray(history.startKeyHistory) ? history.startKeyHistory : [];\n\t\t\t\tvar clearedAt = self.host.getClearedAt();\n\t\t\t\tif (clearedAt) {\n\t\t\t\t\t// SURFACE items only: page 1 also carries bg stubs reaching far\n\t\t\t\t\t// past the horizon, and reading their age as \"the frontier is\n\t\t\t\t\t// pre-horizon\" falsely ended the pager with post-horizon surface\n\t\t\t\t\t// pages still unfetched.\n\t\t\t\t\tvar surfaceItems = chatList.filter(function (it: any) { return !(it && it._fromBgChain); });\n\t\t\t\t\tif (surfaceItems.length > 0) {\n\t\t\t\t\t\tvar oldestUpdated = Number(surfaceItems[surfaceItems.length - 1] && surfaceItems[surfaceItems.length - 1].updated);\n\t\t\t\t\t\tif (isFinite(oldestUpdated) && oldestUpdated <= clearedAt) self.state.historyEndOfList = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Clear loading flags BEFORE this render so the final paint is\n\t\t\t// indicator-free (and the view's scroll-restore math sees matching heights).\n\t\t\tif (self.state.historyRequestToken === token) { self.state.loadingHistory = false; self.state.loadingOlderHistory = false; }\n\t\t\tself.updateHistoryCache();\n\t\t\tself.host.notify();\n\n\t\t\t// ── deferred indexing-stub batch (first-paint split) ──────────────\n\t\t\t// The conversation is already on screen; when the stub batch lands it\n\t\t\t// is classified/mapped like any page and STRIP-THEN-MERGED: existing\n\t\t\t// copies of incoming ids are removed first (retained rows may sit at\n\t\t\t// provisional positions), then the batch merges by timestamp.\n\t\t\tvar bgPending = !fetchMore && history && (history as any).bgPending;\n\t\t\tif (bgPending) {\n\t\t\t\t// Ownership id for the shared loading flag: a same-token refetch can\n\t\t\t\t// mint a SECOND bgPending, and the older handler settling later must\n\t\t\t\t// not clear (or keep) the flag the newer batch owns.\n\t\t\t\tvar batchId = ++_bgHistoryBatchSeq;\n\t\t\t\t// SILENT unless this is the chat's genuine FIRST PAINT. Two quiet\n\t\t\t\t// cases: an ended chain's head refresh (endOfList already true),\n\t\t\t\t// and a MID-WALK tab return — the walk restarts for cursor\n\t\t\t\t// safety, but the conversation is already on screen and flashing\n\t\t\t\t// \"Loading indexing history\" over it on every return was the\n\t\t\t\t// reported bug. Only a never-walked chat announces the batch.\n\t\t\t\tif (history.endOfList !== true && (history as any).firstLoad === true) {\n\t\t\t\t\tself.state.bgHistoryLoading = true;\n\t\t\t\t\tself.host.notify();\n\t\t\t\t}\n\t\t\t\tvar releaseBgFlag = function () {\n\t\t\t\t\tif (_bgHistoryBatchSeq === batchId) self.state.bgHistoryLoading = false;\n\t\t\t\t};\n\t\t\t\t(bgPending as Promise<any>).then(function (batch: any) {\n\t\t\t\t\tif (token !== self.state.gateRefreshToken) { releaseBgFlag(); return; }\n\t\t\t\t\tvar bList: any[] = (batch && Array.isArray(batch.list)) ? batch.list : [];\n\t\t\t\t\tbList.forEach(function (item: any) {\n\t\t\t\t\t\tif (isBgIndexingQueue(item.queue_name)) {\n\t\t\t\t\t\t\tvar t = item.compact ? item.request_text : extractLastUserTextFromRequest(item.request_body);\n\t\t\t\t\t\t\tif (isIndexingRequestText(t)) item._isBgTask = true;\n\t\t\t\t\t\t\telse item._isOnBgQueue = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tvar sorted = bList.sort(function (a: any, b: any) {\n\t\t\t\t\t\tvar ai = typeof a.id === 'string' ? a.id : '', bi = typeof b.id === 'string' ? b.id : '';\n\t\t\t\t\t\treturn ai > bi ? -1 : (ai < bi ? 1 : 0);\n\t\t\t\t\t});\n\t\t\t\t\tvar m2 = mapHistoryListToMessages(sorted, platform, {\n\t\t\t\t\t\tclearedAt: self.host.getClearedAt(),\n\t\t\t\t\t\tprojectId: id.projectId,\n\t\t\t\t\t\tformatIndexingLabel: self.host.formatIndexingLabel,\n\t\t\t\t\t}).messages;\n\t\t\t\t\tself.applyHydratedBodies(m2);\n\t\t\t\t\tif (keptScreenAwaitingBg && !m2.length && batch && batch.endOfList === true) {\n\t\t\t\t\t\t// The empty page 1 was kept ONLY on this batch's word — and it\n\t\t\t\t\t\t// just proved the chat empty server-side (an emptied/cleared\n\t\t\t\t\t\t// transcript). Let the kept screen go: drop this chat's settled\n\t\t\t\t\t\t// server bubbles, keep staged and in-flight local work and any\n\t\t\t\t\t\t// other chat's strays for their own reconcilers, and remember\n\t\t\t\t\t\t// the end. Without this the stale transcript was indelible and\n\t\t\t\t\t\t// even re-persisted itself into the history cache.\n\t\t\t\t\t\tself.state.messages = self.state.messages.filter(function (m: any) {\n\t\t\t\t\t\t\tif (typeof m._serverItemId !== 'string') return true;\n\t\t\t\t\t\t\tif (m._ownerKey !== undefined && m._ownerKey !== loadKey) return true;\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t});\n\t\t\t\t\t\tself.state.historyEndOfList = true;\n\t\t\t\t\t\treleaseBgFlag();\n\t\t\t\t\t\tself.updateHistoryCache();\n\t\t\t\t\t\tself.host.notify();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tvar incoming: any = {};\n\t\t\t\t\tm2.forEach(function (m: any) { if (m._serverItemId) incoming[m._serverItemId + '|' + m.role] = true; });\n\t\t\t\t\tvar baseList = self.state.messages.filter(function (m: any) { return !(m._serverItemId && incoming[m._serverItemId + '|' + m.role]); });\n\t\t\t\t\tvar mergedList: ChatMessage[] = [];\n\t\t\t\t\tvar pi2 = 0, ei2 = 0;\n\t\t\t\t\twhile (pi2 < m2.length && ei2 < baseList.length) {\n\t\t\t\t\t\tvar pm2: any = m2[pi2], em2: any = baseList[ei2];\n\t\t\t\t\t\tvar eid2 = em2._serverItemId;\n\t\t\t\t\t\tif (typeof eid2 !== 'string') break; // staged/local tail\n\t\t\t\t\t\tvar pid2 = pm2._serverItemId;\n\t\t\t\t\t\tif (typeof pid2 !== 'string' || pid2 <= eid2) { mergedList.push(pm2); pi2++; }\n\t\t\t\t\t\telse { mergedList.push(em2); ei2++; }\n\t\t\t\t\t}\n\t\t\t\t\twhile (pi2 < m2.length) mergedList.push(m2[pi2++]);\n\t\t\t\t\twhile (ei2 < baseList.length) mergedList.push(baseList[ei2++]);\n\t\t\t\t\tself.state.messages = mergedList;\n\t\t\t\t\tif (batch && batch.endOfList === true) self.state.historyEndOfList = true;\n\t\t\t\t\treleaseBgFlag();\n\t\t\t\t\tself.updateHistoryCache();\n\t\t\t\t\tself.host.notify();\n\t\t\t\t\t// The other half of the refresh. Everything this batch brought in\n\t\t\t\t\t// sits ABOVE or AMONG the newest turn, so a reader pinned to the\n\t\t\t\t\t// bottom was left stranded above it by exactly the batch's height,\n\t\t\t\t\t// with nothing to put them back (every scroll-anchor method no-ops\n\t\t\t\t\t// while pinned, and this handler ended here).\n\t\t\t\t\tif (self.host.settleScroll) self.host.settleScroll();\n\t\t\t\t}, function () {\n\t\t\t\t\t// Stubs missing until the next refresh re-asks; never fatal.\n\t\t\t\t\treleaseBgFlag();\n\t\t\t\t\tself.host.notify();\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!fetchMore) {\n\t\t\t\t// Ration BACKGROUND polls here exactly as the drain does (see\n\t\t\t\t// MAX_CONCURRENT_BG_POLLS); foreground items — a reply the user is\n\t\t\t\t// waiting on — are never rationed. The allow-set is taken from the\n\t\t\t\t// OLDEST bg items: ids sort with newest largest (the same ordering the\n\t\t\t\t// older-page merge above relies on) and the server settles a queue\n\t\t\t\t// FIFO, so the oldest are the only ones that can resolve next. Taking\n\t\t\t\t// the newest instead would wedge the batch — they cannot settle until\n\t\t\t\t// everything ahead of them has, and nothing ahead would hold a poll.\n\t\t\t\tvar bgAllow: { [id: string]: boolean } = {};\n\t\t\t\tvar bgHistBudget = MAX_CONCURRENT_BG_POLLS - self._countBgPolls();\n\t\t\t\tif (bgHistBudget > 0) {\n\t\t\t\t\tvar bgIds = chatList.filter(function (it: any) {\n\t\t\t\t\t\tif (it.status !== 'running' && it.status !== 'pending') return false;\n\t\t\t\t\t\tif (!it.poll || !it.id) return false;\n\t\t\t\t\t\tif (!(it._isBgTask || it._isOnBgQueue)) return false;\n\t\t\t\t\t\treturn !self.historyItemPolls.has(it.id);\n\t\t\t\t\t}).map(function (it: any) { return it.id as string; }).sort();\n\t\t\t\t\tfor (var ba = 0; ba < bgIds.length && ba < bgHistBudget; ba++) bgAllow[bgIds[ba]] = true;\n\t\t\t\t}\n\t\t\t\tchatList.forEach(function (item: any) {\n\t\t\t\t\tif (item.status !== 'running' && item.status !== 'pending') return;\n\t\t\t\t\tif (!item.poll || !item.id) return;\n\t\t\t\t\t// Every live poll registers its item id in historyItemPolls — an\n\t\t\t\t\t// immediate dispatch (dispatchAgentRequest ~123), a queued send\n\t\t\t\t\t// (~253), a bg task (drain), or an earlier history poll — so the\n\t\t\t\t\t// has() check below already skips exactly the items a live poll\n\t\t\t\t\t// covers (including the one the current dispatch is polling). Do NOT\n\t\t\t\t\t// additionally skip every OTHER running/pending item just because\n\t\t\t\t\t// some immediate dispatch is in flight: that dispatch polls only ITS\n\t\t\t\t\t// item, so blanket-skipping stranded a concurrent \"-bg\" indexing item\n\t\t\t\t\t// (a separate server queue runs in parallel) — or any item whose own\n\t\t\t\t\t// poll had since died — with no live poller, leaving a \"Thinking...\"\n\t\t\t\t\t// that never clears even after the server settled everything.\n\t\t\t\t\tif (self.historyItemPolls.has(item.id)) return;\n\t\t\t\t\t// An in-flight immediate dispatch polls its own MAIN-QUEUE item but\n\t\t\t\t\t// registers that id in historyItemPolls only AFTER its provider POST\n\t\t\t\t\t// returns; in the sliver before that, a remount can surface the item\n\t\t\t\t\t// here still unregistered. Skip re-polling MAIN-QUEUE items while a\n\t\t\t\t\t// dispatch is in flight so we don't stack a 2nd poll on the item the\n\t\t\t\t\t// dispatch is about to poll. Bg-queue items (_isBgTask indexing tasks\n\t\t\t\t\t// and _isOnBgQueue chats) run on a SEPARATE queue the immediate\n\t\t\t\t\t// dispatch never polls, so they MUST still get their poll — skipping\n\t\t\t\t\t// them was the stranded-\"Thinking\" bug this guard must not revive.\n\t\t\t\t\tif (self.pendingAgentRequests[self.getHistoryCacheKey()] && !item._isBgTask && !item._isOnBgQueue) return;\n\t\t\t\t\t// Background indexing polls are suppressed while paused; foreground\n\t\t\t\t\t// replies the user is waiting on are not.\n\t\t\t\t\tif ((item._isBgTask || item._isOnBgQueue) && self.isPollingPaused()) return;\n\t\t\t\t\t// Over the bg poll budget: leave this one unpolled. The drain picks\n\t\t\t\t\t// it up once an attached poll settles and frees a slot.\n\t\t\t\t\tif ((item._isBgTask || item._isOnBgQueue) && !bgAllow[item.id]) return;\n\t\t\t\t\tvar capturedId = item.id;\n\t\t\t\t\tvar isBg = !!(item._isBgTask || item._isOnBgQueue);\n\t\t\t\t\t// A foreground item here is a reply the user is still waiting on (a reload or a tab\n\t\t\t\t\t// return re-attaches it), so it gets the same early probe as a fresh send. Background\n\t\t\t\t\t// items keep the flat cadence: nobody is watching, and they are what the\n\t\t\t\t\t// MAX_CONCURRENT_BG_POLLS budget exists to protect.\n\t\t\t\t\tvar pollOpts = {\n\t\t\t\t\t\tonResponse: function (response: any) { if (isPollStopped(response)) return; self.handleHistoryItemResolution(capturedId, response, platform); },\n\t\t\t\t\t\tonError: function (err: any) {\n\t\t\t\t\t\t\tself.historyItemPolls.delete(capturedId);\n\t\t\t\t\t\t\tvar isNotExists = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));\n\t\t\t\t\t\t\tvar aIdx = self.state.messages.findIndex(function (m) { return m.isPending && m._serverItemId === capturedId; });\n\t\t\t\t\t\t\tif (isNotExists) {\n\t\t\t\t\t\t\t\tvar uIdx = self.state.messages.findIndex(function (m) { return m.role === 'user' && m._serverItemId === capturedId && !m.isCancelled; });\n\t\t\t\t\t\t\t\t// Decide bg-ness from whichever bubble actually exists. A\n\t\t\t\t\t\t\t\t// QUEUED pass has no assistant placeholder (history.ts emits\n\t\t\t\t\t\t\t\t// none), so reading it off the placeholder alone classified\n\t\t\t\t\t\t\t\t// every queued indexing pass as foreground: the rebuild below\n\t\t\t\t\t\t\t\t// then dropped isBackgroundTask/_indexFile, ejecting the pass\n\t\t\t\t\t\t\t\t// from its collapsed row as a raw \"Indexing: <file>\" chat\n\t\t\t\t\t\t\t\t// bubble, and promoteNextQueuedToRunning span up a \"Thinking...\"\n\t\t\t\t\t\t\t\t// on an unrelated queued FOREGROUND message.\n\t\t\t\t\t\t\t\tvar isBg = (aIdx !== -1 && !!self.state.messages[aIdx].isBackgroundTask)\n\t\t\t\t\t\t\t\t\t|| (uIdx !== -1 && !!self.state.messages[uIdx].isBackgroundTask);\n\t\t\t\t\t\t\t\tif (aIdx !== -1) self.state.messages.splice(aIdx, 1);\n\t\t\t\t\t\t\t\tif (!isBg) {\n\t\t\t\t\t\t\t\t\tif (uIdx !== -1) { var ex = self.state.messages[uIdx]; self.state.messages[uIdx] = { role: 'user', content: ex.content, isCancelled: true, _serverItemId: ex._serverItemId }; }\n\t\t\t\t\t\t\t\t\tself.cancelledServerIds.delete(capturedId); self.promoteNextQueuedToRunning();\n\t\t\t\t\t\t\t\t} else if (uIdx !== -1) {\n\t\t\t\t\t\t\t\t\t// Same carry-over every other rebuild does, so the pass stays\n\t\t\t\t\t\t\t\t\t// a member of its file's row while reading as cancelled.\n\t\t\t\t\t\t\t\t\tvar bex = self.state.messages[uIdx];\n\t\t\t\t\t\t\t\t\tvar bcancelled: ChatMessage = { role: 'user', content: bex.content, isCancelled: true, isBackgroundTask: true, _serverItemId: bex._serverItemId };\n\t\t\t\t\t\t\t\t\tif (bex._indexFile) bcancelled._indexFile = bex._indexFile;\n\t\t\t\t\t\t\t\t\tif (bex._useBgQueue) bcancelled._useBgQueue = true;\n\t\t\t\t\t\t\t\t\tself.state.messages[uIdx] = bcancelled;\n\t\t\t\t\t\t\t\t\tself.promoteNextBgQueuedToRunning();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tself.host.notify(); self.updateHistoryCache(); return;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (aIdx !== -1) {\n\t\t\t\t\t\t\t\tvar wasBg = self.state.messages[aIdx].isBackgroundTask;\n\t\t\t\t\t\t\t\tself.state.messages[aIdx] = { role: 'assistant', content: getErrorMessage(err), isError: true };\n\t\t\t\t\t\t\t\tif (wasBg) self.state.messages[aIdx].isBackgroundTask = true;\n\t\t\t\t\t\t\t\tself.host.notify(); self.updateHistoryCache();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tvar pp = isBg\n\t\t\t\t\t\t? item.poll(Object.assign({ latency: POLL_INTERVAL }, pollOpts))\n\t\t\t\t\t\t: self._fgPollWithEarlyProbe(item, capturedId, pollOpts);\n\t\t\t\t\t// Anything on the BACKGROUND queue is pausable, not just items whose\n\t\t\t\t\t// prompt text we recognise as an indexing task. _isBgTask vs\n\t\t\t\t\t// _isOnBgQueue is a DISPLAY distinction (\"Indexing: file\" vs a normal\n\t\t\t\t\t// chat bubble); keying the pause off _isBgTask alone left every\n\t\t\t\t\t// bg-queue item we could not text-match polling forever.\n\t\t\t\t\tself._trackPoll(capturedId, (item._isBgTask || item._isOnBgQueue) ? 'bg' : 'fg', pp);\n\t\t\t\t\tif (pp && pp.catch) pp.catch(function () { });\n\t\t\t\t});\n\t\t\t\tself.drainBgTaskQueue();\n\t\t\t}\n\n\t\t\t// Learn which files the queue is still working on. Only on a FIRST page:\n\t\t\t// this describes the whole queue, not the page, so paging older history\n\t\t\t// would re-ask for an answer that has not changed.\n\t\t\tif (!fetchMore) self.refreshLiveIndexState();\n\n\t\t\t// Sticky, NOT forcing: this runs after every first-page load, including\n\t\t\t// the one resumePolling fires on visibilitychange. Forcing yanked a\n\t\t\t// reader who had scrolled up back to the bottom. On a genuine mount the\n\t\t\t// user is still pinned, so this behaves identically there.\n\t\t\t//\n\t\t\t// settleScroll when the host has one: it makes the same decision, and it\n\t\t\t// is also called again once the deferred bg batch merges, so a pinned\n\t\t\t// reader lands on the REAL bottom instead of the surface page's.\n\t\t\tif (!fetchMore) return self.host.settleScroll ? self.host.settleScroll() : self.host.scrollToBottomIfSticky();\n\t\t}).catch(function (err: any) {\n\t\t\tconsole.warn('[chat-engine] getChatHistory failed', err);\n\t\t}).then(function () {\n\t\t\tif (self.state.historyRequestToken === token) {\n\t\t\t\tvar wasLoading = self.state.loadingHistory || self.state.loadingOlderHistory;\n\t\t\t\tself.state.loadingHistory = false; self.state.loadingOlderHistory = false;\n\t\t\t\tif (wasLoading) self.host.notify();\n\t\t\t}\n\t\t\t// Every first-page load ends here — mount, resumePolling, a cache-restore\n\t\t\t// refresh — and every one of them can leave a box too short to scroll,\n\t\t\t// which is the only trigger there is for reaching page 2. The view (which\n\t\t\t// alone can measure) pages its way out of it. Fired after the flags are\n\t\t\t// cleared so the fill loop does not see a request still in flight.\n\t\t\tif (self.host.onHistoryLoaded) self.host.onHistoryLoaded(!!fetchMore, token as number);\n\t\t});\n\t}\n\n\t// --- attachment upload orchestration ---------------------------------\n\t// Upload one attachment (a file = 1 member, a folder = N) to db storage and\n\t// queue indexing per member. The bytes I/O + chip rendering go through host\n\t// hooks; the overwrite/reindex flow, status lifecycle, and indexing live here.\n\tuploadSingleAttachment(att: any, stageId?: string): Promise<Array<{ name: string; url: string; storagePath: string }>> {\n\t\tvar self = this;\n\t\tvar id = this.host.getIdentity();\n\t\t// progress stays null until the first byte-progress event. Every upload\n\t\t// opens with a get-signed-url round trip that reports nothing, so a chip\n\t\t// initialised to 0 rendered an empty, motionless bar for the whole\n\t\t// preparing phase and read as hung. null is the signal for \"preparing\"\n\t\t// (barber pole); a number means bytes are actually moving (real bar).\n\t\tatt.status = 'uploading'; att.progress = null; att.errorMessage = '';\n\t\tatt.errorCode = ''; att.errorDetail = ''; // clear any prior failure (retry)\n\t\tthis.host.renderAttachmentChips();\n\t\tvar members = (att.kind === 'folder')\n\t\t\t? (att.files || []).map(function (f: any) { return { file: f.file, relPath: f.path, storagePath: self.host.storagePathFor(f.path) }; })\n\t\t\t: [{ file: att.file, relPath: att.name, storagePath: this.host.storagePathFor(att.name) }];\n\t\tvar total = members.length;\n\t\tif (!total) return Promise.reject(new Error('Empty attachment'));\n\t\tvar urls: Array<{ name: string; url: string; storagePath: string }> = [];\n\t\tvar anyIndexFailed = false;\n\t\tvar chain: Promise<any> = Promise.resolve();\n\t\tmembers.forEach(function (member: any, idx: number) {\n\t\t\tchain = chain.then(function () {\n\t\t\t\tvar hadExists = false;\n\t\t\t\tvar skipped = false;\n\t\t\t\t// True when the file already existed and we are re-indexing over it\n\t\t\t\t// (user chose Reindex, OR Overwrite replaced the bytes). Drives the\n\t\t\t\t// delete-then-repost of the stale \"src::\" record below. Kept separate\n\t\t\t\t// from hadExists, which must keep driving ONLY the Reindexing/Indexing\n\t\t\t\t// label (isReindex) — overwrite still labels as \"Indexing:\".\n\t\t\t\tvar existedBefore = false;\n\t\t\t\tvar onProg = function (p: any) {\n\t\t\t\t\tif (p && p.total) {\n\t\t\t\t\t\tatt.progress = Math.floor(((idx + p.loaded / p.total) / total) * 100);\n\t\t\t\t\t\tself.host.renderAttachmentChips();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tvar doMemberUpload = function (checkExistence: boolean) {\n\t\t\t\t\treturn self.host.uploadFile({\n\t\t\t\t\t\tfile: member.file, storagePath: member.storagePath, checkExistence: checkExistence,\n\t\t\t\t\t\tonProgress: onProg, setAbort: function (abort) { att._abort = abort; },\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t\treturn doMemberUpload(true).catch(function (err: any) {\n\t\t\t\t\tvar code = err && (err.code || (err.body && err.body.code));\n\t\t\t\t\tvar msg = err && (err.message || (err.body && err.body.message) || (typeof err === 'string' ? err : ''));\n\t\t\t\t\tvar isExists = code === 'EXISTS' || (msg && /exist/i.test(msg));\n\t\t\t\t\tif (!isExists) throw err; // a member upload failed → whole attachment fails (red)\n\t\t\t\t\treturn self.host.promptOverwrite(member.file.name).then(function (choice) {\n\t\t\t\t\t\tif (choice === 'overwrite') {\n\t\t\t\t\t\t\texistedBefore = true;\n\t\t\t\t\t\t\t// The bytes at this path are about to change while the\n\t\t\t\t\t\t\t// path itself does not, so the browser-cached mint for\n\t\t\t\t\t\t\t// it would keep handing back the old signed url and the\n\t\t\t\t\t\t\t// old cached body. This is the one place that knows,\n\t\t\t\t\t\t\t// so it marks the path for a refreshed mint.\n\t\t\t\t\t\t\tmarkImagePreviewStale(self.host.getIdentity().projectId || 'default', member.storagePath);\n\t\t\t\t\t\t\treturn doMemberUpload(false); // replace the existing file\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (choice === 'skip') { skipped = true; return; } // leave it untouched; no upload/index\n\t\t\t\t\t\thadExists = true; existedBefore = true; // keep it; Reindex\n\t\t\t\t\t});\n\t\t\t\t}).then(function () {\n\t\t\t\t\tif (skipped) return; // user skipped this member — no url, no index request\n\t\t\t\t\treturn self.host.getTemporaryUrl(member.storagePath);\n\t\t\t\t}).then(function (url: string) {\n\t\t\t\t\tif (skipped) return; // guard the indexing branch for a skipped member\n\t\t\t\t\turls.push({ name: member.relPath, url: url, storagePath: member.storagePath });\n\t\t\t\t\tif (att.kind !== 'folder') { att.uploadedUrl = url; att.storagePath = member.storagePath; }\n\t\t\t\t\tvar mime = member.file.type || self.host.getMimeType(member.file.name);\n\t\t\t\t\t// Delete-then-repost: when the file already existed (Reindex or\n\t\t\t\t\t// Overwrite), delete the stale \"src::<storagePath>\" index record\n\t\t\t\t\t// first — the skapi backend cascades the delete to its\n\t\t\t\t\t// reference-linked children — so re-indexing REPLACES rather than\n\t\t\t\t\t// colliding/duplicating. Awaited before the index request is\n\t\t\t\t\t// enqueued. Best-effort + optional-hook guarded: a missing record,\n\t\t\t\t\t// a permission error, or a host without the hook must not block\n\t\t\t\t\t// indexing.\n\t\t\t\t\t// Then CREATE the file record before any pass is enqueued. Ordering matters: the\n\t\t\t\t\t// delete above wipes it (and cascades to its rows), so creating first would just\n\t\t\t\t\t// delete what we made. Every pass references \"src::<path>\", and a pass is a\n\t\t\t\t\t// separate model turn that cannot know whether an earlier one created it, so\n\t\t\t\t\t// guaranteeing it here is what stops the backend rejecting whole windows with\n\t\t\t\t\t// NOT_EXISTS on reference.unique_id.\n\t\t\t\t\t// Already being indexed: a second run would open a second collapsed row\n\t\t\t\t\t// for the same file and re-read the whole document. Decided BEFORE the\n\t\t\t\t\t// delete-then-repost, which would otherwise wipe the records the LIVE\n\t\t\t\t\t// run has already written and then not re-index them. Asked of the\n\t\t\t\t\t// QUEUE, not just this page — see isIndexRunLive.\n\t\t\t\t\tvar alreadyIndexing = false;\n\t\t\t\t\tvar preIndex = self.claimIndexRun(member.storagePath).then(function (claimed) {\n\t\t\t\t\t\talreadyIndexing = !claimed;\n\t\t\t\t\t\tif (alreadyIndexing) {\n\t\t\t\t\t\t\tconsole.log('[chat-engine] skipping a duplicate index request for', member.storagePath);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (existedBefore && typeof self.host.deleteExistingFileRecord === 'function') {\n\t\t\t\t\t\t\treturn Promise.resolve(self.host.deleteExistingFileRecord(member.storagePath)).catch(function () { });\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tpreIndex = preIndex.then(function () {\n\t\t\t\t\t\tif (alreadyIndexing) return;\n\t\t\t\t\t\tif (typeof self.host.ensureFileIndexRecord !== 'function') return;\n\t\t\t\t\t\treturn Promise.resolve(self.host.ensureFileIndexRecord(member.storagePath, {\n\t\t\t\t\t\t\tname: member.file.name,\n\t\t\t\t\t\t\tmime: mime || undefined,\n\t\t\t\t\t\t\tsize: member.file.size,\n\t\t\t\t\t\t})).catch(function () { });\n\t\t\t\t\t});\n\t\t\t\t\t// The access group the host actually recorded this file at. Read\n\t\t\t\t\t// AFTER ensureFileIndexRecord so the value here is the one the\n\t\t\t\t\t// \"src::\" record really carries, never a second guess at it.\n\t\t\t\t\tvar accessGroup: 'public' | 'authorized' | 'private' | undefined;\n\t\t\t\t\tpreIndex = preIndex.then(function () {\n\t\t\t\t\t\tif (alreadyIndexing) return;\n\t\t\t\t\t\tif (typeof self.host.uploadAccessGroup !== 'function') return;\n\t\t\t\t\t\treturn Promise.resolve(self.host.uploadAccessGroup(member.storagePath))\n\t\t\t\t\t\t\t.then(function (g) { accessGroup = g || undefined; })\n\t\t\t\t\t\t\t.catch(function () { });\n\t\t\t\t\t});\n\t\t\t\t\t// Run a client-side attachment parser (e.g. .hwp) if one matches; its\n\t\t\t\t\t// output is inlined into the indexing request (falls back to office\n\t\t\t\t\t// extraction / web_fetch when no parser matches or it yields nothing).\n\t\t\t\t\treturn preIndex.then(function () {\n\t\t\t\t\t\treturn parseAttachmentContent(member.file, member.file.name, mime || undefined);\n\t\t\t\t\t}).then(function (parsedContent: string | null) {\n\t\t\t\t\tif (alreadyIndexing) return;\n\t\t\t\t\t// Tracked so a chat waiting on awaitIndexingDrained cannot be sent\n\t\t\t\t\t// in the window between this call and the queue accepting it.\n\t\t\t\t\treturn self.trackIndexDispatch(notifyAgentSaveAttachment({\n\t\t\t\t\t\tplatform: id.platform as 'claude' | 'openai',\n\t\t\t\t\t\tmodel: id.model,\n\t\t\t\t\t\tservice: id.projectId,\n\t\t\t\t\t\tpublicProjectId: id.publicProjectId,\n\t\t\t\t\t\towner: id.owner,\n\t\t\t\t\t\tuserId: id.userId || id.projectId,\n\t\t\t\t\t\tserviceName: id.serviceName,\n\t\t\t\t\t\tserviceDescription: id.serviceDescription,\n\t\t\t\t\t\tattachment: {\n\t\t\t\t\t\t\tname: member.file.name, storagePath: member.storagePath,\n\t\t\t\t\t\t\tmime: mime || undefined, size: member.file.size, url: url,\n\t\t\t\t\t\t\taccessGroup: accessGroup,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tparsedContent: parsedContent || undefined,\n\t\t\t\t\t}).then(function (ack: any) {\n\t\t\t\t\t\tif (ack && typeof ack.id === 'string') {\n\t\t\t\t\t\t\tself.bgTaskQueue.push({\n\t\t\t\t\t\t\t\tprojectId: id.projectId, platform: id.platform as 'claude' | 'openai', id: ack.id,\n\t\t\t\t\t\t\t\tfilename: member.file.name,\n\t\t\t\t\t\t\t\tstoragePath: member.storagePath,\n\t\t\t\t\t\t\t\tisReindex: hadExists,\n\t\t\t\t\t\t\t\tmime: mime || undefined,\n\t\t\t\t\t\t\t\tsize: member.file.size,\n\t\t\t\t\t\t\t\tstatus: ack.status === 'running' ? 'running' : 'pending',\n\t\t\t\t\t\t\t\tpoll: ack.poll,\n\t\t\t\t\t\t\t\t// Puts this file's row directly above the chat turn it was\n\t\t\t\t\t\t\t\t// attached to (drainBgTaskQueue). Undefined for an\n\t\t\t\t\t\t\t\t// attachment-only send, which appends.\n\t\t\t\t\t\t\t\tstageId: stageId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tself.drainBgTaskQueue(); // surface \"Indexing: <file>\" as soon as THIS file uploads\n\t\t\t\t\t\t}\n\t\t\t\t\t}, function (e: any) {\n\t\t\t\t\t\tconsole.error('[chat-engine] indexing request failed', e);\n\t\t\t\t\t\t// Nothing was queued, so hand the slot back: the retry (a later\n\t\t\t\t\t\t// send of the same chip) must not be refused by this client's own\n\t\t\t\t\t\t// claim. See claimIndexRun.\n\t\t\t\t\t\tself.releaseIndexRun(member.storagePath);\n\t\t\t\t\t\tanyIndexFailed = true; // uploaded but not indexed → yellow\n\t\t\t\t\t\t// Record the first index error's code/message for the report dialog.\n\t\t\t\t\t\tif (!att.errorCode && !att.errorDetail) {\n\t\t\t\t\t\t\tatt.errorCode = (e && (e.code || (e.body && e.body.code))) || '';\n\t\t\t\t\t\t\tatt.errorDetail = (e && (e.message || (e.body && e.body.message))) || (typeof e === 'string' ? e : '');\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t\treturn chain.then(function () {\n\t\t\tatt._abort = null; att.progress = 100;\n\t\t\tif (att.kind === 'folder') att.uploadedUrls = urls.map(function (u) { return { path: u.name, url: u.url, storagePath: u.storagePath }; });\n\t\t\tatt.status = anyIndexFailed ? 'indexError' : 'done';\n\t\t\tif (att.status === 'indexError') att.errorMessage = 'File indexing failed';\n\t\t\tself.host.renderAttachmentChips();\n\t\t\treturn urls;\n\t\t});\n\t}\n\n\t// Upload all not-yet-done attachments sequentially. Resolves to the full\n\t// list of { name, url, storagePath } for composing the chat message.\n\t//\n\t// `batchId` scopes the run to the chips stamped with it at Send time. The\n\t// composer stays live during an upload, so by the time this runs the\n\t// attachment list can already hold chips the user picked for the NEXT\n\t// message — uploading those here would attach them to the wrong turn, and\n\t// collecting the previous batch's finished urls would attach files the user\n\t// already sent. Omitted (no batch) means every chip, the old behavior.\n\t//\n\t// `stageId` is the turn these chips were attached to, carried onto every indexing\n\t// task so its collapsed row renders directly ABOVE that turn's bubble (see\n\t// BgTaskEntry.stageId). Omitted for an attachment-only send, which has no turn.\n\tuploadPendingAttachments(batchId?: string, stageId?: string): Promise<Array<{ name: string; url: string; storagePath?: string }>> {\n\t\tvar self = this;\n\t\tthis.host.resetOverwriteBatch();\n\t\tthis._uploadBatches += 1;\n\t\tthis.state.uploadingAttachments = true;\n\t\tthis.host.updateComposerControls();\n\t\tthis.host.renderAttachmentChips();\n\t\tvar collected: Array<{ name: string; url: string; storagePath?: string }> = [];\n\t\tvar snapshot = this.state.attachments.filter(function (a: any) {\n\t\t\treturn batchId ? a._batchId === batchId : true;\n\t\t});\n\t\tvar chain: Promise<any> = Promise.resolve();\n\t\tsnapshot.forEach(function (att: any) {\n\t\t\tchain = chain.then(function () {\n\t\t\t\tif (!self.state.attachments.some(function (a: any) { return a.id === att.id; })) return; // removed\n\t\t\t\tif (att.status === 'done' || att.status === 'indexError') {\n\t\t\t\t\tif (att.kind === 'folder' && att.uploadedUrls) {\n\t\t\t\t\t\tatt.uploadedUrls.forEach(function (u: any) { collected.push({ name: u.path, url: u.url, storagePath: u.storagePath }); });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (att.uploadedUrl) { collected.push({ name: att.name, url: att.uploadedUrl, storagePath: att.storagePath }); return; }\n\t\t\t\t}\n\t\t\t\treturn self.uploadSingleAttachment(att, stageId).then(function (us) {\n\t\t\t\t\tcollected.push.apply(collected, us);\n\t\t\t\t}).catch(function (err: any) {\n\t\t\t\t\tvar removed = !self.state.attachments.some(function (a: any) { return a.id === att.id; });\n\t\t\t\t\tvar aborted = err && (err.message === 'Aborted' || err === 'Aborted');\n\t\t\t\t\tif (removed || aborted) return;\n\t\t\t\t\tatt.status = 'error';\n\t\t\t\t\tatt.errorMessage = 'File upload has failed';\n\t\t\t\t\t// Preserve the original error code/message for the report dialog.\n\t\t\t\t\tatt.errorCode = (err && (err.code || (err.body && err.body.code))) || '';\n\t\t\t\t\tatt.errorDetail = (err && (err.message || (err.body && err.body.message))) || (typeof err === 'string' ? err : '');\n\t\t\t\t\tself.host.renderAttachmentChips();\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t\tvar done = function () {\n\t\t\tself._uploadBatches = Math.max(0, self._uploadBatches - 1);\n\t\t\t// Only the LAST batch standing clears the flag — a second send made\n\t\t\t// while this one was uploading is still running.\n\t\t\tself.state.uploadingAttachments = self._uploadBatches > 0;\n\t\t\tself.host.updateComposerControls(); self.host.renderAttachmentChips();\n\t\t\treturn collected;\n\t\t};\n\t\treturn chain.then(done, done);\n\t}\n\n\t// Stop timers / abort the typewriter (view teardown).\n\tstop(): void {\n\t\tthis.state.typingAbort = true;\n\t}\n\n\t// Bump the gate token so any in-flight immediate-send result is dropped\n\t// (called by the view on a service/platform switch or history clear).\n\tbumpGate(): void {\n\t\tthis.state.gateRefreshToken += 1;\n\t}\n}\n","/**\n * Background file-indexing turns, collapsed into ONE row per file.\n *\n * A single upload can produce many chat turns: the first \"Indexing: <file>\" pass\n * plus up to MAX_INDEXING_RESUME_PASSES CONTINUE passes, each with its own\n * request AND response bubble. Rendered flat, that reads as the same task\n * repeating forever, and any real question the user asks in between gets buried.\n *\n * buildChatDisplayList turns the flat message array into a DISPLAY list in which\n * every message belonging to one run of one file (however far apart the passes\n * sit, and whatever else is interleaved between them) is represented by a single\n * group entry, rendered at the position of that run's FIRST loaded pass.\n *\n * First, not newest. The message array is ordered by request CREATION time, and\n * a run's later passes are created one at a time as the previous one resolves —\n * by the client for the paged text path, and by the WORKER itself for the\n * rendered-page (PDF) path, which the client only learns about on its next\n * first-page history fetch. So a pass is routinely created minutes after the\n * upload, on a queue that runs in parallel with the foreground chat. Anchoring\n * at the newest pass meant one such late pass dragged the whole run — every\n * earlier pass with it — below any question the user had asked in the meantime,\n * and made a run that had visibly finished before the question render after it.\n * Anchoring at the first pass puts the row where the run actually began, which\n * is a position no later pass can change:\n * - a new pass never relocates the row, so nothing under the reader shifts;\n * - a question asked after the upload always renders below the row, which is\n * the order it happened in.\n * The cost is that a long-running index does not follow the conversation to the\n * bottom: once the user has chatted past the upload, the spinner and the Stop\n * button sit above their newest turns. That is a scroll away, and the row no\n * longer lies about when the work started.\n *\n * Paging older history is the one thing that CAN move the row: an older page\n * carrying earlier passes of a run already on screen moves it up into that page.\n * That happens at most once per run, only for a run whose start was never\n * loaded (`mayHaveOlder`), and it is the same event that already re-derives\n * `runKey` — so the view treats it as a new row either way.\n *\n * The group deliberately reports no authoritative pass TOTAL. History is paged\n * newest-first, so any total computed from loaded messages is a lower bound that\n * a later scroll-up would contradict. It reports STATE (indexing / indexed /\n * failed), how many passes are currently loaded, and `mayHaveOlder` when the\n * file's first pass is not among them.\n *\n * For the same reason it also reports NOT KNOWING. A run whose start is still\n * being paged in, and a worker-driven run whose queue state has not been asked\n * for yet, are both rows whose state is a moving target — and on a chatbox that\n * was just opened, that is most of them. `resolving` marks those, so the view can\n * say which wait it is waiting on rather than committing to \"indexing\" or\n * \"indexed\" on a fraction of the evidence.\n *\n * Pure and view-agnostic: agent.vue and the BunnyQuery widget both render from\n * this, so the two stay identical.\n */\nimport type { ChatMessage, IndexingFileRef } from './host';\nimport { isPagedReadFile, isImageVisionFile } from './office';\nimport { windowedIndexingEnabled } from './config';\nimport { MAX_INDEXING_RESUME_PASSES } from './requests';\n\nexport type IndexingGroupStatus = 'active' | 'done' | 'error' | 'cancelled';\n\nexport type IndexingGroup = {\n\t/** The FILE this row is about: storage path when known (a file can be\n\t * re-uploaded under a name that already exists elsewhere), else name. Shared\n\t * by every run of that file, and what ChatSession.cancelIndexingGroup and\n\t * _indexKeyOf match on — never use it as a render key.\n\t *\n\t * It IS the key for persistent view state, above all the expansion state. That\n\t * used to be keyed by runKey, which is renamed the moment a run's true first\n\t * pass loads (see below) — so a row the user had opened silently closed itself\n\t * mid-indexing, every time a pass arrived ahead of the earlier ones. This never\n\t * changes for the life of a file. The cost is that two runs OF THE SAME FILE\n\t * (an index and a later re-index) open and close together, which is a fair\n\t * reading of \"show me this file's steps\" and is not a state the user can be\n\t * surprised out of. */\n\tkey: string;\n\t/** Identity of this ROW: one indexing RUN of that file. A file indexed on\n\t * Monday and re-indexed on Wednesday is two runs, and collapsing them into\n\t * one row erased Monday's from Monday's place in the conversation, claimed\n\t * its passes for Wednesday, and let Monday's failure be overwritten by\n\t * Wednesday's success. Named after the run's FIRST loaded pass (see where it\n\t * is assigned below), so passes appended to the run and other runs appearing\n\t * on either side of it never rename a row already on screen.\n\t *\n\t * This is the RENDER key, and only that. It is renamed when the run's true\n\t * first pass finally loads — routine while a worker-driven chain is running,\n\t * since a pass adopted from the queue can reach the client before the earlier\n\t * ones are paged in — and a rename is exactly right for a DOM key (the row did\n\t * change identity) but wrong for anything the USER set. Key that on `key`. */\n\trunKey: string;\n\tname: string;\n\tpath?: string;\n\tmime?: string;\n\tsize?: number;\n\t/** True when any loaded pass was a re-index of an already-stored file. */\n\tisReindex: boolean;\n\t/** Every message of this file, in chat order, with its index in the source\n\t * array (so cancel/typewriter paths keep addressing the real message). */\n\tmembers: { msg: ChatMessage; index: number }[];\n\t/** Indexing passes LOADED (request bubbles), never a server-side total. */\n\tpassCount: number;\n\tstatus: IndexingGroupStatus;\n\t/** Server item ids of the passes that are still queued/running, so the row can\n\t * offer a stop button (ChatSession.cancelIndexingGroup cancels each). Empty\n\t * when nothing is cancellable — a finished file, or a live pass whose server\n\t * id has not come back yet. */\n\tcancellableIds: string[];\n\t/** This row is in the middle of stopping: a cancel request is in flight for one\n\t * of its passes, or the user stopped the run and a pass is still running. Both\n\t * mean the same thing to a view — the Stop has been spent, so the button reads\n\t * \"Stopping...\" and is not offered again. */\n\tcancelling: boolean;\n\t/** The user stopped this run.\n\t *\n\t * NOT the same as `status === 'cancelled'`, and the difference is the whole\n\t * reason it exists: a stop landing on a pass that is already RUNNING cannot\n\t * un-run it, so the row stays `active` until that pass settles. `status` then\n\t * describes the work (something is still running) and this describes the user's\n\t * decision (no more of it will be started). */\n\tstopped: boolean;\n\t/** Why the last cancel attempt failed (e.g. the pass had already finished). */\n\tcancelError?: string;\n\t/** The file's first pass is not among the loaded messages, so earlier passes\n\t * exist in history that has not been paged in yet. */\n\tmayHaveOlder: boolean;\n\t/** Position in the source array this collapsed row renders at: the index of\n\t * the run's FIRST loaded pass (see the file docstring for why not the last). */\n\tanchorIndex: number;\n\t/** Identity of the turn at `anchorIndex` — its server item id, or its local id\n\t * while it has none, or `''` when it has neither. The views stamp this on the\n\t * row (`data-row-pos`) so the scroll anchor can tell a row that RELOCATED (an\n\t * older page moved the run's start) from one that merely gained a pass. They\n\t * must not re-derive it from `members`: which member the row renders at is\n\t * this module's decision, and the two silently disagreed once already. */\n\tanchorId: string;\n\t/** `members` minus the turns an EXPANDED row should not show: every CONTINUE\n\t * request, and the running pass's empty placeholder.\n\t *\n\t * A continuation's request bubble says \"Indexing (continuing) <file>\" and\n\t * nothing else — it repeats the row's own header once per pass, so a long file\n\t * read as the same line over and over with the actual findings buried between\n\t * them. The pass is still represented, by its RESPONSE. The placeholder goes\n\t * for a different reason: the row now carries one loader of its own for as long\n\t * as work remains, and two spinners in one open row is noise.\n\t *\n\t * Additive. `members` is untouched and is still what every count, status,\n\t * cancel and anchor decision reads — several of them are only correct on the\n\t * full list (a `mayHaveOlder` run's members[0] IS a continuation). */\n\tvisibleMembers: { msg: ChatMessage; index: number }[];\n\t/** Who advances this file's chain, which decides what can confirm it is over:\n\t * 'single' one pass and done; 'client' this client dispatches each CONTINUE\n\t * pass and stops on the model's completion marker; 'worker' the server advances\n\t * the loop off the renderer's page count and the client is only a spectator. */\n\tdriver: 'single' | 'client' | 'worker';\n\t/** Positively established that no further indexing work will happen for this\n\t * run. NOT \"the file was fully read\" — a cap-out, a failure and a stop are all\n\t * finished, and the row's own status says which.\n\t *\n\t * False means \"not established\", which includes \"still running\" AND \"we have\n\t * not been able to find out\". The view shows a loader for both, deliberately:\n\t * the alternative default is the failure this exists to prevent, a row that\n\t * reads \"Indexed\" between two passes of a file still being read. */\n\tfinished: boolean;\n\t/** This row cannot honestly claim a state yet, because something it is derived\n\t * FROM is still being fetched. Both `status` and `finished` are read off the\n\t * passes that happen to be LOADED, and on a freshly opened chatbox that is a\n\t * moving target: history pages newest-first, so a long run arrives as a tail\n\t * of CONTINUE passes while its beginning is still being paged in. The row was\n\t * picking a side through that window — a spinner reading \"Indexing\" for a file\n\t * that finished last week, or a green \"Indexed\" for one still being read — and\n\t * both are verdicts drawn from a fraction of the run.\n\t *\n\t * Only ever set from status 'done'. A loaded pending pass PROVES the run is\n\t * live, and an error or a stop is the newest pass's own outcome, which\n\t * newest-first paging always has in hand — none of those is a guess, and\n\t * hiding any of them behind a loader would lose something the user needs.\n\t *\n\t * For the 'history' reason this means \"a fetch is IN FLIGHT\", not \"the picture\n\t * is incomplete\". Older history is paged in by explicit triggers only (the\n\t * viewport fill, the user scrolling to the top) and nothing auto-fetches on a\n\t * row's behalf, so a run whose start is still unloaded once the paging stops\n\t * has to go back to reporting what it does know — `mayHaveOlder` and the `+` on\n\t * the pass count carry the rest. A \"loading...\" that never ends is the same lie\n\t * pointing the other way.\n\t *\n\t * The 'status' reason is weaker on purpose: \"the queue has not answered\", which\n\t * a permanently failing query never resolves. That is deliberate, because it is\n\t * the SAME question as what the row should say when it cannot find out, and\n\t * every alternative is worse: a grey clock reading \"checking\" claims less than\n\t * the yellow spinner reading \"Indexing\" that it replaced. It also self-heals in\n\t * practice — the answer is re-sought on every first-page history load and every\n\t * settling pass — and gating it on an in-flight query instead would mean\n\t * threading a second liveness flag through a retry ladder with nine exit\n\t * points, i.e. trading this for a flag that can stick in the other direction. */\n\tresolving: boolean;\n\t/** Which wait, so the row can name it instead of just spinning. 'history':\n\t * older pages are being fetched and this run's first pass is not among the\n\t * loaded ones. 'status': the queue has not yet said whether this file is still\n\t * being worked on, which is the only thing that can end a worker-driven run. */\n\tresolvingReason?: 'history' | 'status';\n\t/** Synthesized from a durable run:: record: none of the run's passes are\n\t * among the loaded messages (bg history still deferred, or the run is older\n\t * than the paging cap). Header-and-status only — members/visibleMembers are\n\t * empty and there is nothing to cancel; the row is replaced by the real\n\t * group the moment actual passes load (same `key`, so expansion state\n\t * carries over). */\n\tstub?: boolean;\n\t/** The run:: record's stored error text, for a stub row's meta line. */\n\tstubError?: string;\n};\n\nexport type DisplayEntry =\n\t| { kind: 'message'; msg: ChatMessage; index: number }\n\t| { kind: 'indexing'; group: IndexingGroup; index: number };\n\nexport type BuildDisplayListOptions = {\n\t/** True while older history remains unpaged, which is what makes a group\n\t * with no first pass genuinely incomplete rather than merely odd. */\n\thasMoreHistory?: boolean;\n\t/** An OLDER-history fetch is in flight right now — a single page, or the whole\n\t * viewport-fill loop (createHistoryFiller's onRunningChange, which spans the\n\t * pages between which a per-request flag keeps dropping to false).\n\t *\n\t * Older specifically. A first-page refresh cannot bring in a run's earlier\n\t * passes, so counting it here would flip every incomplete row to \"still\n\t * loading\" for the length of a poll that could never have answered it. */\n\tloadingOlderHistory?: boolean;\n\t/** Files the SERVER still has unresolved indexing work for, keyed exactly like\n\t * IndexingGroup.key (ChatSession.getLiveIndexState). */\n\tliveIndexKeys?: { [fileKey: string]: boolean };\n\t/** Whether `liveIndexKeys` has been answered at least once for this chat. False\n\t * is \"we do not know\", and a worker-driven run stays unfinished on it. */\n\tliveIndexChecked?: boolean;\n\t/** Files carrying the durable done:: completion marker (one prefix sweep),\n\t * keyed like IndexingGroup.key (storage path; the bare-name fallback keys\n\t * of very old prompts simply never match — they keep the queue inference).\n\t * A marker is PROOF the file was read to the end: it settles a worker-run\n\t * green without waiting for the queue answer, and it is never withheld by\n\t * the resolving logic. A live queue hit still outranks it (a re-index in\n\t * flight whose marker-cascade delete lagged). */\n\tdoneKeys?: { [fileKey: string]: boolean };\n\t/** Server item ids of passes that were on a row when the user STOPPED it\n\t * (ChatSession.state.stoppedIndexIds). A run holding any of them is a run the\n\t * user stopped — see the status derivation for why a stop usually leaves no\n\t * other trace in the messages. Ids rather than a file key on purpose: they name\n\t * one RUN, so a later re-index of the same file cannot inherit the stop. */\n\tstoppedIndexIds?: { [serverItemId: string]: boolean };\n\t/** Whether the WORKER drives the windowed text/grid loop (chatEngineConfig's\n\t * windowedIndexing). Passed in rather than read from config so this stays a\n\t * pure function of its inputs and can be exercised for both settings. */\n\twindowedIndexing?: boolean;\n\t/** Durable run:: records, keyed by STORAGE PATH (the consumer's marker\n\t * sweep). Each key with no real group in the loaded messages gets a\n\t * synthesized header-only row (see IndexingGroup.stub), placed by its\n\t * `started` timestamp. A real group for the same file — matched by key,\n\t * path, or name — always suppresses the stub: loaded passes are evidence,\n\t * the record is only a summary. */\n\trunStubs?: { [storagePath: string]: RunStubInfo };\n\t/** The platform whose chat this list is for. run:: records are per-FILE,\n\t * but a chat is per (project, platform): a run started under Claude has\n\t * its passes in the Claude conversation and is invisible to the\n\t * OpenAI-scoped queue probe, so its stub could never be covered and never\n\t * be confirmed — it just sat there, in a chat it did not belong to.\n\t * Records minted before this was stamped carry no platform and are shown\n\t * in both, which keeps the leak to the historical set. */\n\tstubPlatform?: 'claude' | 'openai';\n\t/** The chat's clear-history horizon (ms epoch). Run records are service-\n\t * wide and know nothing about a cleared chat, so without this every\n\t * \"Clear chat history\" resurrects one row per indexed file. A stub whose\n\t * run ended (or, unfinished, began) at or before this moment is dropped —\n\t * unless the queue says the file is live RIGHT NOW, which no horizon can\n\t * make untrue. */\n\tstubClearedAt?: number;\n\t/** Clock injection for tests; defaults to Date.now(). Only run-stub\n\t * staleness reads it. */\n\tnow?: number;\n};\n\n/** The display-relevant fields of a run:: record (see requests.ts\n * runIndexUniqueId for the record's contract). */\nexport type RunStubInfo = {\n\tstatus: 'working' | 'done' | 'error' | 'cancelled';\n\tfilename?: string;\n\tstarted?: number;\n\tfinished?: number;\n\terror?: string;\n\t/** Chat that owns this run. Absent on records minted before it was\n\t * stamped; see BuildDisplayListOptions.stubPlatform. */\n\tplatform?: 'claude' | 'openai';\n};\n\n/** Canonical form of an indexing key for COMPARISON only (never for storage).\n *\n * The two sides of every stub-vs-group comparison come from one string but by two\n * routes: the run:: record id keeps `attachment.storagePath` verbatim\n * (requests.ts runIndexUniqueId), while the group's key is recovered from the pass\n * prompt and trimmed on the way (history.ts parseIndexingRequestText). A path whose\n * first or last character is whitespace therefore produced two keys for one file, the\n * stub was never suppressed, and the file drew two rows.\n *\n * Trim only. NOT NFC: both keys derive from the same string with no normalization on\n * either side, so no NFC/NFD divergence is reachable here, and normalizing a key that\n * is also an S3 object key elsewhere is how storage paths get silently renamed.\n */\nexport function canonIndexKey(s?: string): string {\n\treturn typeof s === 'string' && s ? s.trim() : '';\n}\n\n/** A 'working' run record older than this with no live-queue confirmation is\n * treated as unknown rather than live: a chain that died without reaching any\n * error path leaves 'working' dangling, and a row must not spin forever on a\n * claim nothing can end. */\nexport const RUN_RECORD_WORKING_STALE_MS = 6 * 60 * 60 * 1000;\n\n// The indexing label is view-formatted (formatIndexingLabel), so parsing it is\n// the FALLBACK path only: it exists for bubbles restored from a history cache\n// written before `_indexFile` was stamped. Live and freshly-mapped bubbles carry\n// the structured ref and never reach this.\n//\n// Shapes produced by formatIndexingLabel:\n// \"Indexing: [name](path) · mime · 1.2 MB\"\n// \"Reindexing: name · mime\"\n// \"Indexing (continuing) [name](path)\"\nconst INDEXING_LABEL_RE = /^(Re)?[Ii]ndexing(\\s*\\(continuing\\))?\\s*:?\\s+(.+)$/;\nconst LEADING_MD_LINK_RE = /^\\[([^\\]]+)\\]\\(([^)]+)\\)/;\n\nexport function parseIndexingLabel(\n\tcontent: string,\n): { name: string; path?: string; continued: boolean; isReindex: boolean } | null {\n\tif (typeof content !== 'string' || !content) return null;\n\tvar firstLine = content.split('\\n')[0].trim();\n\tvar m = firstLine.match(INDEXING_LABEL_RE);\n\tif (!m) return null;\n\t// Only the first \" · \" segment is the file; the rest is mime/size trivia.\n\tvar head = m[3].split(' · ')[0].trim();\n\tvar link = head.match(LEADING_MD_LINK_RE);\n\tvar name = link ? link[1].trim() : head;\n\tif (!name) return null;\n\treturn {\n\t\tname: name,\n\t\tpath: link ? link[2].trim() : undefined,\n\t\tcontinued: !!m[2],\n\t\tisReindex: !!m[1],\n\t};\n}\n\n/** The file a background-indexing bubble belongs to, structured ref preferred. */\nfunction readFileRef(msg: ChatMessage): (IndexingFileRef & { continued: boolean }) | null {\n\tvar ref = msg && msg._indexFile;\n\tif (ref && (ref.path || ref.name)) {\n\t\treturn {\n\t\t\tname: ref.name || ref.path || '',\n\t\t\tpath: ref.path,\n\t\t\tmime: ref.mime,\n\t\t\tsize: ref.size,\n\t\t\tisReindex: ref.isReindex,\n\t\t\tcontinued: !!ref.continued,\n\t\t};\n\t}\n\tvar parsed = parseIndexingLabel(msg && msg.content);\n\tif (!parsed) return null;\n\treturn {\n\t\tname: parsed.name,\n\t\tpath: parsed.path,\n\t\tisReindex: parsed.isReindex,\n\t\tcontinued: parsed.continued,\n\t};\n}\n\nfunction isPendingMsg(m: ChatMessage): boolean {\n\treturn !!(m.isPending || m.isPendingInProcess || m.isPendingQueued || m.isSendingToServer);\n}\n\n/**\n * A member an EXPANDED row should not render. See IndexingGroup.visibleMembers.\n *\n * A CANCELLED continuation is an exception and stays: a cancelled item is given no\n * response bubble at all, so hiding its request would erase the only evidence that\n * the pass existed. A user bubble we cannot classify (it joined the run by server\n * id, not by a label we could parse) also stays — showing an unexpected turn is a\n * far smaller error than silently dropping one.\n */\nfunction isHiddenPass(m: ChatMessage): boolean {\n\tif (m.role === 'user') {\n\t\tif (m.isCancelled) return false;\n\t\tvar ref = readFileRef(m);\n\t\treturn !!(ref && ref.continued);\n\t}\n\treturn !!m.isPending;\n}\n\n/**\n * Collapse background-indexing turns into per-file groups.\n *\n * Messages that are not background-indexing pass through untouched, at their\n * original positions and with their original indices.\n */\nexport function buildChatDisplayList(\n\tmessages: ChatMessage[],\n\topts?: BuildDisplayListOptions,\n): DisplayEntry[] {\n\tvar list = Array.isArray(messages) ? messages : [];\n\tvar liveIndexKeys = (opts && opts.liveIndexKeys) || {};\n\tvar liveIndexChecked = !!(opts && opts.liveIndexChecked);\n\tvar doneKeys = (opts && opts.doneKeys) || {};\n\tvar stoppedIndexIds = (opts && opts.stoppedIndexIds) || {};\n\tvar windowedIndexing = opts && opts.windowedIndexing !== undefined\n\t\t? !!opts.windowedIndexing\n\t\t: windowedIndexingEnabled();\n\tvar hasMoreHistory = !!(opts && opts.hasMoreHistory);\n\tvar loadingOlderHistory = !!(opts && opts.loadingOlderHistory);\n\tvar stubPlatform = opts && opts.stubPlatform;\n\n\t// One entry per RUN (see IndexingGroup.runKey), addressed by an internal id\n\t// while the list is being walked; runKey is assigned at the end, once the\n\t// number of runs per file is known.\n\tvar groups: { [runId: string]: IndexingGroup } = {};\n\tvar order: string[] = [];\n\tvar runOfIndex: (string | undefined)[] = new Array(list.length);\n\t// A response bubble carries no file metadata of its own; it is tied to its\n\t// request by the server item id, with the immediately preceding request as\n\t// the fallback for locally-pushed bubbles that have no id yet.\n\tvar runByItemId: { [itemId: string]: string } = {};\n\t// Row already opened for a file NAME, so a pass that reports no storage path\n\t// joins it instead of opening a second row for the same file.\n\tvar keyByName: { [name: string]: string } = {};\n\t// The run currently being accumulated for each file, every run of it, and the\n\t// file each run belongs to (a run id is opaque — a file key can contain any\n\t// character, so it must never be parsed back out of one).\n\tvar openRunOfKey: { [key: string]: string } = {};\n\tvar runsOfKey: { [key: string]: string[] } = {};\n\tvar keyOfRun: { [runId: string]: string } = {};\n\t// Newest pass timestamp seen for each open run, so a FIRST pass can be told from a\n\t// re-index (it arrives AFTER the run it follows) apart from a misordered older pass\n\t// (it arrives before). Only the second must not re-open.\n\tvar newestTsOfRun: { [runId: string]: number } = {};\n\tvar runSeq = 0;\n\n\tfor (var i = 0; i < list.length; i++) {\n\t\tvar msg = list[i];\n\t\tif (!msg || !msg.isBackgroundTask) continue;\n\n\t\tvar runId: string | undefined;\n\t\tvar ref = msg.role === 'user' ? readFileRef(msg) : null;\n\t\t// A pass already attributed to a run stays with it, whatever its label says.\n\t\t// Reading the label FIRST made attribution depend on walk order: a first pass\n\t\t// (\"A new file has just been uploaded\") re-opened its file's run at the line\n\t\t// below, so if history delivered a run's continuations before its first pass -\n\t\t// which paging and the bg merge can do - the continuations opened a run, the\n\t\t// late first pass deleted it and opened a second, and the abandoned one was\n\t\t// force-finished. One run then rendered as TWO rows for the same file: a green\n\t\t// \"complete\" and a yellow \"in progress\". The same applies to a duplicate copy\n\t\t// of a pass. The id is the stable identity here; the label is a description.\n\t\tif (msg._serverItemId && runByItemId[msg._serverItemId]) {\n\t\t\trunId = runByItemId[msg._serverItemId];\n\t\t} else if (ref) {\n\t\t\t// Path first — a file can be re-uploaded under a name that already\n\t\t\t// exists elsewhere. But a pass that supplied no path (a compact\n\t\t\t// continuation label recovered from an old history cache) is still the\n\t\t\t// same file as the path-bearing passes above it, so let it join them\n\t\t\t// rather than splitting one file across two collapsed rows.\n\t\t\tvar key = ref.path || keyByName[ref.name] || ref.name;\n\t\t\t// A FIRST pass (\"A new file has just been uploaded\") when this file\n\t\t\t// already has a run open starts a new one: it is a re-index, or a\n\t\t\t// re-upload over the same storage path. Continuations join the run.\n\t\t\t//\n\t\t\t// ...but only when this pass is genuinely NEW. A first pass whose id is\n\t\t\t// already attributed is the same pass reached twice (a duplicate bubble, or\n\t\t\t// a walk that reaches it after the continuations it opened), and re-opening\n\t\t\t// on it splits one run in half.\n\t\t\tvar alreadySeen = !!(msg._serverItemId && runByItemId[msg._serverItemId]);\n\t\t\t// ...and only when it is actually LATER than the run it would replace. A\n\t\t\t// re-index's first pass follows the previous run; a misordered one precedes\n\t\t\t// the continuations already walked, and re-opening on it abandons a live run\n\t\t\t// (rendered green \"complete\") beside the fragment (yellow \"in progress\").\n\t\t\t// Timestamps decide it when both are known; without them the old\n\t\t\t// label-only behaviour stands, so the re-index case is unchanged.\n\t\t\tvar openId = openRunOfKey[key];\n\t\t\tvar notLater = false;\n\t\t\tif (openId && typeof msg._ts === 'number' && typeof newestTsOfRun[openId] === 'number') {\n\t\t\t\tnotLater = (msg._ts as number) <= newestTsOfRun[openId];\n\t\t\t}\n\t\t\tif (!ref.continued && !alreadySeen && !notLater && openRunOfKey[key]) delete openRunOfKey[key];\n\t\t\trunId = openRunOfKey[key];\n\t\t\tif (!runId) {\n\t\t\t\trunId = 'run' + (runSeq++);\n\t\t\t\topenRunOfKey[key] = runId;\n\t\t\t\tkeyOfRun[runId] = key;\n\t\t\t\t(runsOfKey[key] || (runsOfKey[key] = [])).push(runId);\n\t\t\t}\n\t\t} else if (msg.role !== 'user') {\n\t\t\t// ADJACENT only. Both paths that create a pass emit its request and\n\t\t\t// response bubbles together, so an id-less response belongs to the\n\t\t\t// message right before it. Falling back to the last file seen ANYWHERE\n\t\t\t// above swallowed stray background bubbles — an indexing prompt whose\n\t\t\t// shape we could not parse, a response whose request is not loaded —\n\t\t\t// into whichever file happened to be indexed most recently, however\n\t\t\t// much unrelated conversation sat in between.\n\t\t\trunId = runOfIndex[i - 1];\n\t\t}\n\t\t// A background bubble we cannot attribute to a file (an unrecognised label,\n\t\t// or a response whose request is not loaded) stays an ordinary message\n\t\t// rather than being folded into whichever group happens to be nearest.\n\t\tif (!runId) continue;\n\t\tif (typeof msg._ts === 'number') {\n\t\t\tvar prevTs = newestTsOfRun[runId];\n\t\t\tif (typeof prevTs !== 'number' || (msg._ts as number) > prevTs) newestTsOfRun[runId] = msg._ts as number;\n\t\t}\n\n\t\tvar g = groups[runId];\n\t\tif (!g) {\n\t\t\tvar fileKey = keyOfRun[runId];\n\t\t\tg = groups[runId] = {\n\t\t\t\tkey: fileKey,\n\t\t\t\trunKey: runId, // provisional; renumbered newest-first below\n\t\t\t\tname: ref ? ref.name : fileKey,\n\t\t\t\tpath: ref ? ref.path : undefined,\n\t\t\t\tmime: ref ? ref.mime : undefined,\n\t\t\t\tsize: ref ? ref.size : undefined,\n\t\t\t\tisReindex: !!(ref && ref.isReindex),\n\t\t\t\tmembers: [],\n\t\t\t\tpassCount: 0,\n\t\t\t\tstatus: 'done',\n\t\t\t\tcancellableIds: [],\n\t\t\t\tcancelling: false,\n\t\t\t\tstopped: false,\n\t\t\t\tmayHaveOlder: false,\n\t\t\t\t// The run's first loaded pass, and never re-stamped: see the file\n\t\t\t\t// docstring. `anchorId` is filled in once every member is known.\n\t\t\t\tanchorIndex: i,\n\t\t\t\tanchorId: '',\n\t\t\t\t// All five are derived once every member is known, below.\n\t\t\t\tvisibleMembers: [],\n\t\t\t\tdriver: 'single',\n\t\t\t\tfinished: false,\n\t\t\t\tresolving: false,\n\t\t\t};\n\t\t\torder.push(runId);\n\t\t}\n\t\tif (ref) {\n\t\t\t// Later passes carry the compact continuation label with no mime/size,\n\t\t\t// so keep the richest values any pass supplied.\n\t\t\tif (ref.name) g.name = ref.name;\n\t\t\tif (ref.path) g.path = ref.path;\n\t\t\tif (ref.mime) g.mime = ref.mime;\n\t\t\tif (typeof ref.size === 'number') g.size = ref.size;\n\t\t\tif (ref.isReindex) g.isReindex = true;\n\t\t\tif (!ref.continued) g.mayHaveOlder = false;\n\t\t\tg.passCount++;\n\t\t}\n\t\tg.members.push({ msg: msg, index: i });\n\t\trunOfIndex[i] = runId;\n\t\tif (msg._serverItemId) runByItemId[msg._serverItemId] = runId;\n\t\tif (ref && ref.name) keyByName[ref.name] = g.key;\n\t}\n\n\t// Name each run after its FIRST loaded pass. That id survives everything the\n\t// list does around it: passes appended to this run, other runs of the same\n\t// file appearing before OR after it, and an older page prepending. (An\n\t// ordinal would not — numbering from either end renames existing rows as soon\n\t// as a run appears at that end, which silently moves the user's expansion to\n\t// a row they never opened.) The one thing that changes it is the run's own\n\t// true first pass finally paging in, which happens at most once per run.\n\t// Whether a run is the NEWEST of its file. Only that one can still be running:\n\t// `liveIndexKeys` is keyed by FILE, shared by every run of it, so without this a\n\t// re-index left last week's finished row spinning for the whole of this week's\n\t// run — one file, two rows, both claiming to be working.\n\tvar newestRunOfKey: { [runId: string]: boolean } = {};\n\tfor (var nk in runsOfKey) {\n\t\tvar nrs = runsOfKey[nk];\n\t\tif (nrs.length) newestRunOfKey[nrs[nrs.length - 1]] = true;\n\t}\n\tfor (var rk in runsOfKey) {\n\t\tvar runIds = runsOfKey[rk];\n\t\tfor (var ri = 0; ri < runIds.length; ri++) {\n\t\t\tvar grpR = groups[runIds[ri]];\n\t\t\tif (!grpR) continue;\n\t\t\tvar first = grpR.members[0];\n\t\t\tvar firstId = first && first.msg && (first.msg._serverItemId || first.msg._localId);\n\t\t\t// A run whose passes are all still local (no server id yet) falls back to\n\t\t\t// its position, which is all there is to go on.\n\t\t\tgrpR.runKey = rk + '#' + (firstId || 'n' + ri);\n\t\t}\n\t}\n\n\t// Status + completeness, once every member is known.\n\tfor (var oi = 0; oi < order.length; oi++) {\n\t\tvar grp = groups[order[oi]];\n\t\t// A file's passes run strictly one after another, so a pass still marked\n\t\t// queued/running with a SETTLED pass after it is stale history, not live\n\t\t// work — the server's row for it simply never left \"running\". Ignoring\n\t\t// those matters most for pages reached by scrolling up (or by the viewport\n\t\t// fill), which get no poll attached to resolve them: one stale row would\n\t\t// otherwise flip a long-finished file back to a spinner with a \"Stop\"\n\t\t// button aimed at a dead item id, permanently.\n\t\tvar lastSettled = -1;\n\t\tfor (var si = 0; si < grp.members.length; si++) {\n\t\t\tif (!isPendingMsg(grp.members[si].msg)) lastSettled = si;\n\t\t}\n\t\tvar active = false;\n\t\tfor (var mi = lastSettled + 1; mi < grp.members.length; mi++) {\n\t\t\tif (isPendingMsg(grp.members[mi].msg)) { active = true; break; }\n\t\t}\n\t\t// Did the user STOP this run? Asked of the WHOLE run, because a stop routinely\n\t\t// leaves nothing behind at the end of it:\n\t\t// - only a QUEUED pass can be removed from the queue, and that is the one\n\t\t// case that produces a cancelled bubble. The pass that is actually running\n\t\t// cannot be un-run — it is flagged cancelled server-side, which is what\n\t\t// stops the worker enqueueing the next window, and then finishes its own\n\t\t// provider call and writes an ordinary, successful answer;\n\t\t// - a PDF (or any worker-driven file) usually has exactly ONE pass live, so\n\t\t// that running pass is normally all a stop has to act on;\n\t\t// - continuations still sitting in bgTaskQueue are dropped by\n\t\t// _applyIndexCancellations before they are ever surfaced, so they leave no\n\t\t// bubble either.\n\t\t// The messages of a stopped run therefore END in a successful pass, and reading\n\t\t// the status off the last member alone reported the stop as a green \"Indexed\"\n\t\t// over a file that was only partly read — with the newest pass's own text still\n\t\t// saying \"More pages remain\" right underneath it.\n\t\t//\n\t\t// Two witnesses, both scoped to one RUN so a later re-index of the same file\n\t\t// can never inherit a stop: a cancelled member (durable — it comes back from\n\t\t// history), and the ids ChatSession recorded when the user hit Stop (this\n\t\t// page's memory only, which is what covers the run that has no cancelled\n\t\t// member at all).\n\t\tvar stopped = false;\n\t\tfor (var ki = 0; ki < grp.members.length; ki++) {\n\t\t\tvar km = grp.members[ki].msg;\n\t\t\tif (km.isCancelled) { stopped = true; break; }\n\t\t\tif (km._serverItemId && stoppedIndexIds[km._serverItemId]) { stopped = true; break; }\n\t\t}\n\t\tgrp.stopped = stopped;\n\t\t// What a stop button would act on: the REQUEST bubble of every pass that is\n\t\t// still queued or running server-side. The assistant placeholder shares its\n\t\t// pass's server id, so ids are de-duplicated. A pass mid-cancel is left out\n\t\t// (its request is already on its way) but keeps the row in a cancelling\n\t\t// state so the button does not flicker back to \"stop\".\n\t\tfor (var xi = 0; xi < grp.members.length; xi++) {\n\t\t\tif (grp.members[xi].msg._cancelling) { grp.cancelling = true; break; }\n\t\t}\n\t\tvar seenIds: { [id: string]: boolean } = {};\n\t\tfor (var ci = 0; ci < grp.members.length; ci++) {\n\t\t\tvar cm = grp.members[ci].msg;\n\t\t\t// Report a failed Stop only while the stop is still something the user\n\t\t\t// can act on. \"Could not remove from queue\" (the pass had just started)\n\t\t\t// stays on that bubble, so reporting it from ANY member meant a row that\n\t\t\t// went on to finish normally kept describing a one-off transient failure\n\t\t\t// as a permanent property of the file, until a full history refresh\n\t\t\t// rebuilt the bubbles.\n\t\t\t//\n\t\t\t// And never for a run that IS stopped, which is the case the message gets\n\t\t\t// wrong: the only thing that failed there is removing the pass already in\n\t\t\t// flight (it cannot be un-run — it finishes and answers), while the stop\n\t\t\t// itself holds. The row says \"Stopping...\" and then \"Indexing cancelled\",\n\t\t\t// which is the accurate account; \"Could not stop this file\" beside it is\n\t\t\t// not.\n\t\t\tif (cm._cancelError && !stopped && (active || grp.cancelling)) grp.cancelError = cm._cancelError;\n\t\t\tif (cm.role !== 'user' || !cm._serverItemId || cm._cancelling || cm.isSendingToServer) continue;\n\t\t\tif (!(cm.isPendingQueued || cm.isPendingInProcess)) continue;\n\t\t\t// Same staleness rule: never offer to stop a pass a later one outlived.\n\t\t\tif (ci < lastSettled) continue;\n\t\t\tif (seenIds[cm._serverItemId]) continue;\n\t\t\tseenIds[cm._serverItemId] = true;\n\t\t\tgrp.cancellableIds.push(cm._serverItemId);\n\t\t}\n\t\tif (active) {\n\t\t\t// A pass IS still running, and a row that claimed otherwise would hide work\n\t\t\t// the user can still see the effects of. The stop is reported as `cancelling`\n\t\t\t// instead — \"Stopping...\", Stop spent — and the row settles to 'cancelled'\n\t\t\t// when that last pass lands.\n\t\t\tgrp.status = 'active';\n\t\t\tif (stopped) grp.cancelling = true;\n\t\t} else if (stopped) {\n\t\t\tgrp.status = 'cancelled';\n\t\t} else {\n\t\t\t// The newest loaded outcome is the file's state: an early pass may have\n\t\t\t// errored and a later one succeeded.\n\t\t\tvar last = grp.members[grp.members.length - 1].msg;\n\t\t\tgrp.status = last.isError ? 'error' : 'done';\n\t\t}\n\t\t// A group whose passes are ALL continuations began before the loaded\n\t\t// window; its earlier passes arrive when older history is paged in.\n\t\tvar sawFirstPass = false;\n\t\tfor (var pi = 0; pi < grp.members.length; pi++) {\n\t\t\tvar pm = grp.members[pi].msg;\n\t\t\tif (pm.role !== 'user') continue;\n\t\t\tvar pref = readFileRef(pm);\n\t\t\tif (pref && !pref.continued) { sawFirstPass = true; break; }\n\t\t}\n\t\tgrp.mayHaveOlder = !sawFirstPass && hasMoreHistory;\n\t\t// Where the row renders, and WHICH turn that is. Derived from the same\n\t\t// member so the two can never drift apart; a group always has a member\n\t\t// (it is created by the first one).\n\t\tvar anchor = grp.members[0];\n\t\tgrp.anchorIndex = anchor.index;\n\t\tgrp.anchorId = anchor.msg._serverItemId || anchor.msg._localId || '';\n\n\t\t// --- what an expanded row renders, and whether the run is over -------------\n\t\tvar sawComplete = false;\n\t\tfor (var vi = 0; vi < grp.members.length; vi++) {\n\t\t\tvar vm = grp.members[vi];\n\t\t\tif (vm.msg._indexComplete) sawComplete = true;\n\t\t\tif (!isHiddenPass(vm.msg)) grp.visibleMembers.push(vm);\n\t\t}\n\t\t// Mirrors ChatSession.maybeResumeIndexing's own routing, which is what makes\n\t\t// the answer match who will actually dispatch the next pass.\n\t\tgrp.driver = !isPagedReadFile(grp.name, grp.mime) ? 'single'\n\t\t\t: isImageVisionFile(grp.name, grp.mime) ? 'worker'\n\t\t\t\t: (windowedIndexing ? 'worker' : 'client');\n\t\tif (grp.status === 'active') {\n\t\t\tgrp.finished = false;\n\t\t} else if (grp.status === 'cancelled') {\n\t\t\t// The user stopped it. Nothing more will run, by construction.\n\t\t\tgrp.finished = true;\n\t\t} else if (grp.driver === 'single') {\n\t\t\t// One pass is the whole job: nothing continues a file that is not a paged\n\t\t\t// read, so a settled pass IS the end. Exact, and survives a reload.\n\t\t\tgrp.finished = true;\n\t\t} else if (grp.driver === 'client') {\n\t\t\t// The three branches this client itself stops dispatching on. Using the\n\t\t\t// same rule means the row cannot disagree with the pipeline: if the client\n\t\t\t// will send no more passes, the run is over whether or not the file was\n\t\t\t// fully read.\n\t\t\tgrp.finished = sawComplete || grp.status === 'error' ||\n\t\t\t\tgrp.passCount >= MAX_INDEXING_RESUME_PASSES;\n\t\t} else {\n\t\t\t// WORKER-driven, and the interesting case. Nothing in the messages can\n\t\t\t// settle it: the loop is advanced inside the worker off the renderer's page\n\t\t\t// count, the client only ever sees passes appear and settle, and the prompt\n\t\t\t// for these paths deliberately never asks for a completion marker — a model\n\t\t\t// that volunteers one is guessing, which is how an 88-page file once\n\t\t\t// \"finished\" at page 15. So sawComplete is deliberately NOT consulted here.\n\t\t\t// Either the server said this was the last pass, or the queue has been\n\t\t\t// asked and holds nothing for this file.\n\t\t\t//\n\t\t\t// A run that is NOT the newest of its file is over by construction: a newer\n\t\t\t// run exists, so this one's chain ended when that one began, and the\n\t\t\t// file-keyed queue answer describes the newer run, not this one.\n\t\t\t//\n\t\t\t// There used to be a third disjunct here, a server-stamped \"this was the\n\t\t\t// run's last pass\" (`_indexFinal`, off an `index_final` field). Nothing ever\n\t\t\t// wrote that field — not the SDK's history mapper, not the worker — so it was\n\t\t\t// permanently false and the two tests below were already carrying the whole\n\t\t\t// decision. It is gone rather than left as a hook, so this reads as what it\n\t\t\t// actually is: for a worker-driven run, ONLY the queue can say it is over.\n\t\t\t// The done:: marker is the third — and strongest — disjunct: written\n\t\t\t// only at a chain's true end (backend worker, or a client's own\n\t\t\t// deterministic completion), it answers without any queue round\n\t\t\t// trip. Gated on the queue NOT claiming the file live, so a\n\t\t\t// re-index whose marker-cascade delete lagged still shows yellow.\n\t\t\tgrp.finished = !newestRunOfKey[order[oi]] ||\n\t\t\t\t(!!doneKeys[grp.key] && !liveIndexKeys[grp.key]) ||\n\t\t\t\t(liveIndexChecked && !liveIndexKeys[grp.key]);\n\t\t}\n\n\t\t// --- is any of that knowable YET? ------------------------------------------\n\t\t// See IndexingGroup.resolving. Both answers above are read off the passes\n\t\t// that happen to be loaded, and while a fetch that would change WHICH passes\n\t\t// those are is still running, the row states the wait instead of picking a\n\t\t// side. Two waits, checked in that order because the first subsumes the\n\t\t// second: a run whose start has not arrived cannot be judged by any queue\n\t\t// answer either.\n\t\tif (grp.status !== 'done') {\n\t\t\t// 'active' is proof the run is live; 'error' and 'cancelled' are the\n\t\t\t// newest pass's own outcome, and newest-first paging always has that pass.\n\t\t\tgrp.resolving = false;\n\t\t} else if (grp.mayHaveOlder && loadingOlderHistory &&\n\t\t\t!liveIndexKeys[grp.key] && !doneKeys[grp.key] && newestRunOfKey[order[oi]]) {\n\t\t\t// The line this draws, and it is the same line the 'status' branch draws:\n\t\t\t// withhold what is UNKNOWN, and what is only INFERRED settled. Never\n\t\t\t// withhold what is PROVEN, in either direction. Two proofs, and an older\n\t\t\t// page can revise neither:\n\t\t\t// liveIndexKeys hit — the server just said this file is on the queue RIGHT\n\t\t\t// NOW. Yellow and spinning, and no amount of older history makes that\n\t\t\t// untrue. (Survives an unanswered `checked` for the reason above: only\n\t\t\t// ABSENCE needs the truncation guard.)\n\t\t\t// not the newest run of this file — a LATER run exists in the loaded\n\t\t\t// messages, so this run's chain ended when that one began. Prepending\n\t\t\t// adds OLDER messages, so it can never add a run after this one.\n\t\t\t// (A third proof used to sit here, a server-stamped last-pass flag, but\n\t\t\t// nothing ever wrote the field it read — see `finished` above.)\n\t\t\t//\n\t\t\t// What is deliberately NOT proof here: `finished` as a whole. Its remaining\n\t\t\t// source is `liveIndexChecked && !liveIndexKeys[key]`, which is an inference\n\t\t\t// from ABSENCE and is exactly what the user asked to stop reading as a green\n\t\t\t// \"Indexed\" mid-fetch. And a blanket `!grp.finished` would be wrong for a\n\t\t\t// second reason: driver 'single' also yields finished, and THAT verdict an\n\t\t\t// older page really can revise — the first pass is what carries the mime, so\n\t\t\t// a page bringing it in re-classifies the file as paged and hands the\n\t\t\t// question back to the queue.\n\t\t\tgrp.resolving = true;\n\t\t\tgrp.resolvingReason = 'history';\n\t\t} else if (!grp.finished && grp.driver === 'worker' && !liveIndexChecked && !liveIndexKeys[grp.key]) {\n\t\t\t// Worker-driven and the queue has not answered. `finished` is already\n\t\t\t// false here and the row would spin \"Indexing\" on the strength of nothing\n\t\t\t// — the same false claim, one round trip long, on every chatbox open of a\n\t\t\t// file that finished days ago. A 'client' run in the same shape is NOT\n\t\t\t// resolving: no answer is being waited for, this client is the one that\n\t\t\t// dispatches the next pass, so \"Indexing\" is a statement about its own\n\t\t\t// intent and is true.\n\t\t\t//\n\t\t\t// A POSITIVE key survives `!liveIndexChecked`, and must. `checked` is set\n\t\t\t// from `!truncated`: a capped page suppresses the whole answer, which is\n\t\t\t// right for ABSENCE (an omitted file would otherwise read as finished) and\n\t\t\t// wrong for PRESENCE, because an item the query did return is proof the\n\t\t\t// file is live. Hiding that behind \"checking...\" would withhold the one\n\t\t\t// thing here that is actually known.\n\t\t\tgrp.resolving = true;\n\t\t\tgrp.resolvingReason = 'status';\n\t\t} else {\n\t\t\tgrp.resolving = false;\n\t\t}\n\t}\n\n\t// --- durable run:: stubs ---------------------------------------------------\n\t// A run record whose passes are not among the loaded messages still deserves\n\t// a row: on a fresh open the bg history is deferred, and a run older than the\n\t// paging cap never loads at all. Synthesized as header-only groups and placed\n\t// by `started` among the messages' own timestamps; a real group for the same\n\t// file always wins (see BuildDisplayListOptions.runStubs).\n\tvar stubList: { started: number; group: IndexingGroup }[] = [];\n\tvar runStubs = opts && opts.runStubs;\n\tif (runStubs) {\n\t\t// Two namespaces, deliberately NOT one map: storage paths are\n\t\t// project-relative and folder trees repeat basenames routinely, so a\n\t\t// flat map let a real group for \"2025/report.pdf\" delete the stub for\n\t\t// \"2026/report.pdf\" with nothing replacing it. A bare NAME only covers\n\t\t// a stub when the group itself has no path (the legacy compact-label\n\t\t// case) and the record has no filename of its own to disambiguate.\n\t\tvar coveredPaths: { [k: string]: boolean } = {};\n\t\tvar coveredPathlessNames: { [k: string]: boolean } = {};\n\t\tfor (var ci = 0; ci < order.length; ci++) {\n\t\t\tvar cg = groups[order[ci]];\n\t\t\tif (cg.path) {\n\t\t\t\tcoveredPaths[canonIndexKey(cg.path)] = true;\n\t\t\t\tif (cg.key) coveredPaths[canonIndexKey(cg.key)] = true;\n\t\t\t} else if (cg.name) coveredPathlessNames[canonIndexKey(cg.name)] = true;\n\t\t\telse if (cg.key) coveredPaths[canonIndexKey(cg.key)] = true;\n\t\t}\n\t\tvar now = opts && typeof opts.now === 'number' ? opts.now : Date.now();\n\t\tvar stubClearedAt = (opts && typeof opts.stubClearedAt === 'number' && opts.stubClearedAt > 0)\n\t\t\t? opts.stubClearedAt : 0;\n\t\tfor (var sp in runStubs) {\n\t\t\tvar rec = runStubs[sp];\n\t\t\tif (!sp || !rec || !rec.status || coveredPaths[canonIndexKey(sp)]) continue;\n\t\t\tvar fname = rec.filename || sp.split('/').pop() || sp;\n\t\t\t// A PATHLESS group (legacy compact label) can only be matched by\n\t\t\t// name, and that is still the right match: the file already has a\n\t\t\t// row, so suppressing avoids a duplicate rather than creating a\n\t\t\t// void. What is gone is the reverse — a group WITH a path no longer\n\t\t\t// writes into the name namespace, so it can no longer delete a\n\t\t\t// same-basename stub from another folder.\n\t\t\tif (coveredPathlessNames[canonIndexKey(fname)]) continue;\n\t\t\t// A run recorded under the OTHER platform's chat belongs to that\n\t\t\t// conversation: its passes live in that history (so no real group\n\t\t\t// can ever cover this stub) and the queue probe is platform-scoped\n\t\t\t// (so it can never confirm it). Records with no platform are\n\t\t\t// legacy and keep the old behaviour rather than vanishing.\n\t\t\tif (stubPlatform && rec.platform && rec.platform !== stubPlatform) continue;\n\t\t\t// Mirrors the real groups' status precedence: a live queue hit outranks\n\t\t\t// whatever the record says (a lagged update must not paint a verdict over\n\t\t\t// visible work), then the record's own terminal statuses, then the\n\t\t\t// queue's authoritative ABSENCE, and only then the stated wait.\n\t\t\t// The bare-NAME disjunct is load-bearing: a legacy pass prompt may carry no\n\t\t\t// storage path at all, so the name is the only key its run can appear under.\n\t\t\t// But it also matched ANY live file sharing this basename, painting a\n\t\t\t// finished run's stub yellow because a same-named file in another folder was\n\t\t\t// indexing. Take the name hit only when it cannot belong to a different\n\t\t\t// file - i.e. no OTHER live key is a path ending in this basename.\n\t\t\tvar live = !!liveIndexKeys[sp] || !!liveIndexKeys[canonIndexKey(sp)];\n\t\t\tif (!live && (liveIndexKeys[fname] || liveIndexKeys[canonIndexKey(fname)])) {\n\t\t\t\tvar claimedByOther = false;\n\t\t\t\tfor (var lk in liveIndexKeys) {\n\t\t\t\t\tif (!liveIndexKeys[lk]) continue;\n\t\t\t\t\tvar lkc = canonIndexKey(lk);\n\t\t\t\t\tif (lkc === canonIndexKey(sp)) continue;\n\t\t\t\t\tif (lkc.length > fname.length && lkc.slice(-(fname.length + 1)) === '/' + fname) {\n\t\t\t\t\t\tclaimedByOther = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlive = !claimedByOther;\n\t\t\t}\n\t\t\t// Cleared-history horizon: a run that ended at or before the clear is\n\t\t\t// part of what the user asked to forget. A live queue hit survives it\n\t\t\t// (see BuildDisplayListOptions.stubClearedAt). A record carrying NO\n\t\t\t// timestamp at all is unplaceable, not old — the horizon cannot judge\n\t\t\t// it, so it is never dropped by one.\n\t\t\tvar recWhen = typeof rec.finished === 'number' ? rec.finished\n\t\t\t\t: typeof rec.started === 'number' ? rec.started : undefined;\n\t\t\tif (stubClearedAt && !live && recWhen !== undefined && recWhen <= stubClearedAt) continue;\n\t\t\tvar st: IndexingGroupStatus = 'active';\n\t\t\tvar fin = false;\n\t\t\tvar res = false;\n\t\t\tvar reason: 'history' | 'status' | undefined;\n\t\t\tif (!live) {\n\t\t\t\t// A done:: marker from the same sweep is as terminal as the record's\n\t\t\t\t// own 'done' — it settles a dangling 'working' the chain never\n\t\t\t\t// flipped (mirrors the real-group doneKeys disjunct).\n\t\t\t\tif (rec.status === 'done' || doneKeys[sp] || doneKeys[canonIndexKey(sp)]\n\t\t\t\t\t|| doneKeys[fname] || doneKeys[canonIndexKey(fname)]) { st = 'done'; fin = true; }\n\t\t\t\telse if (rec.status === 'error') { st = 'error'; fin = true; }\n\t\t\t\telse if (rec.status === 'cancelled') { st = 'cancelled'; fin = true; }\n\t\t\t\telse if (liveIndexChecked) {\n\t\t\t\t\t// 'working' is a CLAIM. The queue has now answered, untruncated,\n\t\t\t\t\t// and holds nothing for this file — the same proof the real-group\n\t\t\t\t\t// ladder settles on. Without this disjunct a stub had no\n\t\t\t\t\t// terminator at all: worker-driven runs are never flipped by this\n\t\t\t\t\t// client, so the row sat grey forever (the reported \"checking\n\t\t\t\t\t// status that never resolves\").\n\t\t\t\t\tst = 'done'; fin = true;\n\t\t\t\t} else if (typeof rec.started === 'number' && now - rec.started > RUN_RECORD_WORKING_STALE_MS) {\n\t\t\t\t\t// Older than any real run and still unconfirmed: a dead claim, not\n\t\t\t\t\t// an open question. Same horizon the files page applies.\n\t\t\t\t\tst = 'error'; fin = true;\n\t\t\t\t} else {\n\t\t\t\t\t// Genuinely unanswered — the queue reply is one round trip away\n\t\t\t\t\t// and this self-heals the moment it lands.\n\t\t\t\t\tres = true; reason = 'status';\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar sg: IndexingGroup = {\n\t\t\t\tkey: sp,\n\t\t\t\t// ONE identity for the run whether it renders from the record or\n\t\t\t\t// from its loaded passes: the views key the DOM off runKey, so a\n\t\t\t\t// 'stub:'-prefixed key meant every handoff was an unmount plus a\n\t\t\t\t// remount somewhere else. Named after the record's start, which\n\t\t\t\t// the real group below reuses when it has one.\n\t\t\t\trunKey: 'run:' + sp + '#' + (typeof rec.started === 'number' ? rec.started : 'n'),\n\t\t\t\tname: fname,\n\t\t\t\tpath: sp,\n\t\t\t\tmime: undefined,\n\t\t\t\tsize: undefined,\n\t\t\t\tisReindex: false,\n\t\t\t\tmembers: [],\n\t\t\t\tpassCount: 0,\n\t\t\t\tstatus: st,\n\t\t\t\tcancellableIds: [],\n\t\t\t\tcancelling: false,\n\t\t\t\tstopped: st === 'cancelled',\n\t\t\t\tmayHaveOlder: hasMoreHistory,\n\t\t\t\tanchorIndex: -1,\n\t\t\t\tanchorId: '',\n\t\t\t\tvisibleMembers: [],\n\t\t\t\tdriver: !isPagedReadFile(fname, undefined) ? 'single'\n\t\t\t\t\t: isImageVisionFile(fname, undefined) ? 'worker'\n\t\t\t\t\t\t: (windowedIndexing ? 'worker' : 'client'),\n\t\t\t\tfinished: fin,\n\t\t\t\tresolving: res,\n\t\t\t\tresolvingReason: reason,\n\t\t\t\tstub: true,\n\t\t\t\tstubError: rec.error || (st === 'error' && !rec.error\n\t\t\t\t\t? 'Indexing did not finish.' : undefined),\n\t\t\t};\n\t\t\t// A record with no `started` cannot be placed in the conversation.\n\t\t\t// Infinity sorts it to the END (nearest the newest turns) instead of\n\t\t\t// above every message the user has ever sent — the row is about\n\t\t\t// something recent, not about the beginning of time.\n\t\t\tstubList.push({ started: typeof rec.started === 'number' ? rec.started : Infinity, group: sg });\n\t\t}\n\t}\n\n\t// --- timestamp-anchor INCOMPLETE real runs ---------------------------------\n\t// A real run's row renders at its first LOADED pass, and while older history\n\t// pages in (newest-first) that is a moving target: the run first appears at\n\t// its newest pass — down by the recent bubbles — then relocates upward as\n\t// earlier passes arrive, so the row visibly jumps. The run:: record's\n\t// `started` is a stable anchor for exactly that window: emit the row at its\n\t// timestamp position instead, and once the true first pass loads\n\t// (mayHaveOlder false) emission returns to the anchor, which by then IS the\n\t// same spot. Newest run of the file only — the record describes it, and an\n\t// older run's passes are already fully placed around it.\n\t//\n\t// NOT gated on mayHaveOlder: that made the position depend on WHICH passes\n\t// happened to be loaded, so a row moved when the sweep resolved, again when\n\t// the first pass paged in, and again when paging ended. A record with a\n\t// `started` places the run at ONE spot for as long as the record exists.\n\tvar suppressAnchor: { [runId: string]: boolean } = {};\n\tvar stubByCanon: { [k: string]: RunStubInfo } = {};\n\tif (runStubs) for (var ck in runStubs) stubByCanon[canonIndexKey(ck)] = runStubs[ck];\n\tif (runStubs) {\n\t\tfor (var ti2 = 0; ti2 < order.length; ti2++) {\n\t\t\tvar tg = groups[order[ti2]];\n\t\t\tif (!newestRunOfKey[order[ti2]]) continue;\n\t\t\tvar trec = (tg.path && (runStubs[tg.path] || stubByCanon[canonIndexKey(tg.path)]))\n\t\t\t\t|| runStubs[tg.key] || stubByCanon[canonIndexKey(tg.key)];\n\t\t\tif (!trec || typeof trec.started !== 'number') continue;\n\t\t\tif (stubPlatform && trec.platform && trec.platform !== stubPlatform) continue;\n\t\t\tsuppressAnchor[order[ti2]] = true;\n\t\t\t// Same identity the stub form uses, so a row that upgrades from\n\t\t\t// record-only to loaded-passes keeps its DOM node and its position.\n\t\t\ttg.runKey = 'run:' + (tg.path || tg.key) + '#' + trec.started;\n\t\t\tstubList.push({ started: trec.started, group: tg });\n\t\t}\n\t}\n\tstubList.sort(function (a, b) { return a.started - b.started; });\n\n\tvar out: DisplayEntry[] = [];\n\tvar si = 0;\n\tfor (var j = 0; j < list.length; j++) {\n\t\t// Splice stubs in by time: everything that started before this message\n\t\t// goes above it. Messages without a timestamp decide nothing.\n\t\tvar mts = list[j] && typeof list[j]._ts === 'number' ? (list[j]._ts as number) : undefined;\n\t\tif (mts !== undefined) {\n\t\t\twhile (si < stubList.length && stubList[si].started <= mts) {\n\t\t\t\tout.push({ kind: 'indexing', group: stubList[si].group, index: -1 - si });\n\t\t\t\tsi++;\n\t\t\t}\n\t\t}\n\t\tvar r = runOfIndex[j];\n\t\tif (r === undefined) {\n\t\t\tout.push({ kind: 'message', msg: list[j], index: j });\n\t\t\tcontinue;\n\t\t}\n\t\t// Every other member of the run is represented by the row at the anchor —\n\t\t// unless the row is timestamp-anchored (incomplete run with a run::\n\t\t// record), in which case the flush above already emitted it.\n\t\tif (groups[r].anchorIndex === j && !suppressAnchor[r]) {\n\t\t\tout.push({ kind: 'indexing', group: groups[r], index: j });\n\t\t}\n\t}\n\twhile (si < stubList.length) {\n\t\tout.push({ kind: 'indexing', group: stubList[si].group, index: -1 - si });\n\t\tsi++;\n\t}\n\treturn out;\n}\n"]}