@sapia-ai/chatbot-v3 1.2.0 → 1.3.1-beta.1.g9504c7e

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 (55) hide show
  1. package/dist/{EmbeddedVideoPlayer-C_8tKis8.js → EmbeddedVideoPlayer-DTzRqNcQ.js} +14 -14
  2. package/dist/{Preview-CbNUoib5.js → Preview-Dd7KyhMk.js} +3 -3
  3. package/dist/api/client.d.ts +10 -6
  4. package/dist/api/places.d.ts +33 -0
  5. package/dist/api/types/messages.d.ts +26 -3
  6. package/dist/api/types/responses.d.ts +19 -17
  7. package/dist/api.js +2 -2
  8. package/dist/core/bubbles/cards.d.ts +14 -0
  9. package/dist/core/bubbles/convert.d.ts +14 -2
  10. package/dist/core/bubbles/counters.d.ts +10 -0
  11. package/dist/core/bubbles/types.d.ts +20 -0
  12. package/dist/core/constants.d.ts +19 -0
  13. package/dist/core/interview.d.ts +30 -7
  14. package/dist/core/persistence.d.ts +3 -0
  15. package/dist/core/store.d.ts +15 -8
  16. package/dist/{dist-7zan-9V3.js → dist-waE-4cub.js} +3 -3
  17. package/dist/embed/createChatbot.d.ts +2 -0
  18. package/dist/{fix-webm-duration-CJ-IsmuV.js → fix-webm-duration-IniZA6tF.js} +2 -2
  19. package/dist/index.js +4866 -4425
  20. package/dist/{jsx-runtime-CpK9sRtl.js → jsx-runtime-DN_m6Qdv.js} +2 -2
  21. package/dist/{messages-t5h3u6nr.js → messages-C00e82NS.js} +43 -38
  22. package/dist/places-CT6PNW7B.js +52 -0
  23. package/dist/react/AnswerInput.d.ts +6 -1
  24. package/dist/react/SapiaChatbot.d.ts +3 -1
  25. package/dist/react/bubbleViewModel.d.ts +13 -6
  26. package/dist/react/strings.d.ts +21 -8
  27. package/dist/react/usePlacesSuggestions.d.ts +16 -0
  28. package/dist/{react-Bx1VLQqP.js → react-A0_ZwPyM.js} +3 -3
  29. package/dist/{react--hlAJW6n.js → react-BDGt_WsZ.js} +3 -3
  30. package/dist/{react-BKQw6USG.js → react-B_YNH2g9.js} +3 -3
  31. package/dist/{react-yXcg2glq.js → react-ByP48xLV.js} +3 -3
  32. package/dist/{react-DFkljL-6.js → react-C9oBRlX8.js} +3 -3
  33. package/dist/{react-Bh9U4IBe.js → react-D5yWOfXN.js} +3 -3
  34. package/dist/{react-BtFG4mMU.js → react-DkQKleWD.js} +2 -2
  35. package/dist/{react-B6p_EGvt.js → react-d-THpGrV.js} +3 -3
  36. package/dist/{react-DJK2_GuR.js → react-euSb4sIX.js} +3 -3
  37. package/dist/ui/chat/ActionDock/ActionDock.d.ts +15 -0
  38. package/dist/ui/chat/ChatBubble/ChatBubble.d.ts +9 -2
  39. package/dist/ui/chat/ChatLog/ChatLog.d.ts +6 -4
  40. package/dist/ui/chat/EditBanner/EditBanner.d.ts +9 -3
  41. package/dist/ui/chat/SummaryCard/SummaryCard.d.ts +18 -23
  42. package/dist/ui/chat/types.d.ts +18 -2
  43. package/dist/ui/inputs/LocationAnswerInput/LocationAnswerInput.d.ts +34 -0
  44. package/dist/ui/inputs/PhoneAnswerInput/PhoneAnswerInput.d.ts +5 -2
  45. package/dist/ui/inputs/TextAnswerInput/TextAnswerInput.d.ts +11 -1
  46. package/dist/ui/primitives/Dialog/Dialog.d.ts +2 -0
  47. package/dist/ui/shell/AgcGuidanceDialog/AgcGuidanceDialog.d.ts +14 -0
  48. package/dist/ui/shell/CopyLinkButton/CopyLinkButton.d.ts +10 -3
  49. package/dist/ui/shell/DoneScreen/DoneScreen.d.ts +1 -5
  50. package/dist/ui/shell/Header/AutoScrollTitle.d.ts +15 -0
  51. package/dist/ui/shell/Header/Header.d.ts +7 -4
  52. package/dist/ui/shell/Header/useAutoScrollTitle.d.ts +16 -0
  53. package/dist/ui/shell/WidgetRoot/themeVariables.d.ts +8 -0
  54. package/dist-umd/sapia-chatbot.umd.js +309 -303
  55. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import { T as e } from "./messages-t5h3u6nr.js";
2
- import { t } from "./react-BtFG4mMU.js";
3
- import { t as n } from "./jsx-runtime-CpK9sRtl.js";
1
+ import { T as e } from "./messages-C00e82NS.js";
2
+ import { t } from "./react-DkQKleWD.js";
3
+ import { t as n } from "./jsx-runtime-DN_m6Qdv.js";
4
4
  import { t as r } from "./defineProperty-DiFpLzd2.js";
