@visma-swno/gaia-chat-ui 5.0.1 → 5.2.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 (91) hide show
  1. package/CHANGELOG.md +182 -93
  2. package/README.md +39 -40
  3. package/dist/app/app.d.ts +84 -4
  4. package/dist/components/canvas/iframe-preview/iframe-preview.d.ts +55 -4
  5. package/dist/components/composer/message-composer.d.ts +53 -0
  6. package/dist/components/conversation/context-changed-divider/context-changed-divider.d.ts +40 -0
  7. package/dist/components/conversation/context-divider.d.ts +55 -0
  8. package/dist/components/conversation/conversation.d.ts +5 -0
  9. package/dist/components/conversation/welcome-message/welcome-message.d.ts +9 -1
  10. package/dist/components/feedback/feedback-confirmation.d.ts +3 -0
  11. package/dist/components/feedback/feedback.d.ts +1 -0
  12. package/dist/components/history/history-item.d.ts +40 -0
  13. package/dist/components/history/history-view.d.ts +41 -0
  14. package/dist/components/layout/app-header/app-header.d.ts +5 -5
  15. package/dist/components/message/assistant-message.d.ts +4 -7
  16. package/dist/components/message/message-actions.d.ts +5 -0
  17. package/dist/components/message/message-attachments.d.ts +36 -0
  18. package/dist/components/message/message-attachments.styles.d.ts +2 -0
  19. package/dist/components/message/message.d.ts +1 -2
  20. package/dist/components/message/renderers/reasoning-block.d.ts +36 -0
  21. package/dist/components/message/renderers/reasoning-block.styles.d.ts +2 -0
  22. package/dist/components/message/renderers/tool-status-block.d.ts +6 -1
  23. package/dist/components/primitives/form-field/form-field.d.ts +8 -0
  24. package/dist/components/primitives/tooltip/tooltip.d.ts +3 -0
  25. package/dist/components/settings/settings-view.d.ts +30 -0
  26. package/dist/components/shared/controllers/iframe-preview-controller.d.ts +11 -0
  27. package/dist/core/adapters/citation-utils.d.ts +5 -3
  28. package/dist/core/adapters/index.d.ts +1 -1
  29. package/dist/core/adapters/memoized-mapper.d.ts +8 -9
  30. package/dist/core/adapters/message-mapper.d.ts +4 -11
  31. package/dist/core/adapters/message-normalizer.d.ts +22 -0
  32. package/dist/core/adapters/message-types.d.ts +38 -10
  33. package/dist/core/adapters/reasoning-utils.d.ts +29 -0
  34. package/dist/core/adapters/tool-utils.d.ts +37 -0
  35. package/dist/core/canvas/canvas-store.d.ts +6 -0
  36. package/dist/core/constants.d.ts +4 -0
  37. package/dist/core/errors.d.ts +3 -2
  38. package/dist/core/messages.d.ts +31 -1
  39. package/dist/core/store/agent-subscriber.d.ts +11 -1
  40. package/dist/core/store/auth-coordinator.d.ts +22 -4
  41. package/dist/core/store/chat-store.d.ts +132 -12
  42. package/dist/core/store/config-manager.d.ts +3 -18
  43. package/dist/core/store/consent-storage.d.ts +10 -0
  44. package/dist/core/store/history-coordinator.d.ts +77 -0
  45. package/dist/core/store/index.d.ts +8 -4
  46. package/dist/core/store/plugin-selection-manager.d.ts +5 -0
  47. package/dist/core/store/run-coordinator.d.ts +45 -7
  48. package/dist/core/store/selection-manager.d.ts +4 -0
  49. package/dist/core/store/selectors/component-selectors.d.ts +57 -5
  50. package/dist/core/store/selectors/index.d.ts +2 -2
  51. package/dist/core/store/selectors/message-selectors.d.ts +4 -33
  52. package/dist/core/store/session-manager.d.ts +53 -8
  53. package/dist/core/store/support-manager.d.ts +3 -0
  54. package/dist/core/store/tool-selection-manager.d.ts +5 -0
  55. package/dist/core/types.d.ts +101 -10
  56. package/dist/custom-elements.json +1 -1
  57. package/dist/{da--slbCKBx.js → da-DDxL51tD.js} +61 -2
  58. package/dist/{index-C2Q856CM.js → esm-lz7YfYzg.js} +3455 -4997
  59. package/dist/{fi-Cc9g_Z1U.js → fi-twx072Zu.js} +64 -5
  60. package/dist/generated/locales/da.d.ts +59 -0
  61. package/dist/generated/locales/fi.d.ts +59 -0
  62. package/dist/generated/locales/nb.d.ts +59 -0
  63. package/dist/generated/locales/nl.d.ts +59 -0
  64. package/dist/generated/locales/sv.d.ts +59 -0
  65. package/dist/index.d.ts +2 -2
  66. package/dist/index.es.js +16632 -13135
  67. package/dist/learning-universe-B_ZGsjBI.js +5 -0
  68. package/dist/markdown-BsU07hR0.js +2696 -0
  69. package/dist/{nb-BvGJ1d1A.js → nb-CeFzi8EU.js} +61 -2
  70. package/dist/{nl-BMUWAHah.js → nl-D1Z5TDkR.js} +61 -2
  71. package/dist/rolldown-runtime--_vEcKDh.js +29 -0
  72. package/dist/services/agent-service.d.ts +12 -9
  73. package/dist/services/api-client.d.ts +6 -0
  74. package/dist/services/api-schemas.d.ts +180 -40
  75. package/dist/services/conversations-client.d.ts +23 -0
  76. package/dist/services/index.d.ts +1 -1
  77. package/dist/services/message-converter.d.ts +5 -0
  78. package/dist/signalr-K7e2DzwD.js +1535 -0
  79. package/dist/{sv-DpcFtI4M.js → sv-BnYyj9E_.js} +60 -1
  80. package/dist/types/events.d.ts +29 -3
  81. package/dist/types/host-context.d.ts +22 -0
  82. package/dist/types/index.d.ts +5 -3
  83. package/dist/types/message-attachment.d.ts +7 -0
  84. package/dist/utils/i18n-check-helpers.d.ts +15 -0
  85. package/dist/utils/polling-task.d.ts +11 -1
  86. package/dist/vscode.html-custom-data.json +100 -7
  87. package/dist/{vsn-B4oW66pe.js → vsn-CBq00924.js} +1 -1
  88. package/package.json +23 -17
  89. package/dist/learning-universe-DsDXQ8wT.js +0 -5
  90. package/dist/markdown-BwfOAOOm.js +0 -1676
  91. package/dist/signalr-C1wWrBvq.js +0 -1783
