@epam/ai-dial-chat-hooks 1.2.0-dev.99 → 1.2.0-rc.0

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.
Files changed (84) hide show
  1. package/api-error/api-error.js +7 -4
  2. package/catalog/catalog-derivations.js +1 -1
  3. package/catalog/deployment-id.js +8 -2
  4. package/catalog/map-deployment-limits-to-catalog.js +16 -24
  5. package/catalog/map-deployment-limits-to-input.js +81 -9
  6. package/catalog/map-deployment-to-catalog-item.js +34 -34
  7. package/catalog/map-entity-details-to-catalog.js +237 -192
  8. package/catalog/map-skill-to-catalog-item.js +61 -54
  9. package/catalog/publish.js +4 -4
  10. package/catalog/useCatalogEditNavigation/useCatalogEditNavigation.js +122 -101
  11. package/catalog/useCatalogItemDetails.js +9 -8
  12. package/catalog/usePublishFolders/usePublishFolders.js +1 -1
  13. package/catalog.d.ts +171 -34
  14. package/catalog.js +23 -23
  15. package/conversation/conversation-transfer/export-conversation.js +24 -16
  16. package/conversation/conversation-transfer/import-conversation.js +80 -31
  17. package/conversation/create-chat-stream-api.js +85 -49
  18. package/conversation/get-model-id-from-conversation-id.js +15 -9
  19. package/conversation/message-utils.js +44 -2
  20. package/conversation/stage.js +6 -2
  21. package/conversation/useActiveConversationSync/useActiveConversationSync.js +7 -8
  22. package/conversation/useConversationExport/useConversationExport.js +9 -9
  23. package/conversation/useConversationHandlers/message-utils.js +8 -5
  24. package/conversation/useConversationHandlers/useConversationHandlers.js +181 -167
  25. package/conversation/useConversationImport/useConversationImport.js +123 -121
  26. package/conversation/useConversationPanelItems/useConversationPanelItems.js +49 -31
  27. package/conversation/useConversationStream/frame-scheduler.js +39 -0
  28. package/conversation/useConversationStream/generation-resume.js +122 -64
  29. package/conversation/useConversationStream/useConversationStream.js +277 -118
  30. package/conversation/useMessageSelectionReply/useMessageSelectionReply.js +189 -0
  31. package/conversation-sources/useConversationSources/useConversationSources.js +31 -24
  32. package/conversation-sources.d.ts +1 -1
  33. package/conversation-transfer.d.ts +2 -1
  34. package/conversation.d.ts +205 -22
  35. package/conversation.js +32 -31
  36. package/file-manager-canvas.d.ts +27 -7
  37. package/file-manager.d.ts +87 -32
  38. package/file-manager.js +25 -24
  39. package/files/attachment-canvas.js +67 -44
  40. package/files/dial-file-manager-copy-move.util.js +9 -8
  41. package/files/dial-file-manager-mapping.util.js +2 -1
  42. package/files/dial-file-manager-path.util.js +24 -2
  43. package/files/dial-file-manager.model.js +23 -19
  44. package/files/dial-file-manager.types.js +3 -3
  45. package/files/file-manager-variant.js +1 -1
  46. package/files/resolve-dial-file-api-path.js +11 -12
  47. package/files/useDialFileListing/useDialFileListing.js +140 -127
  48. package/files/useDialFileManager/useDialFileManager.js +139 -135
  49. package/files/useDialFileManagerSections/useDialFileManagerSections.js +155 -0
  50. package/files/useDialFileManagerTabConfig/useDialFileManagerTabConfig.js +20 -15
  51. package/files/useDialFileMutations/useDialFileMutations.js +65 -60
  52. package/files/useDialFileUploadBatch/useDialFileUploadBatch.js +117 -110
  53. package/files/useFileAttachmentPicker/useFileAttachmentPicker.js +28 -23
  54. package/index.d.ts +630 -128
  55. package/index.js +136 -134
  56. package/mcp-apps/useMcpAppTools/useMcpAppTools.js +1 -1
  57. package/oauth/authorize-url.js +3 -3
  58. package/oauth/toolset-id.js +5 -3
  59. package/oauth/useToolsetLogin/useToolsetLogin.js +8 -8
  60. package/oauth.d.ts +34 -2
  61. package/oauth.js +9 -9
  62. package/package.json +19 -23
  63. package/scheduled-task/scheduled-task-description.js +43 -39
  64. package/scheduled-task/scheduled-task-trigger.js +74 -71
  65. package/scheduled-task/use-scheduled-task-runs.js +162 -50
  66. package/scheduled-task/use-scheduled-tasks.js +52 -48
  67. package/scheduled-tasks.d.ts +27 -6
  68. package/scheduled-tasks.js +2 -2
  69. package/shared/application-schema.js +5 -2
  70. package/shared/cron-day-of-month.js +13 -0
  71. package/skill/skill-archive.js +19 -0
  72. package/skill/skill-types.js +8 -7
  73. package/skill/skill.js +52 -29
  74. package/skill/useSkillArchiveImport/useSkillArchiveImport.js +38 -34
  75. package/skill/useSkillEditorLoad.js +65 -59
  76. package/skill/useSkillEditorSubmit.js +105 -93
  77. package/skill/useSkillFileActions.js +70 -58
  78. package/skill-editor.d.ts +62 -13
  79. package/skill-editor.js +9 -9
  80. package/usage/map-user-usage-to-model-limits.js +137 -95
  81. package/usage.d.ts +8 -3
  82. package/usePageFileDrag/usePageFileDrag.js +3 -3
  83. package/utils.d.ts +26 -6
  84. package/utils.js +10 -10
package/conversation.d.ts CHANGED
@@ -215,6 +215,7 @@ export declare interface ChatStreamApi {
215
215
  stopCompletion: (dto: {
216
216
  generationId: string;
217
217
  path: string;
218
+ content?: string;
218
219
  }) => Promise<void>;
219
220
  }
220
221
 