5
5
  //#region ../../node_modules/.pnpm/react-player@3.4.0_@svta+cml-cta@1.0.6_@svta+cml-structured-field-values@1.1.3_@svta+cm_a4f64f295cc2a316f39ce360b0a6e480/node_modules/react-player/dist/patterns.js
6
6
  var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx)($|\?)/i, o = /\.(mp4|og[gv]|webm|mov|m4v)(#t=[,\d+]+)?($|\?)/i, s = /\.(m3u8)($|\?)/i, c = /\.(mpd)($|\?)/i, l = /stream\.mux\.com\/(?!\w+\.m3u8)(\w+)/, u = /(?:youtu\.be\/|youtube(?:-nocookie|education)?\.com\/(?:embed\/|v\/|watch\/|watch\?v=|watch\?.+&v=|shorts\/|live\/))((\w|-){11})|youtube\.com\/playlist\?list=|youtube\.com\/user\//, d = /vimeo\.com\/(?!progressive_redirect).+/, f = /(?:wistia\.(?:com|net)|wi\.st)\/(?:medias|embed)\/(?:iframe\/)?([^?]+)/, p = /open\.spotify\.com\/(\w+)\/(\w+)/i, m = /(?:www\.|go\.)?twitch\.tv\/([a-zA-Z0-9_]+|(videos?\/|\?video=)\d+)($|\?)/, h = /tiktok\.com\/(?:player\/v1\/|share\/video\/|@[^/]+\/video\/)([0-9]+)/, g = (e, t) => {
@@ -34,7 +34,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
34
34
  canEnablePIP: () => !0,
35
35
  player: (0, i.lazy)(() => import(
36
36
  /* webpackChunkName: 'reactPlayerHls' */
37
- "./react-Bx1VLQqP.js"
37
+ "./react-A0_ZwPyM.js"
38
38
  ))
39
39
  },
40
40
  {
@@ -44,7 +44,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
44
44
  canEnablePIP: () => !0,
45
45
  player: (0, i.lazy)(() => import(
46
46
  /* webpackChunkName: 'reactPlayerDash' */
47
- "./react-yXcg2glq.js"
47
+ "./react-ByP48xLV.js"
48
48
  ))
49
49
  },
50
50
  {
@@ -54,7 +54,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
54
54
  canEnablePIP: () => !0,
55
55
  player: (0, i.lazy)(() => import(
56
56
  /* webpackChunkName: 'reactPlayerMux' */
57
- "./dist-7zan-9V3.js"
57
+ "./dist-waE-4cub.js"
58
58
  ))
59
59
  },
60
60
  {
@@ -63,7 +63,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
63
63
  canPlay: _.youtube,
64
64
  player: (0, i.lazy)(() => import(
65
65
  /* webpackChunkName: 'reactPlayerYouTube' */
66
- "./react--hlAJW6n.js"
66
+ "./react-BDGt_WsZ.js"
67
67
  ))
68
68
  },
69
69
  {
@@ -72,7 +72,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
72
72
  canPlay: _.vimeo,
73
73
  player: (0, i.lazy)(() => import(
74
74
  /* webpackChunkName: 'reactPlayerVimeo' */
75
- "./react-DFkljL-6.js"
75
+ "./react-C9oBRlX8.js"
76
76
  ))
77
77
  },
78
78
  {
@@ -82,7 +82,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
82
82
  canEnablePIP: () => !0,
83
83
  player: (0, i.lazy)(() => import(
84
84
  /* webpackChunkName: 'reactPlayerWistia' */
85
- "./react-BKQw6USG.js"
85
+ "./react-B_YNH2g9.js"
86
86
  ))
87
87
  },
88
88
  {
@@ -92,7 +92,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
92
92
  canEnablePIP: () => !1,
93
93
  player: (0, i.lazy)(() => import(
94
94
  /* webpackChunkName: 'reactPlayerSpotify' */
95
- "./react-DJK2_GuR.js"
95
+ "./react-euSb4sIX.js"
96
96
  ))
97
97
  },
98
98
  {
@@ -102,7 +102,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
102
102
  canEnablePIP: () => !1,
103
103
  player: (0, i.lazy)(() => import(
104
104
  /* webpackChunkName: 'reactPlayerTwitch' */
105
- "./react-B6p_EGvt.js"
105
+ "./react-d-THpGrV.js"
106
106
  ))
107
107
  },
108
108
  {
@@ -112,7 +112,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
112
112
  canEnablePIP: () => !1,
113
113
  player: (0, i.lazy)(() => import(
114
114
  /* webpackChunkName: 'reactPlayerTiktok' */
115
- "./react-Bh9U4IBe.js"
115
+ "./react-D5yWOfXN.js"
116
116
  ))
117
117
  },