package/dist/app/app.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PropertyValues } from 'lit';
2
2
  import { StrategyType } from '../core/store';
3
3
  import { TokenFetcher } from '../services/auth-service';
4
- import { FrontendTool, HostContextProvider } from '../types';
4
+ import { FrontendTool, HostContext, HostContextProvider } from '../types';
5
5
  import { BaseElement } from '../components/shared/base-element';
6
6
  /**
7
7
  * Root chat widget component.
@@ -12,6 +12,7 @@ import { BaseElement } from '../components/shared/base-element';
12
12
  * @element gaia-chat
13
13
  *
14
14
  * @fires {ConversationClearedEvent} conversation-cleared - When the user clears the conversation
15
+ * @fires {ConversationRestoredEvent} conversation-restored - When a conversation is restored from history, carrying the persisted host-context snapshot so the host app can re-orient to the tenant / customer / company it was about.
15
16
  * @fires {MessageSentEvent} message-sent - When the user sends a message
16
17
  * @fires {ToolCallApprovedEvent} tool-call-approved - When the user approves a tool call
17
18
  * @fires {ToolCallDeclinedEvent} tool-call-declined - When the user declines a tool call
@@ -27,6 +28,24 @@ import { BaseElement } from '../components/shared/base-element';
27
28
  * auth-strategy="visitor"
28
29
  * ></gaia-chat>
29
30
  * ```
31
+ *
32
+ * ### Host-provided conversation id
33
+ *
34
+ * Setting the `conversation-id` attribute opens that conversation as a
35
+ * **scoped view** without overwriting the user's normal stored session. This
36
+ * is for host apps that need to deep-link back into a specific conversation
37
+ * — e.g. a report designer reopening the chat that produced a given report.
38
+ * Removing the attribute restores the localStorage-backed conversation.
39
+ *
40
+ * ```html
41
+ * <gaia-chat conversation-id="d4f9..." profile-id="default"></gaia-chat>
42
+ * ```
43
+ *
44
+ * If the user clears the chat while a host-provided `conversation-id` is set,
45
+ * `conversation-cleared` fires with `previousConversationId` matching the
46
+ * pinned value. Treat that as the user opting out of the deep-link — typical
47
+ * responses are to clear/update the attribute, or leave it pinned and accept
48
+ * that the next mount will re-restore the deep-linked conversation.
30
49
  */