@@ -297,7 +298,7 @@ export declare interface ConversationStreamOverlayNotifier {
297
298
  }
298
299
 
299
300
  /** The exact `startStream` shape `useConversationStream` returns. */
300
- export declare type ConversationStreamStarter = (conversationPath: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum) => void;
301
+ export declare type ConversationStreamStarter = (conversationPath: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum, options?: StartStreamOptions) => void;
301
302
 
302
303
  /**
303
304
  * Host-owned transport for the DIAL Core completion protocol. Implemented at
@@ -307,10 +308,14 @@ export declare type ConversationStreamStarter = (conversationPath: string, userC
307
308
  export declare interface ConversationStreamTransport {
308
309
  /** Starts a completion; delivers chunks/completion/error through `options`, aborted via `options.signal`. */
309
310
  streamCompletion(path: string, message: string | undefined, model: string, options: StreamCompletionOptions, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum, messageIndex?: number, clientChannelId?: string): void;
310
- /** Requests the backend stop an active generation. */
311
+ /**
312
+ * Requests the backend stop an active generation. `content` is the answer text shown
313
+ * so far; the backend saves it for a generation whose text it does not hold.
314
+ */
311
315
  stopCompletion(params: {
312
316
  generationId: string;
313
317
  path: string;
318
+ content?: string;
314
319
  }): Promise<void>;
315
320
  /** Opens a stream of resource-update events for `path`, until aborted via `signal`. */
316
321
  watchConversation(path: string, signal: AbortSignal): Promise<ReadableStream<Uint8Array>>;
@@ -347,6 +352,12 @@ export declare interface CreateChatStreamApiDeps {
347
352
  getTimezone?: () => string | undefined;
348
353
  /** `fetch` implementation to issue requests through. Defaults to the global `fetch`. */
349
354
  fetchImpl?: typeof fetch;
355
+ /**
356
+ * How long an open completion stream may go without receiving a byte
357
+ * (keepalive comments included) before it is reported as a
358
+ * {@link StreamInterruptedError}. Defaults to {@link DEFAULT_STREAM_IDLE_TIMEOUT_MS}.
359
+ */
360
+ idleTimeoutMs?: number;
350
361
  }
351
362
 
352
363
  /**
@@ -361,6 +372,11 @@ export declare const createMessagePair: (content: string, customContent?: Messag
361
372
  /** Fallback text of a {@link GenerationConflictError} when no message is supplied. */
362
373
  export declare const DEFAULT_GENERATION_CONFLICT_MESSAGE = "A response is already being generated in this conversation. Wait for it to finish or stop it before sending another message.";
363
374
 
375
+ /** Safe fallback for hosts that do not supply a translated persistence warning. */
376
+ export declare const DEFAULT_GENERATION_PERSISTENCE_ERROR_MESSAGE = "The response could not be saved. It is still shown here, but may be lost if you reload or leave this page. Copy it before continuing.";
377
+
378
+ export declare const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 45000;
379
+
364
380
  /**
365
381
  * Derives the row-action visibility state for a single conversation item.
366
382
  *
@@ -376,6 +392,12 @@ export declare const DEFAULT_GENERATION_CONFLICT_MESSAGE = "A response is alread
376
392
  */
377
393
  export declare const deriveConversationRowActionState: (item: Pick<ConversationListItemDto, "sharedWithMe" | "publishedWithMe" | "isReadonly">, publishHistory: PublishHistoryEntry[] | undefined, recipients: RecipientsCountEntry) => ConversationRowActionState;
378
394
 
395
+ /**
396
+ * Returns the deployment a conversation belongs to, resolved from its id
397
+ * alone, or `undefined` when no candidate matches `deployments`.
398
+ */
399
+ export declare const findDeploymentForConversationId: (deployments: DeploymentItemDto[], conversationId: string) => DeploymentItemDto | undefined;
400
+
379
401
  /**
380
402
  * Normalises a version string for display. The server falls back to a bare
381
403
  * `package.json` version (`0.45.0`), while a CI-supplied `CHAT_VERSION` is
@@ -395,6 +417,12 @@ export declare class GenerationConflictError extends Error {
395
417
  constructor(message?: string);
396
418
  }
397
419
 
420
+ /** Identifies a failed terminal save independently of the model's generation outcome. */
421
+ export declare class GenerationPersistenceError extends Error {
422
+ static readonly type = "conversation_save_failed";
423
+ constructor();
424
+ }
425
+
398
426
  /**
399
427
  * Strips the leading bucket segment from a conversation id and decodes any
400
428
  * already-percent-encoded remainder back to raw, so callers that re-encode
@@ -407,6 +435,21 @@ export declare const getConversationPath: (conversationId: string) => string;
407
435
  */
408
436
  export declare const getConversationSource: (item: Pick<ConversationListItemDto, "sharedWithMe" | "publishedWithMe">) => FilterTab;
409
437
 
438
+ /**
439
+ * Returns the tool values the conversation's last message sets through its
440
+ * `form_schema`, restricted to `toolIds`, plus a key identifying that exact
441
+ * application. `undefined` when the last message is not an assistant message
442
+ * or sets no known tool.
443
+ *
444
+ * Streamed chunks and reloads re-create an identical `form_schema`; comparing
445
+ * keys rather than object identity applies an app's value once and leaves a
446
+ * later user toggle alone until the app sends a different value.
447
+ */
448
+ export declare const getFormSchemaToolSyncKey: (conversationId: string, messages: Message[], toolIds: readonly string[]) => {
449
+ key: string;
450
+ values: Record<string, boolean>;
451
+ } | undefined;
452
+
410
453
  /**
411
454
  * Returns the deployment the conversation was last running on: scanning
412
455
  * backwards, the `new_deployment_id` of a `model_changed` status message or
@@ -417,7 +460,7 @@ export declare const getConversationSource: (item: Pick<ConversationListItemDto,
417
460
  * an edit truncates past one: the marker is appended at the end of the
418
461
  * timeline, so truncating at an earlier message drops it, and the model the
419
462
  * user picked reverted on the next page load even though the answer had been
420
- * regenerated on it (issue #8712). The assistant message the backend writes
463
+ * regenerated on it ([#8712](https://github.com/epam/ai-dial-chat/issues/8712)). The assistant message the backend writes
421
464
  * carries the deployment that produced it, which survives that truncation
422
465
  * because it *is* the regenerated message.
423
466
  */
