@accurix/centrinfo-widget 2.0.0 → 5.0.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.
package/dist/runtime.cjs CHANGED
@@ -1 +1,2 @@
1
- const e=require(`./config-DsNMbdKp.cjs`),t=t=>t.demo?new e.S:t.preview?new e.x(new e.C(t.apiBaseUrl,t.token,t.gifApiKey,t.analyticsContextToken,{agentName:t.agentName,agentAvatarUrl:t.agentAvatarUrl},t.identityToken,t.getIdentityToken,t.chatSurface),t.strings):new e.C(t.apiBaseUrl,t.token,t.gifApiKey,t.analyticsContextToken,{agentName:t.agentName,agentAvatarUrl:t.agentAvatarUrl},t.identityToken,t.getIdentityToken,t.chatSurface);exports.ResultTable=e.m,exports.WidgetAnalyticsChart=e._,exports.buildWidgetAnalyticsChartModel=e.v,exports.createChatTransport=t,exports.createPreferredAudioRecorder=e.u,exports.createVoiceAudioConstraints=e.d,exports.formatResultCell=e.h,exports.renderRich=e.a,exports.resolveConfig=e.t,exports.serializeResultCsv=e.g,exports.stopRecorderWithFlush=e.f,exports.useChat=e.n;
1
+ const e=require(`./styles-BgWsSZsR.cjs`),t=(e,n)=>{let r=e.replace(/\/\*[\s\S]*?\*\//g,``),i=e=>n.some(t=>e.includes(t)),a=[],o=0;for(;o<r.length;){let e=r.indexOf(`{`,o);if(e<0)break;let s=r.slice(o,e).trim(),c=1,l=e+1;for(;l<r.length&&c>0;)r[l]===`{`?c++:r[l]===`}`&&c--,l++;let u=r.slice(e+1,l-1);if(s.startsWith(`@`))if(/^@(media|supports|container)\b/.test(s)){let e=t(u,n);e&&a.push(`${s} {\n${e}\n}`)}else /^@keyframes\b/.test(s)&&i(s)&&a.push(`${s} {${u}}`);else i(s)&&a.push(`${s} {${u}}`);o=l}return a.join(`
2
+ `)},n=t(e.t,[`.cf-action`,`.cf-form`,`.cf-booking`]),r=t=>t.demo?new e.Y:t.preview?new e.J(new e.X(t.apiBaseUrl,t.token,t.gifApiKey,t.analyticsContextToken,{agentName:t.agentName,agentAvatarUrl:t.agentAvatarUrl},t.identityToken,t.getIdentityToken,t.chatSurface),t.strings):new e.X(t.apiBaseUrl,t.token,t.gifApiKey,t.analyticsContextToken,{agentName:t.agentName,agentAvatarUrl:t.agentAvatarUrl},t.identityToken,t.getIdentityToken,t.chatSurface);exports.ActionsArea=e._,exports.ResultTable=e.U,exports.StringsProvider=e.L,exports.WIDGET_ACTION_STYLES=n,exports.WidgetAnalyticsChart=e.K,exports.buildWidgetAnalyticsChartModel=e.q,exports.createAdaptiveVoiceActivityDetector=e.o,exports.createChatTransport=r,exports.createPreferredAudioRecorder=e.s,exports.createVoiceAudioConstraints=e.c,exports.findLiveSupportAction=e.r,exports.formatResultCell=e.W,exports.looksLikeEcho=e.f,exports.reconnectableHandbackId=e.i,exports.renderRich=e.E,exports.resolveConfig=e.n,exports.selectStyleRules=t,exports.serializeResultCsv=e.G,exports.stopRecorderWithFlush=e.l,exports.usableTranscript=e.g,exports.useChat=e.a;
@@ -1,4 +1,4 @@
1
- import { _ as PublicChatActionField, a as Source, c as WidgetConfig, d as WidgetUser, f as ActionResult, g as PublicChatAction, h as GifResult, i as FeaturedLink, m as DemoSlotsResult, n as ChatArtifact, o as Visitor, p as AnalyticsVisualization, r as ChatMessage, s as WidgetActionTranslation, t as BootstrapInfo, u as WidgetThemeTokens, v as Transport, y as WidgetStrings } from "./types-B0r4SXaT.cjs";
1
+ import { C as WidgetStrings, S as StringsProvider, _ as DemoSlotsResult, a as MessageAttachment, b as PublicChatActionField, c as Visitor, f as WidgetThemeTokens, g as DemoBooking, h as AnalyticsVisualization, i as FeaturedLink, l as WidgetActionTranslation, m as ActionResult, n as ChatArtifact, o as SchedulerInfo, p as WidgetUser, r as ChatMessage, s as Source, t as BootstrapInfo, u as WidgetConfig, v as GifResult, x as Transport, y as PublicChatAction } from "./types-BGKFxmKB.cjs";
2
2
  import * as preact0 from "preact";
3
3
  import { JSX } from "preact";
4
4
 
@@ -156,23 +156,6 @@ declare const ResultTable: ({
156
156
  //#region src/rich.d.ts
157
157
  declare const renderRich: (text: string) => JSX.Element[];
158
158
  //#endregion
159
- //#region src/audio.d.ts
160
- interface VoiceAudioCapabilities {
161
- echoCancellation?: boolean;
162
- noiseSuppression?: boolean;
163
- autoGainControl?: boolean;
164
- channelCount?: boolean;
165
- voiceIsolation?: boolean;
166
- }
167
- /**
168
- * Build a best-effort microphone profile for conversational speech. Every
169
- * enhancement is capability-driven and optional, so unsupported processing
170
- * cannot make microphone permission fail.
171
- */
172
- declare const createVoiceAudioConstraints: (deviceId?: string, supported?: VoiceAudioCapabilities) => MediaTrackConstraints;
173
- declare const createPreferredAudioRecorder: (stream: MediaStream) => MediaRecorder;
174
- declare const stopRecorderWithFlush: (recorder: MediaRecorder | null | undefined) => void;
175
- //#endregion
176
159
  //#region src/useChat.d.ts
177
160
  /** One past conversation, for the in-widget history list. */
178
161
  interface HistoryEntry {
@@ -183,7 +166,18 @@ interface HistoryEntry {
183
166
  title: string;
184
167
  ended: boolean;
185
168
  }
169
+ /** The catalogue action that brings a teammate into the chat, when usable.
170
+ * A backend older than the liveHandoff flag is recognised by its fixed id. */
171
+ declare const findLiveSupportAction: (actions: PublicChatAction[] | undefined) => PublicChatAction | undefined;
172
+ /** The ai_handback notice that may still offer to reconnect: the latest one,
173
+ * while the AI has the chat and the visitor has not already asked again. */
174
+ declare const reconnectableHandbackId: (messages: ChatMessage[], liveMode: "ai" | "queued" | "human") => string | undefined;
186
175
  /** Optional extras when sending — an inline image (GIF) or an extracted file. */
176
+ interface VoiceReply {
177
+ status: 'idle' | 'answering' | 'speaking' | 'done' | 'failed';
178
+ /** The assistant message answering the voice turn. */
179
+ agentId?: string;
180
+ }
187
181
  interface SendOpts {
188
182
  imageUrl?: string;
189
183
  /** Voice-call turns should speak the assistant reply using provider TTS when configured. */
@@ -194,6 +188,19 @@ interface SendOpts {
194
188
  attachmentName?: string;
195
189
  /** Text extracted from the attachment, folded into the backend question. */
196
190
  attachmentText?: string;
191
+ attachmentId?: string;
192
+ /** The attached file itself, kept in memory so it can be previewed. */
193
+ attachmentFile?: Blob;
194
+ /** Several files sent with the message (replaces the single fields). */
195
+ attachments?: OutgoingAttachment[];
196
+ }
197
+ interface OutgoingAttachment {
198
+ id?: string;
199
+ name: string;
200
+ /** Text extracted from the file, folded into the backend question. */
201
+ text?: string;
202
+ /** Kept in memory so it can be previewed. */
203
+ file?: Blob;
197
204
  }
198
205
  interface ChatApi {
199
206
  persona: BootstrapInfo | null;
@@ -201,6 +208,12 @@ interface ChatApi {
201
208
  sending: boolean;
202
209
  /** True while a TTS reply audio element is actively playing. */
203
210
  assistantSpeaking: boolean;
211
+ /** Progress of the answer to the latest voice turn (a send or retry with
212
+ * forceVoicePlayback): answering until its audio starts, speaking while it
213
+ * plays, then done — or failed when the request failed. Done is only set
214
+ * once playback has ended or there was nothing to play, so a caller can
215
+ * safely reopen the microphone. */
216
+ voiceReply: VoiceReply;
204
217
  visitor: Visitor;
205
218
  /** Effective starter prompts: host `starters` if set, else token `starterQuestions`. */
206
219
  starters: string[];
@@ -215,17 +228,36 @@ interface ChatApi {
215
228
  /** Human currently typing in the live chat, if any. */
216
229
  agentTypingName?: string;
217
230
  send: (text: string, opts?: SendOpts) => void;
231
+ /** Add to the question being answered (the visitor kept talking while the
232
+ * reply was prepared): cancels that reply and asks again with all of it.
233
+ * Also completes a held question (see `hold`). An ordinary send otherwise. */
234
+ amend: (text: string, opts?: SendOpts) => void;
235
+ /** The visitor started talking while the reply was prepared: cancel it now
236
+ * (so its audio never plays over them) but keep the question, to be asked
237
+ * again by `amend` with their words, or by `resumeHeld` if it was noise.
238
+ * Returns false when nothing was in flight. */
239
+ hold: () => boolean;
240
+ /** Ask a held question again, unchanged (what was heard was not speech). */
241
+ resumeHeld: () => void;
242
+ /** Lower (true) or restore (false) the reply being read aloud, while the
243
+ * visitor may be talking over it: it keeps playing until we know whether
244
+ * that was the visitor or the reply's own echo. */
245
+ duckSpeaking: (ducked: boolean) => void;
218
246
  sendGif: (url: string) => void;
219
247
  /** Soft visitor typing hint for the staff console. */
220
248
  notifyTyping: (isTyping: boolean) => void;
221
249
  /** Cancel the in-flight streaming reply (Stop button). */
222
250
  stop: () => void;
223
251
  /** Re-run a failed turn in place. */
224
- retry: (agentId: string, question: string) => void;
252
+ retry: (agentId: string, question: string, opts?: Pick<SendOpts, 'forceVoicePlayback'>) => void;
225
253
  /** Record a 👍/👎 on an assistant reply (optional comment on 👎). Optimistic. */
226
254
  rateMessage: (messageId: string, rating: 'up' | 'down', comment?: string) => void;
227
255
  /** Append a proactive assistant message (auto-engagement). No-op duplicate-guarded. */
228
256
  injectAssistant: (content: string) => void;
257
+ /** After a teammate handed the chat back to the AI: offer the live-support
258
+ * action again (its form opens in the conversation). False when this
259
+ * widget has no live-support action. */
260
+ reconnectSupport: () => boolean;
229
261
  /** Add/update/remove local-only bubbles used by the live voice capture UI. */
230
262
  appendUserDraft: (content: string) => string;
231
263
  patchMessage: (id: string, fields: Partial<ChatMessage>) => void;
@@ -235,9 +267,15 @@ interface ChatApi {
235
267
  /** Submit an inline action form; persists identity so Case-1 auto-handoff can fire later. */
236
268
  submitForm: (type: string, payload: Record<string, unknown>, identity?: Visitor, /** Backend-declared endpoint; authoritative when present. */
237
269
  endpointOverride?: string) => Promise<ActionResult>;
270
+ confirmHostedBooking: (inquiryId: string, eventUri: string, inviteeUri: string) => Promise<DemoBooking | undefined>;
238
271
  transcribe: (audio: Blob | string, mimeType: string, languageHint?: string, durationSeconds?: number) => Promise<string>;
239
- /** Extract text from an attached image/PDF (folded into the next message). */
240
- extract: (fileBase64: string, mimeType: string, filename?: string) => Promise<string>;
272
+ uploadAttachment: (fileBase64: string, mimeType: string, filename: string, analyze: boolean) => Promise<{
273
+ id: string;
274
+ text: string;
275
+ analysisFailed: boolean;
276
+ }>;
277
+ /** The file attached to a visitor message, for preview. */
278
+ loadAttachment: (message: Pick<ChatMessage, 'id'>, attachment: MessageAttachment, index?: number) => Promise<Blob>;
241
279
  searchGifs: (query: string) => Promise<GifResult[]>;
242
280
  /** Booking availability in a window (booked slots + connected-calendar busy ranges). */
243
281
  demoSlots: (fromISO: string, toISO: string) => Promise<DemoSlotsResult>;
@@ -272,7 +310,117 @@ interface ChatApi {
272
310
  }
273
311
  declare const useChat: (transport: Transport, config: ResolvedConfig, active?: boolean) => ChatApi;
274
312
  //#endregion
313
+ //#region src/components.d.ts
314
+ /** Submit handler shared by the forms + handoff card. */
315
+ type SubmitForm = (type: string, payload: Record<string, unknown>, identity?: Visitor, /** Backend-declared endpoint; authoritative when present. */
316
+ endpointOverride?: string) => Promise<ActionResult>;
317
+ type ConfirmHostedBooking = (inquiryId: string, eventUri: string, inviteeUri: string) => Promise<DemoBooking | undefined>;
318
+ declare const ActionsArea: ({
319
+ actions,
320
+ descriptors,
321
+ visitor,
322
+ onSubmitForm,
323
+ onDemoSlots,
324
+ onConfirmHostedBooking,
325
+ scheduler,
326
+ exclude,
327
+ openAction,
328
+ translations,
329
+ onClose
330
+ }: {
331
+ /** Legacy tool ids. Used only when `descriptors` is absent (older backend). */
332
+ actions?: string[];
333
+ /** Structured descriptors — preferred. */
334
+ descriptors?: PublicChatAction[];
335
+ visitor: Visitor;
336
+ onSubmitForm: SubmitForm;
337
+ onDemoSlots?: (fromISO: string, toISO: string) => Promise<DemoSlotsResult>;
338
+ onConfirmHostedBooking?: ConfirmHostedBooking;
339
+ scheduler?: SchedulerInfo;
340
+ exclude?: string[];
341
+ /** Action id the backend resolved for this turn — opens its form directly. */
342
+ openAction?: string;
343
+ /** Locale-specific copy keyed by stable action ID. */
344
+ translations?: Record<string, WidgetActionTranslation>;
345
+ /** A host that shows the actions in its own panel: closing or cancelling
346
+ * the action closes that panel instead of returning to the action menu. */
347
+ onClose?: () => void;
348
+ }) => JSX.Element | null;
349
+ //#endregion
350
+ //#region src/style-rules.d.ts
351
+ /**
352
+ * Picks the rules for some components out of a stylesheet, so another
353
+ * surface can render those components without the whole widget stylesheet.
354
+ *
355
+ * A rule is kept when its selector names one of the class prefixes; at-rules
356
+ * such as @media keep only their matching inner rules and are dropped when
357
+ * none match. Comments are removed. This is a small parser for our own,
358
+ * well-formed stylesheet — not a general CSS parser.
359
+ */
360
+ declare const selectStyleRules: (css: string, classPrefixes: string[]) => string;
361
+ //#endregion
362
+ //#region src/transcript.d.ts
363
+ /** A transcript worth sending as the visitor's turn: annotations stripped,
364
+ * and neither noise, silence nor a leaked transcription prompt. Returns ''
365
+ * when there is nothing to send. */
366
+ declare const usableTranscript: (text: string) => string;
367
+ /** The microphone picked up the AI's own reply from the speakers, not the
368
+ * visitor (shared with every voice surface). */
369
+ declare const looksLikeEcho: (transcript: string, spoken: string) => boolean;
370
+ //#endregion
371
+ //#region src/audio.d.ts
372
+ interface VoiceAudioCapabilities {
373
+ echoCancellation?: boolean;
374
+ noiseSuppression?: boolean;
375
+ autoGainControl?: boolean;
376
+ channelCount?: boolean;
377
+ voiceIsolation?: boolean;
378
+ }
379
+ /**
380
+ * Build a best-effort microphone profile for conversational speech. Every
381
+ * enhancement is capability-driven and optional, so unsupported processing
382
+ * cannot make microphone permission fail.
383
+ */
384
+ declare const createVoiceAudioConstraints: (deviceId?: string, supported?: VoiceAudioCapabilities) => MediaTrackConstraints;
385
+ interface AdaptiveVoiceActivityOptions {
386
+ calibrationSamples?: number;
387
+ ambientWindowSamples?: number;
388
+ ambientPercentile?: number;
389
+ smoothing?: number;
390
+ minimumNoiseFloor?: number;
391
+ speechToNoiseRatio?: number;
392
+ quietToNoiseRatio?: number;
393
+ minimumEndSilenceMs?: number;
394
+ maximumEndSilenceMs?: number;
395
+ }
396
+ interface VoiceActivitySample {
397
+ speech: boolean;
398
+ quiet: boolean;
399
+ calibrated: boolean;
400
+ noiseFloor: number;
401
+ speechThreshold: number;
402
+ quietThreshold: number;
403
+ endOfSpeechDelayMs: number;
404
+ }
405
+ /**
406
+ * Learn the room's ambient level continuously and classify relative changes.
407
+ * The detector is synchronous and runs on samples already collected for the
408
+ * level meter, so it adds no network request or post-recording delay.
409
+ */
410
+ declare const createAdaptiveVoiceActivityDetector: (options?: AdaptiveVoiceActivityOptions) => {
411
+ observe: (rms: number) => VoiceActivitySample;
412
+ reset: () => void;
413
+ };
414
+ declare const createPreferredAudioRecorder: (stream: MediaStream) => MediaRecorder;
415
+ declare const stopRecorderWithFlush: (recorder: MediaRecorder | null | undefined) => void;
416
+ //#endregion
275
417
  //#region src/runtime.d.ts
418
+ /**
419
+ * The widget's action buttons, forms and booking picker, for surfaces that
420
+ * render ActionsArea. They read the --cf-* theme variables, which the host
421
+ * surface maps onto its own theme.
422
+ */
423
+ declare const WIDGET_ACTION_STYLES: string;
276
424
  declare const createChatTransport: (config: ResolvedConfig) => Transport;
277
425
  //#endregion
278
- export { type ActionResult, type AnalyticsVisualization, type BootstrapInfo, type ChatApi, type ChatArtifact, type ChatMessage, type DemoSlotsResult, type HistoryEntry, type PublicChatAction, type PublicChatActionField, type ResolvedConfig, ResultTable, type Source, type Transport, WidgetAnalyticsChart, type WidgetConfig, type WidgetThemeTokens, type WidgetUser, buildWidgetAnalyticsChartModel, createChatTransport, createPreferredAudioRecorder, createVoiceAudioConstraints, formatResultCell, renderRich, resolveConfig, serializeResultCsv, stopRecorderWithFlush, useChat };
426
+ export { type ActionResult, ActionsArea, type AnalyticsVisualization, type BootstrapInfo, type ChatApi, type ChatArtifact, type ChatMessage, type DemoSlotsResult, type HistoryEntry, type MessageAttachment, type PublicChatAction, type PublicChatActionField, type ResolvedConfig, ResultTable, type Source, StringsProvider, type Transport, type VoiceReply, WIDGET_ACTION_STYLES, WidgetAnalyticsChart, type WidgetConfig, type WidgetThemeTokens, type WidgetUser, buildWidgetAnalyticsChartModel, createAdaptiveVoiceActivityDetector, createChatTransport, createPreferredAudioRecorder, createVoiceAudioConstraints, findLiveSupportAction, formatResultCell, looksLikeEcho, reconnectableHandbackId, renderRich, resolveConfig, selectStyleRules, serializeResultCsv, stopRecorderWithFlush, usableTranscript, useChat };
@@ -1,4 +1,4 @@
1
- import { _ as PublicChatActionField, a as Source, c as WidgetConfig, d as WidgetUser, f as ActionResult, g as PublicChatAction, h as GifResult, i as FeaturedLink, m as DemoSlotsResult, n as ChatArtifact, o as Visitor, p as AnalyticsVisualization, r as ChatMessage, s as WidgetActionTranslation, t as BootstrapInfo, u as WidgetThemeTokens, v as Transport, y as WidgetStrings } from "./types-1ZJJY7Da.mjs";
1
+ import { C as WidgetStrings, S as StringsProvider, _ as DemoSlotsResult, a as MessageAttachment, b as PublicChatActionField, c as Visitor, f as WidgetThemeTokens, g as DemoBooking, h as AnalyticsVisualization, i as FeaturedLink, l as WidgetActionTranslation, m as ActionResult, n as ChatArtifact, o as SchedulerInfo, p as WidgetUser, r as ChatMessage, s as Source, t as BootstrapInfo, u as WidgetConfig, v as GifResult, x as Transport, y as PublicChatAction } from "./types-DhmmWqaj.mjs";
2
2
  import * as preact0 from "preact";
3
3
  import { JSX } from "preact";
4
4
 
@@ -156,23 +156,6 @@ declare const ResultTable: ({
156
156
  //#region src/rich.d.ts
157
157
  declare const renderRich: (text: string) => JSX.Element[];
158
158
  //#endregion
159
- //#region src/audio.d.ts
160
- interface VoiceAudioCapabilities {
161
- echoCancellation?: boolean;
162
- noiseSuppression?: boolean;
163
- autoGainControl?: boolean;
164
- channelCount?: boolean;
165
- voiceIsolation?: boolean;
166
- }
167
- /**
168
- * Build a best-effort microphone profile for conversational speech. Every
169
- * enhancement is capability-driven and optional, so unsupported processing
170
- * cannot make microphone permission fail.
171
- */
172
- declare const createVoiceAudioConstraints: (deviceId?: string, supported?: VoiceAudioCapabilities) => MediaTrackConstraints;
173
- declare const createPreferredAudioRecorder: (stream: MediaStream) => MediaRecorder;
174
- declare const stopRecorderWithFlush: (recorder: MediaRecorder | null | undefined) => void;
175
- //#endregion
176
159
  //#region src/useChat.d.ts
177
160
  /** One past conversation, for the in-widget history list. */
178
161
  interface HistoryEntry {
@@ -183,7 +166,18 @@ interface HistoryEntry {
183
166
  title: string;
184
167
  ended: boolean;
185
168
  }
169
+ /** The catalogue action that brings a teammate into the chat, when usable.
170
+ * A backend older than the liveHandoff flag is recognised by its fixed id. */
171
+ declare const findLiveSupportAction: (actions: PublicChatAction[] | undefined) => PublicChatAction | undefined;
172
+ /** The ai_handback notice that may still offer to reconnect: the latest one,
173
+ * while the AI has the chat and the visitor has not already asked again. */
174
+ declare const reconnectableHandbackId: (messages: ChatMessage[], liveMode: "ai" | "queued" | "human") => string | undefined;
186
175
  /** Optional extras when sending — an inline image (GIF) or an extracted file. */
176
+ interface VoiceReply {
177
+ status: 'idle' | 'answering' | 'speaking' | 'done' | 'failed';
178
+ /** The assistant message answering the voice turn. */
179
+ agentId?: string;
180
+ }
187
181
  interface SendOpts {
188
182
  imageUrl?: string;
189
183
  /** Voice-call turns should speak the assistant reply using provider TTS when configured. */
@@ -194,6 +188,19 @@ interface SendOpts {
194
188
  attachmentName?: string;
195
189
  /** Text extracted from the attachment, folded into the backend question. */
196
190
  attachmentText?: string;
191
+ attachmentId?: string;
192
+ /** The attached file itself, kept in memory so it can be previewed. */
193
+ attachmentFile?: Blob;
194
+ /** Several files sent with the message (replaces the single fields). */
195
+ attachments?: OutgoingAttachment[];
196
+ }
197
+ interface OutgoingAttachment {
198
+ id?: string;
199
+ name: string;
200
+ /** Text extracted from the file, folded into the backend question. */
201
+ text?: string;
202
+ /** Kept in memory so it can be previewed. */
203
+ file?: Blob;
197
204
  }
198
205
  interface ChatApi {
199
206
  persona: BootstrapInfo | null;
@@ -201,6 +208,12 @@ interface ChatApi {
201
208
  sending: boolean;
202
209
  /** True while a TTS reply audio element is actively playing. */
203
210
  assistantSpeaking: boolean;
211
+ /** Progress of the answer to the latest voice turn (a send or retry with
212
+ * forceVoicePlayback): answering until its audio starts, speaking while it
213
+ * plays, then done — or failed when the request failed. Done is only set
214
+ * once playback has ended or there was nothing to play, so a caller can
215
+ * safely reopen the microphone. */
216
+ voiceReply: VoiceReply;
204
217
  visitor: Visitor;
205
218
  /** Effective starter prompts: host `starters` if set, else token `starterQuestions`. */
206
219
  starters: string[];
@@ -215,17 +228,36 @@ interface ChatApi {
215
228
  /** Human currently typing in the live chat, if any. */
216
229
  agentTypingName?: string;
217
230
  send: (text: string, opts?: SendOpts) => void;
231
+ /** Add to the question being answered (the visitor kept talking while the
232
+ * reply was prepared): cancels that reply and asks again with all of it.
233
+ * Also completes a held question (see `hold`). An ordinary send otherwise. */
234
+ amend: (text: string, opts?: SendOpts) => void;
235
+ /** The visitor started talking while the reply was prepared: cancel it now
236
+ * (so its audio never plays over them) but keep the question, to be asked
237
+ * again by `amend` with their words, or by `resumeHeld` if it was noise.
238
+ * Returns false when nothing was in flight. */
239
+ hold: () => boolean;
240
+ /** Ask a held question again, unchanged (what was heard was not speech). */
241
+ resumeHeld: () => void;
242
+ /** Lower (true) or restore (false) the reply being read aloud, while the
243
+ * visitor may be talking over it: it keeps playing until we know whether
244
+ * that was the visitor or the reply's own echo. */
245
+ duckSpeaking: (ducked: boolean) => void;
218
246
  sendGif: (url: string) => void;
219
247
  /** Soft visitor typing hint for the staff console. */
220
248
  notifyTyping: (isTyping: boolean) => void;
221
249
  /** Cancel the in-flight streaming reply (Stop button). */
222
250
  stop: () => void;
223
251
  /** Re-run a failed turn in place. */
224
- retry: (agentId: string, question: string) => void;
252
+ retry: (agentId: string, question: string, opts?: Pick<SendOpts, 'forceVoicePlayback'>) => void;
225
253
  /** Record a 👍/👎 on an assistant reply (optional comment on 👎). Optimistic. */
226
254
  rateMessage: (messageId: string, rating: 'up' | 'down', comment?: string) => void;
227
255
  /** Append a proactive assistant message (auto-engagement). No-op duplicate-guarded. */
228
256
  injectAssistant: (content: string) => void;
257
+ /** After a teammate handed the chat back to the AI: offer the live-support
258
+ * action again (its form opens in the conversation). False when this
259
+ * widget has no live-support action. */
260
+ reconnectSupport: () => boolean;
229
261
  /** Add/update/remove local-only bubbles used by the live voice capture UI. */
230
262
  appendUserDraft: (content: string) => string;
231
263
  patchMessage: (id: string, fields: Partial<ChatMessage>) => void;
@@ -235,9 +267,15 @@ interface ChatApi {
235
267
  /** Submit an inline action form; persists identity so Case-1 auto-handoff can fire later. */
236
268
  submitForm: (type: string, payload: Record<string, unknown>, identity?: Visitor, /** Backend-declared endpoint; authoritative when present. */
237
269
  endpointOverride?: string) => Promise<ActionResult>;
270
+ confirmHostedBooking: (inquiryId: string, eventUri: string, inviteeUri: string) => Promise<DemoBooking | undefined>;
238
271
  transcribe: (audio: Blob | string, mimeType: string, languageHint?: string, durationSeconds?: number) => Promise<string>;
239
- /** Extract text from an attached image/PDF (folded into the next message). */
240
- extract: (fileBase64: string, mimeType: string, filename?: string) => Promise<string>;
272
+ uploadAttachment: (fileBase64: string, mimeType: string, filename: string, analyze: boolean) => Promise<{
273
+ id: string;
274
+ text: string;
275
+ analysisFailed: boolean;
276
+ }>;
277
+ /** The file attached to a visitor message, for preview. */
278
+ loadAttachment: (message: Pick<ChatMessage, 'id'>, attachment: MessageAttachment, index?: number) => Promise<Blob>;
241
279
  searchGifs: (query: string) => Promise<GifResult[]>;
242
280
  /** Booking availability in a window (booked slots + connected-calendar busy ranges). */
243
281
  demoSlots: (fromISO: string, toISO: string) => Promise<DemoSlotsResult>;
@@ -272,7 +310,117 @@ interface ChatApi {
272
310
  }
273
311
  declare const useChat: (transport: Transport, config: ResolvedConfig, active?: boolean) => ChatApi;
274
312
  //#endregion
313
+ //#region src/components.d.ts
314
+ /** Submit handler shared by the forms + handoff card. */
315
+ type SubmitForm = (type: string, payload: Record<string, unknown>, identity?: Visitor, /** Backend-declared endpoint; authoritative when present. */
316
+ endpointOverride?: string) => Promise<ActionResult>;
317
+ type ConfirmHostedBooking = (inquiryId: string, eventUri: string, inviteeUri: string) => Promise<DemoBooking | undefined>;
318
+ declare const ActionsArea: ({
319
+ actions,
320
+ descriptors,
321
+ visitor,
322
+ onSubmitForm,
323
+ onDemoSlots,
324
+ onConfirmHostedBooking,
325
+ scheduler,
326
+ exclude,
327
+ openAction,
328
+ translations,
329
+ onClose
330
+ }: {
331
+ /** Legacy tool ids. Used only when `descriptors` is absent (older backend). */
332
+ actions?: string[];
333
+ /** Structured descriptors — preferred. */
334
+ descriptors?: PublicChatAction[];
335
+ visitor: Visitor;
336
+ onSubmitForm: SubmitForm;
337
+ onDemoSlots?: (fromISO: string, toISO: string) => Promise<DemoSlotsResult>;
338
+ onConfirmHostedBooking?: ConfirmHostedBooking;
339
+ scheduler?: SchedulerInfo;
340
+ exclude?: string[];
341
+ /** Action id the backend resolved for this turn — opens its form directly. */
342
+ openAction?: string;
343
+ /** Locale-specific copy keyed by stable action ID. */
344
+ translations?: Record<string, WidgetActionTranslation>;
345
+ /** A host that shows the actions in its own panel: closing or cancelling
346
+ * the action closes that panel instead of returning to the action menu. */
347
+ onClose?: () => void;
348
+ }) => JSX.Element | null;
349
+ //#endregion
350
+ //#region src/style-rules.d.ts
351
+ /**
352
+ * Picks the rules for some components out of a stylesheet, so another
353
+ * surface can render those components without the whole widget stylesheet.
354
+ *
355
+ * A rule is kept when its selector names one of the class prefixes; at-rules
356
+ * such as @media keep only their matching inner rules and are dropped when
357
+ * none match. Comments are removed. This is a small parser for our own,
358
+ * well-formed stylesheet — not a general CSS parser.
359
+ */
360
+ declare const selectStyleRules: (css: string, classPrefixes: string[]) => string;
361
+ //#endregion
362
+ //#region src/transcript.d.ts
363
+ /** A transcript worth sending as the visitor's turn: annotations stripped,
364
+ * and neither noise, silence nor a leaked transcription prompt. Returns ''
365
+ * when there is nothing to send. */
366
+ declare const usableTranscript: (text: string) => string;
367
+ /** The microphone picked up the AI's own reply from the speakers, not the
368
+ * visitor (shared with every voice surface). */
369
+ declare const looksLikeEcho: (transcript: string, spoken: string) => boolean;
370
+ //#endregion
371
+ //#region src/audio.d.ts
372
+ interface VoiceAudioCapabilities {
373
+ echoCancellation?: boolean;
374
+ noiseSuppression?: boolean;
375
+ autoGainControl?: boolean;
376
+ channelCount?: boolean;
377
+ voiceIsolation?: boolean;
378
+ }
379
+ /**
380
+ * Build a best-effort microphone profile for conversational speech. Every
381
+ * enhancement is capability-driven and optional, so unsupported processing
382
+ * cannot make microphone permission fail.
383
+ */
384
+ declare const createVoiceAudioConstraints: (deviceId?: string, supported?: VoiceAudioCapabilities) => MediaTrackConstraints;
385
+ interface AdaptiveVoiceActivityOptions {
386
+ calibrationSamples?: number;
387
+ ambientWindowSamples?: number;
388
+ ambientPercentile?: number;
389
+ smoothing?: number;
390
+ minimumNoiseFloor?: number;
391
+ speechToNoiseRatio?: number;
392
+ quietToNoiseRatio?: number;
393
+ minimumEndSilenceMs?: number;
394
+ maximumEndSilenceMs?: number;
395
+ }
396
+ interface VoiceActivitySample {
397
+ speech: boolean;
398
+ quiet: boolean;
399
+ calibrated: boolean;
400
+ noiseFloor: number;
401
+ speechThreshold: number;
402
+ quietThreshold: number;
403
+ endOfSpeechDelayMs: number;
404
+ }
405
+ /**
406
+ * Learn the room's ambient level continuously and classify relative changes.
407
+ * The detector is synchronous and runs on samples already collected for the
408
+ * level meter, so it adds no network request or post-recording delay.
409
+ */
410
+ declare const createAdaptiveVoiceActivityDetector: (options?: AdaptiveVoiceActivityOptions) => {
411
+ observe: (rms: number) => VoiceActivitySample;
412
+ reset: () => void;
413
+ };
414
+ declare const createPreferredAudioRecorder: (stream: MediaStream) => MediaRecorder;
415
+ declare const stopRecorderWithFlush: (recorder: MediaRecorder | null | undefined) => void;
416
+ //#endregion
275
417
  //#region src/runtime.d.ts
418
+ /**
419
+ * The widget's action buttons, forms and booking picker, for surfaces that
420
+ * render ActionsArea. They read the --cf-* theme variables, which the host
421
+ * surface maps onto its own theme.
422
+ */
423
+ declare const WIDGET_ACTION_STYLES: string;
276
424
  declare const createChatTransport: (config: ResolvedConfig) => Transport;
277
425
  //#endregion
278
- export { type ActionResult, type AnalyticsVisualization, type BootstrapInfo, type ChatApi, type ChatArtifact, type ChatMessage, type DemoSlotsResult, type HistoryEntry, type PublicChatAction, type PublicChatActionField, type ResolvedConfig, ResultTable, type Source, type Transport, WidgetAnalyticsChart, type WidgetConfig, type WidgetThemeTokens, type WidgetUser, buildWidgetAnalyticsChartModel, createChatTransport, createPreferredAudioRecorder, createVoiceAudioConstraints, formatResultCell, renderRich, resolveConfig, serializeResultCsv, stopRecorderWithFlush, useChat };
426
+ export { type ActionResult, ActionsArea, type AnalyticsVisualization, type BootstrapInfo, type ChatApi, type ChatArtifact, type ChatMessage, type DemoSlotsResult, type HistoryEntry, type MessageAttachment, type PublicChatAction, type PublicChatActionField, type ResolvedConfig, ResultTable, type Source, StringsProvider, type Transport, type VoiceReply, WIDGET_ACTION_STYLES, WidgetAnalyticsChart, type WidgetConfig, type WidgetThemeTokens, type WidgetUser, buildWidgetAnalyticsChartModel, createAdaptiveVoiceActivityDetector, createChatTransport, createPreferredAudioRecorder, createVoiceAudioConstraints, findLiveSupportAction, formatResultCell, looksLikeEcho, reconnectableHandbackId, renderRich, resolveConfig, selectStyleRules, serializeResultCsv, stopRecorderWithFlush, usableTranscript, useChat };
package/dist/runtime.mjs CHANGED
@@ -1 +1,2 @@
1
- import{C as e,S as t,_ as n,a as r,d as i,f as a,g as o,h as s,m as c,n as l,t as u,u as d,v as f,x as p}from"./config-CkU4urQY.mjs";const m=n=>n.demo?new t:n.preview?new p(new e(n.apiBaseUrl,n.token,n.gifApiKey,n.analyticsContextToken,{agentName:n.agentName,agentAvatarUrl:n.agentAvatarUrl},n.identityToken,n.getIdentityToken,n.chatSurface),n.strings):new e(n.apiBaseUrl,n.token,n.gifApiKey,n.analyticsContextToken,{agentName:n.agentName,agentAvatarUrl:n.agentAvatarUrl},n.identityToken,n.getIdentityToken,n.chatSurface);export{c as ResultTable,n as WidgetAnalyticsChart,f as buildWidgetAnalyticsChartModel,m as createChatTransport,d as createPreferredAudioRecorder,i as createVoiceAudioConstraints,s as formatResultCell,r as renderRich,u as resolveConfig,o as serializeResultCsv,a as stopRecorderWithFlush,l as useChat};
1
+ import{E as e,G as t,J as n,K as r,L as i,U as a,W as o,X as s,Y as c,_ as l,a as u,c as d,f,g as p,i as m,l as h,n as g,o as _,q as v,r as y,s as b,t as x}from"./styles-CIJFMOKa.mjs";const S=(e,t)=>{let n=e.replace(/\/\*[\s\S]*?\*\//g,``),r=e=>t.some(t=>e.includes(t)),i=[],a=0;for(;a<n.length;){let e=n.indexOf(`{`,a);if(e<0)break;let o=n.slice(a,e).trim(),s=1,c=e+1;for(;c<n.length&&s>0;)n[c]===`{`?s++:n[c]===`}`&&s--,c++;let l=n.slice(e+1,c-1);if(o.startsWith(`@`))if(/^@(media|supports|container)\b/.test(o)){let e=S(l,t);e&&i.push(`${o} {\n${e}\n}`)}else /^@keyframes\b/.test(o)&&r(o)&&i.push(`${o} {${l}}`);else r(o)&&i.push(`${o} {${l}}`);a=c}return i.join(`
2
+ `)},C=S(x,[`.cf-action`,`.cf-form`,`.cf-booking`]),w=e=>e.demo?new c:e.preview?new n(new s(e.apiBaseUrl,e.token,e.gifApiKey,e.analyticsContextToken,{agentName:e.agentName,agentAvatarUrl:e.agentAvatarUrl},e.identityToken,e.getIdentityToken,e.chatSurface),e.strings):new s(e.apiBaseUrl,e.token,e.gifApiKey,e.analyticsContextToken,{agentName:e.agentName,agentAvatarUrl:e.agentAvatarUrl},e.identityToken,e.getIdentityToken,e.chatSurface);export{l as ActionsArea,a as ResultTable,i as StringsProvider,C as WIDGET_ACTION_STYLES,r as WidgetAnalyticsChart,v as buildWidgetAnalyticsChartModel,_ as createAdaptiveVoiceActivityDetector,w as createChatTransport,b as createPreferredAudioRecorder,d as createVoiceAudioConstraints,y as findLiveSupportAction,o as formatResultCell,f as looksLikeEcho,m as reconnectableHandbackId,e as renderRich,g as resolveConfig,S as selectStyleRules,t as serializeResultCsv,h as stopRecorderWithFlush,p as usableTranscript,u as useChat};