bunnyquery 1.8.2 → 1.8.3

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.
package/dist/engine.d.mts CHANGED
@@ -826,7 +826,17 @@ type AttachmentSaveInfo = {
826
826
  model?: string;
827
827
  service: string;
828
828
  owner: string;
829
- userId?: string;
829
+ /**
830
+ * Queue base for this indexing pass: "<userId>-bg". REQUIRED, and it must be
831
+ * the SAME value the chat turn uses (ChatSession.dispatchComposedMessage's
832
+ * `id.userId || id.serviceId`) — the backend serialises requests that share a
833
+ * queue name and runs different ones IN PARALLEL, so a pass enqueued under a
834
+ * different base does not hold the chat back at all. It was optional once,
835
+ * defaulting to `service`; the chatbox omitted it, and its files were indexed
836
+ * on "<serviceId>-bg" while its question ran on "<userId>-bg" — the question
837
+ * was answered from a file nothing had read yet. Pass `userId || serviceId`.
838
+ */
839
+ userId: string;
830
840
  serviceName?: string;
831
841
  serviceDescription?: string;
832
842
  attachment: {
@@ -861,6 +871,14 @@ declare function extractOpenAIText(response: any): any;
861
871
  declare function listClaudeModels(service: string, owner: string): Promise<any>;
862
872
  declare function listOpenAIModels(service: string, owner: string): Promise<any>;
863
873
  declare const BG_INDEXING_QUEUE_SUFFIX = "-bg";
874
+ /**
875
+ * The one place the background-indexing queue name is spelled out. The backend
876
+ * serialises requests sharing a queue name and runs different names in PARALLEL,
877
+ * so every indexing pass AND the chat turn that must wait behind them have to
878
+ * resolve to the identical string — see AttachmentSaveInfo.userId for what
879
+ * happens when they do not.
880
+ */
881
+ declare function bgIndexingQueueName(userId?: string, service?: string): string;
864
882
  /**
865
883
  * True when a request belongs to the background-indexing queue.
866
884
  *
@@ -931,6 +949,11 @@ interface ChatIdentity {
931
949
  interface PinnedDispatchContext {
932
950
  identity: ChatIdentity;
933
951
  systemPrompt: string;
952
+ /** Id returned by stageOutgoingMessage. The turn's bubble is already on
953
+ * screen (staged while its attachments upload), so dispatchComposedMessage
954
+ * REPLACES that bubble in place instead of pushing a second one at the
955
+ * bottom — the message keeps the position it was sent in. */
956
+ stageId?: string;
934
957
  }
935
958
  /**
936
959
  * The file a background-indexing bubble belongs to. Stamped on the REQUEST
@@ -964,6 +987,17 @@ interface ChatMessage {
964
987
  /** Set on background-indexing REQUEST bubbles only (see IndexingFileRef). */
965
988
  _indexFile?: IndexingFileRef;
966
989
  _useBgQueue?: boolean;
990
+ /** Local id of a turn STAGED at Send time while its attachments upload. The
991
+ * bubble exists before any server request does, so it is never matched by
992
+ * _serverItemId and is never promoted/cancelled by the queue machinery —
993
+ * dispatchComposedMessage consumes it (pinned.stageId) when the turn is
994
+ * finally sent. Staged bubbles are deliberately kept OUT of the history
995
+ * cache: an unmount kills the upload that would resolve them, so a cached
996
+ * copy would replay as a bubble that uploads forever. */
997
+ _stageId?: string;
998
+ /** True on a staged bubble while its files are still uploading (renders
999
+ * "(Uploading files...)" instead of "(In queue)"). */
1000
+ isUploadingAttachments?: boolean;
967
1001
  _serverItemId?: string;
968
1002
  _localId?: string;
969
1003
  _cancelling?: boolean;
@@ -1238,7 +1272,21 @@ declare class ChatSession {
1238
1272
  private _pauseReasons;
1239
1273
  private _resuming;
1240
1274
  private _lidSeq;
1275
+ private _stageSeq;
1276
+ /** How many attachment-upload batches are running. uploadingAttachments is a
1277
+ * single flag but batches overlap (the composer stays live, so the user can
1278
+ * send a second one while the first uploads), and a nested finish must not
1279
+ * clear the flag out from under the batch still running. */
1280
+ private _uploadBatches;
1281
+ /** Indexing requests whose ack has not come back yet. Until it does the item
1282
+ * is not on the server's queue, so awaitIndexingDrained cannot see it — and
1283
+ * would read the gap between "pass N settled" and "pass N+1 accepted" as the
1284
+ * file being finished. */
1285
+ private _indexDispatchesInFlight;
1241
1286
  constructor(host: ChatHost);
1287
+ /** Wrap an indexing-request dispatch so awaitIndexingDrained counts it as
1288
+ * live work from the moment it is sent, not from the moment it is acked. */
1289
+ trackIndexDispatch<T>(p: Promise<T>): Promise<T>;
1242
1290
  /**
1243
1291
  * Register a live poll so (a) a remount dedupes against it instead of stacking a
1244
1292
  * SECOND poll on the same item, and (b) pausePolling can stop it.
@@ -1300,6 +1348,68 @@ declare class ChatSession {
1300
1348
  */
1301
1349
  private _callProviderFor;
1302
1350
  dispatchAgentRequest(params: any): Promise<any>;
1351
+ /**
1352
+ * Put a turn on screen the INSTANT the user hits Send, before its attachments
1353
+ * have finished uploading. Uploads run in the background now (the composer is
1354
+ * cleared and stays usable), so without a staged bubble the message would
1355
+ * appear only once its files were up — below anything the user sent in the
1356
+ * meantime, in an order that never matches what they typed.
1357
+ *
1358
+ * Staged bubbles carry _useBgQueue because that is where a turn with
1359
+ * attachments ultimately dispatches (behind its own indexing tasks). That flag
1360
+ * is also what keeps promoteNextQueuedToRunning / resolveQueuedUserBubble off
1361
+ * them: those advance the SERVER queue, and a staged turn has no server
1362
+ * request behind it yet.
1363
+ *
1364
+ * Returns the id to hand back as PinnedDispatchContext.stageId at dispatch.
1365
+ */
1366
+ stageOutgoingMessage(displayText: string): string;
1367
+ private _stageIndex;
1368
+ /**
1369
+ * Where a staged turn belongs once it is finally sent: BELOW every indexing
1370
+ * row, because that is the order it ran in and the order the server history
1371
+ * will report on the next load (its request id is newer than every pass it
1372
+ * waited for). While its files were uploading it sat above them — the rows
1373
+ * are injected as each file's pass starts, after the bubble was staged.
1374
+ *
1375
+ * Returns the index to insert at, or -1 to leave the turn where it is. Never
1376
+ * moves a turn UP: a bubble that already sits below the indexing rows (or a
1377
+ * chat with no indexing at all) must not jump backwards over anything.
1378
+ */
1379
+ private _settledStagePosition;
1380
+ /** The staged turn's files are up; it is now just waiting its place in the
1381
+ * queue. Drops the "(Uploading files...)" note back to "(In queue)". */
1382
+ markStagedMessageQueued(stageId: string): void;
1383
+ /**
1384
+ * Resolves once this project's background-indexing queue has nothing left to
1385
+ * run, so a chat enqueued right after it is genuinely last.
1386
+ *
1387
+ * Sending the chat as soon as the uploads finish is not enough, which is the
1388
+ * whole reason this exists: indexing a file is a CHAIN, and each pass is only
1389
+ * enqueued once the previous one lands (the client mints CONTINUE passes for
1390
+ * text/grid files, the worker mints them for PDFs and windowed reads). Every
1391
+ * one of those passes therefore queues up BEHIND a chat sent at upload time,
1392
+ * and the model answers from a file it has only partly read.
1393
+ *
1394
+ * The queue is read from the server's status index rather than from
1395
+ * bgTaskQueue: that mirror holds only what this client dispatched or adopted,
1396
+ * and it stops being maintained once the view unmounts. An empty answer has to
1397
+ * repeat before it is believed — see INDEXING_DRAIN_IDLE_LOOKS — and a look
1398
+ * that fails counts as busy, so a dropped request delays the turn instead of
1399
+ * releasing it early.
1400
+ *
1401
+ * Reads the identity PINNED at Send time, never a live one: the user may be in
1402
+ * another project by now, and this must keep asking about the one they sent
1403
+ * from.
1404
+ */
1405
+ awaitIndexingDrained(identity: ChatIdentity): Promise<'drained' | 'timedout' | 'skipped'>;
1406
+ /**
1407
+ * Abandon a staged turn — its uploads failed outright, so nothing will be
1408
+ * dispatched. The bubble stays (the user's text is not silently thrown away)
1409
+ * but settles into a plain, non-pending message; the caller reports the
1410
+ * failure separately.
1411
+ */
1412
+ settleStagedMessage(stageId: string): void;
1303
1413
  dispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any, pinned?: PinnedDispatchContext): void;
1304
1414
  promoteNextBgQueuedToRunning(): void;
1305
1415
  promoteNextQueuedToRunning(): void;
@@ -1423,7 +1533,7 @@ declare class ChatSession {
1423
1533
  url: string;
1424
1534
  storagePath: string;
1425
1535
  }>>;
1426
- uploadPendingAttachments(): Promise<Array<{
1536
+ uploadPendingAttachments(batchId?: string): Promise<Array<{
1427
1537
  name: string;
1428
1538
  url: string;
1429
1539
  storagePath?: string;
@@ -1432,4 +1542,4 @@ declare class ChatSession {
1432
1542
  bumpGate(): void;
1433
1543
  }
1434
1544
 
1435
- export { type AiAgentPlatform, type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, BOM, BOM_EXTS, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_INPUT_CAP_RATIO, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, EXT_CONTENT_TYPES, type EncodingClass, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_BUDGET_RATIO, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, HTML_EXTS, HTML_HEAD_WINDOW, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingRequestRef, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type ParsedAiAgent, type PinnedDispatchContext, RENDER_FROM_TOKEN, RTF_EXTS, TOOL_AND_RESPONSE_BUFFER, XML_EXTS, applyEncodingDeclaration, buildAiAgentValue, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, contentTypeForExt, createHistoryFiller, createInlineLinkRegex, encodePathSegments, encodingClassForExt, ensureHtmlCharset, ensureXmlEncoding, escapeRtfNonAscii, estimateMessageTokens, estimateTextTokens, extOf, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, getProjectContextWindow, groupAttachmentFailures, hasBom, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isIndexingRequestText, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, looksLikeRtf, makeExtractPlaceholder, mapHistoryListToMessages, needsBomForExt, normalizeAttachmentPathCandidate, normalizeExt, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAiAgentValue, parseAttachmentContent, parseIndexingLabel, parseIndexingRequestText, prepareDownloadText, readExpiredAttachmentHref, registerAttachmentParser, registerModelContextWindows, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, setProjectContextWindow, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };
1545
+ export { type AiAgentPlatform, type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, BOM, BOM_EXTS, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_INPUT_CAP_RATIO, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, EXT_CONTENT_TYPES, type EncodingClass, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_BUDGET_RATIO, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, HTML_EXTS, HTML_HEAD_WINDOW, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingRequestRef, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type ParsedAiAgent, type PinnedDispatchContext, RENDER_FROM_TOKEN, RTF_EXTS, TOOL_AND_RESPONSE_BUFFER, XML_EXTS, applyEncodingDeclaration, bgIndexingQueueName, buildAiAgentValue, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, contentTypeForExt, createHistoryFiller, createInlineLinkRegex, encodePathSegments, encodingClassForExt, ensureHtmlCharset, ensureXmlEncoding, escapeRtfNonAscii, estimateMessageTokens, estimateTextTokens, extOf, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, getProjectContextWindow, groupAttachmentFailures, hasBom, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isIndexingRequestText, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, looksLikeRtf, makeExtractPlaceholder, mapHistoryListToMessages, needsBomForExt, normalizeAttachmentPathCandidate, normalizeExt, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAiAgentValue, parseAttachmentContent, parseIndexingLabel, parseIndexingRequestText, prepareDownloadText, readExpiredAttachmentHref, registerAttachmentParser, registerModelContextWindows, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, setProjectContextWindow, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };
package/dist/engine.d.ts CHANGED
@@ -826,7 +826,17 @@ type AttachmentSaveInfo = {
826
826
  model?: string;
827
827
  service: string;
828
828
  owner: string;
829
- userId?: string;
829
+ /**
830
+ * Queue base for this indexing pass: "<userId>-bg". REQUIRED, and it must be
831
+ * the SAME value the chat turn uses (ChatSession.dispatchComposedMessage's
832
+ * `id.userId || id.serviceId`) — the backend serialises requests that share a
833
+ * queue name and runs different ones IN PARALLEL, so a pass enqueued under a
834
+ * different base does not hold the chat back at all. It was optional once,
835
+ * defaulting to `service`; the chatbox omitted it, and its files were indexed
836
+ * on "<serviceId>-bg" while its question ran on "<userId>-bg" — the question
837
+ * was answered from a file nothing had read yet. Pass `userId || serviceId`.
838
+ */
839
+ userId: string;
830
840
  serviceName?: string;
831
841
  serviceDescription?: string;
832
842
  attachment: {
@@ -861,6 +871,14 @@ declare function extractOpenAIText(response: any): any;
861
871
  declare function listClaudeModels(service: string, owner: string): Promise<any>;
862
872
  declare function listOpenAIModels(service: string, owner: string): Promise<any>;
863
873
  declare const BG_INDEXING_QUEUE_SUFFIX = "-bg";
874
+ /**
875
+ * The one place the background-indexing queue name is spelled out. The backend
876
+ * serialises requests sharing a queue name and runs different names in PARALLEL,
877
+ * so every indexing pass AND the chat turn that must wait behind them have to
878
+ * resolve to the identical string — see AttachmentSaveInfo.userId for what
879
+ * happens when they do not.
880
+ */
881
+ declare function bgIndexingQueueName(userId?: string, service?: string): string;
864
882
  /**
865
883
  * True when a request belongs to the background-indexing queue.
866
884
  *
@@ -931,6 +949,11 @@ interface ChatIdentity {
931
949
  interface PinnedDispatchContext {
932
950
  identity: ChatIdentity;
933
951
  systemPrompt: string;
952
+ /** Id returned by stageOutgoingMessage. The turn's bubble is already on
953
+ * screen (staged while its attachments upload), so dispatchComposedMessage
954
+ * REPLACES that bubble in place instead of pushing a second one at the
955
+ * bottom — the message keeps the position it was sent in. */
956
+ stageId?: string;
934
957
  }
935
958
  /**
936
959
  * The file a background-indexing bubble belongs to. Stamped on the REQUEST
@@ -964,6 +987,17 @@ interface ChatMessage {
964
987
  /** Set on background-indexing REQUEST bubbles only (see IndexingFileRef). */
965
988
  _indexFile?: IndexingFileRef;
966
989
  _useBgQueue?: boolean;
990
+ /** Local id of a turn STAGED at Send time while its attachments upload. The
991
+ * bubble exists before any server request does, so it is never matched by
992
+ * _serverItemId and is never promoted/cancelled by the queue machinery —
993
+ * dispatchComposedMessage consumes it (pinned.stageId) when the turn is
994
+ * finally sent. Staged bubbles are deliberately kept OUT of the history
995
+ * cache: an unmount kills the upload that would resolve them, so a cached
996
+ * copy would replay as a bubble that uploads forever. */
997
+ _stageId?: string;
998
+ /** True on a staged bubble while its files are still uploading (renders
999
+ * "(Uploading files...)" instead of "(In queue)"). */
1000
+ isUploadingAttachments?: boolean;
967
1001
  _serverItemId?: string;
968
1002
  _localId?: string;
969
1003
  _cancelling?: boolean;
@@ -1238,7 +1272,21 @@ declare class ChatSession {
1238
1272
  private _pauseReasons;
1239
1273
  private _resuming;
1240
1274
  private _lidSeq;
1275
+ private _stageSeq;
1276
+ /** How many attachment-upload batches are running. uploadingAttachments is a
1277
+ * single flag but batches overlap (the composer stays live, so the user can
1278
+ * send a second one while the first uploads), and a nested finish must not
1279
+ * clear the flag out from under the batch still running. */
1280
+ private _uploadBatches;
1281
+ /** Indexing requests whose ack has not come back yet. Until it does the item
1282
+ * is not on the server's queue, so awaitIndexingDrained cannot see it — and
1283
+ * would read the gap between "pass N settled" and "pass N+1 accepted" as the
1284
+ * file being finished. */
1285
+ private _indexDispatchesInFlight;
1241
1286
  constructor(host: ChatHost);
1287
+ /** Wrap an indexing-request dispatch so awaitIndexingDrained counts it as
1288
+ * live work from the moment it is sent, not from the moment it is acked. */
1289
+ trackIndexDispatch<T>(p: Promise<T>): Promise<T>;
1242
1290
  /**
1243
1291
  * Register a live poll so (a) a remount dedupes against it instead of stacking a
1244
1292
  * SECOND poll on the same item, and (b) pausePolling can stop it.
@@ -1300,6 +1348,68 @@ declare class ChatSession {
1300
1348
  */
1301
1349
  private _callProviderFor;
1302
1350
  dispatchAgentRequest(params: any): Promise<any>;
1351
+ /**
1352
+ * Put a turn on screen the INSTANT the user hits Send, before its attachments
1353
+ * have finished uploading. Uploads run in the background now (the composer is
1354
+ * cleared and stays usable), so without a staged bubble the message would
1355
+ * appear only once its files were up — below anything the user sent in the
1356
+ * meantime, in an order that never matches what they typed.
1357
+ *
1358
+ * Staged bubbles carry _useBgQueue because that is where a turn with
1359
+ * attachments ultimately dispatches (behind its own indexing tasks). That flag
1360
+ * is also what keeps promoteNextQueuedToRunning / resolveQueuedUserBubble off
1361
+ * them: those advance the SERVER queue, and a staged turn has no server
1362
+ * request behind it yet.
1363
+ *
1364
+ * Returns the id to hand back as PinnedDispatchContext.stageId at dispatch.
1365
+ */
1366
+ stageOutgoingMessage(displayText: string): string;
1367
+ private _stageIndex;
1368
+ /**
1369
+ * Where a staged turn belongs once it is finally sent: BELOW every indexing
1370
+ * row, because that is the order it ran in and the order the server history
1371
+ * will report on the next load (its request id is newer than every pass it
1372
+ * waited for). While its files were uploading it sat above them — the rows
1373
+ * are injected as each file's pass starts, after the bubble was staged.
1374
+ *
1375
+ * Returns the index to insert at, or -1 to leave the turn where it is. Never
1376
+ * moves a turn UP: a bubble that already sits below the indexing rows (or a
1377
+ * chat with no indexing at all) must not jump backwards over anything.
1378
+ */
1379
+ private _settledStagePosition;
1380
+ /** The staged turn's files are up; it is now just waiting its place in the
1381
+ * queue. Drops the "(Uploading files...)" note back to "(In queue)". */
1382
+ markStagedMessageQueued(stageId: string): void;
1383
+ /**
1384
+ * Resolves once this project's background-indexing queue has nothing left to
1385
+ * run, so a chat enqueued right after it is genuinely last.
1386
+ *
1387
+ * Sending the chat as soon as the uploads finish is not enough, which is the
1388
+ * whole reason this exists: indexing a file is a CHAIN, and each pass is only
1389
+ * enqueued once the previous one lands (the client mints CONTINUE passes for
1390
+ * text/grid files, the worker mints them for PDFs and windowed reads). Every
1391
+ * one of those passes therefore queues up BEHIND a chat sent at upload time,
1392
+ * and the model answers from a file it has only partly read.
1393
+ *
1394
+ * The queue is read from the server's status index rather than from
1395
+ * bgTaskQueue: that mirror holds only what this client dispatched or adopted,
1396
+ * and it stops being maintained once the view unmounts. An empty answer has to
1397
+ * repeat before it is believed — see INDEXING_DRAIN_IDLE_LOOKS — and a look
1398
+ * that fails counts as busy, so a dropped request delays the turn instead of
1399
+ * releasing it early.
1400
+ *
1401
+ * Reads the identity PINNED at Send time, never a live one: the user may be in
1402
+ * another project by now, and this must keep asking about the one they sent
1403
+ * from.
1404
+ */
1405
+ awaitIndexingDrained(identity: ChatIdentity): Promise<'drained' | 'timedout' | 'skipped'>;
1406
+ /**
1407
+ * Abandon a staged turn — its uploads failed outright, so nothing will be
1408
+ * dispatched. The bubble stays (the user's text is not silently thrown away)
1409
+ * but settles into a plain, non-pending message; the caller reports the
1410
+ * failure separately.
1411
+ */
1412
+ settleStagedMessage(stageId: string): void;
1303
1413
  dispatchComposedMessage(composed: string, useBgQueue?: boolean, composedForLlm?: string, extractContent?: any, fileUrls?: any, pinned?: PinnedDispatchContext): void;
1304
1414
  promoteNextBgQueuedToRunning(): void;
1305
1415
  promoteNextQueuedToRunning(): void;
@@ -1423,7 +1533,7 @@ declare class ChatSession {
1423
1533
  url: string;
1424
1534
  storagePath: string;
1425
1535
  }>>;
1426
- uploadPendingAttachments(): Promise<Array<{
1536
+ uploadPendingAttachments(batchId?: string): Promise<Array<{
1427
1537
  name: string;
1428
1538
  url: string;
1429
1539
  storagePath?: string;
@@ -1432,4 +1542,4 @@ declare class ChatSession {
1432
1542
  bumpGate(): void;
1433
1543
  }
1434
1544
 
1435
- export { type AiAgentPlatform, type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, BOM, BOM_EXTS, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_INPUT_CAP_RATIO, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, EXT_CONTENT_TYPES, type EncodingClass, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_BUDGET_RATIO, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, HTML_EXTS, HTML_HEAD_WINDOW, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingRequestRef, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type ParsedAiAgent, type PinnedDispatchContext, RENDER_FROM_TOKEN, RTF_EXTS, TOOL_AND_RESPONSE_BUFFER, XML_EXTS, applyEncodingDeclaration, buildAiAgentValue, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, contentTypeForExt, createHistoryFiller, createInlineLinkRegex, encodePathSegments, encodingClassForExt, ensureHtmlCharset, ensureXmlEncoding, escapeRtfNonAscii, estimateMessageTokens, estimateTextTokens, extOf, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, getProjectContextWindow, groupAttachmentFailures, hasBom, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isIndexingRequestText, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, looksLikeRtf, makeExtractPlaceholder, mapHistoryListToMessages, needsBomForExt, normalizeAttachmentPathCandidate, normalizeExt, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAiAgentValue, parseAttachmentContent, parseIndexingLabel, parseIndexingRequestText, prepareDownloadText, readExpiredAttachmentHref, registerAttachmentParser, registerModelContextWindows, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, setProjectContextWindow, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };
1545
+ export { type AiAgentPlatform, type AttachmentFailureGroup, type AttachmentParser, type AttachmentSaveInfo, BG_INDEXING_QUEUE_SUFFIX, BOM, BOM_EXTS, type BgTaskEntry, type BoundedChatOptions, type BuildDisplayListOptions, type BuildIndexingUserMessageOptions, CLAUDE_INPUT_CAP_RATIO, CLAUDE_PER_REQUEST_INPUT_CAP, CONTEXT_WINDOW_BY_MODEL, CONTEXT_WINDOW_DEFAULT, type CallClaudeWithMcpParams, type ChatEngineConfig, type ChatHost, type ChatIdentity, type ChatMessage, ChatSession, type ChatState, type ChatSystemPromptParams, type ClaudeMcpServerRequest, type ClaudeMcpToolConfig, type ClaudeMessage, type ClaudeRole, type ComposedUserMessage, DEFAULT_CLAUDE_MODEL, DEFAULT_OPENAI_MODEL, type DisplayEntry, EXPIRED_ATTACHMENT_URL_HOST, EXPIRED_ATTACHMENT_URL_ORIGIN, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, EXT_CONTENT_TYPES, type EncodingClass, type ExtractDirective, type FillHistoryViewportOptions, HISTORY_BUDGET_RATIO, HISTORY_FILL_SLACK_PX, HISTORY_TOKEN_BUDGET, HTML_EXTS, HTML_HEAD_WINDOW, type IndexingAttachmentInfo, type IndexingFileRef, type IndexingGroup, type IndexingGroupStatus, type IndexingRequestRef, type IndexingSystemPromptParams, type InlineLinkContext, type InlineLinkPart, LINK_LABEL_MAX_DISPLAY_CHARS, LINK_REFRESH_WINDOW_MS, MAX_HISTORY_FILL_PAGES, MAX_HISTORY_MESSAGES, MAX_PARSED_CONTENT_CHARS, MCP_NAME, MIN_INPUT_TOKEN_BUDGET, type MapHistoryOptions, OUTPUT_TOKEN_RESERVE, type OpenAIMessage, POLL_INTERVAL, type ParsedAiAgent, type PinnedDispatchContext, RENDER_FROM_TOKEN, RTF_EXTS, TOOL_AND_RESPONSE_BUFFER, XML_EXTS, applyEncodingDeclaration, bgIndexingQueueName, buildAiAgentValue, buildBoundedChatMessages, buildChatDisplayList, buildChatSystemPrompt, buildDisplayExpiredAttachmentHref, buildIndexingContinueMessage, buildIndexingRenderContinueTemplate, buildIndexingRenderMessage, buildIndexingSystemPrompt, buildIndexingUserMessage, buildIndexingWindowMessage, callClaudeWithMcp, callClaudeWithPublicMcp, callOpenAIWithPublicMcp, chatEngineConfig, classifyInlineLink, clearAttachmentParsers, composeUserMessage, configureChatEngine, contentTypeForExt, createHistoryFiller, createInlineLinkRegex, encodePathSegments, encodingClassForExt, ensureHtmlCharset, ensureXmlEncoding, escapeRtfNonAscii, estimateMessageTokens, estimateTextTokens, extOf, extractClaudeText, extractLastUserTextFromRequest, extractOpenAIText, extractRemotePathFromAttachmentHref, fillHistoryViewport, filterListByClearHorizon, findAttachmentParser, formatChatTimestamp, getAttachmentParsers, getChatHistory, getContextWindow, getErrorMessage, getExpiredAttachmentVisiblePath, getProjectContextWindow, groupAttachmentFailures, hasBom, isAuthExpiredError, isBgIndexingQueue, isErrorResponseBody, isHttpUrlLike, isIndexingRequestText, isNonRetryableRequestError, isOfficeFile, isServerExtractable, isServiceDbAttachmentHref, listClaudeModels, listOpenAIModels, looksLikeRtf, makeExtractPlaceholder, mapHistoryListToMessages, needsBomForExt, normalizeAttachmentPathCandidate, normalizeExt, normalizeTextContent, normalizeTrailingInlineToken, notifyAgentSaveAttachment, parseAiAgentValue, parseAttachmentContent, parseIndexingLabel, parseIndexingRequestText, prepareDownloadText, readExpiredAttachmentHref, registerAttachmentParser, registerModelContextWindows, repairUrlEntities, repairUrlWhitespace, safeDecodeURIComponent, sanitizeAttachmentLinksForHistory, setProjectContextWindow, stripFileBlocksFromHistory, transformContentWithImages, transformContentWithOpenAIImages, truncateLabelForDisplay, wallClockNow };