@@ -430,6 +473,21 @@ export declare const getLastDeploymentId: (messages: Message[]) => string | null
430
473
  */
431
474
  export declare const getLastUserMessageToolConfiguration: (messages: Message[]) => Record<string, unknown> | undefined;
432
475
 
476
+ /**
477
+ * Returns the tool configuration a (re-)loaded conversation should show: the
478
+ * last user message's `configuration_value`, overlaid in order by the
479
+ * `form_schema` values of the assistant messages after it. An app that turned
480
+ * a toggle off in its final response must not see it re-armed on reload just
481
+ * because the user message that started the run had it on.
482
+ */
483
+ export declare const getLatestToolConfiguration: (messages: Message[]) => Record<string, unknown> | undefined;
484
+
485
+ /**
486
+ * Returns every deployment id a conversation id may belong to, longest first,
487
+ * or an empty array when the format is unrecognised.
488
+ */
489
+ export declare const getModelIdCandidatesFromConversationId: (id: string) => string[];
490
+
433
491
  /**
434
492
  * Extracts the deployment/model ID from a DIAL Core conversation ID.
435
493
  *
@@ -513,6 +571,15 @@ export declare const getStarterSubmitText: (starter: StarterOption, description?
513
571
  */
514
572
  export declare const getTimeOfDayGreeting: (hour: number, translations: GreetingTranslations, firstName?: string) => string;
515
573
 
574
+ /**
575
+ * Returns the boolean values an assistant message's `form_schema` sets, keyed
576
+ * by property name, or `undefined` when no property resolves to a boolean.
577
+ * Lets a DIAL app switch a tools-menu toggle (e.g. `deep_research`) per
578
+ * message — on while a run is in progress, off once its result is delivered.
579
+ * Not filtered by tool id: `restoreToolConfiguration` ignores unknown ids.
580
+ */
581
+ export declare const getToolConfigurationFromFormSchema: (formSchema: DeploymentConfigurationSchema | undefined) => Record<string, boolean> | undefined;
582
+
516
583
  /** Pre-translated greeting phrase strings for each time-of-day period. */
