@accurix/centrinfo-widget 5.0.0 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,362 @@
1
1
  import * as preact0 from "preact";
2
2
 
3
- //#region src/i18n.d.ts
3
+ //#region ../centrinfo-results/src/analytics-explanation.d.ts
4
4
 
5
+ /**
6
+ * Framework-agnostic analytics explanation core.
7
+ *
8
+ * Every surface (Liveboard SDK vanilla DOM, the Preact widget and full-page
9
+ * chat app, and the React dashboard) renders an explanation from the SAME
10
+ * display model built here, so wording, order and value-status rules never
11
+ * drift between surfaces. Renderers only map this model onto their own markup
12
+ * and theme tokens.
13
+ *
14
+ * Step-by-step order (fixed):
15
+ * 1. lead plain business answer (headline + summary)
16
+ * 2. comparison each compared period with its value + status chip
17
+ * 3. conclusions what the data supports
18
+ * 4. limits in-progress / unconfirmed zero / missing period / caveats
19
+ * 5. checked "Times in <tz> · Checked <time>"
20
+ * 6. investigate causes, recommendations, outlook, follow-ups (optional
21
+ * disclosure, collapsed by default)
22
+ *
23
+ * Zero is only "confirmed" when the source says so. An empty bucket or an
24
+ * unconfirmed zero reads as "no records yet" and never produces a % change.
25
+ *
26
+ * Pure TypeScript, no DOM or framework imports: safe for every SDK bundle.
27
+ */
28
+ type AnalyticsExplanationValueStatus = 'observed' | 'confirmed_zero' | 'empty_bucket' | 'unconfirmed_zero' | 'missing';
29
+ interface AnalyticsExplanationPeriodRangeInput {
30
+ label: string;
31
+ start?: string;
32
+ end?: string;
33
+ timezone?: string;
34
+ }
35
+ interface AnalyticsExplanationEvidenceItemInput {
36
+ id: string;
37
+ text: string;
38
+ kind?: string;
39
+ metric?: string;
40
+ period?: AnalyticsExplanationPeriodRangeInput;
41
+ filters?: string[];
42
+ value?: number;
43
+ valueStatus?: AnalyticsExplanationValueStatus | string;
44
+ statusReason?: string;
45
+ source?: {
46
+ kind?: 'card' | 'supporting_query' | string;
47
+ insightId?: string;
48
+ queryRunId?: string;
49
+ liveboardTileId?: string;
50
+ };
51
+ checkedAt?: string;
52
+ }
53
+ interface AnalyticsExplanationPeriodInput {
54
+ evidenceId?: string;
55
+ label: string;
56
+ start?: string;
57
+ end?: string;
58
+ timezone?: string;
59
+ current?: boolean;
60
+ inProgress?: boolean;
61
+ value?: number;
62
+ valueText?: string;
63
+ valueStatus?: AnalyticsExplanationValueStatus | string;
64
+ statusReason?: string;
65
+ source?: string;
66
+ }
67
+ interface AnalyticsExplanationMissingInput {
68
+ evidenceId?: string;
69
+ label: string;
70
+ period?: AnalyticsExplanationPeriodRangeInput;
71
+ reason: string;
72
+ }
73
+ interface AnalyticsExplanationFreshnessInput {
74
+ status?: string;
75
+ dataAsOf?: string;
76
+ expectedThrough?: string;
77
+ lagDays?: number;
78
+ checkedAt?: string;
79
+ timezone?: string;
80
+ }
81
+ /** Structural explanation shape every surface's DTO satisfies. */
82
+ interface AnalyticsExplanationInput {
83
+ explanationId?: string;
84
+ conversationalPreface?: string;
85
+ headline?: string;
86
+ summary?: string;
87
+ evidence?: string[];
88
+ headlineEvidenceIds?: string[];
89
+ summaryEvidenceIds?: string[];
90
+ businessMeaningEvidenceIds?: string[];
91
+ evidenceStatements?: Array<{
92
+ text: string;
93
+ evidenceIds?: string[];
94
+ }>;
95
+ evidenceItems?: AnalyticsExplanationEvidenceItemInput[];
96
+ periods?: AnalyticsExplanationPeriodInput[];
97
+ missing?: AnalyticsExplanationMissingInput[];
98
+ timezone?: string;
99
+ checkedAt?: string;
100
+ currentPeriodInProgress?: boolean;
101
+ cached?: boolean;
102
+ dataFreshness?: AnalyticsExplanationFreshnessInput;
103
+ businessMeaning?: string;
104
+ possibleDrivers?: Array<{
105
+ hypothesis: string;
106
+ howToCheck: string;
107
+ evidenceIds?: string[];
108
+ }>;
109
+ recommendations?: Array<{
110
+ action: string;
111
+ why: string;
112
+ successMetric?: string;
113
+ evidenceIds?: string[];
114
+ }>;
115
+ forecast?: {
116
+ text: string;
117
+ qualityStatus?: string;
118
+ limitations?: string;
119
+ horizon?: string;
120
+ };
121
+ limitations?: string[];
122
+ followUps?: string[];
123
+ source?: string;
124
+ /** "basic" = the free explanation built from the facts; "detailed" = checked AI wording. */
125
+ level?: 'basic' | 'detailed' | string;
126
+ /** The detailed AI explanation that loads separately (poll by explanationId). */
127
+ aiExplanation?: AnalyticsAIExplanationInput | null;
128
+ }
129
+ /** State of the detailed AI explanation, as returned by every surface. */
130
+ type AnalyticsAIExplanationStatus = 'pending' | 'ready' | 'failed' | 'not_requested';
131
+ interface AnalyticsAIExplanationInput {
132
+ status: AnalyticsAIExplanationStatus | string;
133
+ explanationId?: string;
134
+ retryAvailable?: boolean;
135
+ }
136
+ declare const ANALYTICS_EXPLANATION_COPY: {
137
+ readonly eyebrow: "Answer from your data";
138
+ readonly provenanceAI: "AI-assisted · evidence checked";
139
+ readonly provenanceGoverned: "Based on current values";
140
+ readonly comparison: "Comparison";
141
+ readonly conclusions: "What we can conclude";
142
+ readonly whyItMatters: "Why it matters";
143
+ readonly limits: "Important limits";
144
+ readonly investigate: "Investigate further";
145
+ readonly evidenceList: "Evidence checked";
146
+ readonly causes: "Possible causes";
147
+ readonly causesHint: "Not proven causes";
148
+ readonly howToCheck: "How to check:";
149
+ readonly recommendations: "Recommended next steps";
150
+ readonly watch: "Watch:";
151
+ readonly outlook: "Outlook";
152
+ readonly followUps: "Ask a follow-up";
153
+ readonly sourceNoteAI: "AI-assisted wording, checked against the live values shown here.";
154
+ readonly sourceNoteGoverned: "Based only on the live values shown here.";
155
+ readonly evidence: "Evidence";
156
+ readonly evidenceMetric: "Metric";
157
+ readonly evidencePeriod: "Period";
158
+ readonly evidenceTimezone: "Timezone";
159
+ readonly evidenceFilters: "Filters";
160
+ readonly evidenceValue: "Value";
161
+ readonly evidenceStatus: "Status";
162
+ readonly evidenceSource: "Source";
163
+ readonly evidenceChecked: "Checked";
164
+ readonly openSource: "Open source";
165
+ readonly closeEvidence: "Close evidence details";
166
+ readonly citationLabel: "Show evidence";
167
+ readonly sourceCard: "This card";
168
+ readonly sourceSupportingQuery: "Supporting query";
169
+ readonly feedbackPrompt: "Was this explanation helpful?";
170
+ readonly feedbackHelpful: "Helpful explanation";
171
+ readonly feedbackNotHelpful: "Unhelpful explanation";
172
+ readonly feedbackReasonsPrompt: "What went wrong? (optional)";
173
+ readonly feedbackCommentPlaceholder: "Anything else? (optional)";
174
+ readonly feedbackSubmit: "Send feedback";
175
+ readonly feedbackThanks: "Thanks for the feedback.";
176
+ readonly feedbackUndo: "Undo";
177
+ readonly feedbackError: "Feedback could not be saved. Try again.";
178
+ readonly notComparable: "Not comparable yet";
179
+ readonly basicExplanation: "Basic explanation";
180
+ readonly preparingDetailed: "Preparing a detailed explanation…";
181
+ readonly detailedReady: "Detailed explanation ready.";
182
+ readonly detailedUnavailable: "A detailed explanation is not available right now.";
183
+ readonly detailedRetry: "Try again";
184
+ readonly region: "Explanation";
185
+ readonly inProgress: "in progress";
186
+ readonly expand: "Expand explanation";
187
+ readonly collapse: "Collapse explanation";
188
+ readonly reasonWrongNumbers: "Wrong numbers";
189
+ readonly reasonMissingComparison: "Missing comparison";
190
+ readonly reasonUnclear: "Unclear";
191
+ readonly reasonTooLong: "Too long";
192
+ };
193
+ /** The explanation panel's copy with a host's overrides on top. */
194
+ type AnalyticsExplanationCopyOverrides = Partial<{ -readonly [K in keyof typeof ANALYTICS_EXPLANATION_COPY]: string }>;
195
+ type AnalyticsComparisonBasis = 'complete' | 'like_for_like' | 'current_in_progress_no_time' | 'not_comparable';
196
+ interface AnalyticsComparisonPeriod {
197
+ label: string;
198
+ start?: string;
199
+ end?: string;
200
+ fullEnd?: string;
201
+ inProgress?: boolean;
202
+ toDate?: boolean;
203
+ }
204
+ /** Backend `periodComparison` (reader-safe projection). */
205
+ interface AnalyticsPeriodComparison {
206
+ comparisonBasis: AnalyticsComparisonBasis | string;
207
+ reason?: string;
208
+ grain?: string;
209
+ measureField?: string;
210
+ seriesField?: string;
211
+ currentPeriod?: AnalyticsComparisonPeriod;
212
+ previousPeriod?: AnalyticsComparisonPeriod;
213
+ currentValue?: number;
214
+ previousToDateValue?: number;
215
+ previousFullValue?: number;
216
+ cutoffAt?: string;
217
+ cutoffSource?: 'now' | 'data_as_of' | string;
218
+ timezone?: string;
219
+ series?: Array<{
220
+ key: string;
221
+ currentValue?: number;
222
+ previousToDateValue?: number;
223
+ previousFullValue?: number;
224
+ }>;
225
+ }
226
+ interface AnalyticsComparisonDisplay {
227
+ basis: AnalyticsComparisonBasis | string;
228
+ kind: 'change' | 'neutral';
229
+ /** Set only for like-for-like (or complete) changes: red/green allowed. */
230
+ percent?: number;
231
+ tone: 'positive' | 'negative' | 'neutral';
232
+ /** Badge text: "↑ 50.0%", "Up from 0", "Today so far: 6 · Yesterday: 26 (full day)". */
233
+ label: string;
234
+ /** "vs yesterday at this time" / "vs same point last week". */
235
+ copy: string;
236
+ /** "Yesterday full day: 26". */
237
+ secondary?: string;
238
+ /** Compact one-line form for KPI cards: "Full day: 26". */
239
+ compactSecondary?: string;
240
+ /** Hover text with the cutoff time. */
241
+ title?: string;
242
+ reason?: string;
243
+ }
244
+ interface AnalyticsGroupComparisonPoint {
245
+ side: 'current' | 'previous';
246
+ basis: string;
247
+ /** Value to plot: previous-to-date on a like-for-like previous bucket. */
248
+ plotValue?: number;
249
+ /** Previous bucket: the full previous value (tooltip). */
250
+ fullValue?: number;
251
+ /** Previous bucket plotted at the same point (label "Yesterday at this time"). */
252
+ toDate: boolean;
253
+ /** Current bucket: this group's change, following the KPI basis rules. */
254
+ display?: AnalyticsComparisonDisplay;
255
+ }
256
+ /**
257
+ * Poll response for a detailed AI explanation. `explanation` is set only when
258
+ * `status` is "ready" and is the CHECKED explanation (never raw model text).
259
+ */
260
+ interface AnalyticsAIExplanationJob<E extends AnalyticsExplanationInput> {
261
+ status: AnalyticsAIExplanationStatus | string;
262
+ explanationId?: string;
263
+ retryAvailable?: boolean;
264
+ explanation?: E | null;
265
+ /**
266
+ * The free basic explanation as updated by the background job (it gains the
267
+ * baseline sentence, e.g. "within the recent range of 22–28"). Present while
268
+ * the AI explanation is pending or after it failed.
269
+ */
270
+ basic?: E | null;
271
+ }
272
+ interface AnalyticsAIExplanationTransport<E extends AnalyticsExplanationInput> {
273
+ /** GET the job by id with the surface's own credentials. */
274
+ poll: (explanationId: string, signal?: AbortSignal) => Promise<AnalyticsAIExplanationJob<E>>;
275
+ /** "Try again": re-request with the retry flag. Omit when retry is impossible. */
276
+ retry?: (explanationId: string, signal?: AbortSignal) => Promise<AnalyticsAIExplanationJob<E>>;
277
+ /** The job reached a final status: let the surface remember it (status only, not the payload). */
278
+ settled?: (explanationId: string, status: 'ready' | 'failed' | 'not_requested') => void;
279
+ }
280
+ //#endregion
281
+ //#region ../centrinfo-results/src/labels.d.ts
282
+ type AnalyticsExplanationCopy = Required<AnalyticsExplanationCopyOverrides>;
283
+ /** Every string the shared result renderer shows. Hosts override any subset. */
284
+ interface ResultLabels {
285
+ resultDetails: string;
286
+ liveMetric: string;
287
+ currentValue: string;
288
+ noMatchTitle: string;
289
+ noMatchBody: string;
290
+ chartType: string;
291
+ chooseChartType: string;
292
+ aggregate: string;
293
+ aggregateTitle: string;
294
+ aggregateCharge: string;
295
+ chartFallback: string;
296
+ chartLine: string;
297
+ chartBar: string;
298
+ chartStackedBar: string;
299
+ chartLineHint: string;
300
+ chartBarHint: string;
301
+ chartStackedBarHint: string;
302
+ aggregationSum: string;
303
+ aggregationAvg: string;
304
+ aggregationMin: string;
305
+ aggregationMax: string;
306
+ aggregationCount: string;
307
+ aggregationCountDistinct: string;
308
+ download: string;
309
+ downloadData: string;
310
+ expandTable: string;
311
+ expandChart: string;
312
+ restoreView: string;
313
+ aboutResult: string;
314
+ aboutPeriod: string;
315
+ aboutResults: string;
316
+ aboutChecked: string;
317
+ aboutTimezone: string;
318
+ aboutSourceData: string;
319
+ aboutFilters: string;
320
+ /** `{count}` placeholder. */
321
+ rowOne: string;
322
+ rowMany: string;
323
+ filtersOne: string;
324
+ filtersMany: string;
325
+ filtersApplied: string;
326
+ notSet: string;
327
+ noValue: string;
328
+ yes: string;
329
+ no: string;
330
+ chartValues: string;
331
+ /** `{measure}`, `{dimension}`. */
332
+ chartTitle: string;
333
+ seriesLimited: string;
334
+ summaryLatest: string;
335
+ summaryNoTrend: string;
336
+ summaryHighest: string;
337
+ summaryNoComparison: string;
338
+ zoomControls: string;
339
+ zoomIn: string;
340
+ zoomOut: string;
341
+ zoomReset: string;
342
+ zoomResetShort: string;
343
+ zoomNone: string;
344
+ zoomAllOne: string;
345
+ zoomAllMany: string;
346
+ zoomRange: string;
347
+ inProgress: string;
348
+ newContent: string;
349
+ updatedAt: string;
350
+ liveData: string;
351
+ viewData: string;
352
+ hideData: string;
353
+ inProgressLegend: string;
354
+ /** Overrides for the explanation panel copy. */
355
+ explanation?: Partial<AnalyticsExplanationCopy>;
356
+ governedResult: string;
357
+ }
358
+ //#endregion
359
+ //#region src/i18n.d.ts
5
360
  /**
6
361
  * Every user-visible chrome string in one place. The widget ships English
7
362
  * defaults; a host localises by passing `labels` to `Centrinfo.init()` —
@@ -11,6 +366,12 @@ import * as preact0 from "preact";
11
366
  * never produces.
12
367
  */
