@sapia-ai/chatbot-v3 1.5.0 → 1.6.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 (44) hide show
  1. package/dist/{EmbeddedVideoPlayer-Dn-boxdp.js → EmbeddedVideoPlayer-Bhz8DKO8.js} +14 -14
  2. package/dist/{Preview-CtMz5fNh.js → Preview-B1ZmYM9V.js} +3 -3
  3. package/dist/api/client.d.ts +8 -1
  4. package/dist/api/types/messages.d.ts +8 -1
  5. package/dist/api/types/responses.d.ts +54 -12
  6. package/dist/api.js +2 -2
  7. package/dist/{client-DfRBtXIE.js → client-C2MWNOYf.js} +552 -545
  8. package/dist/core/bubbles/cards.d.ts +3 -1
  9. package/dist/core/bubbles/demographicRun.d.ts +57 -0
  10. package/dist/core/bubbles/selection.d.ts +3 -1
  11. package/dist/core/bubbles/types.d.ts +11 -0
  12. package/dist/core/interview/engine.d.ts +33 -2
  13. package/dist/core/interview/reveal.d.ts +5 -2
  14. package/dist/core/store.d.ts +10 -2
  15. package/dist/core/theme/branding.d.ts +5 -2
  16. package/dist/{dist-Cl2Oi3Sl.js → dist-CoO0i-y0.js} +3 -3
  17. package/dist/embed/createChatbot.d.ts +0 -2
  18. package/dist/{fix-webm-duration-CVQSf7rp.js → fix-webm-duration-CXijcUXq.js} +2 -2
  19. package/dist/index.js +5987 -5684
  20. package/dist/{jsx-runtime-CdNykazB.js → jsx-runtime-BcXxfixh.js} +2 -2
  21. package/dist/react/SapiaChatbot.d.ts +1 -3
  22. package/dist/react/strings.d.ts +5 -4
  23. package/dist/react/useDemographicForm.d.ts +14 -0
  24. package/dist/{react-BIgNJUOD.js → react-Cp-K_L89.js} +3 -3
  25. package/dist/{react-DlJlpUiG.js → react-D3tMg8u4.js} +3 -3
  26. package/dist/{react-DEJ3NRa3.js → react-D8jZKei2.js} +3 -3
  27. package/dist/{react-BKViU2cv.js → react-DtGzNzM1.js} +3 -3
  28. package/dist/{react-BC7MhdYE.js → react-LDcTld2q.js} +3 -3
  29. package/dist/{react-78ZA32q8.js → react-g5b2mM7w.js} +3 -3
  30. package/dist/{react-BSaO3Elx.js → react-hklchtwF.js} +3 -3
  31. package/dist/{react-eOBKoj54.js → react-vc8uDric.js} +3 -3
  32. package/dist/{react-D4Z0N-x7.js → react-wrZMUHWq.js} +2 -2
  33. package/dist/ui/chat/ActionDock/ActionDock.d.ts +5 -0
  34. package/dist/ui/chat/ChatLog/ChatLog.d.ts +3 -7
  35. package/dist/ui/chat/DemographicDetailsCard/DemographicDetailsCard.d.ts +14 -0
  36. package/dist/ui/chat/TypingIndicator/TypingIndicator.d.ts +9 -25
  37. package/dist/ui/chat/types.d.ts +8 -1
  38. package/dist/ui/inputs/DemographicForm/DemographicForm.d.ts +35 -0
  39. package/dist/ui/inputs/LocationAnswerInput/LocationCombobox.d.ts +4 -2
  40. package/dist/ui/inputs/OptionList/OptionList.d.ts +4 -0
  41. package/dist/ui/inputs/formCard.d.ts +12 -0
  42. package/dist/ui/shell/LogoTile/LogoTile.d.ts +6 -1
  43. package/dist-umd/sapia-chatbot.umd.js +274 -274
  44. package/package.json +1 -1
@@ -8,7 +8,9 @@ export declare enum BubbleCard {
8
8
  PII_FORM_INTRO = "PII_FORM_INTRO",
9
9
  PII_DETAILS = "PII_DETAILS",
10
10
  CUSTOMER_SATISFACTION_FORM = "CUSTOMER_SATISFACTION_FORM",
11
- CUSTOMER_SATISFACTION_INTRO = "CUSTOMER_SATISFACTION_INTRO"
11
+ CUSTOMER_SATISFACTION_INTRO = "CUSTOMER_SATISFACTION_INTRO",
12
+ DEMOGRAPHIC_FORM = "DEMOGRAPHIC_FORM",
13
+ DEMOGRAPHIC_DETAILS = "DEMOGRAPHIC_DETAILS"
12
14
  }