517
584
  export declare interface GreetingTranslations {
518
585
  morningWithName: string;
@@ -546,11 +613,12 @@ export declare const hasStructuredAnnouncement: ({ title, description, }: Announ
546
613
  export declare const isAnswerIncomplete: (answer: Message | undefined) => boolean;
547
614
 
548
615
  /**
549
- * True when the conversation's last message is an unresolved assistant
550
- * placeholder: the backend only persists a conversation at generation start
551
- * (empty placeholder) and at generation end (final content, or a partial
552
- * flagged `streamErrorMessage`/`wasStoppedByUser`), so this shape means a
553
- * generation was still active elsewhere when the conversation was loaded.
616
+ * True when the conversation has a pending background message, or its last
617
+ * message is an unresolved assistant placeholder: the backend only persists a
618
+ * conversation at generation start (empty placeholder) and at generation end
619
+ * (final content, or a partial flagged `streamErrorMessage`/`wasStoppedByUser`).
620
+ * This can mean generation is still active elsewhere, or that its terminal save
621
+ * failed.
554
622
  */
555
623
  export declare const isAwaitingGenerationResume: (conversation: Conversation) => boolean;
556
624
 
@@ -593,9 +661,12 @@ declare interface LocalModeValues {
593
661
  }
594
662
 
595
663
  /**
596
- * Returns the normalized stages of a raw stage array or a message-like
597
- * payload (reading `custom_content.stages`, falling back to
598
- * `customContent.stages`), or `undefined` when there are none.
664
+ * Returns the normalized stages of a complete raw stage array or a
665
+ * message-like payload (reading `custom_content.stages`, falling back to
666
+ * `customContent.stages`), or `undefined` when there are none. An entry
667
+ * without an `index` takes its array position — the identity a complete
668
+ * non-streaming array's `parent_stage_index` refers to — while explicit
669
+ * (possibly sparse) indexes are kept. Not for partial stream deltas.
599
670
  */
600
671
  export declare const mapStages: (source: RawStage[] | RawStageSource | null | undefined) => Stage[] | undefined;
601
672
 
@@ -624,6 +695,20 @@ export declare interface MessagePair {
624
695
  assistantMessage: Message;
625
696
  }
626
697
 
698
+ /** A stable snapshot of one eligible native text selection. */
699
+ export declare interface MessageSelectionReplySnapshot {
700
+ /** Scope that owned the selection when it was captured. */
701
+ conversationId: string;
702
+ /** Message text root containing the captured range. */
703
+ body: HTMLDivElement;
704
+ /** Captured native range. */
705
+ range: Range;
706
+ /** Native selected text preserved for the generated file. */
707
+ text: string;
708
+ /** Visible fragment of the selected range. */
709
+ rect: DOMRect;
710
+ }
711
+
627
712
  /**
628
713
  * Normalises a stored response-format string to the current enum. Legacy data
629
714
  * may contain `'Markdown'` or `'PlainText'` (capital-first) instead of the
@@ -667,6 +752,11 @@ export declare interface RawStage {
667
752
  tag?: string | null;
668
753
  /** Files produced or referenced by this stage. */
669
754
  attachments?: RawStageAttachment[] | null;
755
+ /**
756
+ * `index` of the parent stage (its array position in a complete unindexed
757
+ * array). Nullish means top level; `0` is a valid parent.
758
+ */
759
+ parent_stage_index?: number | null;
670
760
  }
671
761
 
672
762
  /**
@@ -753,6 +843,18 @@ export declare const shouldRerunGenerationOnEdit: (messages: Message[], messageI
753
843
  /** True when the first user/assistant exchange is complete and LLM naming may still run. */
754
844
  export declare const shouldWatchForDisplayNameUpdate: (conversation: Conversation) => boolean;
755
845
 
846
+ /** Per-start options of {@link UseConversationStreamResult.startStream}. */
847
+ export declare interface StartStreamOptions {
848
+ /**
849
+ * Treats a `GenerationConflictError` as "this turn is already being
850
+ * generated" — e.g. a page reloaded before that generation saved its start
851
+ * state — and joins the running generation instead of showing the conflict
852
+ * message, which remains the fallback. Only for a start that sends no new
853
+ * user text; a send the user typed must keep reporting the conflict.
854
+ */
855
+ resumeOnConflict?: boolean;
856
+ }
857
+
756
858
  /** Options accepted by {@link ConversationStreamTransport.streamCompletion}. */
757
859
  export declare interface StreamCompletionOptions {
758
860
  onChunk: (chunk: StreamChunk) => void;
@@ -761,10 +863,34 @@ export declare interface StreamCompletionOptions {
761
863
  signal: AbortSignal;
762
864
  }
763
865
 
866
+ /**
867
+ * Reported through `onError` when the network connection carrying a
868
+ * completion stream is lost (a rejected `fetch`, or a read that fails after a
869
+ * 2xx response) or goes silent past the idle timeout — what a laptop sleep or
870
+ * a phone lock mid-generation produces. The backend-owned generation may
871
+ * still be running, so the caller can recover it rather than treat the
872
+ * response as failed. `cause` holds the original error, when there is one.
873
+ */
874
+ export declare class StreamInterruptedError extends Error {
875
+ constructor(cause?: unknown);
876
+ }
877
+
878
+ /**
879
+ * Reported through `onError` when DIAL Core itself signals a failure with an
880
+ * in-band `{ error: { message } }` SSE chunk. Its `message` is upstream text
881
+ * intended for the user, unlike a transport failure (failed `fetch`, non-OK
882
+ * status, broken stream), whose message is technical detail. A custom
883
+ * transport raises this for any user-facing upstream error text.
884
+ */
885
+ export declare class StreamUpstreamError extends Error {
886
+ constructor(message: string);
887
+ }
888
+
764
889
  /**
765
890
  * Returns a renderable `Stage` for one raw payload: `index` defaults to `0`,
766
891
  * `name` to `''`, an unrecognized `status` to `null` (still running), and
767
- * `content`/`tag`/`attachments` are passed through when present.
892
+ * `content`/`tag`/`attachments`/`parent_stage_index` are passed through when
893
+ * present (a parent of `0` included).
768
894
  */
769
895
  export declare const toStage: (stage: RawStage) => Stage;
770
896
 
@@ -784,7 +910,8 @@ export declare interface TranscribeWithDeploymentParams {
784
910
  * 1. If the active conversation is not present in the list, requests a
785
911
  * refresh. The list and refresh callback are intentionally excluded from
786
912
  * the dependency array to avoid a refresh-loop on every list update.
787
- * 2. Marks the active conversation as viewed whenever it or the list changes.
913
+ * 2. Marks the active conversation as viewed when its matching identity becomes
914
+ * available. List refreshes and persistence rollback do not retry the write.
788
915
  */
789
916
  export declare const useActiveConversationSync: ({ activeConversationId, items, refreshConversations, markConversationViewed, conversationIdsMatch, toPanelConversationId, }: UseActiveConversationSyncParams) => string | undefined;
790
917
 
@@ -985,10 +1112,14 @@ export declare interface UseConversationLookupMapsParams {
985
1112
  * Returns a memoised array whose shape is compatible with the conversation
986
1113
  * panel's item contract. All app-specific concerns (icon URL resolution,
987
1114
  * route generation, id normalisation) are injected via resolver callbacks.
1115
+ *
1116
+ * While every input except `items` is unchanged, a DTO that is referentially
1117
+ * the same as in the previous render maps to the same item object, so a list
1118
+ * change (or a navigation that re-derives the list) re-renders only the rows
1119
+ * whose DTO actually changed.
988
1120
  */
989
- export declare const useConversationPanelItems: ({ items, deployments, isDeploymentsLoading, toPanelConversationId, resolveIconUrl, resolveIconTooltip, resolveHref, resolveTaskBadge, }: UseConversationPanelItemsParams) => {
990
- showTaskBadge?: boolean | undefined;
991
- taskBadgeLabel?: string | undefined;
1121
+ export declare const useConversationPanelItems: ({ items, deployments, isDeploymentsLoading, toPanelConversationId, resolveIconUrl, resolveIconTooltip, resolveHref, resolveTaskPresentation, }: UseConversationPanelItemsParams) => {
1122
+ leadingIcon?: ReactNode;
992
1123
  isUnread?: boolean | undefined;
993
1124
  id: string;
994
1125
  title: string;
@@ -1024,11 +1155,12 @@ export declare interface UseConversationPanelItemsResolvers {
1024
1155
  /** Resolves the href to navigate to when the conversation row is clicked. */
1025
1156
  resolveHref: (panelConversationId: string) => string;
1026
1157
  /**
1027
- * Returns badge metadata for a scheduled-task conversation, or `undefined`
1028
- * when the item should not show a task badge.
1158
+ * Returns the row presentation for a scheduled-task conversation — a
1159
+ * host-rendered leading icon that replaces the deployment avatar, and the
1160
+ * unread flag — or `undefined` for an ordinary conversation.
1029
1161
  */
1030
- resolveTaskBadge?: (item: ConversationListItemDto) => {
1031
- label: string;
1162
+ resolveTaskPresentation?: (item: ConversationListItemDto) => {
1163
+ leadingIcon?: ReactNode;
1032
1164
  isUnread: boolean;
1033
1165
  } | undefined;
1034
1166
  }
@@ -1041,7 +1173,7 @@ export declare interface UseConversationPanelItemsResolvers {
1041
1173
  * `transport`/`generation`/`channel`/`overlay` capabilities rather than any
1042
1174
  * app context or `server-api` import.
1043
1175
  */
1044
- export declare const useConversationStream: ({ conversationId, state: { setConversation, conversationRef }, transport, generation: { startGeneration, completeGeneration }, channel, overlay, onStopError, generationConflictMessage, }: UseConversationStreamParams) => UseConversationStreamResult;
1176
+ export declare const useConversationStream: ({ conversationId, state: { setConversation, conversationRef }, transport, generation: { startGeneration, completeGeneration }, channel, overlay, onStopError, generationConflictMessage, generationPersistenceErrorMessage, onStreamError, batchChunksPerFrame, }: UseConversationStreamParams) => UseConversationStreamResult;
1045
1177
 
1046
1178
  /** Parameters for {@link useConversationStream}. */
1047
1179
  export declare interface UseConversationStreamParams {
@@ -1059,17 +1191,39 @@ export declare interface UseConversationStreamParams {
1059
1191
  * {@link DEFAULT_GENERATION_CONFLICT_MESSAGE}.
1060
1192
  */
1061
1193
  generationConflictMessage?: string;
1194
+ /** Host-translated warning shown when the received answer could not be saved. */
1195
+ generationPersistenceErrorMessage?: string;
1196
+ /**
1197
+ * Receives the original error of every failed stream. The hook shows only
1198
+ * host-supplied or upstream-supplied text on the message bubble and hides
1199
+ * transport detail (e.g. `Failed to fetch`), so this is where the host can
1200
+ * still log or report the raw error.
1201
+ */
1202
+ onStreamError?: (error: Error) => void;
1203
+ /**
1204
+ * Coalesces the displayed chunk updates into one `setConversation` per
1205
+ * animation frame. Chunks still reach the per-path buffer immediately, and
1206
+ * any pending update is flushed before completion, error, stop, or a
1207
+ * superseding generation. Defaults to `false` (one update per chunk).
1208
+ */
1209
+ batchChunksPerFrame?: boolean;
1062
1210
  }
1063
1211
 
1064
1212
  /** Return value of {@link useConversationStream}. */
1065
1213
  export declare interface UseConversationStreamResult {
1066
- startStream: (conversationId: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum) => void;
1214
+ startStream: (conversationId: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum, options?: StartStreamOptions) => void;
1067
1215
  handleStop: () => void;
1068
1216
  resumeIfAwaitingGeneration: (currentConversationId: string, conversation: Conversation) => void;
1069
1217
  /** Restores the accumulated live assistant message when its conversation is loaded again before completion. */
1070
1218
  restoreBufferedGeneration: (currentConversationId: string, conversation: Conversation) => Conversation;
1071
1219
  isStreaming: boolean;
1072
1220
  canStopStreaming: boolean;
1221
+ /** Whether the displayed conversation's terminal read failed. */
1222
+ hasConversationReloadError: boolean;
1223
+ /** Whether a retry of that read is in flight. */
1224
+ isReloadingConversation: boolean;
1225
+ /** Retries the failed read without saving or regenerating the answer. */
1226
+ retryConversationReload: () => Promise<void>;
1073
1227
  }
1074
1228
 
1075
1229
  /**
@@ -1105,6 +1259,35 @@ export declare interface UseImportFilePickerResult {
1105
1259
  handleFileChange: (event: ChangeEvent<HTMLInputElement>) => void;
1106
1260
  }
1107
1261
 
1262
+ /**
1263
+ * Captures eligible message text and creates Reply files for an existing composer
1264
+ * attachment flow without acquiring host deployment, upload or localization knowledge.
1265
+ */
1266
+ export declare const useMessageSelectionReply: ({ conversationId, enabled, droppedFiles, onDroppedFilesConsumed, }: UseMessageSelectionReplyParams) => {
1267
+ contentRef: (node: HTMLDivElement | null) => (() => void) | undefined;
1268
+ actionRef: RefObject<HTMLDivElement | null>;
1269
+ selection: MessageSelectionReplySnapshot | null;
1270
+ onReply: () => void;
1271
+ dismiss: () => void;
1272
+ pendingFiles: File[];
1273
+ onFilesConsumed: () => void;
1274
+ focusRequestId: number | undefined;
1275
+ onAttachmentsChange: (attachments: Attachment[]) => void;
1276
+ addedRevision: number;
1277
+ };
1278
+
1279
+ /** Parameters accepted by {@link useMessageSelectionReply}. */
1280
+ export declare interface UseMessageSelectionReplyParams {
1281
+ /** Identifier used to discard selection and queued files after a scope change. */
1282
+ conversationId: string;
1283
+ /** Whether the host currently permits a Reply attachment. */
1284
+ enabled: boolean;
1285
+ /** Files from the host's ordinary page-drop queue. */
1286
+ droppedFiles: File[];
1287
+ /** Acknowledges the captured page-drop batch after the composer accepts it. */
1288
+ onDroppedFilesConsumed: () => void;
1289
+ }
1290
+
1108
1291
  /**
1109
1292
  * Derives the tools submenu from the active deployment's configuration schema:
1110
1293
  * every boolean property becomes a toggle. Manages toggle state locally, resets
package/conversation.js CHANGED
@@ -1,32 +1,33 @@
1
1
  import { buildAnnouncementSignature as e, hasAnnouncementContent as t, hasStructuredAnnouncement as n, sanitizeAnnouncementHtml as r, sanitizeAnnouncementMessageHtml as i } from "./conversation/announcement-message.js";
2
- import { DEFAULT_GENERATION_CONFLICT_MESSAGE as a, GenerationConflictError as o, createChatStreamApi as s } from "./conversation/create-chat-stream-api.js";
3
- import { shouldWatchForDisplayNameUpdate as c } from "./conversation/display-name-watch.js";
4
- import { formatAppVersion as l, sanitizeFooterHtml as u } from "./conversation/footer-message.js";
5
- import { getModelIdFromConversationId as d } from "./conversation/get-model-id-from-conversation-id.js";
6
- import { getTimeOfDayGreeting as f } from "./conversation/greeting.js";
7
- import { createDeploymentChangedMessage as p } from "./conversation/message-factory.js";
8
- import { getLastDeploymentId as m, getLastUserMessageToolConfiguration as h, isMessageStreaming as g, messageHasStages as _, normalizeResponseFormat as v } from "./conversation/message-utils.js";
9
- import { getQuickAppConversationStarters as y } from "./conversation/quick-app-conversation-starters.js";
10
- import { mapStages as b, toStage as x } from "./conversation/stage.js";
11
- import { getStarterPopulateText as S, getStartersFromSchema as C } from "./conversation/starter-option.js";
12
- import { deriveConversationRowActionState as w } from "./conversation/deriveConversationRowActionState/deriveConversationRowActionState.js";
13
- import { useActiveConversationSync as T } from "./conversation/useActiveConversationSync/useActiveConversationSync.js";
14
- import { useAsyncConfirmDialog as E } from "./conversation/useAsyncConfirmDialog/useAsyncConfirmDialog.js";
15
- import { useConversationLookupMaps as D } from "./conversation/useConversationLookupMaps/useConversationLookupMaps.js";
16
- import { getConversationSource as O, useConversationPanelItems as k } from "./conversation/useConversationPanelItems/useConversationPanelItems.js";
17
- import { useImportFilePicker as A } from "./conversation/useImportFilePicker/useImportFilePicker.js";
18
- import { useAttachmentUpload as j } from "./conversation/useAttachmentUpload/useAttachmentUpload.js";
19
- import { AudioTranscriptionError as M, AudioTranscriptionErrorReason as N } from "./conversation/useTranscribeAudio/audio-transcription-error.js";
20
- import { useTranscribeAudio as P } from "./conversation/useTranscribeAudio/useTranscribeAudio.js";
21
- import { attachmentToDto as F, attachmentsToDtos as I } from "./conversation/useConversationHandlers/attachment-to-dto.js";
22
- import { createMessagePair as L } from "./conversation/useConversationHandlers/message-factory.js";
23
- import { hasActiveToolConfig as R, isAnswerIncomplete as z, isMessageChanged as B, shouldRerunGenerationOnEdit as V } from "./conversation/useConversationHandlers/message-utils.js";
24
- import { getStarterConversationText as H, getStarterDisplayText as U, getStarterSubmitText as W } from "./conversation/useConversationHandlers/starter-option.js";
25
- import { getConversationPath as G } from "./conversation/useConversationStream/conversation-path.js";
26
- import { useConversationHandlers as K } from "./conversation/useConversationHandlers/useConversationHandlers.js";
27
- import { applyChunkToMessages as q, mergeStages as J } from "./conversation/useConversationStream/apply-chunk.js";
28
- import { isAwaitingGenerationResume as Y } from "./conversation/useConversationStream/generation-resume.js";
29
- import { useConversationStream as X } from "./conversation/useConversationStream/useConversationStream.js";
30
- import { useChatSettingsFormConfig as Z } from "./useChatSettingsFormConfig/useChatSettingsFormConfig.js";
31
- import { useToolsMenu as Q } from "./useToolsMenu/useToolsMenu.js";
32
- export { M as AudioTranscriptionError, N as AudioTranscriptionErrorReason, a as DEFAULT_GENERATION_CONFLICT_MESSAGE, o as GenerationConflictError, q as applyChunkToMessages, F as attachmentToDto, I as attachmentsToDtos, e as buildAnnouncementSignature, s as createChatStreamApi, p as createDeploymentChangedMessage, L as createMessagePair, w as deriveConversationRowActionState, l as formatAppVersion, G as getConversationPath, O as getConversationSource, m as getLastDeploymentId, h as getLastUserMessageToolConfiguration, d as getModelIdFromConversationId, y as getQuickAppConversationStarters, H as getStarterConversationText, U as getStarterDisplayText, S as getStarterPopulateText, W as getStarterSubmitText, C as getStartersFromSchema, f as getTimeOfDayGreeting, R as hasActiveToolConfig, t as hasAnnouncementContent, n as hasStructuredAnnouncement, z as isAnswerIncomplete, Y as isAwaitingGenerationResume, B as isMessageChanged, g as isMessageStreaming, b as mapStages, J as mergeStages, _ as messageHasStages, v as normalizeResponseFormat, r as sanitizeAnnouncementHtml, i as sanitizeAnnouncementMessageHtml, u as sanitizeFooterHtml, V as shouldRerunGenerationOnEdit, c as shouldWatchForDisplayNameUpdate, x as toStage, T as useActiveConversationSync, E as useAsyncConfirmDialog, j as useAttachmentUpload, Z as useChatSettingsFormConfig, K as useConversationHandlers, D as useConversationLookupMaps, k as useConversationPanelItems, X as useConversationStream, A as useImportFilePicker, Q as useToolsMenu, P as useTranscribeAudio };
2
+ import { DEFAULT_GENERATION_CONFLICT_MESSAGE as a, DEFAULT_GENERATION_PERSISTENCE_ERROR_MESSAGE as o, DEFAULT_STREAM_IDLE_TIMEOUT_MS as s, GenerationConflictError as c, GenerationPersistenceError as l, StreamInterruptedError as u, StreamUpstreamError as d, createChatStreamApi as f } from "./conversation/create-chat-stream-api.js";
3
+ import { shouldWatchForDisplayNameUpdate as p } from "./conversation/display-name-watch.js";
4
+ import { formatAppVersion as m, sanitizeFooterHtml as h } from "./conversation/footer-message.js";
5
+ import { findDeploymentForConversationId as g, getModelIdCandidatesFromConversationId as _, getModelIdFromConversationId as v } from "./conversation/get-model-id-from-conversation-id.js";
6
+ import { getTimeOfDayGreeting as y } from "./conversation/greeting.js";
7
+ import { createDeploymentChangedMessage as b } from "./conversation/message-factory.js";
8
+ import { getFormSchemaToolSyncKey as x, getLastDeploymentId as S, getLastUserMessageToolConfiguration as C, getLatestToolConfiguration as w, getToolConfigurationFromFormSchema as T, isMessageStreaming as E, messageHasStages as D, normalizeResponseFormat as O } from "./conversation/message-utils.js";
9
+ import { getQuickAppConversationStarters as k } from "./conversation/quick-app-conversation-starters.js";
10
+ import { mapStages as A, toStage as j } from "./conversation/stage.js";
11
+ import { getStarterPopulateText as M, getStartersFromSchema as N } from "./conversation/starter-option.js";
12
+ import { deriveConversationRowActionState as P } from "./conversation/deriveConversationRowActionState/deriveConversationRowActionState.js";
13
+ import { useActiveConversationSync as F } from "./conversation/useActiveConversationSync/useActiveConversationSync.js";
14
+ import { useAsyncConfirmDialog as I } from "./conversation/useAsyncConfirmDialog/useAsyncConfirmDialog.js";
15
+ import { useConversationLookupMaps as L } from "./conversation/useConversationLookupMaps/useConversationLookupMaps.js";
16
+ import { getConversationSource as R, useConversationPanelItems as z } from "./conversation/useConversationPanelItems/useConversationPanelItems.js";
17
+ import { useImportFilePicker as B } from "./conversation/useImportFilePicker/useImportFilePicker.js";
18
+ import { useMessageSelectionReply as V } from "./conversation/useMessageSelectionReply/useMessageSelectionReply.js";
19
+ import { useAttachmentUpload as H } from "./conversation/useAttachmentUpload/useAttachmentUpload.js";
20
+ import { AudioTranscriptionError as U, AudioTranscriptionErrorReason as W } from "./conversation/useTranscribeAudio/audio-transcription-error.js";
21
+ import { useTranscribeAudio as G } from "./conversation/useTranscribeAudio/useTranscribeAudio.js";
22
+ import { attachmentToDto as K, attachmentsToDtos as q } from "./conversation/useConversationHandlers/attachment-to-dto.js";
23
+ import { createMessagePair as J } from "./conversation/useConversationHandlers/message-factory.js";
24
+ import { hasActiveToolConfig as Y, isAnswerIncomplete as X, isMessageChanged as Z, shouldRerunGenerationOnEdit as Q } from "./conversation/useConversationHandlers/message-utils.js";
25
+ import { getStarterConversationText as $, getStarterDisplayText as ee, getStarterSubmitText as te } from "./conversation/useConversationHandlers/starter-option.js";
26
+ import { getConversationPath as ne } from "./conversation/useConversationStream/conversation-path.js";
27
+ import { useConversationHandlers as re } from "./conversation/useConversationHandlers/useConversationHandlers.js";
28
+ import { applyChunkToMessages as ie, mergeStages as ae } from "./conversation/useConversationStream/apply-chunk.js";
29
+ import { isAwaitingGenerationResume as oe } from "./conversation/useConversationStream/generation-resume.js";
30
+ import { useConversationStream as se } from "./conversation/useConversationStream/useConversationStream.js";
31
+ import { useChatSettingsFormConfig as ce } from "./useChatSettingsFormConfig/useChatSettingsFormConfig.js";
32
+ import { useToolsMenu as le } from "./useToolsMenu/useToolsMenu.js";
33
+ export { U as AudioTranscriptionError, W as AudioTranscriptionErrorReason, a as DEFAULT_GENERATION_CONFLICT_MESSAGE, o as DEFAULT_GENERATION_PERSISTENCE_ERROR_MESSAGE, s as DEFAULT_STREAM_IDLE_TIMEOUT_MS, c as GenerationConflictError, l as GenerationPersistenceError, u as StreamInterruptedError, d as StreamUpstreamError, ie as applyChunkToMessages, K as attachmentToDto, q as attachmentsToDtos, e as buildAnnouncementSignature, f as createChatStreamApi, b as createDeploymentChangedMessage, J as createMessagePair, P as deriveConversationRowActionState, g as findDeploymentForConversationId, m as formatAppVersion, ne as getConversationPath, R as getConversationSource, x as getFormSchemaToolSyncKey, S as getLastDeploymentId, C as getLastUserMessageToolConfiguration, w as getLatestToolConfiguration, _ as getModelIdCandidatesFromConversationId, v as getModelIdFromConversationId, k as getQuickAppConversationStarters, $ as getStarterConversationText, ee as getStarterDisplayText, M as getStarterPopulateText, te as getStarterSubmitText, N as getStartersFromSchema, y as getTimeOfDayGreeting, T as getToolConfigurationFromFormSchema, Y as hasActiveToolConfig, t as hasAnnouncementContent, n as hasStructuredAnnouncement, X as isAnswerIncomplete, oe as isAwaitingGenerationResume, Z as isMessageChanged, E as isMessageStreaming, A as mapStages, ae as mergeStages, D as messageHasStages, O as normalizeResponseFormat, r as sanitizeAnnouncementHtml, i as sanitizeAnnouncementMessageHtml, h as sanitizeFooterHtml, Q as shouldRerunGenerationOnEdit, p as shouldWatchForDisplayNameUpdate, j as toStage, F as useActiveConversationSync, I as useAsyncConfirmDialog, H as useAttachmentUpload, ce as useChatSettingsFormConfig, re as useConversationHandlers, L as useConversationLookupMaps, z as useConversationPanelItems, se as useConversationStream, B as useImportFilePicker, V as useMessageSelectionReply, le as useToolsMenu, G as useTranscribeAudio };
@@ -21,6 +21,9 @@ export declare const annotationToOoxmlCanvasContent: (annotation: Annotation, an
21
21
  /**
22
22
  * Builds a `PdfCanvasContent` for a PDF citation annotation, including highlights
23
23
  * for the clicked annotation's document within its citation group.
24
+ * When the clicked annotation has a page but no selector with valid geometry,
25
+ * an invisible page-anchor highlight is added and selected so the viewer
26
+ * still opens that page.
24
27
  * Returns `null` if the annotation has no PDF source attachment.
25
28
  */
26
29
  export declare const annotationToPdfCanvasContent: (annotation: Annotation, groups: AnnotationGroup[], resolvers: AttachmentCanvasUrlResolvers) => PdfCanvasContent | null;
@@ -37,6 +40,8 @@ export declare interface AttachmentCanvasUrlResolvers {
37
40
  resolveDialUrl: (attachment: DisplayAttachment) => string | undefined;
38
41
  /** Resolves a DIAL Core file id to a fetchable metadata URL (used for cache-freshness validation). */
39
42
  resolveDialFileMetadataUrl: (fileId: string) => string | undefined;
43
+ /** URL of a host-served bootstrap document that renders HTML with no download URL (inline `data`) under its own response CSP instead of the embedding page's — forwarded as `HtmlCanvasContent.srcdocHostUrl`. When omitted, that HTML renders via plain `srcdoc`. */
44
+ htmlSrcdocHostUrl?: string;
40
45
  }
41
46
 
42
47
  /** The type of content the canvas can display. */
@@ -127,10 +132,16 @@ export declare const hasAttachmentTextSource: (attachment: DisplayAttachment, re
127
132
  declare interface HtmlCanvasContent {
128
133
  /** Discriminates the content type to select the correct renderer. */
129
134
  type: AttachmentContentType.Html;
130
- /** Full HTML text rendered via `srcdoc` in a sandboxed iframe. Used for file attachments. */
135
+ /** Full HTML text rendered via `srcdoc` in a sandboxed iframe. Populated only when no `url` is available (local, non-downloadable file attachments); when `url` is set, "View source" instead calls `resolveSourceText`. */
131
136
  srcdoc?: string;
132
- /** External URL rendered via `src` in a sandboxed iframe. Used for external link sources. */
137
+ /** URL rendered via `src` in a sandboxed iframe when `srcdoc` is absent, or in preference to `srcdoc` when `isSameOriginUrl` is set. Also used as the download-button/"Open in new tab" target. */
133
138
  url?: string;
139
+ /** True when `url`'s origin matches the embedding document's own origin. Forces the iframe sandbox to omit `allow-same-origin` — granting it would let a same-origin framed document reach this page's own cookies/storage — and makes `src` take precedence over `srcdoc`; also skips the `contentDocument` block-detection check, since the iframe is intentionally opaque-origin either way. */
140
+ isSameOriginUrl?: boolean;
141
+ /** Lazily fetches the full HTML source text for the "View source" toggle. Used instead of an eagerly-populated `srcdoc` when `url` is set; absent when `srcdoc` is already populated. */
142
+ resolveSourceText?: () => Promise<string>;
143
+ /** Host-served bootstrap document used to render `srcdoc` without inheriting the embedding page's CSP. When set alongside `srcdoc`, the iframe loads this URL via `src` (still `sandbox="allow-scripts"`) and posts `{ type: HTML_PREVIEW_FRAME_RENDER_MESSAGE, html: srcdoc }` to it once loaded, so the HTML renders under that response's own policy. Ignored when `srcdoc` is absent or `isSameOriginUrl` selects `url`. */
144
+ srcdocHostUrl?: string;
134
145
  }
135
146
 
136
147
  /** Content payload for image attachments. */
@@ -189,7 +200,7 @@ declare interface OoxmlDocxHighlightLocation {
189
200
  path: number[];
190
201
  /** Inclusive start character offset within the story's matched text. */
191
202
  start: number;
192
- /** Exclusive end character offset, already converted from the wire's inclusive `end`. */
203
+ /** Exclusive end character offset — the wire's `end`, already exclusive, copied through unchanged. */
193
204
  endExclusive: number;
194
205
  /** The cited text, compared against the text resolved over `[start, endExclusive)`. */
195
206
  text: string;
@@ -253,7 +264,7 @@ declare interface OoxmlPptxHighlightLocation {
253
264
  shapeId: string;
254
265
  /** Inclusive start character offset within the shape's matched text. */
255
266
  start: number;
256
- /** Exclusive end character offset, already converted from the wire's inclusive `end`. */
267
+ /** Exclusive end character offset — the wire's `end`, already exclusive, copied through unchanged. */
257
268
  endExclusive: number;
258
269
  /** The cited text, compared against the text resolved over `[start, endExclusive)`. */
259
270
  text: string;
@@ -330,9 +341,18 @@ export declare const resolveGroupedVisualizerCanvasContent: (attachments: Displa
330
341
 
331
342
  /**
332
343
  * Resolves an HTML canvas content payload from a DisplayAttachment.
333
- * Fetches and inlines the HTML as `srcdoc` when the attachment has a download URL or inline data.
334
- * Returns `null` if no source is available, or an `ErrorCanvasContent` on fetch failure.
335
- * Rejects `srcdoc` payloads larger than 1 MiB to prevent browser truncation.
344
+ * When the attachment has a download URL, that URL is the primary render
345
+ * target so the preview loads via `src` and gets its own response-level CSP
346
+ * instead of inheriting the host document's — no HTML text is fetched up
347
+ * front; `resolveSourceText` fetches it lazily, only when the "View source"
348
+ * toggle is used, and rejects if that fetch fails. `isSameOriginUrl` reflects
349
+ * a real comparison against the embedding document's own origin.
350
+ * With no download URL (local file or inline data), falls back to `srcdoc`,
351
+ * rejecting payloads larger than 1 MiB to prevent browser truncation, and
352
+ * forwards `resolvers.htmlSrcdocHostUrl` so that HTML can still render under
353
+ * its own response-level CSP.
354
+ * Returns `null` if no source is available, or an `ErrorCanvasContent` when
355
+ * that fallback fetch fails.
336
356
  */
337
357
  export declare const resolveHtmlCanvasContent: (attachment: DisplayAttachment, resolvers: AttachmentCanvasUrlResolvers) => Promise<HtmlCanvasContent | ErrorCanvasContent | null>;
338
358