bunnyquery 1.8.5 → 1.8.6

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/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/viewport_fill.ts","../src/engine/session.ts","../src/engine/indexing_groups.ts"],"names":["remotePath","i","resolvedModel","m"],"mappings":"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","file":"engine.cjs","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\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): ComposedUserMessage {\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 = attachmentUrls.filter((u) => isServerExtractable(u.name));\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};\n\nexport function buildChatSystemPrompt(params: ChatSystemPromptParams): string {\n\tconst { projectId, serviceName, serviceDescription } = 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.\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 \"GODADDY\" appears as \"DNH*GODADDY#4070277042\", and a card as \"4140****2941\". 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- Most 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) have ALREADY had their text extracted on the server and inlined in the same message between the \"BEGIN FILE CONTENT\" / \"END FILE CONTENT\" markers - read it directly there and do NOT call web_fetch for those files. A \"[skapi: ...]\" note in that block means the 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\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 * 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 * 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 * 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 * Deliberately far longer than EXPIRED_LINK_REFRESH_EXPIRES_SECONDS above, and\n * that is the whole trick: the url is short-lived while the file stays available\n * locally for a WEEK. What keeps an image painting is the cached BODY, not a live\n * url. Once the browser evicts that body it refetches with a url that has since\n * expired, gets a 403, and the error path re-mints with `refresh`. That path is\n * therefore 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// 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 */\nexport function linkUnavailableKeyForPath(remotePath: string): string {\n\treturn 'path:' + (remotePath || '');\n}\n\nexport function linkUnavailableKeyForHref(href: string): string {\n\treturn 'href:' + (href || '');\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 getContextWindow: a suffixed id\n// falls back to its family rather than to the platform default). Claude figures\n// 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// 'claude-opus-4-7' read 200000 here, which was wrong by 5x, and the default\n// Claude model 'claude-sonnet-4-6' was absent entirely so it fell through to\n// CONTEXT_WINDOW_DEFAULT.claude. Neither was observable, because the history\n// budget and the Claude per-request cap below bind long before the window does.\nexport var CONTEXT_WINDOW_BY_MODEL: Record<string, number> = {\n\t// exact ids\n\t'claude-opus-5': 1000000, 'claude-opus-4-8': 1000000, 'claude-opus-4-7': 1000000,\n\t'claude-sonnet-5': 1000000, 'claude-sonnet-4-6': 1000000, 'claude-sonnet-4': 200000,\n\t'claude-haiku-4-5': 200000, 'gpt-5.4': 128000, 'gpt-5.6-luna': 128000,\n\t// family keys\n\t'claude-opus': 1000000, 'claude-sonnet': 1000000, 'claude-haiku': 200000,\n\t'gpt-5.6': 128000, 'gpt-5': 128000,\n};\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> = {};\n\n/**\n * Record context windows from a provider models listing. Accepts the raw list\n * items and reads `max_input_tokens` (Anthropic); items without it are skipped,\n * so passing an OpenAI listing is a no-op rather than an error.\n */\nexport function registerModelContextWindows(models: Array<{ id?: string; max_input_tokens?: number }> | null | undefined): 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\tvar reported = m ? Number(m.max_input_tokens) : NaN;\n\t\tif (id && Number.isFinite(reported) && reported > 0) {\n\t\t\tapiReportedContextWindows[id] = Math.floor(reported);\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}\nexport var OUTPUT_TOKEN_RESERVE = 22000;\nexport var TOOL_AND_RESPONSE_BUFFER = 4000;\nexport var MIN_INPUT_TOKEN_BUDGET = 8000;\nexport var CLAUDE_PER_REQUEST_INPUT_CAP = 28000;\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// Calibrated to reproduce the previous fixed values at the default windows:\n// claude 200000 -> cap 27840 (was 28000, so the 28000 floor holds), and\n// openai 128000 -> history 8160 (~the previous 8000). Both are floored at the\n// old constants, so these can only ever raise a budget, never lower one.\nexport var CLAUDE_INPUT_CAP_RATIO = 0.16;\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 * Resolve a model's context window, most specific source first:\n * 1. per-project override (project settings)\n * 2. the provider's own models listing (Anthropic `max_input_tokens`)\n * 3. an exact entry in CONTEXT_WINDOW_BY_MODEL\n * 4. a family entry, by dropping trailing '-' segments off the id\n * 5. the platform default\n *\n * Step 4 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 */\nexport function getContextWindow(platform: string, model?: string, projectId?: string): number {\n\tvar override = projectId ? getProjectContextWindow(projectId) : null;\n\tif (override) return override;\n\n\tvar normalized = (model || '').trim().toLowerCase();\n\tif (normalized) {\n\t\tif (apiReportedContextWindows[normalized]) return apiReportedContextWindows[normalized];\n\t\tif (CONTEXT_WINDOW_BY_MODEL[normalized]) return CONTEXT_WINDOW_BY_MODEL[normalized];\n\n\t\tvar parts = normalized.split('-');\n\t\tfor (var end = parts.length - 1; end > 0; end--) {\n\t\t\tvar family = parts.slice(0, end).join('-');\n\t\t\tif (CONTEXT_WINDOW_BY_MODEL[family]) return CONTEXT_WINDOW_BY_MODEL[family];\n\t\t}\n\t}\n\treturn CONTEXT_WINDOW_DEFAULT[platform];\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 contextWindow = getContextWindow(options.platform, options.model, options.projectId);\n\tvar contextBasedBudget = Math.max(MIN_INPUT_TOKEN_BUDGET,\n\t\tcontextWindow - OUTPUT_TOKEN_RESERVE - TOOL_AND_RESPONSE_BUFFER);\n\t// Scaling is gated on an EXPLICIT per-project window set from project\n\t// settings. Without one, the fixed ceilings apply exactly as before, so every\n\t// existing project keeps byte-identical behavior and nobody's token spend\n\t// moves because a table value was corrected. With one, the Claude per-request\n\t// cap and the history budget scale off the window, so raising it genuinely\n\t// sends more history instead of being absorbed by a hardcoded ceiling.\n\t// Both derive from contextBasedBudget (pre-Claude-cap) so the two platforms\n\t// scale symmetrically rather than the Claude cap compounding the ratio down.\n\tvar scaled = !!(options.projectId && getProjectContextWindow(options.projectId));\n\tvar claudeInputCap = scaled\n\t\t? Math.max(CLAUDE_PER_REQUEST_INPUT_CAP, Math.round(contextBasedBudget * CLAUDE_INPUT_CAP_RATIO))\n\t\t: CLAUDE_PER_REQUEST_INPUT_CAP;\n\tvar availableInputBudget = options.platform === 'claude'\n\t\t? Math.min(contextBasedBudget, claudeInputCap) : contextBasedBudget;\n\tvar systemCost = estimateTextTokens(options.systemPrompt) + 12;\n\tvar historyAllowance = scaled\n\t\t? Math.max(HISTORY_TOKEN_BUDGET, Math.round(contextBasedBudget * HISTORY_BUDGET_RATIO))\n\t\t: HISTORY_TOKEN_BUDGET;\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 = scaled\n\t\t? Math.max(MAX_HISTORY_MESSAGES, Math.round(MAX_HISTORY_MESSAGES * (budgetForHistory / HISTORY_TOKEN_BUDGET)))\n\t\t: MAX_HISTORY_MESSAGES;\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' loading=\"lazy\" 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 } 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\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}\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\t// Same headroom the chip cache uses: drop the url before it dies, never after.\n\tif (hit && Date.now() - hit.at < LINK_REFRESH_WINDOW_MS) return hit.url;\n\treturn null;\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\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\tif (warm) { img.setAttribute('src', warm); return; } // same frame, no flash\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}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\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\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\timg.removeAttribute('src');\n\tresolveImagePreviewUrl(ctx, path, type, true).then(function (url) {\n\t\timg.setAttribute('src', url);\n\t}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tif (ctx.onError) ctx.onError(path, e);\n\t});\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\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 MAX_TOKENS = 25000;\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-4-6';\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 (MAX_TOKENS, 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: MAX_TOKENS,\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: MAX_TOKENS,\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// 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\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 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: MAX_TOKENS,\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\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 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: MAX_TOKENS,\n\t\t\t...skapiExtract,\n\t\t\t...skapiRender,\n\t\t\t...skapiWindow,\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 * 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: { service?: string; owner?: string; platform: 'claude' | 'openai'; queue?: string; status?: 'pending' | 'running' | 'resolved' | 'failed' },\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);\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 * 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 } from './requests';\nimport { isErrorResponseBody, getErrorMessage } from './errors';\nimport { sanitizeAttachmentLinksForHistory } from './links';\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\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\tvar userText = extractLastUserTextFromRequest(requestBody);\n\t\tvar assistantText = isPending ? '' : ((extractAssistantText(response) || '').trim() || '');\n\t\tvar isErrorResponse = !isPending && (isFailed || 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 && !!assistantText &&\n\t\t\tassistantText.indexOf(INDEXING_COMPLETE_MARKER) !== -1;\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 (isInProcess) userMsg.isPendingInProcess = true;\n\t\t\tif (isQueued) userMsg.isPendingQueued = true;\n\t\t\tif (isCancelledItem) userMsg.isCancelled = 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\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._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._isBgTask) okm.isBackgroundTask = 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\treturn { messages: mapped, runningItemIds: runningItemIds };\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\tANTHROPIC_MESSAGES_API_URL,\n\tOPENAI_RESPONSES_API_URL,\n\ttype BgTaskEntry,\n} from './requests';\nimport { isPagedReadFile, isImageVisionFile, isWindowedReadFile } from './office';\nimport { windowedIndexingEnabled } from './config';\nimport { isErrorResponseBody, isAuthExpiredError, isNonRetryableRequestError, getErrorMessage } from './errors';\nimport { buildBoundedChatMessages } from './budget';\nimport { createInlineLinkRegex } from './links';\nimport { markImagePreviewStale } from './image_preview';\nimport { mapHistoryListToMessages, extractLastUserTextFromRequest, isIndexingRequestText, parseIndexingRequestText } 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.\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// 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\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\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(getChatHistory(\n\t\t\t\t{ service: id.projectId, owner: id.owner, platform: platform as 'claude' | 'openai', queue: queue, status: status },\n\t\t\t\t{ limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t)).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\tthis._adoptWorkerIndexingPasses(0);\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\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\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 * 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}\n\t\t\t\t\tvar dp = initial.poll({ latency: POLL_INTERVAL });\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 existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };\n\t\t\t\tvar reply: ChatMessage = { role: 'assistant', content: result.content, isError: result.isError };\n\n\t\t\t\t// REPLACE the trailing pending \"Thinking...\" bubble in the cache with\n\t\t\t\t// the answer (falling back to append when none is present), regardless\n\t\t\t\t// of whether this chat is the currently-visible view. The cache must\n\t\t\t\t// NEVER retain a pending \"Thinking...\" bubble: even when the chatbox is\n\t\t\t\t// showing this chat, typewriteLatestReply swaps the bubble only in\n\t\t\t\t// state.messages and NEVER re-snapshots the cache — so appending a\n\t\t\t\t// duplicate here would leave the cached copy stuck pending, and a later\n\t\t\t\t// cache-first remount (agent.vue's loadChatHistory) would re-render that\n\t\t\t\t// \"Thinking...\" forever. typewriteLatestReply still finds this reply (it\n\t\t\t\t// reads the latest non-pending assistant from the cache), so replacing is\n\t\t\t\t// correct for the visible case too. The next fresh history fetch\n\t\t\t\t// reconciles it either way.\n\t\t\t\tvar msgs = existing.messages.slice();\n\t\t\t\tvar idx = -1;\n\t\t\t\tfor (var i = msgs.length - 1; i >= 0; i--) {\n\t\t\t\t\tvar m = msgs[i];\n\t\t\t\t\tif (m && m.isPending && m.role === 'assistant' && !m.isBackgroundTask) { idx = i; break; }\n\t\t\t\t}\n\t\t\t\tif (idx !== -1) {\n\t\t\t\t\treply._serverItemId = msgs[idx]._serverItemId;\n\t\t\t\t\tmsgs[idx] = reply;\n\t\t\t\t} else {\n\t\t\t\t\tmsgs.push(reply);\n\t\t\t\t}\n\t\t\t\tself.aiChatHistoryCache[params.key] = {\n\t\t\t\t\tmessages: msgs,\n\t\t\t\t\tendOfList: existing.endOfList,\n\t\t\t\t\tstartKeyHistory: existing.startKeyHistory,\n\t\t\t\t};\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\tPromise.resolve(getChatHistory(\n\t\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status },\n\t\t\t\t\t{ limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t)).then(function (r: any) { settle(r); }, 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.host.scrollToBottom(true);\n\n\t\t\tvar capturedComposed = composed, capturedPlatform = aiPlatform, capturedKey = key;\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\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 = result.poll({ latency: POLL_INTERVAL });\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\tvar immediatePlaceholder: ChatMessage = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, ...(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.host.scrollToBottom(true);\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 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});\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\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\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\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\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}\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): 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\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(getChatHistory(\n\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status },\n\t\t\t\t{ limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t)).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\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);\n\t\t\t}, WORKER_PASS_ADOPT_ATTEMPTS[attempt + 1]);\n\t\t}, function () { self._adoptingWorkerPasses = false; });\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]) this.bgTaskQueue.splice(i, 1);\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\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\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)) { endOfClientChain(); return; }\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)) { endOfClientChain(); return; } // a failed pass is not \"incomplete\"\n\t\t\tvar answer = (platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '';\n\t\t\tif (answer.indexOf(INDEXING_COMPLETE_MARKER) !== -1) { endOfClientChain(); return; } // fully indexed\n\t\t\tvar pass = (entry.resumePass || 0) + 1;\n\t\t\tif (pass > MAX_INDEXING_RESUME_PASSES) { endOfClientChain(); return; } // give up after the cap\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (!id || id.platform === 'none' || id.projectId !== entry.projectId) return;\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\n\t\tvar fetchHistory = function () { return getChatHistory({ service: projectId, owner: owner, platform: platform }, 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\tif (isIndexingRequestText(extractLastUserTextFromRequest(item.request_body))) 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\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\n\t\t\tif (fetchMore) {\n\t\t\t\tself.state.messages = mapped.concat(self.state.messages);\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\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\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 (mm.isBackgroundTask) continue;\n\t\t\t\t\t// Belongs to a different chat (another project, or another\n\t\t\t\t\t// platform on this one) — it must not be carried onto THIS\n\t\t\t\t\t// chat's freshly-fetched history.\n\t\t\t\t\tif (mm._ownerKey !== undefined && mm._ownerKey !== loadKey) continue;\n\t\t\t\t\tif (mm._serverItemId && serverIds[mm._serverItemId]) continue;\n\t\t\t\t\tif (!mm._serverItemId) {\n\t\t\t\t\t\t// A staged turn (files still uploading) has no server request\n\t\t\t\t\t\t// yet, so nothing in `mapped` can stand for it — rescue it\n\t\t\t\t\t\t// unconditionally. The mappedHasPendingAssistant skip below is\n\t\t\t\t\t\t// about a turn the server ALREADY has; applying it here would\n\t\t\t\t\t\t// delete the user's message mid-upload whenever some other\n\t\t\t\t\t\t// turn happened to be in flight.\n\t\t\t\t\t\tif (mm._stageId) { rescued.push(mm); continue; }\n\t\t\t\t\t\tif (mappedHasPendingAssistant) continue;\n\t\t\t\t\t\tif (mm.isSendingToServer || mm.isPendingQueued || mm.isPendingInProcess || mm.isPending) rescued.push(mm);\n\t\t\t\t\t\telse if (self.state.sending && mm.role === 'user') {\n\t\t\t\t\t\t\tvar next = self.state.messages[ri + 1];\n\t\t\t\t\t\t\tif (next && !next.isBackgroundTask && next.isPending && !next._serverItemId) rescued.push(mm);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\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 retainedOlder: ChatMessage[] = (!sharesPage1 || oldestInPage1 === 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\treturn (m._serverItemId as string) < (oldestInPage1 as string);\n\t\t\t\t});\n\t\t\t\tkeptOlderPages = retainedOlder.length > 0;\n\t\t\t\tself.state.messages = keptOlderPages ? retainedOlder.concat(mapped) : mapped;\n\t\t\t\trescued.forEach(function (m) { self.state.messages.push(m); });\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 && chatList.length > 0) {\n\t\t\t\t\tvar oldestUpdated = Number(chatList[chatList.length - 1] && chatList[chatList.length - 1].updated);\n\t\t\t\t\tif (isFinite(oldestUpdated) && oldestUpdated <= clearedAt) self.state.historyEndOfList = true;\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\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 pp = item.poll({\n\t\t\t\t\t\tlatency: POLL_INTERVAL,\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\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\tif (!fetchMore) return 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\tatt.status = 'uploading'; att.progress = 0; 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};\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/** 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};\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 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\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\tgrp.finished = !newestRunOfKey[order[oi]] ||\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] && 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\tvar out: DisplayEntry[] = [];\n\tfor (var j = 0; j < list.length; j++) {\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\tif (groups[r].anchorIndex === j) out.push({ kind: 'indexing', group: groups[r], index: j });\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/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/viewport_fill.ts","../src/engine/session.ts","../src/engine/indexing_groups.ts"],"names":["remotePath","i","resolvedModel","m"],"mappings":"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","file":"engine.cjs","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\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): ComposedUserMessage {\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 = attachmentUrls.filter((u) => isServerExtractable(u.name));\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};\n\nexport function buildChatSystemPrompt(params: ChatSystemPromptParams): string {\n\tconst { projectId, serviceName, serviceDescription } = 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.\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 \"GODADDY\" appears as \"DNH*GODADDY#4070277042\", and a card as \"4140****2941\". 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- Most 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) have ALREADY had their text extracted on the server and inlined in the same message between the \"BEGIN FILE CONTENT\" / \"END FILE CONTENT\" markers - read it directly there and do NOT call web_fetch for those files. A \"[skapi: ...]\" note in that block means the 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\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 * 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 * 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 * 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 * Deliberately far longer than EXPIRED_LINK_REFRESH_EXPIRES_SECONDS above, and\n * that is the whole trick: the url is short-lived while the file stays available\n * locally for a WEEK. What keeps an image painting is the cached BODY, not a live\n * url. Once the browser evicts that body it refetches with a url that has since\n * expired, gets a 403, and the error path re-mints with `refresh`. That path is\n * therefore 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// 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 */\nexport function linkUnavailableKeyForPath(remotePath: string): string {\n\treturn 'path:' + (remotePath || '');\n}\n\nexport function linkUnavailableKeyForHref(href: string): string {\n\treturn 'href:' + (href || '');\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 getContextWindow: a suffixed id\n// falls back to its family rather than to the platform default). Claude figures\n// 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// 'claude-opus-4-7' read 200000 here, which was wrong by 5x, and the default\n// Claude model 'claude-sonnet-4-6' was absent entirely so it fell through to\n// CONTEXT_WINDOW_DEFAULT.claude. Neither was observable, because the history\n// budget and the Claude per-request cap below bind long before the window does.\nexport var CONTEXT_WINDOW_BY_MODEL: Record<string, number> = {\n\t// exact ids\n\t'claude-opus-5': 1000000, 'claude-opus-4-8': 1000000, 'claude-opus-4-7': 1000000,\n\t'claude-sonnet-5': 1000000, 'claude-sonnet-4-6': 1000000, 'claude-sonnet-4': 200000,\n\t'claude-haiku-4-5': 200000, 'gpt-5.4': 128000, 'gpt-5.6-luna': 128000,\n\t// family keys\n\t'claude-opus': 1000000, 'claude-sonnet': 1000000, 'claude-haiku': 200000,\n\t'gpt-5.6': 128000, 'gpt-5': 128000,\n};\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> = {};\n\n/**\n * Record context windows from a provider models listing. Accepts the raw list\n * items and reads `max_input_tokens` (Anthropic); items without it are skipped,\n * so passing an OpenAI listing is a no-op rather than an error.\n */\nexport function registerModelContextWindows(models: Array<{ id?: string; max_input_tokens?: number }> | null | undefined): 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\tvar reported = m ? Number(m.max_input_tokens) : NaN;\n\t\tif (id && Number.isFinite(reported) && reported > 0) {\n\t\t\tapiReportedContextWindows[id] = Math.floor(reported);\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}\nexport var OUTPUT_TOKEN_RESERVE = 22000;\nexport var TOOL_AND_RESPONSE_BUFFER = 4000;\nexport var MIN_INPUT_TOKEN_BUDGET = 8000;\nexport var CLAUDE_PER_REQUEST_INPUT_CAP = 28000;\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// Calibrated to reproduce the previous fixed values at the default windows:\n// claude 200000 -> cap 27840 (was 28000, so the 28000 floor holds), and\n// openai 128000 -> history 8160 (~the previous 8000). Both are floored at the\n// old constants, so these can only ever raise a budget, never lower one.\nexport var CLAUDE_INPUT_CAP_RATIO = 0.16;\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 * Resolve a model's context window, most specific source first:\n * 1. per-project override (project settings)\n * 2. the provider's own models listing (Anthropic `max_input_tokens`)\n * 3. an exact entry in CONTEXT_WINDOW_BY_MODEL\n * 4. a family entry, by dropping trailing '-' segments off the id\n * 5. the platform default\n *\n * Step 4 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 */\nexport function getContextWindow(platform: string, model?: string, projectId?: string): number {\n\tvar override = projectId ? getProjectContextWindow(projectId) : null;\n\tif (override) return override;\n\n\tvar normalized = (model || '').trim().toLowerCase();\n\tif (normalized) {\n\t\tif (apiReportedContextWindows[normalized]) return apiReportedContextWindows[normalized];\n\t\tif (CONTEXT_WINDOW_BY_MODEL[normalized]) return CONTEXT_WINDOW_BY_MODEL[normalized];\n\n\t\tvar parts = normalized.split('-');\n\t\tfor (var end = parts.length - 1; end > 0; end--) {\n\t\t\tvar family = parts.slice(0, end).join('-');\n\t\t\tif (CONTEXT_WINDOW_BY_MODEL[family]) return CONTEXT_WINDOW_BY_MODEL[family];\n\t\t}\n\t}\n\treturn CONTEXT_WINDOW_DEFAULT[platform];\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 contextWindow = getContextWindow(options.platform, options.model, options.projectId);\n\tvar contextBasedBudget = Math.max(MIN_INPUT_TOKEN_BUDGET,\n\t\tcontextWindow - OUTPUT_TOKEN_RESERVE - TOOL_AND_RESPONSE_BUFFER);\n\t// Scaling is gated on an EXPLICIT per-project window set from project\n\t// settings. Without one, the fixed ceilings apply exactly as before, so every\n\t// existing project keeps byte-identical behavior and nobody's token spend\n\t// moves because a table value was corrected. With one, the Claude per-request\n\t// cap and the history budget scale off the window, so raising it genuinely\n\t// sends more history instead of being absorbed by a hardcoded ceiling.\n\t// Both derive from contextBasedBudget (pre-Claude-cap) so the two platforms\n\t// scale symmetrically rather than the Claude cap compounding the ratio down.\n\tvar scaled = !!(options.projectId && getProjectContextWindow(options.projectId));\n\tvar claudeInputCap = scaled\n\t\t? Math.max(CLAUDE_PER_REQUEST_INPUT_CAP, Math.round(contextBasedBudget * CLAUDE_INPUT_CAP_RATIO))\n\t\t: CLAUDE_PER_REQUEST_INPUT_CAP;\n\tvar availableInputBudget = options.platform === 'claude'\n\t\t? Math.min(contextBasedBudget, claudeInputCap) : contextBasedBudget;\n\tvar systemCost = estimateTextTokens(options.systemPrompt) + 12;\n\tvar historyAllowance = scaled\n\t\t? Math.max(HISTORY_TOKEN_BUDGET, Math.round(contextBasedBudget * HISTORY_BUDGET_RATIO))\n\t\t: HISTORY_TOKEN_BUDGET;\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 = scaled\n\t\t? Math.max(MAX_HISTORY_MESSAGES, Math.round(MAX_HISTORY_MESSAGES * (budgetForHistory / HISTORY_TOKEN_BUDGET)))\n\t\t: MAX_HISTORY_MESSAGES;\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' loading=\"lazy\" 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 } 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\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}\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\t// Same headroom the chip cache uses: drop the url before it dies, never after.\n\tif (hit && Date.now() - hit.at < LINK_REFRESH_WINDOW_MS) return hit.url;\n\treturn null;\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\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\tif (warm) { img.setAttribute('src', warm); return; } // same frame, no flash\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}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\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\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\timg.removeAttribute('src');\n\tresolveImagePreviewUrl(ctx, path, type, true).then(function (url) {\n\t\timg.setAttribute('src', url);\n\t}, function (e) {\n\t\timg.setAttribute('data-bq-img-state', 'error');\n\t\tif (ctx.onError) ctx.onError(path, e);\n\t});\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\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 MAX_TOKENS = 25000;\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 (MAX_TOKENS, 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: MAX_TOKENS,\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: MAX_TOKENS,\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// 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\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 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: MAX_TOKENS,\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\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 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: MAX_TOKENS,\n\t\t\t...skapiExtract,\n\t\t\t...skapiRender,\n\t\t\t...skapiWindow,\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 * 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: { service?: string; owner?: string; platform: 'claude' | 'openai'; queue?: string; status?: 'pending' | 'running' | 'resolved' | 'failed' },\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);\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 * 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 } from './requests';\nimport { isErrorResponseBody, getErrorMessage } from './errors';\nimport { sanitizeAttachmentLinksForHistory } from './links';\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\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\tvar userText = extractLastUserTextFromRequest(requestBody);\n\t\tvar assistantText = isPending ? '' : ((extractAssistantText(response) || '').trim() || '');\n\t\tvar isErrorResponse = !isPending && (isFailed || 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 && !!assistantText &&\n\t\t\tassistantText.indexOf(INDEXING_COMPLETE_MARKER) !== -1;\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 (isInProcess) userMsg.isPendingInProcess = true;\n\t\t\tif (isQueued) userMsg.isPendingQueued = true;\n\t\t\tif (isCancelledItem) userMsg.isCancelled = 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\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._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._isBgTask) okm.isBackgroundTask = 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\treturn { messages: mapped, runningItemIds: runningItemIds };\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\tANTHROPIC_MESSAGES_API_URL,\n\tOPENAI_RESPONSES_API_URL,\n\ttype BgTaskEntry,\n} from './requests';\nimport { isPagedReadFile, isImageVisionFile, isWindowedReadFile } from './office';\nimport { windowedIndexingEnabled } from './config';\nimport { isErrorResponseBody, isAuthExpiredError, isNonRetryableRequestError, getErrorMessage } from './errors';\nimport { buildBoundedChatMessages } from './budget';\nimport { createInlineLinkRegex } from './links';\nimport { markImagePreviewStale } from './image_preview';\nimport { mapHistoryListToMessages, extractLastUserTextFromRequest, isIndexingRequestText, parseIndexingRequestText } 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.\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// 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\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\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(getChatHistory(\n\t\t\t\t{ service: id.projectId, owner: id.owner, platform: platform as 'claude' | 'openai', queue: queue, status: status },\n\t\t\t\t{ limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t)).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\tthis._adoptWorkerIndexingPasses(0);\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\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\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 * 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}\n\t\t\t\t\tvar dp = initial.poll({ latency: POLL_INTERVAL });\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 existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };\n\t\t\t\tvar reply: ChatMessage = { role: 'assistant', content: result.content, isError: result.isError };\n\n\t\t\t\t// REPLACE the trailing pending \"Thinking...\" bubble in the cache with\n\t\t\t\t// the answer (falling back to append when none is present), regardless\n\t\t\t\t// of whether this chat is the currently-visible view. The cache must\n\t\t\t\t// NEVER retain a pending \"Thinking...\" bubble: even when the chatbox is\n\t\t\t\t// showing this chat, typewriteLatestReply swaps the bubble only in\n\t\t\t\t// state.messages and NEVER re-snapshots the cache — so appending a\n\t\t\t\t// duplicate here would leave the cached copy stuck pending, and a later\n\t\t\t\t// cache-first remount (agent.vue's loadChatHistory) would re-render that\n\t\t\t\t// \"Thinking...\" forever. typewriteLatestReply still finds this reply (it\n\t\t\t\t// reads the latest non-pending assistant from the cache), so replacing is\n\t\t\t\t// correct for the visible case too. The next fresh history fetch\n\t\t\t\t// reconciles it either way.\n\t\t\t\tvar msgs = existing.messages.slice();\n\t\t\t\tvar idx = -1;\n\t\t\t\tfor (var i = msgs.length - 1; i >= 0; i--) {\n\t\t\t\t\tvar m = msgs[i];\n\t\t\t\t\tif (m && m.isPending && m.role === 'assistant' && !m.isBackgroundTask) { idx = i; break; }\n\t\t\t\t}\n\t\t\t\tif (idx !== -1) {\n\t\t\t\t\treply._serverItemId = msgs[idx]._serverItemId;\n\t\t\t\t\tmsgs[idx] = reply;\n\t\t\t\t} else {\n\t\t\t\t\tmsgs.push(reply);\n\t\t\t\t}\n\t\t\t\tself.aiChatHistoryCache[params.key] = {\n\t\t\t\t\tmessages: msgs,\n\t\t\t\t\tendOfList: existing.endOfList,\n\t\t\t\t\tstartKeyHistory: existing.startKeyHistory,\n\t\t\t\t};\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\tPromise.resolve(getChatHistory(\n\t\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status },\n\t\t\t\t\t{ limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t\t)).then(function (r: any) { settle(r); }, 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.host.scrollToBottom(true);\n\n\t\t\tvar capturedComposed = composed, capturedPlatform = aiPlatform, capturedKey = key;\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\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 = result.poll({ latency: POLL_INTERVAL });\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\tvar immediatePlaceholder: ChatMessage = { role: 'assistant', content: '', isPending: true, isPendingInProcess: true, ...(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.host.scrollToBottom(true);\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 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});\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\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\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\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\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}\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): 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\tvar ask = function (status: 'pending' | 'running') {\n\t\t\treturn Promise.resolve(getChatHistory(\n\t\t\t\t{ service: svcId, owner: owner, platform: platform as 'claude' | 'openai', queue: queue, status: status },\n\t\t\t\t{ limit: WORKER_PASS_ADOPT_LIMIT },\n\t\t\t)).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\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);\n\t\t\t}, WORKER_PASS_ADOPT_ATTEMPTS[attempt + 1]);\n\t\t}, function () { self._adoptingWorkerPasses = false; });\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]) this.bgTaskQueue.splice(i, 1);\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\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\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)) { endOfClientChain(); return; }\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)) { endOfClientChain(); return; } // a failed pass is not \"incomplete\"\n\t\t\tvar answer = (platform === 'openai' ? extractOpenAIText(response) : extractClaudeText(response)) || '';\n\t\t\tif (answer.indexOf(INDEXING_COMPLETE_MARKER) !== -1) { endOfClientChain(); return; } // fully indexed\n\t\t\tvar pass = (entry.resumePass || 0) + 1;\n\t\t\tif (pass > MAX_INDEXING_RESUME_PASSES) { endOfClientChain(); return; } // give up after the cap\n\t\t\tvar id = this.host.getIdentity();\n\t\t\tif (!id || id.platform === 'none' || id.projectId !== entry.projectId) return;\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\n\t\tvar fetchHistory = function () { return getChatHistory({ service: projectId, owner: owner, platform: platform }, 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\tif (isIndexingRequestText(extractLastUserTextFromRequest(item.request_body))) 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\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\n\t\t\tif (fetchMore) {\n\t\t\t\tself.state.messages = mapped.concat(self.state.messages);\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\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\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 (mm.isBackgroundTask) continue;\n\t\t\t\t\t// Belongs to a different chat (another project, or another\n\t\t\t\t\t// platform on this one) — it must not be carried onto THIS\n\t\t\t\t\t// chat's freshly-fetched history.\n\t\t\t\t\tif (mm._ownerKey !== undefined && mm._ownerKey !== loadKey) continue;\n\t\t\t\t\tif (mm._serverItemId && serverIds[mm._serverItemId]) continue;\n\t\t\t\t\tif (!mm._serverItemId) {\n\t\t\t\t\t\t// A staged turn (files still uploading) has no server request\n\t\t\t\t\t\t// yet, so nothing in `mapped` can stand for it — rescue it\n\t\t\t\t\t\t// unconditionally. The mappedHasPendingAssistant skip below is\n\t\t\t\t\t\t// about a turn the server ALREADY has; applying it here would\n\t\t\t\t\t\t// delete the user's message mid-upload whenever some other\n\t\t\t\t\t\t// turn happened to be in flight.\n\t\t\t\t\t\tif (mm._stageId) { rescued.push(mm); continue; }\n\t\t\t\t\t\tif (mappedHasPendingAssistant) continue;\n\t\t\t\t\t\tif (mm.isSendingToServer || mm.isPendingQueued || mm.isPendingInProcess || mm.isPending) rescued.push(mm);\n\t\t\t\t\t\telse if (self.state.sending && mm.role === 'user') {\n\t\t\t\t\t\t\tvar next = self.state.messages[ri + 1];\n\t\t\t\t\t\t\tif (next && !next.isBackgroundTask && next.isPending && !next._serverItemId) rescued.push(mm);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\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 retainedOlder: ChatMessage[] = (!sharesPage1 || oldestInPage1 === 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\treturn (m._serverItemId as string) < (oldestInPage1 as string);\n\t\t\t\t});\n\t\t\t\tkeptOlderPages = retainedOlder.length > 0;\n\t\t\t\tself.state.messages = keptOlderPages ? retainedOlder.concat(mapped) : mapped;\n\t\t\t\trescued.forEach(function (m) { self.state.messages.push(m); });\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 && chatList.length > 0) {\n\t\t\t\t\tvar oldestUpdated = Number(chatList[chatList.length - 1] && chatList[chatList.length - 1].updated);\n\t\t\t\t\tif (isFinite(oldestUpdated) && oldestUpdated <= clearedAt) self.state.historyEndOfList = true;\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\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 pp = item.poll({\n\t\t\t\t\t\tlatency: POLL_INTERVAL,\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\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\tif (!fetchMore) return 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\tatt.status = 'uploading'; att.progress = 0; 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};\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/** 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};\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 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\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\tgrp.finished = !newestRunOfKey[order[oi]] ||\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] && 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\tvar out: DisplayEntry[] = [];\n\tfor (var j = 0; j < list.length; j++) {\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\tif (groups[r].anchorIndex === j) out.push({ kind: 'indexing', group: groups[r], index: j });\n\t}\n\treturn out;\n}\n"]}