13
15
  /**
14
16
  * The card this content bubble stands for, or undefined for ordinary text. The backend's
@@ -0,0 +1,57 @@
1
+ import { MCQQuestionOption } from '../../api/types/messages';
2
+ import { ChatLog, DemographicFormField } from '../../api/types/responses';
3
+ import { BubbleStatus, MessageBubble } from './types';
4
+ /** Id prefix of the synthetic candidate turn the card is answered in. */
5
+ export declare const DEI_FORM_BUBBLE_ID_PREFIX = "dei-form";
6
+ /** Id prefix of the candidate turn standing in for an answered run. */
7
+ export declare const DEI_DETAILS_BUBBLE_ID_PREFIX = "dei-details";
8
+ /** The option ids ticked on the card, keyed by questionId, before it is posted. */
9
+ export type DemographicAnswers = Record<string, string[]>;
10
+ /**
11
+ * Replace the prompt the diversity run opens on — and the inline option list it would have drawn —
12
+ * with the card's placeholder turn. The run's own prompts are the card's field labels, so none of
13
+ * them reaches the transcript as a message; the template's intro hints above stay as they are and
14
+ * the card reads as the reply to them.
15
+ *
16
+ * Applied on the live stream. A transcript that does not hold the run's opening prompt is returned
17
+ * unchanged, which also makes re-marking after the prompt is gone a no-op.
18
+ *
19
+ * @example
20
+ * ```js
21
+ * // bubbles: [...hints, agent(gender), candidateInline(gender)]; fields start at gender
22
+ * markDemographicFormBubble(bubbles, fields) // [...hints, formBubble(candidate)]
23
+ * ```
24
+ */
25
+ export declare const markDemographicFormBubble: (bubbles: MessageBubble[], fields?: DemographicFormField[]) => MessageBubble[];
26
+ /**
27
+ * The options ticked for each question, in dialogue order. A question with nothing ticked is
28
+ * absent, and an id the question never offered is dropped rather than posted.
29
+ */
30
+ export declare const demographicSelections: (fields: DemographicFormField[], answers: DemographicAnswers) => {
31
+ field: DemographicFormField;
32
+ options: MCQQuestionOption[];
33
+ }[];
34
+ /**
35
+ * Draw the halves of a diversity run the backend folded a reloaded transcript into. The form
36
+ * message becomes the card while the run is still open, and nothing once it has been answered; the
37
+ * responses message becomes the answered card.
38
+ *
39
+ * @returns the bubbles for a folded half, or undefined for any other turn
40
+ * @example
41
+ * ```js
42
+ * // chatLogs: [{formType, fields}, {formType, responses: [{prompt: "Gender", answer: "Woman"}]}]
43
+ * demographicRunBubbles(chatLogs[0], chatLogs[1]) // []
44
+ * demographicRunBubbles(chatLogs[1]) // [answered card: Gender — Woman]
45
+ * ```
46
+ */
47
+ export declare const demographicRunBubbles: (chatLog: ChatLog, nextChatLog?: ChatLog) => MessageBubble[] | undefined;
48
+ /**
49
+ * The diversity run a reloaded transcript is still waiting on, so the engine can redraw the card.
50
+ * A run that has been posted comes back with its responses beside it and needs no card.
51
+ */
52
+ export declare const openDemographicForm: (chatLogs: ChatLog[]) => DemographicFormField[] | undefined;
53
+ /** Swap the card's placeholder turn for the answered card, built from the same answers. */
54
+ export declare const swapFormForDemographicDetails: (bubbles: MessageBubble[], fields: DemographicFormField[], answers: DemographicAnswers, status: BubbleStatus) => {
55
+ bubbles: MessageBubble[];
56
+ detailsBubbleId: string;
57
+ };
@@ -1,4 +1,4 @@
1
- import { QuestionRule } from '../../api/types/messages';
1
+ import { QuestionType, QuestionRule } from '../../api/types/messages';
2
2
  import { MessageBubble } from './types';