13
368
  interface WidgetStrings {
369
+ /**
370
+ * Labels for analytics answers (KPI, chart, table, details, explanation).
371
+ * Any subset overrides the English defaults; `explanation` holds the
372
+ * explanation panel's wording.
373
+ */
374
+ analytics?: Partial<ResultLabels>;
14
375
  /** Optional full-page labels. Older integrations use the core labels as fallbacks. */
15
376
  fullPageNewConversation?: string;
16
377
  fullPageHistory?: string;
@@ -101,6 +462,7 @@ interface WidgetStrings {
101
462
  /** Per-message 👍/👎 feedback. */
102
463
  feedbackHelpful: string;
103
464
  feedbackNotHelpful: string;
465
+ feedbackAnswerPrompt: string;
104
466
  feedbackThanks: string;
105
467
  /** End-of-chat CSAT prompt. */
106
468
  csatPrompt: string;
@@ -116,6 +478,8 @@ interface WidgetStrings {
116
478
  emptyReply: string;
117
479
  errorGeneric: string;
118
480
  errorRateLimit: string;
481
+ /** Shown in place of an analytics result that is not kept in local storage. */
482
+ resultExpired: string;
119
483
  attaching: string;
120
484
  attachTooLarge: string;
121
485
  attachFailed: string;
@@ -198,6 +562,7 @@ interface WidgetStrings {
198
562
  bookingLoadingScheduler: string;
199
563
  bookingMeetingLink: string;
200
564
  bookingManageLink: string;
565
+ bookingUnverifiedLink: string;
201
566
  bookingCheckingDetails: string;
202
567
  bookingDetailsUnavailable: string;
203
568
  bookingRetryDetails: string;
@@ -296,6 +661,7 @@ interface AnalyticsVisualizationColumn {
296
661
  dataType: 'text' | 'number' | 'currency' | 'percent' | 'boolean' | 'date' | 'datetime';
297
662
  semanticRole: 'identifier' | 'dimension' | 'measure' | 'date' | 'geography' | 'boolean';
298
663
  aggregation?: 'none' | 'sum' | 'avg' | 'count' | 'count_distinct' | 'min' | 'max';
664
+ allowedAggregations?: Array<'none' | 'sum' | 'avg' | 'count' | 'count_distinct' | 'min' | 'max'>;
299
665
  formatPattern?: string;
300
666
  currencyCode?: string;
301
667
  description?: string;
@@ -313,21 +679,101 @@ interface AnalyticsVisualizationRecommendation {
313
679
  reason?: string;
314
680
  confidence?: number;
315
681
  }
682
+ type AnalyticsValueStatus = 'observed' | 'confirmed_zero' | 'empty_bucket' | 'unconfirmed_zero' | 'missing';
683
+ interface AnalyticsEvidencePeriod {
684
+ label: string;
685
+ start?: string;
686
+ end?: string;
687
+ timezone?: string;
688
+ }
689
+ interface AnalyticsExplanationEvidenceItem {
690
+ id: string;
691
+ text: string;
692
+ kind?: string;
693
+ metric?: string;
694
+ period?: AnalyticsEvidencePeriod;
695
+ filters?: string[];
696
+ value?: number;
697
+ valueStatus: AnalyticsValueStatus | string;
698
+ statusReason?: string;
699
+ source: {
700
+ kind: 'card' | 'supporting_query' | string;
701
+ insightId?: string;
702
+ queryRunId?: string;
703
+ liveboardTileId?: string;
704
+ };
705
+ checkedAt?: string;
706
+ }
707
+ interface AnalyticsExplanationPeriod {
708
+ evidenceId?: string;
709
+ label: string;
710
+ start?: string;
711
+ end?: string;
712
+ timezone?: string;
713
+ current?: boolean;
714
+ inProgress?: boolean;
715
+ value?: number;
716
+ valueText?: string;
717
+ valueStatus: AnalyticsValueStatus | string;
718
+ statusReason?: string;
719
+ source?: 'card' | 'supporting_query' | string;
720
+ }
721
+ interface AnalyticsExplanationMissing {
722
+ evidenceId?: string;
723
+ label: string;
724
+ period?: AnalyticsEvidencePeriod;
725
+ reason: string;
726
+ }
727
+ interface AnalyticsExplanationDataFreshness {
728
+ status: string;
729
+ dataAsOf?: string;
730
+ expectedThrough?: string;
731
+ lagDays?: number;
732
+ checkedAt?: string;
733
+ timezone?: string;
734
+ }
735
+ interface AnalyticsValueProvenance {
736
+ rowIndex: number;
737
+ field: string;
738
+ period?: string;
739
+ filled: 'empty_bucket' | string;
740
+ status: 'empty_bucket' | 'confirmed_zero' | 'unconfirmed_zero' | string;
741
+ reason?: string;
742
+ }
316
743
  interface AnalyticsVisualizationExplanation {
744
+ /** Stable opaque id; used only for "Was this helpful?" feedback. */
745
+ explanationId?: string;
317
746
  conversationalPreface?: string;
318
747
  metricReference?: string;
319
748
  headline: string;
320
749
  summary: string;
321
750
  evidence?: string[];
751
+ headlineEvidenceIds?: string[];
752
+ summaryEvidenceIds?: string[];
753
+ businessMeaningEvidenceIds?: string[];
754
+ evidenceStatements?: Array<{
755
+ text: string;
756
+ evidenceIds?: string[];
757
+ }>;
758
+ evidenceItems?: AnalyticsExplanationEvidenceItem[];
759
+ periods?: AnalyticsExplanationPeriod[];
760
+ missing?: AnalyticsExplanationMissing[];
761
+ timezone?: string;
762
+ checkedAt?: string;
763
+ currentPeriodInProgress?: boolean;
764
+ cached?: boolean;
765
+ dataFreshness?: AnalyticsExplanationDataFreshness;
322
766
  businessMeaning?: string;
323
767
  possibleDrivers?: Array<{
324
768
  hypothesis: string;
325
769
  howToCheck: string;
770
+ evidenceIds?: string[];
326
771
  }>;
327
772
  recommendations?: Array<{
328
773
  action: string;
329
774
  why: string;
330
775
  successMetric?: string;
776
+ evidenceIds?: string[];
331
777
  }>;
332
778
  forecast?: {
333
779
  text: string;
@@ -338,6 +784,12 @@ interface AnalyticsVisualizationExplanation {
338
784
  limitations?: string[];
339
785
  followUps?: string[];
340
786
  source: 'governed_result' | 'ai_grounded' | 'rag_deterministic_analysis' | 'analysis_contract' | string;
787
+ /** The detailed AI explanation that loads separately (poll by explanationId). */
788
+ aiExplanation?: {
789
+ status: string;
790
+ explanationId?: string;
791
+ retryAvailable?: boolean;
792
+ } | null;
341
793
  }
342
794
  interface AnalyticsVisualizationAnalysis {
343
795
  summary: string;
@@ -467,6 +919,7 @@ interface AnalyticsVisualization {
467
919
  tableAvailable?: boolean;
468
920
  downloadAvailable?: boolean;
469
921
  explanation?: AnalyticsVisualizationExplanation;
922
+ valueProvenance?: AnalyticsValueProvenance[];
470
923
  }
471
924
  interface SpeechResult {
472
925
  providerReady: boolean;
@@ -543,6 +996,11 @@ interface StreamCallbacks {
543
996
  interface ActionResult {
544
997
  ok: boolean;
545
998
  note?: string;
999
+ /** Saved conversation message for this completed action. */
1000
+ receipt?: {
1001
+ id: string;
1002
+ content: string;
1003
+ };
546
1004
  /** Present on book-a-demo when a connected scheduler fulfilled it live —
547
1005
  * a real calendar event was created (event mode) or a Calendly link was
548
1006
  * resolved (link mode). Absent when it fell back to a staff-follow-up request. */
@@ -568,6 +1026,11 @@ interface DemoBooking {
568
1026
  endAt?: string;
569
1027
  timezone?: string;
570
1028
  title?: string;
1029
+ /** Returned with hosted booking confirmation for immediate chat display. */
1030
+ receipt?: {
1031
+ id: string;
1032
+ content: string;
1033
+ };
571
1034
  }
572
1035
  interface HostedBookingConfirmation {
573
1036
  sessionId: string;
@@ -587,6 +1050,31 @@ interface FeedbackInput {
587
1050
  question?: string;
588
1051
  answer?: string;
589
1052
  }
1053
+ /** "Was this helpful?" vote on one analytics explanation
1054
+ * (POST /public-chat/explanation-feedback). One vote per visitor session per
1055
+ * explanation; `clear` removes it. Never billed. */
1056
+ interface ExplanationFeedbackInput {
1057
+ sessionId: string;
1058
+ explanationId: string;
1059
+ rating: 'up' | 'down' | 'clear';
1060
+ reasons?: Array<'wrong_numbers' | 'missing_comparison' | 'unclear' | 'too_long'>;
1061
+ comment?: string;
1062
+ modelId?: string;
1063
+ modelVersion?: number;
1064
+ /** Which public surface showed the explanation. */
1065
+ surface?: 'widget' | 'chat_app';
1066
+ }
1067
+ /** Detailed AI explanation job for an analytics answer
1068
+ * (GET /public-chat/analytics-explanations/:id). `explanation` is set only
1069
+ * when ready and is the checked, public-safe explanation. */
1070
+ interface ExplanationJob {
1071
+ status: 'pending' | 'ready' | 'failed' | 'not_requested' | string;
1072
+ explanationId?: string;
1073
+ retryAvailable?: boolean;
1074
+ explanation?: Record<string, unknown> | null;
1075
+ /** The free basic explanation as updated by the job (gains the baseline sentence). */
1076
+ basic?: Record<string, unknown> | null;
1077
+ }
590
1078
  /** A [start, end) window the org's calendar is busy. */
591
1079
  interface BusyRange {
592
1080
  start: string;
@@ -664,6 +1152,13 @@ interface Transport {
664
1152
  /** Record a 👍/👎 on an assistant reply (`POST /public-chat/feedback`).
665
1153
  * Best-effort — a failed rating never disrupts the chat. */
666
1154
  sendFeedback(input: FeedbackInput): Promise<void>;
1155
+ /** Record a vote on an analytics explanation. Rejects on failure so the UI
1156
+ * can offer a retry (unlike `sendFeedback`). Optional for custom transports. */
1157
+ sendExplanationFeedback?(input: ExplanationFeedbackInput): Promise<void>;
1158
+ /** Poll the detailed AI explanation of an analytics answer. Optional. */
1159
+ fetchExplanation?(explanationId: string, sessionId: string, surface?: 'widget' | 'chat_app', signal?: AbortSignal): Promise<ExplanationJob>;
1160
+ /** "Try again" on a failed detailed AI explanation. Optional. */
1161
+ retryExplanation?(explanationId: string, sessionId: string, surface?: 'widget' | 'chat_app'): Promise<ExplanationJob>;
667
1162
  }
668
1163
  //#endregion
669
1164
  //#region src/types.d.ts
@@ -736,6 +1231,11 @@ interface WidgetConfig {
736
1231
  labels?: Partial<WidgetStrings>;
737
1232
  /** Locale used to select a translation bundle. Defaults to browser locale. */
738
1233
  locale?: string;
1234
+ /**
1235
+ * Text direction. `auto` (default) follows the locale: Arabic, Hebrew,
1236
+ * Persian, Urdu and similar scripts render right-to-left.
1237
+ */
1238
+ dir?: 'ltr' | 'rtl' | 'auto';
739
1239
  /**
740
1240
  * Translation data keyed by locale (`fr`, `fr-CA`, `yo`, ...). Exact locale
741
1241
  * wins, then its base language. Explicit `labels` still wins over the pack.
@@ -835,6 +1335,14 @@ interface WidgetConfig {
835
1335
  role: 'user' | 'assistant';
836
1336
  content: string;
837
1337
  }) => void;
1338
+ /** Called only for a server-cited source in a signed analytics answer.
1339
+ * The host should open it through its authorized analytics client. */
1340
+ onOpenAnalyticsSource?: (source: {
1341
+ kind: 'liveboard_tile' | 'insight';
1342
+ id: string;
1343
+ /** Result filters for a host to validate against the destination board. */
1344
+ appliedFilters?: AnalyticsVisualization['appliedFilters'];
1345
+ }) => void;
838
1346
  onAction?: (action: string) => void;
839
1347
  onHandoff?: () => void;
840
1348
  }
@@ -998,6 +1506,10 @@ interface ChatMessage {
998
1506
  feedback?: 'up' | 'down';
999
1507
  visualization?: AnalyticsVisualization;
1000
1508
  artifacts?: ChatArtifact[];
1509
+ /** Set on a restored message whose analytics result was not kept in local storage. */
1510
+ resultExpired?: {
1511
+ title?: string;
1512
+ };
1001
1513
  }
1002
1514
  interface Source {
1003
1515
  title?: string;
@@ -1086,4 +1598,4 @@ interface SchedulerInfo {
1086
1598
  };
1087
1599
  }
1088
1600
  //#endregion
1089
- export { WidgetStrings as C, StringsProvider as S, DemoSlotsResult as _, MessageAttachment as a, PublicChatActionField as b, Visitor as c, WidgetHandle as d, WidgetThemeTokens as f, DemoBooking as g, AnalyticsVisualization as h, FeaturedLink as i, WidgetActionTranslation as l, ActionResult as m, ChatArtifact as n, SchedulerInfo as o, WidgetUser as p, ChatMessage as r, Source as s, BootstrapInfo as t, WidgetConfig as u, GifResult as v, Transport as x, PublicChatAction as y };
1601
+ export { StringsProvider as C, AnalyticsExplanationInput as D, AnalyticsAIExplanationTransport as E, AnalyticsGroupComparisonPoint as O, Transport as S, ResultLabels as T, DemoSlotsResult as _, MessageAttachment as a, PublicChatAction as b, Visitor as c, WidgetHandle as d, WidgetThemeTokens as f, DemoBooking as g, AnalyticsVisualization as h, FeaturedLink as i, AnalyticsPeriodComparison as k, WidgetActionTranslation as l, ActionResult as m, ChatArtifact as n, SchedulerInfo as o, WidgetUser as p, ChatMessage as r, Source as s, BootstrapInfo as t, WidgetConfig as u, ExplanationFeedbackInput as v, WidgetStrings as w, PublicChatActionField as x, GifResult as y };