118
118
  {
@@ -181,7 +181,7 @@ var i = /* @__PURE__ */ e(t(), 1), a = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3
181
181
  x.displayName = "Player";
182
182
  var ee = x, S = (0, i.lazy)(() => import(
183
183
  /* webpackChunkName: 'reactPlayerPreview' */
184
- "./Preview-CbNUoib5.js"
184
+ "./Preview-Dd7KyhMk.js"
185
185
  )), C = [], w = (e, t) => {
186
186
  let n = (n) => {
187
187
  for (let t of [...C, ...e]) if (n && t.canPlay(n)) return t;
@@ -1265,4 +1265,4 @@ var $ = n(), xe = (e) => {
1265
1265
  //#endregion
1266
1266
  export { Te as EmbeddedVideoPlayer };
1267
1267
 
1268
- //# sourceMappingURL=EmbeddedVideoPlayer-C_8tKis8.js.map
1268
+ //# sourceMappingURL=EmbeddedVideoPlayer-DTzRqNcQ.js.map
@@ -1,5 +1,5 @@
1
- import { T as e } from "./messages-t5h3u6nr.js";
2
- import { t } from "./react-BtFG4mMU.js";
1
+ import { T as e } from "./messages-C00e82NS.js";
2
+ import { t } from "./react-DkQKleWD.js";
3
3
  //#region ../../node_modules/.pnpm/react-player@3.4.0_@svta+cml-cta@1.0.6_@svta+cml-structured-field-values@1.1.3_@svta+cm_a4f64f295cc2a316f39ce360b0a6e480/node_modules/react-player/dist/Preview.js
4
4
  var n = /* @__PURE__ */ e(t(), 1), r = "64px", i = {}, a = ({ src: e, light: t, oEmbedUrl: a, onClickPreview: o, playIcon: s, previewTabIndex: c, previewAriaLabel: l }) => {
5
5
  let [u, d] = (0, n.useState)(null);
@@ -81,4 +81,4 @@ var n = /* @__PURE__ */ e(t(), 1), r = "64px", i = {}, a = ({ src: e, light: t,
81
81
  //#endregion
82
82
  export { a as default };
83
83
 
84
- //# sourceMappingURL=Preview-CbNUoib5.js.map
84
+ //# sourceMappingURL=Preview-Dd7KyhMk.js.map
@@ -18,10 +18,16 @@ export type NextStreamHandlers = {
18
18
  * bundled message (consecutive hints arrive as separate baseIds in one run).
19
19
  */
20
20
  onDelta: (text: string, messageId: string) => void;
21
- /** Optional leading frame carrying the question structure (types/rules/options) before the text. */
22
- onMeta?: (question: Question) => void;
23
- /** The pre-interview "what to expect" summary, emitted once before any dialogue content. */
21
+ /**
22
+ * Optional leading frame carrying the question structure (types/rules/options) before the text.
23
+ * `messageId` is the baseId the following TEXT_MESSAGE_* frames prefix their ids with, so a
24
+ * caller buffering several bundled messages can pair each one with its own snapshot.
25
+ */
26
+ onMeta?: (question: Question, messageId: string) => void;
27
+ /** "What to expect" counts, emitted at the position of the summary bubble inside a message. */
24
28
  onSummary?: (summary: AssessmentSummary) => void;
29
+ /** The assessment's resume link, emitted at the position of the copy-link bubble. */
30
+ onLink?: (url: string) => void;
25
31
  /** Aborts the in-flight stream (new request / unmount). */
26
32
  signal?: AbortSignal;
27
33
  };
@@ -45,9 +51,7 @@ export declare class ChatbotApiClient {
45
51
  * `type`. Fires onMeta from STATE_SNAPSHOT and onDelta per TEXT_MESSAGE_CONTENT,
46
52
  * then resolves with the authoritative NextResponse carried by RUN_FINISHED.
47
53
  */
48
- nextStream(assessmentId: string, candidateResponse: CandidateResponseInput | undefined, handlers: NextStreamHandlers, options?: {
49
- summaryContinued?: boolean;
50
- }): Promise<NextResponse | undefined>;
54
+ nextStream(assessmentId: string, candidateResponse: CandidateResponseInput | undefined, handlers: NextStreamHandlers): Promise<NextResponse | undefined>;
51
55
  editAnswer(assessmentId: string, editCandidateResponse: EditCandidateResponseInput): Promise<EditAnswerResponse>;
52
56
  extractHumanName(assessmentId: string, input: {
53
57
  userText: string;
@@ -0,0 +1,33 @@
1
+ export type Coordinate = {
2
+ lat: number;
3
+ lng: number;
4
+ };
5
+ /** The answer value the backend parses for a location PII question. */
6
+ export type LocationAnswer = {
7
+ address: string;
8
+ coordinate: Coordinate | null;
9
+ };
10
+ export type PlaceSuggestion = {
11
+ placeId: string;
12
+ /** Full prediction text, used as the accessible option label. */
13
+ description: string;
14
+ mainText: string;
15
+ secondaryText: string;
16
+ };
17
+ export type PlacesRequest = {
18
+ /** Host override; defaults to the key legacy ships. */
19
+ apiKey?: string;
20
+ signal?: AbortSignal;
21
+ /**
22
+ * Injected transport. Unit tests only — nothing in the app passes it, including the demo's
23
+ * offline mock, so a location question in `?stream=mock` makes real Places requests.
24
+ */
25
+ fetchImpl?: typeof fetch;
26
+ };
27
+ /** Address predictions for what the candidate has typed so far. */
28
+ export declare const fetchPlaceSuggestions: (input: string, options?: PlacesRequest) => Promise<PlaceSuggestion[]>;
29
+ /**
30
+ * Resolves a chosen prediction to the answer we store. Falls back to the prediction's own text when
31
+ * the details call returns no formatted address, so a selection never submits an empty address.
32
+ */
33
+ export declare const fetchPlaceAnswer: (suggestion: PlaceSuggestion, options?: PlacesRequest) => Promise<LocationAnswer>;
@@ -18,7 +18,9 @@ export declare enum QuestionType {
18
18
  VIDEO = "VIDEO",
19
19
  SLIDER = "SLIDER",
20
20
  DROPDOWN = "DROPDOWN",
21
- BGQ = "BUTTON_GROUP_QUESTION"
21
+ BGQ = "BUTTON_GROUP_QUESTION",
22
+ /** Text the candidate acknowledges with a single button; carries no assessed answer. */
23
+ BREAK = "BREAK"
22
24
  }
23
25
  export declare enum ContentType {
24
26
  TEXT = "TEXT",
@@ -71,8 +73,16 @@ export declare enum AssessmentStatus {
71
73
  * identifiers pass through untouched.
72
74
  */
73
75
  export declare enum MessageIdentifier {
76
+ SMS_CONSENT_QUESTION = "SMS_CONSENT_QUESTION_MESSAGE",
77
+ SMS_CONSENT_ANSWER = "SMS_CONSENT_ANSWER_MESSAGE",
78
+ TERMS_CONSENT_QUESTION = "TERMS_AND_CONDITIONS_CONSENT_QUESTION_MESSAGE",
79
+ TERMS_CONSENT_ANSWER = "TERMS_AND_CONDITIONS_CONSENT_ANSWER_MESSAGE",
74
80
  SUBMIT_QUESTION = "SUBMIT_QUESTION_MESSAGE",
75
- FEEDBACK_CUSTOMER_SATISFACTION_QUESTION = "FEEDBACK_CUSTOMER_SATISFACTION_QUESTION_MESSAGE"
81
+ SUBMIT_ANSWER = "SUBMIT_ANSWER_MESSAGE",
82
+ RATING_CUSTOMER_SATISFACTION_QUESTION = "RATING_CUSTOMER_SATISFACTION_QUESTION_MESSAGE",
83
+ RATING_CUSTOMER_SATISFACTION_ANSWER = "RATING_CUSTOMER_SATISFACTION_ANSWER_MESSAGE",
84
+ FEEDBACK_CUSTOMER_SATISFACTION_QUESTION = "FEEDBACK_CUSTOMER_SATISFACTION_QUESTION_MESSAGE",
85
+ FEEDBACK_CUSTOMER_SATISFACTION_ANSWER = "FEEDBACK_CUSTOMER_SATISFACTION_ANSWER_MESSAGE"
76
86
  }
77
87
  export type Trigger = {
78
88
  action: string;
@@ -110,7 +120,20 @@ export declare enum ContentComponent {
110
120
  TEXT = "Text",
111
121
  VOICE_PLAYER = "VoicePlayer",
112
122
  VIDEO_PLAYER = "VideoPlayer",
113
- SLIDER = "Slider"
123
+ SLIDER = "Slider",
124
+ /** The bubble is a placeholder for the "what to expect" card, not text. */
125
+ ASSESSMENT_SUMMARY = "AssessmentSummary",
126
+ /** The bubble is a placeholder for the resume-link control, not text. */
127
+ COPY_LINK = "CopyLink"
128
+ }
129
+ /**
130
+ * Whole-bubble values the backend uses to mark a content bubble as a card placeholder. The stream
131
+ * never sends them — it emits an event at that bubble's position instead — so these are only
132
+ * reached on a transcript stored before the backend began annotating `component`.
133
+ */
134
+ export declare enum ContentMarker {
135
+ ASSESSMENT_SUMMARY = "{assessment.summary}",
136
+ ASSESSMENT_LINK = "{assessment.link}"
114
137
  }
115
138
  /** BE message kind: an unanswerable agent aside vs a real question. */
116
139
  export declare enum MessageKind {
@@ -27,11 +27,16 @@ export type StartAtsResponse = {
27
27
  /** Role/position title for the welcome + header (optional; falls back to branding.title). */
28
28
  roleTitle?: string;
29
29
  /**
30
- * Pre-interview "what to expect" summary. Returned here too (not just on the
31
- * stream) so it survives reload — re-hydration goes through /start, which never
32
- * replays the stream. The store captures whichever source arrives first.
30
+ * "What to expect" counts. Returned here too (not just on the stream) so they survive reload —
31
+ * re-hydration goes through /start, which never replays the stream. The store captures whichever
32
+ * source arrives first.
33
33
  */
34
34
  summary?: AssessmentSummary;
35
+ /**
36
+ * The assessment's resume link, for the copy-link bubble on a reloaded transcript (the stream's
37
+ * ASSESSMENT_LINK frame is the live source). Absent until the backend ships the field.
38
+ */
39
+ assessmentLink?: string;
35
40
  };
36
41
  export type NextResponse = {
37
42
  nextResponse: AgentResponse;
@@ -82,6 +87,7 @@ export declare enum AgUiEventType {
82
87
  RUN_STARTED = "RUN_STARTED",
83
88
  STATE_SNAPSHOT = "STATE_SNAPSHOT",
84
89
  ASSESSMENT_SUMMARY = "ASSESSMENT_SUMMARY",
90
+ ASSESSMENT_LINK = "ASSESSMENT_LINK",
85
91
  TEXT_MESSAGE_START = "TEXT_MESSAGE_START",
86
92
  TEXT_MESSAGE_CONTENT = "TEXT_MESSAGE_CONTENT",
87
93
  TEXT_MESSAGE_END = "TEXT_MESSAGE_END",
@@ -89,16 +95,10 @@ export declare enum AgUiEventType {
89
95
  RUN_FINISHED = "RUN_FINISHED",
90
96
  RUN_ERROR = "RUN_ERROR"
91
97
  }
92
- /** Lifecycle of the BE-authored Continue action on the pre-interview summary. */
93
- export declare enum SummaryActionStatus {
94
- /** The BE stopped at the gate and is waiting for the click. */
95
- PENDING = "PENDING",
96
- /** The gate is already past (reload after continuing). */
97
- CLICKED = "CLICKED"
98
- }
99
98
  /**
100
- * Pre-interview "what to expect" summary (AG-UI ASSESSMENT_SUMMARY, emitted once before dialogue).
101
- * The backend sends structured counts only; the frontend owns the category labels/descriptions.
99
+ * "What to expect" counts for the card the client draws inside the introduction break (AG-UI
100
+ * ASSESSMENT_SUMMARY). The backend sends structured counts only; the labels come from the
101
+ * translation file.
102
102
  */
103
103
  export type AssessmentSummary = {
104
104
  title: string;
@@ -108,15 +108,15 @@ export type AssessmentSummary = {
108
108
  type: QuestionType;
109
109
  count: number;
110
110
  }[];
111
- /** BE-authored Continue action; status PENDING gates the dialogue, CLICKED is past the gate. */
112
- continueAction: {
113
- label: string;
114
- status: SummaryActionStatus;
115
- };
116
111
  };
117
112
  /** STATE_SNAPSHOT.snapshot.question — same data as our Question, but `types` is `questionTypes`. */
118
113
  export type SnapshotQuestion = {
119
114
  _id: string;
115
+ /**
116
+ * Id of the chat-log message this question belongs to — the baseId the TEXT_MESSAGE_* frames
117
+ * prefix their own ids with. Distinct from `_id`, which identifies the question itself.
118
+ */
119
+ messageId?: string;
120
120
  masterId?: string;
121
121
  /** Bubble template: Hint (agent context, unanswerable) vs Question. */
122
122
  kind?: MessageKind;
@@ -140,6 +140,8 @@ export type AgUiFrame = {
140
140
  };
141
141
  /** ASSESSMENT_SUMMARY payload (present only on that frame). */
142
142
  summary?: AssessmentSummary;
143
+ /** ASSESSMENT_LINK payload — the assessment's resume link (present only on that frame). */
144
+ url?: string;
143
145
  /** TEXT_MESSAGE_* message id, shape "<baseId>:<contentIndex>"; segments bundled messages. */
144
146
  messageId?: string;
145
147
  delta?: string;
package/dist/api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { S as e, _ as t, a as n, b as r, c as i, d as a, f as o, g as s, h as c, i as l, l as u, m as d, n as f, o as p, p as m, r as h, s as g, t as _, u as v, v as y, x as b, y as x } from "./messages-t5h3u6nr.js";
2
- export { s as API_ORIGIN_BY_ENV, d as AgUiEventType, _ as AssessmentStatus, f as ButtonType, t as CHATBOT_API_PATH, m as ChatbotApiClient, h as ContentComponent, l as ContentType, y as DEFAULT_LOCAL_API_ORIGIN, x as ENVIRONMENTS, n as MessageIdentifier, p as MessageKind, g as MessageSender, i as PHService, u as PiiQuestionType, v as QuestionType, r as REGIONS, a as RuleName, c as SummaryActionStatus, o as VideoQuestionType, b as buildChatbotBaseUrl, e as resolveApiOrigin };
1
+ import { S as e, _ as t, a as n, b as r, c as i, d as a, f as o, g as s, h as c, i as l, l as u, m as d, n as f, o as p, p as m, r as h, s as g, t as _, u as v, v as y, x as b, y as x } from "./messages-C00e82NS.js";
2
+ export { s as API_ORIGIN_BY_ENV, c as AgUiEventType, _ as AssessmentStatus, f as ButtonType, t as CHATBOT_API_PATH, d as ChatbotApiClient, h as ContentComponent, l as ContentMarker, n as ContentType, y as DEFAULT_LOCAL_API_ORIGIN, x as ENVIRONMENTS, p as MessageIdentifier, g as MessageKind, i as MessageSender, u as PHService, v as PiiQuestionType, a as QuestionType, r as REGIONS, o as RuleName, m as VideoQuestionType, b as buildChatbotBaseUrl, e as resolveApiOrigin };
@@ -0,0 +1,14 @@
1
+ import { MessageItem } from './types';
2
+ /** A card a marker content bubble is drawn as, in place of its text. */
3
+ export declare enum BubbleCard {
4
+ ASSESSMENT_SUMMARY = "ASSESSMENT_SUMMARY",
5
+ COPY_LINK = "COPY_LINK"
6
+ }
7
+ /**
8
+ * The card this content bubble stands for, or undefined for ordinary text. The backend's
9
+ * `component` is authoritative; the raw value is matched as a fallback so a transcript stored
10
+ * before the backend annotated components still draws the card instead of printing the marker.
11
+ * Matched on the whole trimmed value — a marker embedded mid-sentence stays text, which is the
12
+ * rule the backend applies too.
13
+ */
14
+ export declare const resolveBubbleCard: (item: MessageItem) => BubbleCard | undefined;
@@ -1,5 +1,5 @@
1
- import { PiiQuestionType, VideoQuestionType, AgentResponse, CandidateResponse, Tag } from '../../api/types/messages';
2
- import { MessageBubble } from './types';
1
+ import { MessageIdentifier, PiiQuestionType, VideoQuestionType, AgentResponse, CandidateResponse, Question, Tag } from '../../api/types/messages';
2
+ import { QuestionRole, MessageBubble } from './types';
3
3
  export declare const piiQuestionTypeFromQuestionTags: (tags?: Tag[]) => PiiQuestionType | undefined;
4
4
  export declare const videoQuestionTypeFromQuestionTags: (tags?: Tag[]) => VideoQuestionType | undefined;
5
5
  /**
@@ -12,6 +12,18 @@ export declare const questionTagsAllowPaste: (tags?: Tag[]) => boolean;
12
12
  * than a dedicated message identifier, and the tag rides along on the answer bubble too.
13
13
  */
14
14
  export declare const questionTagsAreSmsConsent: (tags?: Tag[]) => boolean;
15
+ /**
16
+ * Classifies a question turn, mirroring the BE's checkIfNormalQuestion: an unanswerable turn is
17
+ * settled first, then a break, then `messageIdentifier` — the BE's own answer — and only then the raw signals
18
+ * the BE itself keys off (masterId, PH_BUTTON_TYPE tag, option triggers, usageWhitelist). The
19
+ * raw fallback exists because the streamed STATE_SNAPSHOT carries no identifier; without it a
20
+ * consent prompt would take an ordinal while it streams and lose it on settle.
21
+ *
22
+ * Submit and feedback are resolved before the consent gates, so a button carrying both markings
23
+ * can never come out as a counted question. SMS consent is resolved before terms consent because
24
+ * both ride the same tag name.
25
+ */
26
+ export declare const resolveQuestionRole: (question?: Question, messageIdentifier?: MessageIdentifier | string) => QuestionRole;
15
27
  export declare const convertRawCandidateResponseToMessageBubble: (response: CandidateResponse) => MessageBubble;
16
28
  export declare const convertRawAgentResponseToMessageBubble: (response: AgentResponse, hasNext?: boolean) => MessageBubble;
17
29
  export declare const convertRawResponseToMessageBubble: (response: CandidateResponse | AgentResponse, hasNext?: boolean) => MessageBubble | undefined;
@@ -0,0 +1,10 @@
1
+ import { MessageBubble } from './types';
2
+ /** A turn that counts as an interview question — see QuestionRole. */
3
+ export declare const isNormalQuestionBubble: (bubble: MessageBubble) => boolean;
4
+ /**
5
+ * 1-based ordinal for each normal agent question turn, keyed by bubble id. Bubbles absent from
6
+ * the map take no "Question n of N" eyebrow.
7
+ */
8
+ export declare const normalQuestionOrdinals: (bubbles: MessageBubble[]) => Map<string, number>;
9
+ /** Normal questions the candidate has answered — the progress bar's value. */
10
+ export declare const normalAnswerCount: (bubbles: MessageBubble[]) => number;
@@ -1,4 +1,22 @@
1
1
  import { AnswerContent, ContentComponent, ContentType, MessageKind, MessageIdentifier, MessageSender, PHService, PiiQuestionType, QuestionRule, QuestionType, Style, Tag, Trigger, VideoQuestionType } from '../../api/types/messages';
2
+ /**
3
+ * What a question turn is for. Only NORMAL turns are interview questions: they are the ones the
4
+ * BE counts in `numOfNormalQuestion`, so they are the only ones that may take an ordinal in
5
+ * "Question n of N" or move the progress bar. Every other role is scaffolding around the
6
+ * interview (an aside, an identity field, a consent gate, the submit button, post-submit
7
+ * feedback). Resolved once at conversion — see `resolveQuestionRole`.
8
+ */
9
+ export declare enum QuestionRole {
10
+ NORMAL = "NORMAL",
11
+ HINT = "HINT",
12
+ PII = "PII",
13
+ TERMS_CONSENT = "TERMS_CONSENT",
14
+ SMS_CONSENT = "SMS_CONSENT",
15
+ SUBMIT = "SUBMIT",
16
+ CUSTOMER_SATISFACTION = "CUSTOMER_SATISFACTION",
17
+ /** An acknowledgement step in the introduction — blocking, but never a counted question. */
18
+ BREAK = "BREAK"
19
+ }
2
20
  export declare enum BubbleStatus {
3
21
  ANSWERED = "ANSWERED",
4
22
  ANSWERING = "ANSWERING",
@@ -41,6 +59,8 @@ export type MessageBubble = {
41
59
  masterId?: string;
42
60
  /** BE-provided message kind; falls back to `types` when absent. */
43
61
  messageKind?: MessageKind;
62
+ /** What this turn is for; only NORMAL turns are counted questions. */
63
+ questionRole: QuestionRole;
44
64
  piiQuestionType?: PiiQuestionType;
45
65
  videoQuestionType?: VideoQuestionType;
46
66
  /** Video answer in flight: upload progress 0–1 (PENDING video bubbles). */
@@ -12,6 +12,25 @@ export declare const QUESTION_TAG_PH_BUTTON_TYPE = "PH_BUTTON_TYPE";
12
12
  export declare const QUESTION_TAG_ALLOW_PASTE = "ALLOW_PASTE";
13
13
  /** PH_BUTTON_TYPE value marking the SMS-consent prompt and its answer. */
14
14
  export declare const QUESTION_TAG_VALUE_SMS_CONSENT = "ph_sms_consent";
15
+ /** PH_BUTTON_TYPE value marking the terms-and-conditions consent prompt and its answer. */
16
+ export declare const QUESTION_TAG_VALUE_TERMS_CONSENT = "ph_i_accept";
17
+ /** masterId the BE gives the terms-and-conditions consent prompt. */
18
+ export declare const QUESTION_MASTER_ID_TERMS_CONSENT = "ph_i_accept";
19
+ /** masterId the BE gives the final submit button. */
20
+ export declare const QUESTION_MASTER_ID_SUBMIT = "ph_submit_assessment";
21
+ /**
22
+ * Bubble id the BE gives the "you already started this assessment" notice. Its link must carry the
23
+ * candidate off to the assessment already in progress, so it is the one agent link that stays in
24
+ * the current tab — a new tab would leave them sitting in this dead duplicate.
25
+ */
26
+ export declare const DUPLICATED_ASSESSMENT_LINK_BUBBLE_ID = "410270a8-73c9-51b8-b6ae-a6effc5e6cda";
27
+ /** BGQ option trigger actions the BE reads as "this is the consent / submit button". */
28
+ export declare const TRIGGER_ACTION_CONSENT = "continue_assessment_with_consent";
29
+ export declare const TRIGGER_ACTION_SUBMIT = "submit_assessment";
30
+ /** Trigger on a break's single button; the click only advances the dialogue. */
31
+ export declare const TRIGGER_ACTION_BREAK = "continue_dialogue";
32
+ /** Fixed answer value a break acknowledgement stores — nothing reads it back. */
33
+ export declare const ANSWER_VALUE_BREAK_CONTINUE = "ph_continue_dialogue";
15
34
  /** Tag values are wire strings, not booleans; only the exact string counts as opt-in. */
16
35
  export declare const QUESTION_TAG_VALUE_TRUE = "true";
17
36
  /**
@@ -1,5 +1,6 @@
1
1
  import { ChatbotApiClient } from '../api/client';
2
2
  import { PiiErrorKey } from './validation/pii';
3
+ import { LocationAnswer } from '../api/places';
3
4
  import { ChatbotEventEmitter } from './events';
4
5
  import { InterviewStore } from './store';
5
6
  export declare const ERROR_TYPE_START_FAILED = "FI_START_ASSESSMENT_FAILED";
@@ -64,6 +65,8 @@ export declare class InterviewEngine {
64
65
  private lastVideoAnswer?;
65
66
  /** Option id held back pending the AGC warning resolution. */
66
67
  private pendingAgcOptionId?;
68
+ /** Once-per-session latch for the AI-use guidance; the persisted flag covers reloads. */
69
+ private agcGuidanceTriggered;
67
70
  constructor(deps: InterviewEngineDeps);
68
71
  /** Fetch the translation file; on failure the bundled fallback is used. */
69
72
  private loadTranslations;
@@ -83,8 +86,6 @@ export declare class InterviewEngine {
83
86
  * the agent's opening message(s). No-op unless we're holding at the gate.
84
87
  */
85
88
  confirmWelcome(): Promise<void>;
86
- /** Candidate clicked Continue on the summary gate — re-call next/stream to stream the dialogue. */
87
- continueFromSummary(): Promise<void>;
88
89
  /**
89
90
  * Ported from legacy firstLoadMessageBasedOnChatLogs: empty history → fetch the
90
91
  * first message; history ending in a HINT (either the agent's question or the
@@ -114,11 +115,12 @@ export declare class InterviewEngine {
114
115
  submitNameAnswer(text: string): Promise<PiiSubmitOutcome>;
115
116
  /** Submit the name value the candidate confirmed in the extraction modal. */
116
117
  submitNameConfirmed(text: string): Promise<void>;
117
- /** Submit a location PII answer (address text + serialized place; legacy handleSelectLocation). */
118
- submitLocationAnswer(location: {
119
- address: string;
120
- [key: string]: unknown;
121
- }): Promise<void>;
118
+ /**
119
+ * Submit a location PII answer (legacy handleSelectLocation). The value must be JSON: the backend
120
+ * parses it before reading `address`/`coordinate`, so a bare address string fails the request.
121
+ * A null coordinate is accepted — it stores the answer without a mappable location.
122
+ */
123
+ submitLocationAnswer(location: LocationAnswer): Promise<void>;
122
124
  /**
123
125
  * Re-edit a previously answered question (legacy EDIT_MODE_ENTER): mark its
124
126
  * candidate bubble EDITING so the input/options re-appear; the next submit
@@ -148,6 +150,12 @@ export declare class InterviewEngine {
148
150
  private editExistingAnswer;
149
151
  /** Question being answered: the one under edit if editing, else the last agent bubble. */
150
152
  private currentEditableQuestionId;
153
+ /**
154
+ * PII subtype of the question the composer targets. Must follow the edit like
155
+ * currentEditableQuestionId does: re-editing an earlier name answer while the interview
156
+ * has moved on would otherwise validate against a later, non-PII question and reject
157
+ * every input.
158
+ */
151
159
  private currentPiiType;
152
160
  /**
153
161
  * Submit the selected option (MCQ/DROPDOWN/BGQ, incl. the terms-accept MCQ) of the
@@ -165,6 +173,14 @@ export declare class InterviewEngine {
165
173
  continueAfterAgcWarning(): Promise<void>;
166
174
  /** Dismiss the AGC warning to edit the answer (legacy "Edit"). */
167
175
  dismissAgcWarning(): void;
176
+ /**
177
+ * Proactive AI-use guidance, shown once per assessment when the candidate reaches their
178
+ * first free-text interview question. Re-editing an earlier answer never triggers it —
179
+ * the candidate has already been told (legacy useAgcGuidance).
180
+ */
181
+ private maybeShowAgcGuidance;
182
+ /** Candidate acknowledged the guidance; persist before a reload can lose it. */
183
+ acknowledgeAgcGuidance(): void;
168
184
  /** Dismiss the edit-failure dialog; the composer reopens on the edit, so send retries it. */
169
185
  dismissEditFailure(): void;
170
186
  /** Emits the legacy INVALID_PASTE_ANSWER_ACTION log; fires only once a paste has been refused. */
@@ -178,6 +194,13 @@ export declare class InterviewEngine {
178
194
  private currentQuestionId;
179
195
  /** The synthetic candidate bubble holding the question's selectable options. */
180
196
  private inlineCandidateBubble;
197
+ /**
198
+ * The role of the question this answer belongs to, read off its agent bubble. Locally-built
199
+ * answer bubbles must carry it: an optimistic bubble that settles without a server echo keeps
200
+ * the role assigned here, and a PII or consent answer wrongly marked NORMAL would move the
201
+ * progress bar.
202
+ */
203
+ private questionRoleFor;
181
204
  private appendOptimisticCandidateBubble;
182
205
  private setPendingBubbleStatus;
183
206
  /** Swap the in-flight bubble for the server-confirmed candidate response. */
@@ -5,3 +5,6 @@ export declare const saveVerifiedEmail: (assessmentId: string, candidateEmail: s
5
5
  /** Whether the candidate opted out of the below-minimum word-count warning for this assessment. */
6
6
  export declare const getSkipShortAnswerWarning: (assessmentId: string) => boolean;
7
7
  export declare const setSkipShortAnswerWarning: (assessmentId: string, skip: boolean) => void;
8
+ /** Whether this assessment's proactive AI-use guidance has already been acknowledged. */
9
+ export declare const getAgcGuidanceShown: (assessmentId: string) => boolean;
10
+ export declare const setAgcGuidanceShown: (assessmentId: string) => void;
@@ -34,15 +34,14 @@ export type InterviewState = {
34
34
  sendingAnswer: boolean;
35
35
  numOfNormalQuestion: number;
36
36
  numOfNormalAnswer: number;
37
- /** Pre-interview "what to expect" summary from the stream; rendered up front once it arrives. */
37
+ /** "What to expect" counts, drawn by the summary bubble inside the introduction break. */
38
38
  assessmentSummary?: AssessmentSummary;
39
- /** True while the fresh-start summary gate is loading (before it resolves) — renders the
40
- * summary card's dots as the sole loader and suppresses the generic typing bubble. */
41
- loadingSummaryGate?: boolean;
42
- /** True while the BE has stopped at the pre-interview summary gate, awaiting a Continue click. */
43
- awaitingSummaryContinue?: boolean;
44
- /** True once the summary is settled (past the gate / reload) — renders as a static pinned header. */
45
- summaryPinned?: boolean;
39
+ /**
40
+ * Resume link for the copy-link bubble. From /start on reload and from the ASSESSMENT_LINK frame
41
+ * while streaming; the widget can be embedded on a host page, so the current URL is only a last
42
+ * resort.
43
+ */
44
+ assessmentLink?: string;
46
45
  branding?: Branding;
47
46
  /** Candidate display name for the welcome/done screens (optional; from /start/ats). */
48
47
  candidateName?: string;
@@ -63,8 +62,16 @@ export type InterviewState = {
63
62
  allowNextAgcDetection?: boolean;
64
63
  /** Terms accepted for this assessment; locks PII and SMS-consent answers against re-editing. */
65
64
  termsAccepted?: boolean;
65
+ /**
66
+ * The BE reported this assessment a duplicate of one already in progress. Latched: the status
67
+ * can be set on the response carrying the notice and gone from the empty one that follows. Holds
68
+ * back the completion screen and freezes every answer — nothing written here can be assessed.
69
+ */
70
+ duplicated?: boolean;
66
71
  /** Show the AGC warning modal (automated content suspected on submit). */
67
72
  showAgcWarning?: boolean;
73
+ /** Show the one-time proactive AI-use guidance modal, before the first free-text answer. */
74
+ showAgcGuidance?: boolean;
68
75
  /** Question whose edited answer failed to save; drives the retry dialog. */
69
76
  editFailedQuestionId?: string;
70
77
  /** Interview language (resolved); drives translations + text direction. */
@@ -1,5 +1,5 @@
1
- import { T as e } from "./messages-t5h3u6nr.js";
2
- import { t } from "./react-BtFG4mMU.js";
1
+ import { T as e } from "./messages-C00e82NS.js";
2
+ import { t } from "./react-DkQKleWD.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-7zan-9V3.js.map
14327
+ //# sourceMappingURL=dist-waE-4cub.js.map
@@ -15,6 +15,8 @@ export type CreateChatbotOptions = {
15
15
  language?: string;
16
16
  /** Absolute http(s) URL offered as a "continue" CTA once the interview ends. */
17
17
  redirectUrl?: string;
18
+ /** Host's own Google Places key for the location question; defaults to the bundled key. */
19
+ placesApiKey?: string;
18
20
  /** Custom fetch (e.g. a mocked SSE stream for demos/tests). */
19
21
  fetchImpl?: typeof fetch;
20
22
  };
@@ -1,4 +1,4 @@
1
- import { C as e } from "./messages-t5h3u6nr.js";
1
+ import { C as e } from "./messages-C00e82NS.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-CJ-IsmuV.js.map
1057
+ //# sourceMappingURL=fix-webm-duration-IniZA6tF.js.map