31
50
  export declare class ChatApp extends BaseElement {
32
51
  static styles: import('lit').CSSResult[];
@@ -42,10 +61,22 @@ export declare class ChatApp extends BaseElement {
42
61
  authStrategy: StrategyType;
43
62
  /** Whether to show a close button in the header. */
44
63
  closeable: boolean;
45
- /** Override the default AI model. Must be in the profile's allowed overrides list. */
46
- selectedModel: string;
64
+ /** Whether to show the conversation history button in the header. */
65
+ enableHistory: boolean;
66
+ /**
67
+ * Host-provided conversation id (#2644). When set, this conversation is
68
+ * restored instead of the one persisted in localStorage. The localStorage
69
+ * value is **not** overwritten — clearing the attribute returns the widget
70
+ * to that previous conversation. Empty string is treated as unset.
71
+ */
72
+ conversationId: string;
47
73
  /** Frontend tool definitions sent to the agent. */
48
74
  tools: FrontendTool[];
75
+ /**
76
+ * Readonly mode: hides the composer, header actions, and connection overlay.
77
+ * Use `setReadonlyMessages()` to inject messages for display.
78
+ */
79
+ readonlyMode: boolean;
49
80
  private get activeLang();
50
81
  private langObserver?;
51
82
  private store;
@@ -54,20 +85,69 @@ export declare class ChatApp extends BaseElement {
54
85
  private canvasActive;
55
86
  private canvasExpanded;
56
87
  private supportSessionEnded;
88
+ private historyOpen;
89
+ private settingsOpen;
90
+ private attachmentsEnabled;
91
+ private supportConnected;
92
+ private isDraggingOver;
93
+ private dragDepth;
57
94
  private disposables;
58
95
  private ctx;
59
96
  private handleInlineQuestionClick;
60
97
  connectedCallback(): void;
61
98
  disconnectedCallback(): void;
62
99
  private handleAuthChanged;
100
+ /**
101
+ * Reconcile the chat surface with the current `conversation-id` attribute
102
+ * when no auth-related prop changed alongside it. Non-empty value → scoped
103
+ * restore (no localStorage write). Empty/absent → fall back to the
104
+ * localStorage-backed conversation via `loadHistory`.
105
+ */
106
+ private applyConversationIdOverride;
63
107
  willUpdate(changedProperties: PropertyValues): void;
64
- private applySelectedModel;
65
108
  private toggleHostAttribute;
66
109
  private handleKeyDown;
110
+ /**
111
+ * Retroactively update the host-context snapshot for the most recent user
112
+ * message. Call this after a mid-run context confirmation (e.g. a frontend
113
+ * tool) so the "Context changed" divider renders immediately.
114
+ */
115
+ patchCurrentMessageHostContext(props: Record<string, unknown>): void;
116
+ /**
117
+ * Returns the host-context snapshot persisted for the active conversation,
118
+ * shaped as a {@link HostContext}, or `null` when none is available.
119
+ *
120
+ * The localStorage-backed restore path (`loadHistory`) hydrates this snapshot
121
+ * but does not emit {@link ConversationRestoredEvent}, so a host app that
122
+ * supplies context via `hostContextProvider` can read it here to keep
123
+ * follow-up messages scoped to the restored tenant/company after a refresh.
124
+ */
125
+ getActiveHostContext(): HostContext | null;
126
+ /** Whether a file dragged over the widget can currently be attached. */
127
+ private get canAcceptDrop();
128
+ private get composer();
129
+ private dragContainsFiles;
130
+ private handleDragEnter;
131
+ private handleDragOver;
132
+ private handleDragLeave;
133
+ private handleDrop;
67
134
  /** Clears the current conversation and resets the chat. */
68
135
  clearConversation(): void;
69
136
  /** Stops any active support session. */
70
137
  stopSupport(): void;
138
+ /** Sends a message programmatically after the chat has initialized. */
139
+ sendMessage(message: string): Promise<void>;
140
+ /**
141
+ * Inject messages for readonly display. Accepts AG-UI format messages
142
+ * (as returned by the inspect API) and runs them through the full message
143
+ * pipeline so tool calls, search results, reasoning, and citations all
144
+ * render correctly.
145
+ *
146
+ * @param messages - AG-UI format message objects from the backend.
147
+ * @param thumbs - Optional map of messageId → "up" | "down" for feedback indicators.
148
+ */
149
+ setReadonlyMessages(messages: ReadonlyArray<Record<string, unknown>>, thumbs?: Readonly<Record<string, string>>): void;
150
+ private waitForInitialization;
71
151
  render(): import('lit-html').TemplateResult<1>;
72
152
  }
73
153
  declare global {
@@ -41,13 +41,64 @@ export declare class IframePreview extends BaseElement {
41
41
  private handleRendererReady;
42
42
  private transpileAndSend;
43
43
  private updateIframeHtml;
44
+ /**
45
+ * Single source of truth for report sanitization. Branches on whether the
46
+ * LLM produced a full document or a fragment, runs DOMPurify with the
47
+ * matching options, then runs the defense-in-depth post-pass. Both the
48
+ * chart-bundle precheck in `updateIframeHtml` and the final `buildHtml`
49
+ * call site consume the same output, so detection and rendering can never
50
+ * disagree about what survives sanitisation.
51
+ */
52
+ private sanitizeContent;
44
53
  private loadChartsScript;
45
54
  /**
46
- * Error harness script injected into the report iframe.
47
- * Catches JS errors and scans the DOM for chart rendering errors,
48
- * then reports render status back to the parent via postMessage.
55
+ * Returns the error harness script tag with a per-render CSP nonce.
56
+ * The nonce matches the one embedded in the Content-Security-Policy meta
57
+ * tag, so `script-src 'unsafe-inline'` is not required.
58
+ */
59
+ private static errorHarness;
60
+ /**
61
+ * Returns the CSP meta tag for the report iframe, scoped to a per-render
62
+ * nonce.
63
+ *
64
+ * Using a nonce eliminates the need for `script-src 'unsafe-inline'`:
65
+ * only `<script nonce="…">` elements whose nonce matches the policy are
66
+ * executed, so a DOMPurify zero-day that lets an inline `<script>` survive
67
+ * sanitization cannot execute — it would have no nonce.
68
+ *
69
+ * The iframe is loaded via `srcdoc`, which does not receive the server's
70
+ * HTTP-header CSP applied to /canvas/*. The policy therefore lives inside
71
+ * the document itself and mirrors the transpile-renderer policy
72
+ * (assistant/src/Api/Program.cs). `connect-src 'none'` is the critical
73
+ * directive — it blocks fetch/XHR/beacon so surviving scripts cannot
74
+ * exfiltrate report contents to an external host.
75
+ */
76
+ private static buildCspMeta;
77
+ /** Tags stripped from LLM-authored report HTML. Script/handler removal is
78
+ * already covered by DOMPurify defaults; these add belt-and-braces against
79
+ * tags that can navigate, load external resources, or submit data.
80
+ *
81
+ * Notably *not* forbidden — these are intended report features:
82
+ * - `<svg>`: pdf-report skill instructs the LLM to inline SVG icons
83
+ * and diagrams (see `assistant/src/Plugins/PdfReport/skills/.../SKILL.md`).
84
+ * The script-execution risk from SVG-mediated DOMPurify mXSS is
85
+ * neutralised by the per-render CSP nonce — a surviving inline `<script>`
86
+ * would have no nonce and the browser would refuse to run it.
87
+ * - `<img>`: pdf-report supports PNG data URIs (`src="data:image/png;…"`),
88
+ * and the iframe CSP already restricts `img-src` to `data: blob:`.
89
+ * - `<style>`: pdf-report embeds all CSS in `<style>` blocks. The element
90
+ * itself is safe; CSS-injection-via-attribute is blocked by
91
+ * `REPORT_FORBID_ATTRS` below.
49
92
  */
50
- private static readonly ERROR_HARNESS;
93
+ private static readonly REPORT_FORBID_TAGS;
94
+ /** Attributes stripped from LLM-authored report HTML. The inline `style`
95
+ * attribute is the main UI-spoofing vector left after `<script>`/handler
96
+ * removal — e.g. `<div style="position:fixed;inset:0;background:#fff;
97
+ * z-index:9999">…fake content…</div>` could mask the rest of the report
98
+ * inside the iframe. The pdf-report skill never instructs the LLM to use
99
+ * inline `style` attributes (it embeds all CSS in a `<style>` block), so
100
+ * forbidding the attribute does not regress intended functionality. */
101
+ private static readonly REPORT_FORBID_ATTRS;
51
102
  private buildHtml;
52
103
  private escapeHtml;
53
104
  render(): import('lit-html').TemplateResult<1>;
@@ -21,28 +21,78 @@ export declare class GaiaMessageComposer extends BaseElement {
21
21
  textareaWrap: HTMLDivElement;
22
22
  textarea: HTMLTextAreaElement;
23
23
  autosize: HTMLDivElement;
24
+ attachmentInput?: HTMLInputElement;
24
25
  private value;
25
26
  private invalid;
27
+ private pendingAttachments;
28
+ private attachmentError;
29
+ private uploadingCount;
30
+ private isRecording;
31
+ private speechSupported;
32
+ private recognition;
26
33
  profileId: string;
27
34
  hostContextProvider?: HostContextProvider;
28
35
  rows: number;
29
36
  maxRows: number;
30
37
  connectedCallback(): void;
31
38
  disconnectedCallback(): void;
39
+ /** Whether an attachment upload is currently in flight. */
40
+ private get uploadingAttachment();
32
41
  private get notAllowedToSendMessage();
42
+ private get canUseVoiceDictation();
33
43
  private isMessageNotAllowed;
34
44
  private validateInput;
45
+ private initSpeechRecognition;
46
+ private toggleRecording;
35
47
  private handleChange;
36
48
  private handleInput;
37
49
  private handleFeedbackClosed;
38
50
  private closeFeedbackIfOpen;
39
51
  private handleSendMessage;
52
+ private handleStopMessage;
40
53
  private resolveHostContext;
41
54
  private dispatchToSupport;
42
55
  private dispatchToAssistant;
56
+ private handleAttachmentButtonClick;
57
+ private clearPendingAttachments;
58
+ /** Dismisses the attachment error banner without discarding staged attachments. */
59
+ private dismissAttachmentError;
60
+ private removePendingAttachment;
61
+ private handleAttachmentSelected;
62
+ private processAttachmentFiles;
63
+ private uploadAttachmentFile;
64
+ /**
65
+ * Whether a file can currently be accepted as a pending attachment.
66
+ *
67
+ * False when attachments are disabled for the profile, the support channel
68
+ * is active, or the composer is disabled/loading. Callers should check this
69
+ * before suppressing native browser behaviour (e.g. paste) so they don't
70
+ * swallow the event without effect. Multiple attachments may be queued, so
71
+ * an in-flight upload does not block accepting further files.
72
+ */
73
+ get canAcceptAttachment(): boolean;
74
+ /**
75
+ * Uploads files dropped anywhere on the chat surface as pending attachments.
76
+ *
77
+ * Called by the root chat component, which owns the drag-and-drop overlay so
78
+ * files can be dropped over the entire widget rather than only the composer.
79
+ * Guards against uploads while attachments are unavailable for the active
80
+ * channel/profile.
81
+ */
82
+ acceptDroppedFiles(files: File[]): Promise<void>;
83
+ /**
84
+ * Uploads a single dropped file as a pending attachment.
85
+ *
86
+ * Thin wrapper around {@link acceptDroppedFiles} retained for callers that
87
+ * only have a single file to hand.
88
+ */
89
+ acceptDroppedFile(file: File): Promise<void>;
43
90
  private handleSuggestedQuestionClick;
44
91
  private handleKeyDown;
92
+ private handlePaste;
45
93
  private maybeEmitTyping;
94
+ private createPreviewUrl;
95
+ private revokeAllPreviewUrls;
46
96
  protected updated(changed: PropertyValues): Promise<void>;
47
97
  /** Sets focus on the textarea. */
48
98
  focus(options?: FocusOptions): void;
@@ -51,6 +101,9 @@ export declare class GaiaMessageComposer extends BaseElement {
51
101
  /** Selects all the text in the textarea. */
52
102
  select(): void;
53
103
  render(): import('lit-html').TemplateResult<1>;
104
+ private getPendingAttachmentPreviews;
105
+ private renderPendingAttachmentPreviews;
106
+ private renderAttachmentError;
54
107
  }
55
108
  declare global {
56
109
  interface HTMLElementTagNameMap {
@@ -0,0 +1,40 @@
1
+ import { BaseElement } from '../../shared/base-element';
2
+ /**
3
+ * Per-key diff between two adjacent host-context snapshots. Drives the expanded
4
+ * comparison view that the divider reveals on click. Mirrors the shape produced
5
+ * by `describeHostContextDiff()` in the conversation renderer — the divider is
6
+ * purely presentational and trusts its caller to compute the diff.
7
+ */
8
+ export type HostContextDiff = {
9
+ added: Record<string, unknown>;
10
+ removed: Record<string, unknown>;
11
+ changed: Record<string, {
12
+ from: unknown;
13
+ to: unknown;
14
+ }>;
15
+ };
16
+ /**
17
+ * Visual divider rendered between two adjacent user messages whose host-supplied
18
+ * context differs (e.g. the host app pivoted from one customer to another mid-chat).
19
+ *
20
+ * Renders a centered "Context changed" disclosure button between two horizontal
21
+ * rules. Clicking the button toggles a panel below that lists the per-key diff —
22
+ * added / changed / removed entries — so the user can compare what shifted.
23
+ *
24
+ * @element gaia-context-changed-divider
25
+ */
26
+ export declare class GaiaContextChangedDivider extends BaseElement {
27
+ /** Per-key diff of host context. Drives the expanded comparison view. */
28
+ diff?: HostContextDiff;
29
+ private expanded;
30
+ static styles: import('lit').CSSResult[];
31
+ private toggle;
32
+ private renderEntries;
33
+ private renderDetails;
34
+ render(): import('lit-html').TemplateResult<1>;
35
+ }
36
+ declare global {
37
+ interface HTMLElementTagNameMap {
38
+ 'gaia-context-changed-divider': GaiaContextChangedDivider;
39
+ }
40
+ }
@@ -0,0 +1,55 @@
1
+ import { HostContextDiff } from './context-changed-divider/context-changed-divider';
2
+ import { UiMessage } from '../../core/adapters/message-types';
3
+ import { HostContextSnapshot } from '../../core/types';
4
+ /**
5
+ * Pure helpers that decide when the `<gaia-context-changed-divider>` fires and what
6
+ * diff it should display. Extracted from `<gaia-conversation>` so the gating
7
+ * invariants — "first user message never fires", "baseline advances on every user
8
+ * message even with no context", "transitions to/from no-context still fire" — can
9
+ * be unit-tested without mounting the conversation component. The renderer just
10
+ * consumes the Map this module produces.
11
+ */
12
+ /**
13
+ * Decide whether a "Context changed" divider should fire between two adjacent user
14
+ * messages' host-context snapshots. Fires whenever the two snapshots differ, treating
15
+ * `undefined`/`null` as a first-class "no host context" state — so a transition from
16
+ * `{ companyId: 123 }` to `undefined` (e.g. user switched profile and the host stopped
17
+ * forwarding companyId) draws a line, just like any other change. The first user
18
+ * message in a conversation never fires; that gating happens in
19
+ * `computeContextChangedMessageIds`, not here.
20
+ *
21
+ * Both ends of the pipeline serialize via JSON-shaped objects, so a key-sorted
22
+ * recursive deep-equal is sufficient — we don't need to handle Maps, Dates, or other
23
+ * non-JSON types.
24
+ */
25
+ export declare function shouldFireContextChangedDivider(previous: HostContextSnapshot | undefined, current: HostContextSnapshot | undefined): boolean;
26
+ /**
27
+ * Classify the differences between two host-context snapshots into added / removed /
28
+ * changed keys. The result is passed straight into `<gaia-context-changed-divider>`,
29
+ * which renders it as the expandable comparison view shown when the user opens the
30
+ * divider.
31
+ */
32
+ export declare function describeHostContextDiff(previous: HostContextSnapshot | undefined, current: HostContextSnapshot | undefined): HostContextDiff;
33
+ /**
34
+ * Identify user messages that need a "Context changed" divider rendered above them,
35
+ * paired with the summary the divider should display. A user message qualifies when
36
+ * its recorded host-context differs from the previous user message's — including
37
+ * transitions to/from "no recorded context". The very first user message never
38
+ * qualifies because there's no prior turn to compare to.
39
+ *
40
+ * Works identically for live sends (snapshot written by the run-coordinator) and
41
+ * rehydrated chats (snapshot loaded from `conversation_v2_messages` via the restore
42
+ * path) — both populate the same `messageHostContexts` map.
43
+ *
44
+ * Returns a Map of message id → diff describing the per-key change. The divider
45
+ * uses the diff to render its expanded comparison view on demand. O(1) lookup per
46
+ * group.
47
+ */
48
+ export declare function computeContextChangedMessageIds(messages: UiMessage[], contexts: Record<string, HostContextSnapshot>): Map<string, HostContextDiff>;
49
+ /**
50
+ * Internal JSON-shape deep-equal. Exported solely for unit tests that lock in the
51
+ * key-order-independence and array-vs-object behavior the divider gating depends on.
52
+ * Not part of the module's public API — callers should use `shouldFireContextChangedDivider`
53
+ * or `describeHostContextDiff` instead of comparing snapshots directly.
54
+ */
55
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
@@ -14,10 +14,14 @@ export declare class GaiaConversation extends BaseElement {
14
14
  private containerRef;
15
15
  private scrollViewRef;
16
16
  private lastMessageRef;
17
+ private selectConversationState;
17
18
  private ctrl;
19
+ private sharingCtrl;
20
+ private sharingPromptTriggered;
18
21
  private handleThumb;
19
22
  private scrollCtrl;
20
23
  protected updated(): Promise<void>;
24
+ private handleSharingPromptResponse;
21
25
  /**
22
26
  * Whether the thinking indicator should be visible.
23
27
  * Hidden when the last message is a pending tool call with a visible
@@ -29,6 +33,7 @@ export declare class GaiaConversation extends BaseElement {
29
33
  */
30
34
  private isMessageInActiveRun;
31
35
  private renderRunGroup;
36
+ private renderRunGroupBody;
32
37
  render(): import('lit-html').TemplateResult<1>;
33
38
  }
34
39
  declare global {
@@ -1,17 +1,25 @@
1
1
  import { WelcomeMessage } from '../../../core/types';
2
2
  import { BaseElement } from '../../shared/base-element';
3
+ export interface SharingPromptResponseEvent {
4
+ accepted: boolean;
5
+ }
3
6
  /**
4
7
  * Welcome screen shown when the conversation is empty.
5
8
  *
6
9
  * Renders a greeting title, optional body text, a call-to-action prompt,
7
- * and optional informational cards driven by the `blocks` field.
10
+ * optional informational cards, and an optional inline consent prompt.
8
11
  *
9
12
  * @element gaia-welcome-message
10
13
  */
11
14
  export declare class GaiaWelcomeMessage extends BaseElement {
12
15
  static styles: import('lit').CSSResult[][];
13
16
  welcomeMessage?: WelcomeMessage;
17
+ /** Whether to show the inline sharing consent prompt below block cards. */
18
+ showSharingPrompt: boolean;
19
+ private handleYes;
20
+ private handleNo;
14
21
  render(): import('lit-html').TemplateResult<1>;
22
+ private renderSharingPrompt;
15
23
  }
16
24
  declare global {
17
25
  interface HTMLElementTagNameMap {
@@ -11,10 +11,13 @@ import { BaseElement } from '../shared/base-element';
11
11
  export declare class GaiaFeedbackConfirmation extends BaseElement {
12
12
  static styles: import('lit').CSSResult[];
13
13
  private ctrl;
14
+ private copyTimeoutId;
14
15
  private copied;
16
+ disconnectedCallback(): void;
15
17
  private get visitorUserId();
16
18
  private get shouldShowPrivacyId();
17
19
  private handleClose;
20
+ private clearCopyTimeout;
18
21
  private handleCopyPrivacyId;
19
22
  render(): import('lit-html').TemplateResult<1>;
20
23
  }
@@ -29,6 +29,7 @@ export declare class GaiaFeedback extends BaseElement {
29
29
  private handleCommentChange;
30
30
  private handleSubmit;
31
31
  private handleConsentConfirmed;
32
+ private submitAndClose;
32
33
  protected firstUpdated(_changedProperties: PropertyValues): void;
33
34
  private handleKeyDown;
34
35
  private handleClose;
@@ -0,0 +1,40 @@
1
+ import { ConversationSummary } from '../../core/types';
2
+ import { BaseElement } from '../shared/base-element';
3
+ /**
4
+ * A single row in {@link GaiaHistoryView}. Shows the title, a context label
5
+ * when available (customer / company / partner), a relative timestamp, and
6
+ * row-level rename / delete actions.
7
+ *
8
+ * Stays stateless w.r.t. the store — actions bubble up as CustomEvents and
9
+ * are handled by the parent `<gaia-history-view>` which forwards them to
10
+ * `HistoryCoordinator`. Rename uses a minimal inline edit mode to keep the
11
+ * MVP scope small (no modal component dependency).
12
+ *
13
+ * @element gaia-history-item
14
+ *
15
+ * @fires history-item-select - When the row is activated. Detail: `{ summary }`.
16
+ * @fires history-item-rename - After the user confirms a new title. Detail: `{ id, title }`.
17
+ * @fires history-item-delete - After the user confirms deletion. Detail: `{ id }`.
18
+ */
19
+ export declare class GaiaHistoryItem extends BaseElement {
20
+ static styles: import('lit').CSSResult[];
21
+ summary: ConversationSummary;
22
+ active: boolean;
23
+ private editing;
24
+ private draftTitle;
25
+ private handleSelect;
26
+ private handleKeyDown;
27
+ private startRename;
28
+ private cancelRename;
29
+ private confirmRename;
30
+ private handleEditKey;
31
+ private handleInput;
32
+ private handleDelete;
33
+ private getContextLabel;
34
+ render(): import('lit-html').TemplateResult<1>;
35
+ }
36
+ declare global {
37
+ interface HTMLElementTagNameMap {
38
+ 'gaia-history-item': GaiaHistoryItem;
39
+ }
40
+ }
@@ -0,0 +1,41 @@
1
+ import { PropertyValues } from 'lit';
2
+ import { BaseElement } from '../shared/base-element';
3
+ /**
4
+ * Full-area conversation history panel. Replaces the chat area inside
5
+ * `<gaia-chat>` when `historyOpen` is true.
6
+ *
7
+ * Renders a profile-scoped list of previous conversations. Row actions (rename,
8
+ * delete) are delegated to `<gaia-history-item>`. Clicking a row restores the
9
+ * conversation into the active chat and fires a `conversation-restored` event
10
+ * via {@link ChatStore.restoreConversationById}.
11
+ *
12
+ * @element gaia-history-view
13
+ */
14
+ export declare class GaiaHistoryView extends BaseElement {
15
+ static styles: import('lit').CSSResult[];
16
+ private ctrl;
17
+ private sentinelObserver?;
18
+ private observedSentinel?;
19
+ private handleClose;
20
+ private handleRetry;
21
+ private handleSelect;
22
+ private handleRename;
23
+ private handleDelete;
24
+ disconnectedCallback(): void;
25
+ protected updated(_changed: PropertyValues): void;
26
+ /**
27
+ * Attach or tear down the IntersectionObserver that watches the bottom-of-list
28
+ * sentinel. The sentinel is only rendered while more pages are available, so
29
+ * this runs on every update and follows the DOM: observe when the sentinel is
30
+ * present, detach when it isn't. The observer's root is the scrollable list
31
+ * container, not the viewport, so nested scroll regions (embedded widget) fire
32
+ * correctly.
33
+ */
34
+ private syncSentinelObserver;
35
+ render(): import('lit-html').TemplateResult<1>;
36
+ }
37
+ declare global {
38
+ interface HTMLElementTagNameMap {
39
+ 'gaia-history-view': GaiaHistoryView;
40
+ }
41
+ }
@@ -1,11 +1,7 @@
1
1
  import { PropertyValues } from 'lit';
2
2
  import { BaseElement } from '../../shared/base-element';
3
3
  /**
4
- * Application header bar with feedback, new-chat, and close actions.
5
- *
6
- * Renders a toolbar with icon buttons for opening the feedback form,
7
- * clearing the conversation, and closing the chat widget. Actions are
8
- * disabled while the chat is initializing or a run is in progress.
4
+ * Application header bar with data settings, feedback, new-chat, and close actions.
9
5
  *
10
6
  * @element gaia-app-header
11
7
  *
@@ -17,15 +13,19 @@ export declare class GaiaAppHeader extends BaseElement {
17
13
  private ctrl;
18
14
  private toolbar;
19
15
  closeable: boolean;
16
+ enableHistory: boolean;
20
17
  connectedCallback(): void;
21
18
  disconnectedCallback(): void;
22
19
  protected updated(changed: PropertyValues): void;
23
20
  private getToolbarButtons;
24
21
  private handleFeedbackClosed;
25
22
  private handleClearConversation;
23
+ private handleToggleHistory;
26
24
  private handleToggleFeedback;
27
25
  private handleCloseChat;
26
+ private toggleDataSettings;
28
27
  render(): import('lit-html').TemplateResult<1>;
28
+ private renderDataSettingsButton;
29
29
  }
30
30
  declare global {
31
31
  interface HTMLElementTagNameMap {
@@ -1,19 +1,16 @@
1
1
  import { nothing } from 'lit';
2
- import { UiAssistantMessage } from '../../core/adapters';
3
- import { SearchCitation } from '../../core/adapters/tool-utils';
2
+ import { UiAssistantMessage } from '../../core/adapters/message-types';
4
3
  import { BaseElement } from '../shared/base-element';
5
4
  export declare class GaiaAssistantMessage extends BaseElement {
6
5
  static styles: import('lit').CSSResult[][];
7
6
  message: UiAssistantMessage;
8
- citations: SearchCitation[];
9
7
  isStreaming: boolean;
10
8
  private bodyEl;
11
- /** Cached result of extractSuggestedQuestions for the current content. */
12
- private cachedExtraction;
13
- private getExtractedContent;
9
+ private expandedToolCallIds;
14
10
  render(): import('lit-html').TemplateResult<1> | typeof nothing;
15
- private renderToolCalls;
11
+ private renderPart;
16
12
  private renderToolCall;
13
+ private toggleToolCall;
17
14
  private handleInlineQuestionClick;
18
15
  }
19
16
  declare global {
@@ -27,6 +27,10 @@ export declare class GaiaMessageActions extends BaseElement {
27
27
  copyContent: string;
28
28
  /** Whether this message belongs to the currently active run. Hides actions while active. */
29
29
  inActiveRun: boolean;
30
+ /** Readonly mode: shows static feedback indicator instead of interactive buttons. */
31
+ readonly: boolean;
32
+ /** Persisted feedback state from API. Used in readonly mode to display the thumb icon. */
33
+ thumb: 'up' | 'down' | null;
30
34
  /** Callback for submitting message thumbs. Set by parent message component. */
31
35
  onThumb?: (messageId: string, isPositive: boolean | null) => Promise<boolean>;
32
36
  private isCopied;
@@ -37,6 +41,7 @@ export declare class GaiaMessageActions extends BaseElement {
37
41
  render(): import('lit-html').TemplateResult<1> | typeof nothing;
38
42
  private renderCopyButton;
39
43
  private renderFeedbackButtons;
44
+ private renderFeedbackIndicator;
40
45
  private handleCopyClick;
41
46
  private handleFeedbackClick;
42
47
  }
@@ -0,0 +1,36 @@
1
+ import { nothing } from 'lit';
2
+ import { MessageAttachment } from '../../types';
3
+ import { BaseElement } from '../shared/base-element';
4
+ export declare class GaiaMessageAttachments extends BaseElement {
5
+ static styles: import('lit').CSSResult[];
6
+ attachments: MessageAttachment[];
7
+ onRemoveAttachment?: (attachment: MessageAttachment) => void;
8
+ fullWidth: boolean;
9
+ compact: boolean;
10
+ render(): import('lit-html').TemplateResult<1> | typeof nothing;
11
+ private renderCompactAttachment;
12
+ private renderAttachment;
13
+ private renderRemoveButton;
14
+ private handleRemoveClick;
15
+ private isImageAttachment;
16
+ private isPdfAttachment;
17
+ /**
18
+ * Splits a file name so the tail (extension and a few trailing characters)
19
+ * stays pinned while the start truncates with an ellipsis, yielding a
20
+ * middle-truncated name such as `Screens…nal.pdf`.
21
+ */
22
+ private splitFileName;
23
+ /** Formats a byte count into a compact, locale-aware size (e.g. `1.2 MB`). */
24
+ private formatFileSize;
25
+ /**
26
+ * Formats a magnitude and byte unit using the active locale, falling back to
27
+ * a plain `value unit` string if the runtime lacks `Intl.NumberFormat` unit
28
+ * support.
29
+ */
30
+ private formatSizeNumber;
31
+ }
32
+ declare global {
33
+ interface HTMLElementTagNameMap {
34
+ 'gaia-message-attachments': GaiaMessageAttachments;
35
+ }
36
+ }