@smooai/chat-widget 0.10.1 → 0.11.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/README.md +4 -0
- package/dist/chat-widget.global.js +72 -5
- package/dist/chat-widget.global.js.map +1 -1
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +72 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +14 -0
- package/src/conversation.ts +26 -0
- package/src/element.ts +64 -4
- package/src/styles.ts +8 -1
package/dist/index.d.ts
CHANGED
|
@@ -88,11 +88,23 @@ interface ChatWidgetConfig {
|
|
|
88
88
|
connectionErrorMessage?: string;
|
|
89
89
|
/** Start the panel open instead of collapsed to the launcher. */
|
|
90
90
|
startOpen?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Hide the "powered by smooth-operator" branding in the header tag and the
|
|
93
|
+
* composer footer. Defaults to `false` (branding shown). The `hide-branding`
|
|
94
|
+
* HTML attribute maps to this.
|
|
95
|
+
*/
|
|
96
|
+
hideBranding?: boolean;
|
|
91
97
|
/**
|
|
92
98
|
* Suggested starter prompts shown as clickable chips before the first message.
|
|
93
99
|
* Clicking one sends it. Capped at 5 for layout.
|
|
94
100
|
*/
|
|
95
101
|
examplePrompts?: string[];
|
|
102
|
+
/**
|
|
103
|
+
* Show mid-conversation suggested-reply chips ("quick replies") under the
|
|
104
|
+
* latest assistant message when the agent returns follow-up suggestions.
|
|
105
|
+
* Clicking one sends it. Defaults to `true` (shown unless explicitly `false`).
|
|
106
|
+
*/
|
|
107
|
+
showSuggestedReplies?: boolean;
|
|
96
108
|
/** Require the visitor's name before chatting. */
|
|
97
109
|
requireName?: boolean;
|
|
98
110
|
/** Require the visitor's email before chatting. */
|
|
@@ -143,6 +155,8 @@ declare class SmoothAgentChatElement extends HTMLElement {
|
|
|
143
155
|
private hasSent;
|
|
144
156
|
/** Starter prompts shown as chips in the empty state. */
|
|
145
157
|
private examplePrompts;
|
|
158
|
+
/** Whether mid-conversation suggested-reply chips are shown (config). */
|
|
159
|
+
private showSuggestedReplies;
|
|
146
160
|
/** Resolved greeting text, cached so async (rAF) renders can reuse it. */
|
|
147
161
|
private greeting;
|
|
148
162
|
/** Current mid-turn interrupt (OTP / tool-confirmation), or null. */
|
|
@@ -161,6 +175,7 @@ declare class SmoothAgentChatElement extends HTMLElement {
|
|
|
161
175
|
private dotEl;
|
|
162
176
|
private inputEl;
|
|
163
177
|
private sendBtn;
|
|
178
|
+
private suggestionsEl;
|
|
164
179
|
/** The live streaming assistant bubble whose textContent the rAF loop drives. */
|
|
165
180
|
private streamBubbleEl;
|
|
166
181
|
/** Message id the reveal is bound to (guards against stale frames after rebuilds). */
|
|
@@ -234,6 +249,16 @@ declare class SmoothAgentChatElement extends HTMLElement {
|
|
|
234
249
|
*/
|
|
235
250
|
private handleMessages;
|
|
236
251
|
private renderMessages;
|
|
252
|
+
/**
|
|
253
|
+
* Render (or clear) the mid-conversation suggested-reply chips under the
|
|
254
|
+
* composer. Shown ONLY when: the feature is enabled, no interrupt / restore
|
|
255
|
+
* overlay is active (those reuse the slot above the composer), and the LATEST
|
|
256
|
+
* message is a finalized assistant turn that carried suggestions. A new turn
|
|
257
|
+
* (agent or the visitor typing) appends messages, so the latest is no longer
|
|
258
|
+
* that assistant message and the chips clear on the next render. Chips reuse
|
|
259
|
+
* the empty-state `.prompts`/`.chip` styling and send via the same path.
|
|
260
|
+
*/
|
|
261
|
+
private renderSuggestions;
|
|
237
262
|
/** True when the host/user prefers reduced motion (snap, no typewriter). */
|
|
238
263
|
private prefersReducedMotion;
|
|
239
264
|
/**
|
|
@@ -444,6 +469,13 @@ interface ChatMessage {
|
|
|
444
469
|
* defensively off the terminal event — see {@link extractCitations}.
|
|
445
470
|
*/
|
|
446
471
|
citations?: Citation[];
|
|
472
|
+
/**
|
|
473
|
+
* Suggested follow-up replies ("quick replies") the agent offered on the
|
|
474
|
+
* terminal `eventual_response`. Set ONLY on the finalized assistant message —
|
|
475
|
+
* never mid-stream. Read defensively (see {@link extractSuggestions}); capped
|
|
476
|
+
* at 4 for layout. Absent when the turn offered none.
|
|
477
|
+
*/
|
|
478
|
+
suggestions?: string[];
|
|
447
479
|
}
|
|
448
480
|
type ConnectionStatus = 'idle' | 'connecting' | 'ready' | 'error' | 'closed';
|
|
449
481
|
/**
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/element.ts","../src/loader-core.ts","../src/persistence.ts","../src/conversation.ts","../src/fingerprint.ts"],"mappings":";;;;UASiB,eAAA;;EAEb,IAAA;;EAEA,UAAA;EAJ4B;EAM5B,OAAA;EAN4B;EAQ5B,WAAA;EAJA;EAMA,SAAA;EAFA;EAIA,eAAA;EAAA;EAEA,mBAAA;EAEA;EAAA,UAAA;EAIA;EAFA,cAAA;EAUA;EARA,MAAA;EAYA;EANA,iBAAA;EAMsB;EAJtB,qBAAA;EAesB;EAbtB,kBAAA;EAasB;EAXtB,sBAAA;AAAA;;;;;;;;;KAWQ,cAAA;AAAA,UAEK,gBAAA;EAyBb;;;;EApBA,QAAA;EA6BmD;;;;EAxBnD,IAAA,GAAO,cAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/element.ts","../src/loader-core.ts","../src/persistence.ts","../src/conversation.ts","../src/fingerprint.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -332,7 +332,9 @@ function resolveConfig(config) {
|
|
|
332
332
|
greeting: config.greeting ?? "Hi! How can I help you today?",
|
|
333
333
|
connectionErrorMessage: config.connectionErrorMessage ?? "We couldn't reach the chat. Please try again in a moment.",
|
|
334
334
|
startOpen: config.startOpen ?? false,
|
|
335
|
+
hideBranding: config.hideBranding ?? false,
|
|
335
336
|
examplePrompts: (config.examplePrompts ?? []).filter((p) => p.trim().length > 0).slice(0, 5),
|
|
337
|
+
showSuggestedReplies: config.showSuggestedReplies ?? true,
|
|
336
338
|
requireName: config.requireName ?? false,
|
|
337
339
|
requireEmail: config.requireEmail ?? false,
|
|
338
340
|
requirePhone: config.requirePhone ?? false,
|
|
@@ -773,6 +775,19 @@ function extractCitations(inner) {
|
|
|
773
775
|
}
|
|
774
776
|
return out;
|
|
775
777
|
}
|
|
778
|
+
/**
|
|
779
|
+
* Pull the suggested follow-up replies out of a terminal `eventual_response`'s
|
|
780
|
+
* `response` object (`response.suggestedNextActions`). Optional + back-compatible
|
|
781
|
+
* like citations — read defensively (tolerating absence, non-array shapes, and
|
|
782
|
+
* non-string / blank entries) and capped at 4 so a chatty agent can't overflow
|
|
783
|
+
* the composer chip row.
|
|
784
|
+
*/
|
|
785
|
+
function extractSuggestions(response) {
|
|
786
|
+
if (!response || typeof response !== "object") return [];
|
|
787
|
+
const raw = response.suggestedNextActions;
|
|
788
|
+
if (!Array.isArray(raw)) return [];
|
|
789
|
+
return raw.filter((s) => typeof s === "string" && s.trim().length > 0).slice(0, 4);
|
|
790
|
+
}
|
|
776
791
|
/** Convert a server message row into a finalized {@link ChatMessage}. */
|
|
777
792
|
function wireMessageToChat(m, idx) {
|
|
778
793
|
const text = typeof m.content?.text === "string" ? m.content.text : "";
|
|
@@ -1123,6 +1138,8 @@ var ConversationController = class {
|
|
|
1123
1138
|
if (!assistant.text) assistant.text = "(no response)";
|
|
1124
1139
|
const citations = extractCitations(inner);
|
|
1125
1140
|
if (citations.length > 0) assistant.citations = citations;
|
|
1141
|
+
const suggestions = extractSuggestions(inner?.response);
|
|
1142
|
+
if (suggestions.length > 0) assistant.suggestions = suggestions;
|
|
1126
1143
|
assistant.streaming = false;
|
|
1127
1144
|
this.emitMessages();
|
|
1128
1145
|
} catch (err) {
|
|
@@ -1587,7 +1604,8 @@ ${mode === "fullpage" ? `
|
|
|
1587
1604
|
}
|
|
1588
1605
|
.close:hover { background: color-mix(in srgb, var(--sac-text) 12%, transparent); transform: translateY(1px); }
|
|
1589
1606
|
.close svg { width: 16px; height: 16px; opacity: .8; }
|
|
1590
|
-
.powered { margin-left: auto; font-size: 10.5px; letter-spacing: .02em; opacity: .6; }
|
|
1607
|
+
.powered { margin-left: auto; font-size: 10.5px; letter-spacing: .02em; opacity: .6; color: inherit; text-decoration: none; }
|
|
1608
|
+
.powered:hover { opacity: .85; text-decoration: underline; }
|
|
1591
1609
|
.header-sep { height: 1px; margin: 0 16px; background: linear-gradient(90deg, transparent, var(--sac-border), transparent); }
|
|
1592
1610
|
|
|
1593
1611
|
/* Full-page header: taller, logo-led, no close. */
|
|
@@ -1859,6 +1877,8 @@ ${mode === "fullpage" ? `
|
|
|
1859
1877
|
color: color-mix(in srgb, var(--sac-text) 38%, transparent);
|
|
1860
1878
|
}
|
|
1861
1879
|
.footer b { font-weight: 600; color: color-mix(in srgb, var(--sac-text) 55%, transparent); }
|
|
1880
|
+
.footer a { color: inherit; text-decoration: none; }
|
|
1881
|
+
.footer a:hover { text-decoration: underline; }
|
|
1862
1882
|
|
|
1863
1883
|
/* ─────────────────── Pre-chat identity form ───────────────────────── */
|
|
1864
1884
|
.prechat { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 18px; padding: 22px 20px; }
|
|
@@ -1950,6 +1970,10 @@ ${mode === "fullpage" ? `
|
|
|
1950
1970
|
transform: translateY(-1px);
|
|
1951
1971
|
}
|
|
1952
1972
|
|
|
1973
|
+
/* ───────────── Mid-conversation suggested-reply chips ─────────────── */
|
|
1974
|
+
.reply-suggestions { padding: 0 14px 4px; }
|
|
1975
|
+
.reply-suggestions:empty { display: none; }
|
|
1976
|
+
|
|
1953
1977
|
/* ─────────────── OTP / tool-confirmation interrupt ────────────────── */
|
|
1954
1978
|
.interrupt { padding: 0 14px; }
|
|
1955
1979
|
.int-card {
|
|
@@ -2112,6 +2136,8 @@ function phoneToE164(value) {
|
|
|
2112
2136
|
return null;
|
|
2113
2137
|
}
|
|
2114
2138
|
}
|
|
2139
|
+
/** Public smooth-operator repo — the "powered by" header tag + footer link here. */
|
|
2140
|
+
const SMOOTH_OPERATOR_URL = "https://github.com/SmooAI/smooth-operator";
|
|
2115
2141
|
const OBSERVED = [
|
|
2116
2142
|
"endpoint",
|
|
2117
2143
|
"agent-id",
|
|
@@ -2120,7 +2146,8 @@ const OBSERVED = [
|
|
|
2120
2146
|
"placeholder",
|
|
2121
2147
|
"greeting",
|
|
2122
2148
|
"start-open",
|
|
2123
|
-
"mode"
|
|
2149
|
+
"mode",
|
|
2150
|
+
"hide-branding"
|
|
2124
2151
|
];
|
|
2125
2152
|
/**
|
|
2126
2153
|
* Inline SVG icons (static, trusted strings — never interpolated with user data).
|
|
@@ -2158,6 +2185,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2158
2185
|
_defineProperty(this, "userInfoSatisfied", false);
|
|
2159
2186
|
_defineProperty(this, "hasSent", false);
|
|
2160
2187
|
_defineProperty(this, "examplePrompts", []);
|
|
2188
|
+
_defineProperty(this, "showSuggestedReplies", true);
|
|
2161
2189
|
_defineProperty(this, "greeting", "");
|
|
2162
2190
|
_defineProperty(this, "interrupt", null);
|
|
2163
2191
|
_defineProperty(this, "interruptEl", null);
|
|
@@ -2171,6 +2199,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2171
2199
|
_defineProperty(this, "dotEl", null);
|
|
2172
2200
|
_defineProperty(this, "inputEl", null);
|
|
2173
2201
|
_defineProperty(this, "sendBtn", null);
|
|
2202
|
+
_defineProperty(this, "suggestionsEl", null);
|
|
2174
2203
|
_defineProperty(this, "streamBubbleEl", null);
|
|
2175
2204
|
_defineProperty(this, "streamMsgId", null);
|
|
2176
2205
|
_defineProperty(this, "streamTarget", "");
|
|
@@ -2237,7 +2266,9 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2237
2266
|
greeting: this.overrides.greeting ?? this.getAttribute("greeting") ?? void 0,
|
|
2238
2267
|
connectionErrorMessage: this.overrides.connectionErrorMessage,
|
|
2239
2268
|
startOpen: this.overrides.startOpen ?? this.hasAttribute("start-open"),
|
|
2269
|
+
hideBranding: this.overrides.hideBranding ?? this.hasAttribute("hide-branding"),
|
|
2240
2270
|
examplePrompts: this.overrides.examplePrompts,
|
|
2271
|
+
showSuggestedReplies: this.overrides.showSuggestedReplies,
|
|
2241
2272
|
requireName: this.overrides.requireName,
|
|
2242
2273
|
requireEmail: this.overrides.requireEmail,
|
|
2243
2274
|
requirePhone: this.overrides.requirePhone,
|
|
@@ -2269,10 +2300,12 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2269
2300
|
onInterrupt: (interrupt) => {
|
|
2270
2301
|
this.interrupt = interrupt;
|
|
2271
2302
|
this.renderInterrupt();
|
|
2303
|
+
this.renderSuggestions();
|
|
2272
2304
|
},
|
|
2273
2305
|
onIdentityRestore: (state) => {
|
|
2274
2306
|
this.identityRestore = state;
|
|
2275
2307
|
this.renderInterrupt();
|
|
2308
|
+
this.renderSuggestions();
|
|
2276
2309
|
}
|
|
2277
2310
|
});
|
|
2278
2311
|
if (resolved.startOpen) this.open = true;
|
|
@@ -2290,7 +2323,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2290
2323
|
<span class="title">${escapeHtml(resolved.agentName)}</span>
|
|
2291
2324
|
<span class="status"><span class="dot off"></span><span class="status-text"></span></span>
|
|
2292
2325
|
</div>
|
|
2293
|
-
|
|
2326
|
+
${resolved.hideBranding ? "" : `<a class="powered" href="${SMOOTH_OPERATOR_URL}" target="_blank" rel="noopener noreferrer">powered by smooth-operator</a>`}
|
|
2294
2327
|
</div>` : `<div class="header">
|
|
2295
2328
|
<div class="avatar">${monogram}</div>
|
|
2296
2329
|
<div class="meta">
|
|
@@ -2300,6 +2333,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2300
2333
|
<button class="close" aria-label="Close chat">${ICON.close}</button>
|
|
2301
2334
|
</div>`;
|
|
2302
2335
|
this.examplePrompts = resolved.examplePrompts;
|
|
2336
|
+
this.showSuggestedReplies = resolved.showSuggestedReplies;
|
|
2303
2337
|
this.greeting = resolved.greeting;
|
|
2304
2338
|
const gating = needsUserInfo(resolved) && !this.userInfoSatisfied;
|
|
2305
2339
|
this.gating = gating;
|
|
@@ -2324,16 +2358,18 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2324
2358
|
<button type="submit" class="pc-submit">Start chat</button>
|
|
2325
2359
|
</form>
|
|
2326
2360
|
</div>`;
|
|
2327
|
-
const
|
|
2361
|
+
const footerInner = [resolved.hideBranding ? "" : `<a href="${SMOOTH_OPERATOR_URL}" target="_blank" rel="noopener noreferrer">powered by <b>smooth‑operator</b></a>`, this.allowChatRestore ? `<button type="button" class="restore-link">Restore my chats</button>` : ""].filter(Boolean).join(" · ");
|
|
2362
|
+
const footerHtml = footerInner ? `<div class="footer">${footerInner}</div>` : "";
|
|
2328
2363
|
const chatHtml = `
|
|
2329
2364
|
<div class="messages"></div>
|
|
2365
|
+
<div class="reply-suggestions"></div>
|
|
2330
2366
|
<div class="interrupt hidden"></div>
|
|
2331
2367
|
<div class="composer-wrap">
|
|
2332
2368
|
<div class="composer">
|
|
2333
2369
|
<textarea rows="1" placeholder="${escapeHtml(resolved.placeholder)}"></textarea>
|
|
2334
2370
|
<button class="send" type="button" aria-label="Send message">${ICON.send}</button>
|
|
2335
2371
|
</div>
|
|
2336
|
-
|
|
2372
|
+
${footerHtml}
|
|
2337
2373
|
</div>`;
|
|
2338
2374
|
const container = document.createElement("div");
|
|
2339
2375
|
container.className = "wrap";
|
|
@@ -2357,6 +2393,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2357
2393
|
this.inputEl = container.querySelector("textarea");
|
|
2358
2394
|
this.sendBtn = container.querySelector(".send");
|
|
2359
2395
|
this.interruptEl = container.querySelector(".interrupt");
|
|
2396
|
+
this.suggestionsEl = container.querySelector(".reply-suggestions");
|
|
2360
2397
|
this.launcherEl?.addEventListener("click", () => this.openChat());
|
|
2361
2398
|
container.querySelector(".close")?.addEventListener("click", () => this.closeChat());
|
|
2362
2399
|
this.sendBtn?.addEventListener("click", () => this.submit());
|
|
@@ -2811,6 +2848,36 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2811
2848
|
if (msg.role === "assistant" && !msg.streaming && msg.citations && msg.citations.length > 0) this.messagesEl.appendChild(this.renderSources(msg.citations));
|
|
2812
2849
|
}
|
|
2813
2850
|
this.scrollToBottom(true);
|
|
2851
|
+
this.renderSuggestions();
|
|
2852
|
+
}
|
|
2853
|
+
/**
|
|
2854
|
+
* Render (or clear) the mid-conversation suggested-reply chips under the
|
|
2855
|
+
* composer. Shown ONLY when: the feature is enabled, no interrupt / restore
|
|
2856
|
+
* overlay is active (those reuse the slot above the composer), and the LATEST
|
|
2857
|
+
* message is a finalized assistant turn that carried suggestions. A new turn
|
|
2858
|
+
* (agent or the visitor typing) appends messages, so the latest is no longer
|
|
2859
|
+
* that assistant message and the chips clear on the next render. Chips reuse
|
|
2860
|
+
* the empty-state `.prompts`/`.chip` styling and send via the same path.
|
|
2861
|
+
*/
|
|
2862
|
+
renderSuggestions() {
|
|
2863
|
+
const el = this.suggestionsEl;
|
|
2864
|
+
if (!el) return;
|
|
2865
|
+
el.replaceChildren();
|
|
2866
|
+
if (!this.showSuggestedReplies) return;
|
|
2867
|
+
if (this.interrupt || this.identityRestore.phase !== "idle") return;
|
|
2868
|
+
const last = this.messages[this.messages.length - 1];
|
|
2869
|
+
if (!last || last.role !== "assistant" || last.streaming || !last.suggestions || last.suggestions.length === 0) return;
|
|
2870
|
+
const chips = document.createElement("div");
|
|
2871
|
+
chips.className = "prompts";
|
|
2872
|
+
for (const suggestion of last.suggestions) {
|
|
2873
|
+
const chip = document.createElement("button");
|
|
2874
|
+
chip.type = "button";
|
|
2875
|
+
chip.className = "chip";
|
|
2876
|
+
chip.textContent = suggestion;
|
|
2877
|
+
chip.addEventListener("click", () => this.submitPrompt(suggestion));
|
|
2878
|
+
chips.appendChild(chip);
|
|
2879
|
+
}
|
|
2880
|
+
el.appendChild(chips);
|
|
2814
2881
|
}
|
|
2815
2882
|
/** True when the host/user prefers reduced motion (snap, no typewriter). */
|
|
2816
2883
|
prefersReducedMotion() {
|