3
3
  /** Which instruction a multi-select question shows above its options. */
4
4
  export declare enum SelectionInstruction {
@@ -32,6 +32,8 @@ export declare const usesSelectionAnswer: (bubble: MessageBubble) => boolean;
32
32
  * multi-select path, even though its answer still goes over the wire as a set of one.
33
33
  */
34
34
  export declare const isMultiSelectBubble: (bubble: MessageBubble) => boolean;
35
+ /** @see isMultiSelectBubble — the same rule for a question described outside a bubble. */
36
+ export declare const isMultiSelectQuestion: (types: QuestionType[], rules?: QuestionRule[]) => boolean;
35
37
  /**
36
38
  * Which instruction the question shows. A cap equal to the number of options on offer states
37
39
  * nothing "any number" does not already allow, so it reads as open-ended — the builder never offers
@@ -83,6 +83,15 @@ export type CustomerSatisfactionResponse = {
83
83
  rating?: number;
84
84
  comment?: string;
85
85
  };
86
+ /**
87
+ * One answered diversity question as the answered card draws it: the template's question and what
88
+ * the candidate chose, already joined for display.
89
+ */
90
+ export type DemographicDetailEntry = {
91
+ questionId: string;
92
+ prompt: string;
93
+ answer: string;
94
+ };
86
95
  export type MessageBubbleData = {
87
96
  messageItems: MessageItem[];
88
97
  answer?: AnswerContent | null;
@@ -92,6 +101,8 @@ export type MessageBubbleData = {
92
101
  piiDetails?: PiiDetailEntry[];
93
102
  /** Present only on the bubble standing in for an answered feedback run. */
94
103
  customerSatisfaction?: CustomerSatisfactionResponse;
104
+ /** Present only on the bubble standing in for an answered diversity run. */
105
+ demographicDetails?: DemographicDetailEntry[];
95
106
  };
96
107
  export type MessageBubble = {
97
108
  status: BubbleStatus;
@@ -3,6 +3,7 @@ import { PiiSubmitOutcome } from '../validation/piiAnswer';
3
3
  import { PiiFormAnswer } from '../validation/piiForm';
4
4
  import { LocationAnswer } from '../../api/places';
5
5
  import { CustomerSatisfactionAnswer } from '../bubbles/customerSatisfactionRun';
6
+ import { DemographicAnswers } from '../bubbles/demographicRun';
6
7
  import { ChatbotEventEmitter } from '../events';
7
8
  import { InterviewStore } from '../store';
8
9
  export type InterviewEngineDeps = {
@@ -18,6 +19,12 @@ export type InterviewEngineDeps = {
18
19
  welcomeGate?: boolean;
19
20
  /** Reveal cadence (ms per character) while streaming; 0 reveals each chunk wholesale (reduced-motion). */
20
21
  streamRevealMs?: number;
22
+ /**
23
+ * Stream agent text word by word (true), or have the backend send each message whole and paint
24
+ * it whole (false, the default). Questions are predefined and the same for every candidate, so
25
+ * by default they must not look generated as they arrive.
26
+ */
27
+ streamText?: boolean;
21
28
  };
22
29
  export declare class InterviewEngine {
23
30
  private readonly client;
@@ -29,6 +36,7 @@ export declare class InterviewEngine {
29
36
  private language;
30
37
  private readonly welcomeGate;
31
38
  private readonly streamRevealMs;
39
+ private readonly streamText;
32
40
  /** Aborts the in-flight stream when a new load starts. */
33
41
  private streamAbort?;
34
42
  /** Monotonic counter for unique live-bubble ids (avoids Date.now in core). */
@@ -134,6 +142,12 @@ export declare class InterviewEngine {
134
142
  private submitResolved;
135
143
  /** Submit the name value the candidate confirmed in the extraction modal. */
136
144
  submitNameConfirmed(text: string): Promise<void>;
145
+ /**
146
+ * Keeps the name the candidate just gave so the done screen can greet them without another
147
+ * /start/ats. Shown exactly as typed — a full name is never split. A first name wins: a full
148
+ * name only fills the slot when nothing better is known yet.
149
+ */
150
+ private rememberCandidateName;
137
151
  /**
138
152
  * Submit a location PII answer (legacy handleSelectLocation). The value must be JSON: the backend
139
153
  * parses it before reading `address`/`coordinate`, so a bare address string fails the request.
@@ -173,6 +187,23 @@ export declare class InterviewEngine {
173
187
  * ```
174
188
  */
175
189
  submitCustomerSatisfactionForm(answer: CustomerSatisfactionAnswer): Promise<void>;
190
+ /**
191
+ * Post the diversity card. Answers go in dialogue order because the backend replays them one at a
192
+ * time against the prompt it has open. A multi-select answer travels as its selections whatever
193
+ * its cap, as it does everywhere else. The card is only sendable once every question carries an
194
+ * answer; that is checked again here so a stale click can never post a partial card.
195
+ *
196
+ * The card becomes the answered card before the request goes out; a failed send leaves it FAILED
197
+ * and retryLastAnswer re-posts the same answers.
198
+ *
199
+ * @example
200
+ * ```js
201
+ * // fields: [gender(MCQ), ethnicity(MSQ)]
202
+ * submitDemographicForm({ gender: ['woman'], ethnicity: ['asian', 'pacific'] })
203
+ * // posts [{ text: 'Woman' }, { text: 'Asian | Pacific', selections: [...] }]
204
+ * ```
205
+ */
206
+ submitDemographicForm(answers: DemographicAnswers): Promise<void>;
176
207
  /**
177
208
  * Re-edit a previously answered question (legacy EDIT_MODE_ENTER): mark its
178
209
  * candidate bubble EDITING so the input/options re-appear; the next submit
@@ -270,8 +301,8 @@ export declare class InterviewEngine {
270
301
  private replacePendingBubble;
271
302
  /**
272
303
  * Loads the next message via /next/stream (the sole load path): consumes the
273
- * AG-UI stream, revealing agent text word-by-word into a transient live bubble,
274
- * then swaps it for the authoritative bubble from the terminal RUN_FINISHED
304
+ * AG-UI stream into a transient live bubble (painted whole, or word by word when streamText
305
+ * is on), then swaps it for the authoritative bubble from the terminal RUN_FINISHED
275
306
  * frame. Shares the candidate-settle and agent-append tails with the answer flow.
276
307
  */
277
308
  private loadNext;
@@ -20,9 +20,10 @@ export type StreamPaint = {
20
20
  /**
21
21
  * A run can bundle several messages: each carries its own message id, and a new id means the
22
22
  * previous one is finished and must be frozen as a hint — only the final message is echoed
23
- * authoritatively in RUN_FINISHED. This owns that segmentation and the word-by-word cadence.
23
+ * authoritatively in RUN_FINISHED. This owns that segmentation and how each message is revealed: whole, or word by word.
24
24
  */
25
25
  export declare class StreamAssembler {
26
+ /** Ms per character for the word-by-word reveal; undefined paints each message whole. */
26
27
  private readonly revealMs;
27
28
  private readonly nextSyntheticId;
28
29
  private readonly paint;
@@ -46,7 +47,9 @@ export declare class StreamAssembler {
46
47
  private readonly metaById;
47
48
  private networkDone;
48
49
  private placed;
49
- constructor(revealMs: number, nextSyntheticId: () => string, paint: StreamPaint);
50
+ constructor(
51
+ /** Ms per character for the word-by-word reveal; undefined paints each message whole. */
52
+ revealMs: number | undefined, nextSyntheticId: () => string, paint: StreamPaint);
50
53
  /** Id the live bubble is painted under — the backend's own once a delta has named it. */
51
54
  get liveId(): string;
52
55
  /** Backend message id of the message currently streaming; undefined before the first delta. */
@@ -1,7 +1,7 @@
1
1
  import { StoreApi } from 'zustand/vanilla';
2
2
  import { AssessmentStatus } from '../api/types/messages';
3
3
  import { Branding } from '../api/types/branding';
4
- import { AssessmentSummary, CustomerSatisfactionFormField, PiiFormField, ResolvedFeatureFlags } from '../api/types/responses';
4
+ import { AssessmentSummary, CustomerSatisfactionFormField, DemographicFormField, PiiFormField, ResolvedFeatureFlags } from '../api/types/responses';
5
5
  import { PiiFormAnswer } from './validation/piiForm';
6
6
  import { MessageBubble } from './bubbles/types';
7
7
  export declare enum InterviewPhase {
@@ -62,8 +62,16 @@ export type InterviewState = {
62
62
  * CUSTOMER_SATISFACTION_FORM frame and from /start on reload; cleared once the card is posted.
63
63
  */
64
64
  csatForm?: CustomerSatisfactionFormField[];
65
+ /**
66
+ * The diversity questions the interview is paused on, in dialogue order. Set from the
67
+ * DEMOGRAPHIC_FORM frame and from /start on reload; cleared once the card is posted.
68
+ */
69
+ deiForm?: DemographicFormField[];
65
70
  branding?: Branding;
66
- /** Candidate display name for the welcome/done screens (optional; from /start/ats). */
71
+ /**
72
+ * Name the welcome and done screens greet the candidate by: /start/ats's first name, or the
73
+ * name given in this session's PII step. Absent → generic copy.
74
+ */
67
75
  candidateName?: string;
68
76
  /** Cohort title from /start/ats, shown as the role in the header and welcome. */
69
77
  jobTitle?: string;
@@ -1,6 +1,9 @@
1
1
  import { Branding } from '../../api/types/branding';
2
2
  import { Theme } from './types';
3
- /** Converts the branding payload (theme array + font) into a Theme object. */
4
- export declare const brandingToTheme: (branding?: Branding) => Theme;
3
+ /**
4
+ * Converts the branding payload (theme array + font) into a Theme object. `assessmentId` only
5
+ * identifies the assessment in contrast warnings, since newer BEs no longer send `customerId`.
6
+ */
7
+ export declare const brandingToTheme: (branding?: Branding, assessmentId?: string) => Theme;
5
8
  /** Merge two themes; `override` (host setTheme) wins per field over `base` (branding). */
6
9
  export declare const mergeThemes: (base: Theme | undefined, override: Theme | undefined) => Theme;
@@ -1,5 +1,5 @@
1
- import { B as e } from "./client-DfRBtXIE.js";
2
- import { t } from "./react-D4Z0N-x7.js";
1
+ import { H as e } from "./client-C2MWNOYf.js";
2
+ import { t } from "./react-wrZMUHWq.js";
3
3
  import { t as n } from "./defineProperty-DiFpLzd2.js";
4
4
  import { n as r, t as i } from "./hls-mBncGwsE.js";
5
5
  import { a, i as o, n as s, r as c, t as l } from "./classPrivateFieldSet2-DtQPURVD.js";
@@ -14324,4 +14324,4 @@ var Kw = Object.prototype.hasOwnProperty, qw = (e, t) => {
14324
14324
  //#endregion
14325
14325
  export { Or as MaxResolution, C as MediaError, kr as MinResolution, Ar as RenditionOrder, rT as default, ha as generatePlayerInitTime, nT as playerSoftwareName, tT as playerSoftwareVersion };
14326
14326
 
14327
- //# sourceMappingURL=dist-Cl2Oi3Sl.js.map
14327
+ //# sourceMappingURL=dist-CoO0i-y0.js.map
@@ -19,8 +19,6 @@ export type CreateChatbotOptions = {
19
19
  placesApiKey?: string;
20
20
  /** Custom fetch (e.g. a mocked SSE stream for demos/tests). */
21
21
  fetchImpl?: typeof fetch;
22
- /** @internal Holds the typing indicator's "reading" phrase open (demos/tests). */
23
- readingPhaseMs?: number;
24
22
  };
25
23
  export type Chatbot = {
26
24
  mount: (target?: string | HTMLElement) => void;
@@ -1,4 +1,4 @@
1
- import { R as e } from "./client-DfRBtXIE.js";
1
+ import { B as e } from "./client-C2MWNOYf.js";
2
2
  //#region ../../node_modules/.pnpm/fix-webm-duration@1.0.6/node_modules/fix-webm-duration/fix-webm-duration.js
3
3
  var t = /* @__PURE__ */ e(((e, t) => {
4
4
  (function(e, n) {
@@ -1054,4 +1054,4 @@ var t = /* @__PURE__ */ e(((e, t) => {
1054
1054
  //#endregion
1055
1055
  export default t();
1056
1056
 
1057
- //# sourceMappingURL=fix-webm-duration-CVQSf7rp.js.map
1057
+ //# sourceMappingURL=fix-webm-duration-CXijcUXq.js.map