@helpai/elements 0.72.1 → 1.1.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/index.d.ts CHANGED
@@ -32,8 +32,8 @@ interface ClientStorage {
32
32
  *
33
33
  * The widget bundles five complete locales (en/fr/ar/es/he — English is also the
34
34
  * fallback for any missing key; see {@link BUILTIN_STRINGS}). Further locales, or
35
- * per-key overrides, are supplied by the page owner (`init({ strings })`) or the
36
- * SaaS backend in the `connect` response — both pushed *partially*: only the keys
35
+ * per-key overrides, are supplied by the page owner (`init({ i18n: { strings } })`)
36
+ * or the SaaS backend in `config.i18n.strings` — both pushed *partially*: only the keys
37
37
  * they want to override.
38
38
  *
39
39
  * To keep render hot-paths cheap, the merged shape is **pre-computed once**
@@ -41,7 +41,7 @@ interface ClientStorage {
41
41
  * populated {@link Strings} map. UI components then read `strings.send` as a
42
42
  * normal property access — no per-render lookup, no per-render allocation.
43
43
  */
44
- type StringKey = "launcherOpen" | "launcherLabel" | "panelTitle" | "composerPlaceholder" | "send" | "stop" | "attach" | "micStart" | "micStop" | "micUnsupported" | "expand" | "collapse" | "fullscreen" | "exitFullscreen" | "resizeHandle" | "scrollToBottom" | "close" | "moreActions" | "soundOn" | "soundOff" | "language" | "theme" | "themeAuto" | "themeLight" | "themeDark" | "textSize" | "textSizeSmall" | "textSizeNormal" | "textSizeLarge" | "history" | "historyTitle" | "historyEmpty" | "historyLoading" | "historyBack" | "historyContinue" | "conversationLoading" | "conversationClosed" | "startNewConversation" | "talkToOperator" | "connectingOperator" | "noOperatorAvailable" | "chattingWithOperator" | "cancelOperatorRequest" | "dateToday" | "dateYesterday" | "dateLastWeek" | "dateOlder" | "newConversation" | "dropZone" | "attachmentTooLarge" | "attachmentTooMany" | "attachmentMimeRejected" | "errorRetry" | "errorGeneric" | "errorRateLimited" | "loading" | "thinking" | "thoughts" | "toolResult" | "sources" | "feedbackUp" | "feedbackDown" | "feedbackThanks" | "copy" | "copied" | "collapseSidebar" | "expandSidebar" | "formSubmit" | "formSkip" | "formSubmitted" | "formSkipped" | "formFillOut" | "formRequired" | "formInvalidEmail" | "formInvalidTel" | "formInvalidUrl" | "formInvalidNumber" | "formTooShort" | "formTooLong" | "formNumberTooSmall" | "formNumberTooLarge" | "formPatternMismatch" | "formChooseAtLeast" | "formChooseAtMost" | "formOther" | "formOtherPlaceholder" | "inputRequired" | "inputBadge" | "inputAnswered" | "inputSkipped" | "inputSubmit" | "inputSubmitHint" | "inputSkip" | "showOptions" | "hideOptions" | "qtypeText" | "qtypeEmail" | "qtypePhone" | "qtypeNumber" | "qtypeDate" | "qtypeChooseOne" | "qtypeChooseAny" | "qtypeBoolean" | "confirmYes" | "confirmNo" | "approve" | "reject" | "approvalPrompt" | "approvalBody" | "approvalYourResponse" | "approvalEditHint" | "approvalSubmitting" | "edit" | "toolParameters" | "statusAwaiting" | "statusResponded" | "statusCompleted" | "statusDenied" | "statusError" | "statusRunning" | "statusSuperseded" | "tabHome" | "tabConversations" | "tabHelp" | "tabNews" | "modulesEmpty" | "moduleBack" | "contentLoading" | "homeGreeting" | "homeGreetingNamed" | "homeGreetingLead" | "homeSearchPlaceholder" | "homeContentTitle" | "homeStatus" | "helpTitle" | "helpSearchPlaceholder" | "helpEmpty" | "helpLoading" | "helpSearchEmpty" | "newsTitle" | "newsEmpty" | "newsLoading" | "newsBack" | "newsPublishedAt";
44
+ type StringKey = "launcherOpen" | "launcherLabel" | "panelTitle" | "composerPlaceholder" | "send" | "stop" | "attach" | "micStart" | "micStop" | "micUnsupported" | "expand" | "collapse" | "fullscreen" | "exitFullscreen" | "resizeHandle" | "scrollToBottom" | "close" | "moreActions" | "soundOn" | "soundOff" | "language" | "theme" | "themeAuto" | "themeLight" | "themeDark" | "textSize" | "textSizeSmall" | "textSizeNormal" | "textSizeLarge" | "history" | "historyTitle" | "historyEmpty" | "historyLoading" | "historyBack" | "historyContinue" | "loadMoreConversations" | "conversationLoading" | "loadPreviousMessages" | "conversationClosed" | "startNewConversation" | "talkToOperator" | "connectingOperator" | "noOperatorAvailable" | "chattingWithOperator" | "cancelOperatorRequest" | "dateToday" | "dateYesterday" | "dateLastWeek" | "dateOlder" | "newConversation" | "dropZone" | "attachmentTooLarge" | "attachmentTooMany" | "attachmentMimeRejected" | "errorRetry" | "errorGeneric" | "errorRateLimited" | "loading" | "thinking" | "thoughts" | "toolResult" | "sources" | "feedbackUp" | "feedbackDown" | "feedbackThanks" | "copy" | "copied" | "collapseSidebar" | "expandSidebar" | "formSubmit" | "formSkip" | "formSubmitted" | "formSkipped" | "formFillOut" | "formRequired" | "formInvalidEmail" | "formInvalidTel" | "formInvalidUrl" | "formInvalidNumber" | "formTooShort" | "formTooLong" | "formNumberTooSmall" | "formNumberTooLarge" | "formPatternMismatch" | "formChooseAtLeast" | "formChooseAtMost" | "formOther" | "formOtherPlaceholder" | "inputRequired" | "inputBadge" | "inputAnswered" | "inputSkipped" | "inputSubmit" | "inputSubmitHint" | "inputSkip" | "showOptions" | "hideOptions" | "qtypeText" | "qtypeEmail" | "qtypePhone" | "qtypeNumber" | "qtypeDate" | "qtypeChooseOne" | "qtypeChooseAny" | "qtypeBoolean" | "confirmYes" | "confirmNo" | "approve" | "reject" | "approvalPrompt" | "approvalBody" | "approvalYourResponse" | "approvalEditHint" | "approvalSubmitting" | "edit" | "toolParameters" | "statusAwaiting" | "statusResponded" | "statusCompleted" | "statusDenied" | "statusError" | "statusRunning" | "statusSuperseded" | "tabHome" | "tabConversations" | "tabHelp" | "tabNews" | "modulesEmpty" | "moduleBack" | "contentLoading" | "homeGreeting" | "homeGreetingNamed" | "homeGreetingLead" | "homeSearchPlaceholder" | "homeContentTitle" | "homeStatus" | "helpTitle" | "helpSearchPlaceholder" | "helpEmpty" | "helpLoading" | "helpSearchEmpty" | "newsTitle" | "newsEmpty" | "newsLoading" | "newsBack" | "newsPublishedAt";
45
45
  /** A partial map for one locale — what overrides look like on the wire. */
46
46
  type LocaleStrings = Partial<Record<StringKey, string>>;
47
47
  /**
@@ -50,8 +50,8 @@ type LocaleStrings = Partial<Record<StringKey, string>>;
50
50
  */
51
51
  type Strings = Record<StringKey, string>;
52
52
  /**
53
- * Override shape accepted by both `init({ strings })` and the server's
54
- * `settings.strings`. Two forms supported:
53
+ * Override shape accepted by both `init({ i18n: { strings } })` and the server's
54
+ * `config.i18n.strings`. Two forms supported:
55
55
  *
56
56
  * 1. **Flat** — `{ send: "Click", stop: "Halt" }`. Applies to the active
57
57
  * locale. Convenient for single-language deployments.
@@ -66,161 +66,6 @@ type Strings = Record<StringKey, string>;
66
66
  */
67
67
  type StringsOverride = LocaleStrings | Partial<Record<string, LocaleStrings>>;
68
68
  //#endregion
69
- //#region src/core/persistence.d.ts
70
- /** Drag-resized panel dimensions. Persisted only when resize is enabled. */
71
- interface WidgetSize {
72
- width: number;
73
- height: number;
74
- }
75
- /**
76
- * User-changeable preferences. Sent to the backend on every request as a
77
- * `userPrefs` field so the server can detect drift (e.g. user changed
78
- * locale on another tab) and reconcile.
79
- *
80
- * Every field is optional — an unset key inherits the server / page-owner
81
- * default. Empty object `{}` means "no preference recorded yet."
82
- */
83
- interface UserPrefs {
84
- /** BCP-47 tag picked from the language switcher. */
85
- locale?: string;
86
- /** Drag-resized panel dimensions. */
87
- widgetSize?: WidgetSize;
88
- /** Sound on/off toggle (icon button). */
89
- soundMuted?: boolean;
90
- /** Theme picked from the theme switcher. */
91
- themeMode?: "auto" | "light" | "dark";
92
- /** Text size picked from the text-size switcher. */
93
- textSize?: "small" | "normal" | "large";
94
- }
95
- //#endregion
96
- //#region src/stream/types.d.ts
97
- /** A 👍/👎 reaction on a rateable (assistant/operator) message; `null` clears a prior choice. */
98
- type FeedbackValue = "up" | "down" | null;
99
- //#endregion
100
- //#region src/stream/protocol.d.ts
101
- /** A tool reference on the wire: `{ code, config }`. `config` is opaque. */
102
- interface ToolRef {
103
- code: string;
104
- config?: Record<string, unknown>;
105
- }
106
- /**
107
- * Who is driving replies in a conversation — the widget mirrors the backend `controlMode`.
108
- * - `ai-agent`: the AI agent answers (normal operation).
109
- * - `awaiting_operator`: operator-control requested, the AI no longer answers — the turn routes to the
110
- * operator — while waiting in the operator queue.
111
- * - `operator`: a workspace operator took over and is replying.
112
- *
113
- * Carried on `HandshakeResponse.controlState`, `LoadConversationResponse.controlState` (resume +
114
- * history-switch), and the `data-control-state` stream part (on the reply stream). Absent / unknown →
115
- * treated as `"ai-agent"`.
116
- */
117
- type ControlMode = "ai-agent" | "awaiting_operator" | "operator";
118
- /**
119
- * The control-state snapshot the widget reads to render composer/typing/banner state. The optional
120
- * `operatorAvailable` (set on the operator-request response + the awaiting terminal part) tells the
121
- * widget whether to show "connecting…" or the async-capture ("leave your details") copy.
122
- */
123
- interface ControlState {
124
- controlMode: ControlMode;
125
- /**
126
- * The operator's 2-letter initials (operator mode only) — shown in the bubble chrome + banner. The
127
- * visitor never sees the full name (privacy); the backend derives the initials. `assignedOperatorId`
128
- * also rides the wire but the widget doesn't render it, so it isn't modeled here.
129
- */
130
- assignedOperatorInitials?: string;
131
- /** Whether anyone was in the operator pool when operator-control was requested (awaiting mode advisory). */
132
- operatorAvailable?: boolean;
133
- }
134
- /** One-shot bot persona shown in the panel header. */
135
- interface ConversationAgent {
136
- name: string;
137
- /** Image URL or data URI. When omitted, initials render from `name`. */
138
- avatar?: string;
139
- /** Subtitle ("AI Assistant", "Support team", …). */
140
- title?: string;
141
- /** Presence indicator. Default: `'online'`. */
142
- status?: "online" | "away" | "offline";
143
- }
144
- /** A clickable quick-reply chip. */
145
- interface ConversationSuggestion {
146
- id: string;
147
- /** What the chip displays. */
148
- label: string;
149
- /** What actually gets sent when clicked. Defaults to `label`. */
150
- text?: string;
151
- }
152
- /** Welcome payload pushed into the message list on first open. */
153
- interface ConversationWelcome {
154
- messages?: Array<{
155
- id: string;
156
- role: "assistant" | "system";
157
- text: string;
158
- }>;
159
- suggestions?: ConversationSuggestion[];
160
- }
161
- /**
162
- * Response from `POST /pai/handshake` — the widget's one mount-time
163
- * round-trip. Deliberately LIGHT: identity + deployment surface only
164
- * (config, agent persona, welcome, page-mode site/blocks, userPrefs).
165
- * The conversation THREAD is a separate, lazily-fetched read
166
- * (`GET /conversation`) that only runs once the widget is activated
167
- * (opened) — a closed launcher costs the page exactly one request.
168
- *
169
- * The `userPrefs` field (when present) is the server's authoritative
170
- * copy of per-visitor preferences — the client should adopt it and update
171
- * its local cache. Lets a user picking French on their phone see the
172
- * widget in French when they open it on their laptop (assuming the same
173
- * `visitorId`, e.g. via authenticated conversation — out of scope for v1).
174
- */
175
- interface HandshakeResponse$1 {
176
- /**
177
- * Public runtime conversation id. The widget mints this UUIDv7 and the backend
178
- * validates that it belongs to the public deployment + visitor.
179
- */
180
- conversationId: string;
181
- visitorId?: string;
182
- /** Bot persona in the panel header (name, avatar, status). */
183
- agent?: ConversationAgent;
184
- /** Initial assistant messages + quick-reply chips. */
185
- welcome?: ConversationWelcome;
186
- /**
187
- * Deployment-wide widget configuration the dashboard admin saved
188
- * (mode / theme / launcher / actions / composer / features / …).
189
- * Client adopts as defaults; customer's `init({...})` still wins
190
- * per-field. Same for every visitor of this deployment.
191
- */
192
- config?: ServerConfig$1;
193
- /** Page-mode site config (logo, title). Backend ships it whenever the deployment renders the page-shell sidebar. */
194
- site?: Record<string, unknown>;
195
- /** Page-mode sidebar blocks (navigation, link cards). Backend ships it whenever the deployment renders the page-shell sidebar. */
196
- blocks?: Record<string, unknown>;
197
- /** Current control state — seeds the composer/typing/banner state on connect. Absent → `ai-agent`. */
198
- controlState?: ControlState;
199
- /**
200
- * Server's authoritative copy of the visitor's preferences. When present,
201
- * client adopts it (overrides local cache) and re-applies it to the UI
202
- * (locale, panel size, sound mute). Absent → client keeps its cache.
203
- */
204
- userPrefs?: UserPrefs;
205
- /**
206
- * Optional rebind metadata. When the server returns a `visitorId` /
207
- * `conversationId` different from what the client sent, this block tells
208
- * the client WHY — useful for telemetry and the `visitorRebound` /
209
- * `conversationRebound` events fired into the host page. Server is free to
210
- * omit it: the client detects rebinding by comparing request vs
211
- * response ids regardless.
212
- *
213
- * Common reasons: `"conflict"` (the id collided with an existing
214
- * record), `"expired"` (the id is too old to be re-used), `"invalid"`
215
- * (malformed / not a UUIDv7). Custom strings are passed through to
216
- * listeners verbatim.
217
- */
218
- rebind?: {
219
- visitorId?: string;
220
- conversationId?: string;
221
- };
222
- }
223
- //#endregion
224
69
  //#region src/core/config/types/common.d.ts
225
70
  /**
226
71
  * Primitive type aliases shared across every config section. Kept in
@@ -290,6 +135,11 @@ type ActionName = "clear" | "expand" | "fullscreen" | "sound" | "history" | "lan
290
135
  type ActionList = ActionName[];
291
136
  //#endregion
292
137
  //#region src/core/config/types/composer.d.ts
138
+ /**
139
+ * Composer chrome and capability flags. `ChatWidgetOptions.composer` owns the
140
+ * send-button skin + attachment limits; `ChatWidgetOptions.features` owns voice,
141
+ * file-upload, HITL, and operator gates.
142
+ */
293
143
  /**
294
144
  * How voice input is captured and transcribed.
295
145
  *
@@ -304,12 +154,6 @@ type VoiceMode = "local" | "server" | "disabled";
304
154
  interface FeatureFlags {
305
155
  /** Voice input behaviour (see {@link VoiceMode}). Default: `'local'`. */
306
156
  voice?: VoiceMode;
307
- /**
308
- * Backend tools the assistant may invoke. Accepts either a bare tool code
309
- * (`"tool:send-money"`) or a rich ref (`{ code, config }`) — the wire
310
- * format always uses the rich shape.
311
- */
312
- tools?: Array<string | ToolRef>;
313
157
  /**
314
158
  * Turn OFF the human-in-the-loop tool UI — the inline ask-questions form and the
315
159
  * approve/reject controls for gated tools. Unset/`false` = shown (default); `true`
@@ -337,7 +181,6 @@ interface ResolvedFeatures {
337
181
  voice: VoiceMode;
338
182
  humanInLoop: boolean;
339
183
  operatorRequest: boolean;
340
- tools?: Array<string | ToolRef>;
341
184
  }
342
185
  /**
343
186
  * Client-side attachment limits. Server enforcement is still required —
@@ -371,7 +214,7 @@ interface ComposerOptions {
371
214
  //#endregion
372
215
  //#region src/core/config/types/feedback.d.ts
373
216
  /**
374
- * Audible + tactile feedback knobs. Both default to enabled (browser
217
+ * Audible + tactile feedback knobs. Both channels default to enabled (browser
375
218
  * autoplay policy still gates audio playback).
376
219
  */
377
220
  /** Lifecycle events the feedback bus can react to. */
@@ -385,7 +228,7 @@ type FeedbackEvent = "messageReceived" | "messageSent" | "error" | "voiceStart"
385
228
  */
386
229
  type SoundEventValue = boolean | string;
387
230
  interface SoundOptions {
388
- /** Master on/off. Default: `false` (opt-in). */
231
+ /** Master on/off. Default: `true` (browser autoplay policy still applies). */
389
232
  enabled?: boolean;
390
233
  /** Global volume 0..1. Default: `0.3` (subtle). */
391
234
  volume?: number;
@@ -410,7 +253,7 @@ interface HapticsOptions {
410
253
  events?: Partial<Record<FeedbackEvent, HapticEventValue>>;
411
254
  }
412
255
  /**
413
- * Section: audible + tactile feedback. Both default to enabled
256
+ * Section: audible + tactile feedback. Both channels default to enabled
414
257
  * (browser autoplay policy still gates audio playback).
415
258
  */
416
259
  interface FeedbackOptions {
@@ -1006,9 +849,11 @@ interface Endpoints {
1006
849
  * use the widget: events, pages, devices, locales, funnels.
1007
850
  *
1008
851
  * Privacy contract (enforced in `src/core/tracking.ts`):
1009
- * - never sends message text, form values, or any user content —
852
+ * - never sends message text or form values —
1010
853
  * event payloads pass through a static per-event allowlist;
1011
- * - the only identifier is the widget's existing anonymous `visitorId`;
854
+ * - the only visitor identifier is the widget's existing anonymous
855
+ * `visitorId`; deployment and anonymous conversation ids provide context;
856
+ * - page metadata is origin + pathname, with query/hash removed;
1012
857
  * - geo + browser are derived server-side (IP + User-Agent header),
1013
858
  * never collected client-side;
1014
859
  * - `navigator.globalPrivacyControl` / Do-Not-Track force it off
@@ -1028,8 +873,9 @@ interface TrackingOptions {
1028
873
  */
1029
874
  endpoint?: string;
1030
875
  /**
1031
- * Per-visitor sampling 0..1. `0.25` tracks ~a quarter of visitors
1032
- * (decided once per page load, so funnels stay intact). Default `1`.
876
+ * Per-widget-runtime sampling 0..1. `0.25` samples roughly a quarter of
877
+ * mounted runtimes; one decision is reused for that runtime's funnel.
878
+ * Default `1`.
1033
879
  */
1034
880
  sampleRate?: number;
1035
881
  /**
@@ -1061,7 +907,8 @@ interface ResolvedTracking {
1061
907
  * Issued by the SaaS portal, pasted into their site code.
1062
908
  * - **Widget settings (L3)** — nested sections owned by the portal
1063
909
  * admin: `presentation`, `behavior`, `theme`, `launcher`, `header`,
1064
- * `composer`, `welcome`, `feedback`, `i18n`, `footer`, `features`.
910
+ * `composer`, `feedback`, `i18n`, `footer`, `features`, and the other
911
+ * schema-backed sections below.
1065
912
  *
1066
913
  * Runtime-only fields (`target`, `storage`, `onMessage` callbacks) live
1067
914
  * alongside at the top level — they're function / DOM types that can't be
@@ -1129,7 +976,7 @@ interface ChatWidgetOptions {
1129
976
  feedback?: FeedbackOptions;
1130
977
  i18n?: I18nOptions;
1131
978
  footer?: FooterOptions;
1132
- /** Capability flags (file upload, voice mode, tools). Server-pushable. */
979
+ /** Capability flags (file upload, voice mode, HITL, operator request). Server-pushable. */
1133
980
  features?: FeatureFlags;
1134
981
  /** Event-driven forms (signal capture, CSAT, intake, consent…). Server-pushable. */
1135
982
  forms?: FormsOptions;
@@ -1256,7 +1103,7 @@ interface ResolvedOptions {
1256
1103
  onError?: ChatWidgetOptions["onError"];
1257
1104
  }
1258
1105
  /**
1259
- * Shape of the server-pushed `widget` object in `HandshakeResponse`.
1106
+ * Shape of the server-pushed `config` object in `HandshakeResponse`.
1260
1107
  *
1261
1108
  * Matches a subset of {@link ChatWidgetOptions} — anything the server can
1262
1109
  * reasonably dictate (UI, behaviour, routing). Callbacks (`onMessage` etc.)
@@ -1326,6 +1173,158 @@ interface LogEntry {
1326
1173
  payload?: unknown;
1327
1174
  }
1328
1175
  //#endregion
1176
+ //#region src/core/persistence.d.ts
1177
+ /** Drag-resized panel dimensions. Persisted only when resize is enabled. */
1178
+ interface WidgetSize {
1179
+ width: number;
1180
+ height: number;
1181
+ }
1182
+ /**
1183
+ * User-changeable preferences. Sent to the backend on every request as a
1184
+ * `userPrefs` field so the server can detect drift (e.g. user changed
1185
+ * locale on another tab) and reconcile.
1186
+ *
1187
+ * Every field is optional — an unset key inherits the server / page-owner
1188
+ * default. Empty object `{}` means "no preference recorded yet."
1189
+ */
1190
+ interface UserPrefs {
1191
+ /** BCP-47 tag picked from the language switcher. */
1192
+ locale?: string;
1193
+ /** Drag-resized panel dimensions. */
1194
+ widgetSize?: WidgetSize;
1195
+ /** Sound on/off toggle (icon button). */
1196
+ soundMuted?: boolean;
1197
+ /** Theme picked from the theme switcher. */
1198
+ themeMode?: "auto" | "light" | "dark";
1199
+ /** Text size picked from the text-size switcher. */
1200
+ textSize?: "small" | "normal" | "large";
1201
+ }
1202
+ //#endregion
1203
+ //#region src/stream/types.d.ts
1204
+ /** A 👍/👎 reaction on a rateable (assistant/operator) message; `null` clears a prior choice. */
1205
+ type FeedbackValue = "up" | "down" | null;
1206
+ //#endregion
1207
+ //#region src/stream/protocol.d.ts
1208
+ /**
1209
+ * Who is driving replies in a conversation — the widget mirrors the backend `controlMode`.
1210
+ * - `ai-agent`: the AI agent answers (normal operation).
1211
+ * - `awaiting_operator`: operator-control requested, the AI no longer answers — the turn routes to the
1212
+ * operator — while waiting in the operator queue.
1213
+ * - `operator`: a workspace operator took over and is replying.
1214
+ *
1215
+ * Carried on `HandshakeResponse.controlState`, `LoadConversationResponse.controlState` (resume +
1216
+ * history-switch), and the `data-control-state` stream part (on the reply stream). Absent / unknown →
1217
+ * treated as `"ai-agent"`.
1218
+ */
1219
+ type ControlMode = "ai-agent" | "awaiting_operator" | "operator";
1220
+ /**
1221
+ * The control-state snapshot the widget reads to render composer/typing/banner state. The optional
1222
+ * `operatorAvailable` (set on the operator-request response + the awaiting terminal part) tells the
1223
+ * widget whether to show "connecting…" or the async-capture ("leave your details") copy.
1224
+ */
1225
+ interface ControlState {
1226
+ controlMode: ControlMode;
1227
+ /** Monotonic state version: orders received snapshots and fences request/cancel retries to their observed cycle. */
1228
+ controlRevision?: number;
1229
+ /**
1230
+ * The operator's 2-letter initials (operator mode only) — shown in the bubble chrome + banner. The
1231
+ * visitor never sees the full name (privacy); the backend derives the initials. `assignedOperatorId`
1232
+ * also rides the wire but the widget doesn't render it, so it isn't modeled here.
1233
+ */
1234
+ assignedOperatorInitials?: string;
1235
+ /** Whether anyone was in the operator pool when operator-control was requested (awaiting mode advisory). */
1236
+ operatorAvailable?: boolean;
1237
+ }
1238
+ /** One-shot bot persona shown in the panel header. */
1239
+ interface ConversationAgent {
1240
+ name: string;
1241
+ /** Image URL or data URI. When omitted, initials render from `name`. */
1242
+ avatar?: string;
1243
+ /** Subtitle ("AI Assistant", "Support team", …). */
1244
+ title?: string;
1245
+ /** Presence indicator. Default: `'online'`. */
1246
+ status?: "online" | "away" | "offline";
1247
+ }
1248
+ /** A clickable quick-reply chip. */
1249
+ interface ConversationSuggestion {
1250
+ id: string;
1251
+ /** What the chip displays. */
1252
+ label: string;
1253
+ /** What actually gets sent when clicked. Defaults to `label`. */
1254
+ text?: string;
1255
+ }
1256
+ /** Welcome payload pushed into the message list on first open. */
1257
+ interface ConversationWelcome {
1258
+ messages?: Array<{
1259
+ id: string;
1260
+ role: "assistant" | "system";
1261
+ text: string;
1262
+ }>;
1263
+ suggestions?: ConversationSuggestion[];
1264
+ }
1265
+ /**
1266
+ * Response from `POST /pai/handshake` — the widget's one mount-time
1267
+ * round-trip. Deliberately LIGHT: identity + deployment surface only
1268
+ * (config, agent persona, welcome, page-mode site/blocks, userPrefs).
1269
+ * The conversation THREAD is a separate, lazily-fetched read
1270
+ * (`GET /conversation`) that only runs once the widget is activated
1271
+ * (opened) — a closed launcher costs the page exactly one request.
1272
+ *
1273
+ * The `userPrefs` field (when present) is the server's authoritative
1274
+ * copy of per-visitor preferences — the client should adopt it and update
1275
+ * its local cache. Lets a user picking French on their phone see the
1276
+ * widget in French when they open it on their laptop (assuming the same
1277
+ * `visitorId`, e.g. via authenticated conversation — out of scope for v1).
1278
+ */
1279
+ interface HandshakeResponse$1 {
1280
+ /**
1281
+ * Public runtime conversation id. The widget mints this UUIDv7 and the backend
1282
+ * validates that it belongs to the public deployment + visitor.
1283
+ */
1284
+ conversationId: string;
1285
+ visitorId?: string;
1286
+ /** Bot persona in the panel header (name, avatar, status). */
1287
+ agent?: ConversationAgent;
1288
+ /** Initial assistant messages + quick-reply chips. */
1289
+ welcome?: ConversationWelcome;
1290
+ /**
1291
+ * Deployment-wide widget configuration the dashboard admin saved
1292
+ * (mode / theme / launcher / actions / composer / features / …).
1293
+ * Client adopts as defaults; customer's `init({...})` still wins
1294
+ * per-field. Same for every visitor of this deployment.
1295
+ */
1296
+ config?: ServerConfig$1;
1297
+ /** Page-mode site config (logo, title). Backend ships it whenever the deployment renders the page-shell sidebar. */
1298
+ site?: Record<string, unknown>;
1299
+ /** Page-mode sidebar blocks (navigation, link cards). Backend ships it whenever the deployment renders the page-shell sidebar. */
1300
+ blocks?: Record<string, unknown>;
1301
+ /** Current control state — seeds the composer/typing/banner state on connect. Absent → `ai-agent`. */
1302
+ controlState?: ControlState;
1303
+ /**
1304
+ * Server's authoritative copy of the visitor's preferences. When present,
1305
+ * client adopts it (overrides local cache) and re-applies it to the UI
1306
+ * (locale, panel size, sound mute). Absent → client keeps its cache.
1307
+ */
1308
+ userPrefs?: UserPrefs;
1309
+ /**
1310
+ * Optional rebind metadata. When the server returns a `visitorId` /
1311
+ * `conversationId` different from what the client sent, this block tells
1312
+ * the client WHY — useful for telemetry and the `visitorRebound` /
1313
+ * `conversationRebound` events fired into the host page. Server is free to
1314
+ * omit it: the client detects rebinding by comparing request vs
1315
+ * response ids regardless.
1316
+ *
1317
+ * Common reasons: `"conflict"` (the id collided with an existing
1318
+ * record), `"expired"` (the id is too old to be re-used), `"invalid"`
1319
+ * (malformed / not a UUIDv7). Custom strings are passed through to
1320
+ * listeners verbatim.
1321
+ */
1322
+ rebind?: {
1323
+ visitorId?: string;
1324
+ conversationId?: string;
1325
+ };
1326
+ }
1327
+ //#endregion
1329
1328
  //#region src/core/events.d.ts
1330
1329
  /**
1331
1330
  * Payload shape per event. Keyed by event name; use `void` for events that
@@ -1779,10 +1778,6 @@ declare const widgetSettingsSchema: z.ZodObject<{
1779
1778
  server: "server";
1780
1779
  disabled: "disabled";
1781
1780
  }>>;
1782
- tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
1783
- code: z.ZodString;
1784
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1785
- }, z.core.$loose>]>>>;
1786
1781
  disableHumanInLoop: z.ZodDefault<z.ZodBoolean>;
1787
1782
  enableOperatorRequest: z.ZodDefault<z.ZodBoolean>;
1788
1783
  }, z.core.$loose>>;
@@ -1899,10 +1894,10 @@ declare const widgetSettingsSchema: z.ZodObject<{
1899
1894
  }, z.core.$loose>;
1900
1895
  type WidgetSettings = z.infer<typeof widgetSettingsSchema>;
1901
1896
  /**
1902
- * Full client widget config — connection + widget settings + page-mode
1903
- * extras. The dashboard / dev configurator typically only edits one
1904
- * of the two halves at a time (`widgetSettingsSchema` for the dashboard
1905
- * surface, `connectionConfigSchema` for the developer-facing fields).
1897
+ * Full tooling schema — connection + widget settings + page-mode
1898
+ * handshake extras. The dashboard / dev configurator typically only
1899
+ * edits one part at a time (`widgetSettingsSchema` for the dashboard
1900
+ * surface, `connectionConfigSchema` for developer-facing fields).
1906
1901
  */
1907
1902
  declare const widgetConfigSchema: z.ZodObject<{
1908
1903
  widgetId: z.ZodDefault<z.ZodString>;
@@ -2118,10 +2113,6 @@ declare const widgetConfigSchema: z.ZodObject<{
2118
2113
  server: "server";
2119
2114
  disabled: "disabled";
2120
2115
  }>>;
2121
- tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
2122
- code: z.ZodString;
2123
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2124
- }, z.core.$loose>]>>>;
2125
2116
  disableHumanInLoop: z.ZodDefault<z.ZodBoolean>;
2126
2117
  enableOperatorRequest: z.ZodDefault<z.ZodBoolean>;
2127
2118
  }, z.core.$loose>>;
@@ -2456,10 +2447,6 @@ declare const widgetConfigPartialSchema: z.ZodObject<{
2456
2447
  server: "server";
2457
2448
  disabled: "disabled";
2458
2449
  }>>;
2459
- tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
2460
- code: z.ZodString;
2461
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2462
- }, z.core.$loose>]>>>;
2463
2450
  disableHumanInLoop: z.ZodDefault<z.ZodBoolean>;
2464
2451
  enableOperatorRequest: z.ZodDefault<z.ZodBoolean>;
2465
2452
  }, z.core.$loose>>>;
@@ -2754,10 +2741,6 @@ declare const widgetSettingsPartialSchema: z.ZodObject<{
2754
2741
  server: "server";
2755
2742
  disabled: "disabled";
2756
2743
  }>>;
2757
- tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
2758
- code: z.ZodString;
2759
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2760
- }, z.core.$loose>]>>>;
2761
2744
  disableHumanInLoop: z.ZodDefault<z.ZodBoolean>;
2762
2745
  enableOperatorRequest: z.ZodDefault<z.ZodBoolean>;
2763
2746
  }, z.core.$loose>>>;
@@ -2914,9 +2897,10 @@ type ConnectionConfigPartial = z.infer<typeof connectionConfigPartialSchema>;
2914
2897
  /**
2915
2898
  * Server-pushable widget settings. Same surface as the editable
2916
2899
  * {@link widgetSettingsSchema} but every field is optional (the server
2917
- * pushes patches, not full configs). Connection fields (publicKey,
2918
- * aiAgentDeploymentId, baseUrl, user, iframe) are deliberately
2919
- * excluded — those are client concerns.
2900
+ * pushes patches, not full configs). Embed identity, host context,
2901
+ * the agent endpoint, storage, and callbacks are deliberately excluded
2902
+ * because they are client concerns. `presentation.iframe` remains a
2903
+ * server-pushable widget setting.
2920
2904
  *
2921
2905
  * Two deltas vs the editable surface:
2922
2906
  * - `forms` is omitted — resolved form definitions are served by the
@@ -3109,10 +3093,6 @@ declare const serverConfigSchema: z.ZodObject<{
3109
3093
  server: "server";
3110
3094
  disabled: "disabled";
3111
3095
  }>>;
3112
- tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
3113
- code: z.ZodString;
3114
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
3115
- }, z.core.$loose>]>>>;
3116
3096
  disableHumanInLoop: z.ZodDefault<z.ZodBoolean>;
3117
3097
  enableOperatorRequest: z.ZodDefault<z.ZodBoolean>;
3118
3098
  }, z.core.$loose>>>;
@@ -3399,10 +3379,6 @@ declare const handshakeResponseSchema: z.ZodObject<{
3399
3379
  server: "server";
3400
3380
  disabled: "disabled";
3401
3381
  }>>;
3402
- tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
3403
- code: z.ZodString;
3404
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
3405
- }, z.core.$loose>]>>>;
3406
3382
  disableHumanInLoop: z.ZodDefault<z.ZodBoolean>;
3407
3383
  enableOperatorRequest: z.ZodDefault<z.ZodBoolean>;
3408
3384
  }, z.core.$loose>>>;
@@ -3593,7 +3569,7 @@ interface ChatWidgetInstance {
3593
3569
  *
3594
3570
  * @example Single widget (default):
3595
3571
  * ```ts
3596
- * mount({ publicKey, mode: 'inline', target: document.getElementById('chat') });
3572
+ * mount({ publicKey, presentation: { mode: 'inline' }, target: document.getElementById('chat') });
3597
3573
  * ```
3598
3574
  * @example Two widgets on one page:
3599
3575
  * ```ts