@eshal-bot/chat-widget 0.2.54 → 0.2.56
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/{chat-widget-MarkdownRenderer-D4fhjH4t.esm.js → chat-widget-MarkdownRenderer-Bc2bbcTo.esm.js} +6 -6
- package/dist/{chat-widget-index-C0VY-3ea.esm.js → chat-widget-index-dlp0htSy.esm.js} +4 -4
- package/dist/chat-widget-markdown-chunk.js +419 -0
- package/dist/chat-widget-markdown-chunk.min.js +1 -1
- package/dist/chat-widget.esm.js +1 -1
- package/dist/chat-widget.js +127 -10
- package/dist/chat-widget.min.js +6 -6
- package/dist/chat-widget.umd.js +8 -8
- package/package.json +1 -1
package/dist/chat-widget.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{S as default}from"./chat-widget-index-
|
|
1
|
+
export{S as default}from"./chat-widget-index-dlp0htSy.esm.js";import"react";import"react-dom/client";import"react/jsx-runtime";import"react-dom";
|
package/dist/chat-widget.js
CHANGED
|
@@ -13640,6 +13640,32 @@
|
|
|
13640
13640
|
}
|
|
13641
13641
|
const VERIFY_CARD = /"type"\s*:\s*"verification"/;
|
|
13642
13642
|
|
|
13643
|
+
/**
|
|
13644
|
+
* What the caller said after the answer that carried the card on screen, or
|
|
13645
|
+
* undefined while nothing has followed it. The call screen redraws its card
|
|
13646
|
+
* on every new line, so a card cannot keep its own "picked" state: an option
|
|
13647
|
+
* list tapped once came back live, ready for a second pick, until the agent's
|
|
13648
|
+
* next answer replaced it. Read from the lines, as the chat reads it from
|
|
13649
|
+
* history (MessageList), it locks the card on the caller's answer, tapped or
|
|
13650
|
+
* said. A verify card is left out: it stays live while the caller talks, until
|
|
13651
|
+
* its code is confirmed (waitsForCode).
|
|
13652
|
+
*/
|
|
13653
|
+
function voiceCardAnswer(lines) {
|
|
13654
|
+
let at = -1;
|
|
13655
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
13656
|
+
if (lines[i].role === "assistant" && lines[i].a2ui) {
|
|
13657
|
+
at = i;
|
|
13658
|
+
break;
|
|
13659
|
+
}
|
|
13660
|
+
}
|
|
13661
|
+
if (at === -1 || VERIFY_CARD.test(lines[at].a2ui)) return undefined;
|
|
13662
|
+
for (let i = at + 1; i < lines.length; i++) {
|
|
13663
|
+
const line = lines[i];
|
|
13664
|
+
if (line.role === "user" && !line.sendFailed && String(line.content || "").trim()) return String(line.content);
|
|
13665
|
+
}
|
|
13666
|
+
return undefined;
|
|
13667
|
+
}
|
|
13668
|
+
|
|
13643
13669
|
/** A verification code card (VerifyCard) whose code is not confirmed yet. */
|
|
13644
13670
|
function waitsForCode(line) {
|
|
13645
13671
|
return Boolean(line?.a2ui && VERIFY_CARD.test(line.a2ui) && !line.cardDone);
|
|
@@ -13743,7 +13769,8 @@
|
|
|
13743
13769
|
* Inbox (contentType human_reply, handoff_ack), the away and holding lines
|
|
13744
13770
|
* sent while the visitor waits for a person (handoff_wait, EV-4803; backend
|
|
13745
13771
|
* services/widgetHandoffLines.ts), the code card an agent sends with Request
|
|
13746
|
-
* verification (verification_request; backend services/verificationRequest.ts)
|
|
13772
|
+
* verification (verification_request; backend services/verificationRequest.ts),
|
|
13773
|
+
* a payment's outcome (payment_status; backend services/paymentEvents.ts)
|
|
13747
13774
|
* and a Skill's reply to a staff
|
|
13748
13775
|
* turn (staffTurn: Instruct Skill, or a hand-back that resumes the Skill;
|
|
13749
13776
|
* backend services/staffTurn.ts). Dev, 15 Oct 2026: a Skill reply sent while
|
|
@@ -13751,7 +13778,7 @@
|
|
|
13751
13778
|
* replies were merged. Mirrors packages/frontend/src/lib/messages/repliedOutsideStream.ts.
|
|
13752
13779
|
*/
|
|
13753
13780
|
function isRepliedOutsideStream(m) {
|
|
13754
|
-
return m?.contentType === 'human_reply' || m?.contentType === 'handoff_ack' || m?.contentType === 'handoff_wait' || m?.contentType === 'verification_request' || m?.staffTurn === true;
|
|
13781
|
+
return m?.contentType === 'human_reply' || m?.contentType === 'handoff_ack' || m?.contentType === 'handoff_wait' || m?.contentType === 'verification_request' || m?.contentType === 'payment_status' || m?.staffTurn === true;
|
|
13755
13782
|
}
|
|
13756
13783
|
|
|
13757
13784
|
/**
|
|
@@ -13763,6 +13790,84 @@
|
|
|
13763
13790
|
return m?.responder === 'ai' || m?.responder === 'human' ? m.responder : null;
|
|
13764
13791
|
}
|
|
13765
13792
|
|
|
13793
|
+
/**
|
|
13794
|
+
* Whether an agent reply put a payment link on the screen.
|
|
13795
|
+
*
|
|
13796
|
+
* Dev, 13 Nov 2026, Aurelia Airways: the agent held a booking and put the
|
|
13797
|
+
* secure payment link on the screen; the customer paid, and heard nothing until
|
|
13798
|
+
* they asked. A payment's outcome now reaches the conversation's event stream
|
|
13799
|
+
* (backend services/paymentEvents.ts, contentType payment_status). The widget
|
|
13800
|
+
* listens to that stream only once a person has the chat, so while a reply's
|
|
13801
|
+
* payment link is open it listens too, and the outcome shows the moment it
|
|
13802
|
+
* lands.
|
|
13803
|
+
*
|
|
13804
|
+
* The link rides an `eshal-ui` card the Skill writes: an action whose value is
|
|
13805
|
+
* the address ("Go to checkout", a Shopify cart; "Pay securely", a checkout
|
|
13806
|
+
* page). Mirrors services/voice-runtime/voice_runtime/payment_link.py `find`.
|
|
13807
|
+
*/
|
|
13808
|
+
|
|
13809
|
+
const FENCE = /```eshal-ui\s*([\s\S]*?)```/g;
|
|
13810
|
+
const PAY_WORDS = /\b(pay|pay now|payment|checkout|check out|purchase|complete (?:the )?(?:booking|order|purchase)|secure (?:payment|checkout)|place (?:the )?order)\b/i;
|
|
13811
|
+
const PAY_PATH = /(?:^|[/._?=&-])(pay|payment|payments|checkout|checkouts|cart|invoice)(?:$|[/._?=&-])/i;
|
|
13812
|
+
function cardsIn(content) {
|
|
13813
|
+
const cards = [];
|
|
13814
|
+
if (typeof content !== 'string' || !content.includes('eshal-ui')) return cards;
|
|
13815
|
+
for (const match of content.matchAll(FENCE)) {
|
|
13816
|
+
try {
|
|
13817
|
+
const parsed = JSON.parse(match[1].trim());
|
|
13818
|
+
if (Array.isArray(parsed)) cards.push(...parsed.filter(c => c && typeof c === 'object'));else if (parsed && typeof parsed === 'object') cards.push(parsed);
|
|
13819
|
+
} catch {
|
|
13820
|
+
/* not a card */
|
|
13821
|
+
}
|
|
13822
|
+
}
|
|
13823
|
+
return cards;
|
|
13824
|
+
}
|
|
13825
|
+
function actionsOf(card) {
|
|
13826
|
+
const own = Array.isArray(card.actions) ? card.actions.filter(a => a && typeof a === 'object') : [];
|
|
13827
|
+
const children = Array.isArray(card.children) ? card.children : Array.isArray(card.items) ? card.items : [];
|
|
13828
|
+
return own.concat(...children.filter(c => c && typeof c === 'object').map(actionsOf));
|
|
13829
|
+
}
|
|
13830
|
+
function addressOf(action) {
|
|
13831
|
+
for (const key of ['value', 'url', 'href', 'link']) {
|
|
13832
|
+
const v = action[key];
|
|
13833
|
+
if (typeof v === 'string' && /^https?:\/\//.test(v)) return v;
|
|
13834
|
+
}
|
|
13835
|
+
return null;
|
|
13836
|
+
}
|
|
13837
|
+
|
|
13838
|
+
/** True when the reply's text carries a card with a payment link. */
|
|
13839
|
+
function hasPaymentLink(content) {
|
|
13840
|
+
for (const card of cardsIn(content)) {
|
|
13841
|
+
const title = String(card.title || '');
|
|
13842
|
+
for (const action of actionsOf(card)) {
|
|
13843
|
+
const url = addressOf(action);
|
|
13844
|
+
if (!url) continue;
|
|
13845
|
+
let path = '';
|
|
13846
|
+
try {
|
|
13847
|
+
const u = new URL(url);
|
|
13848
|
+
path = `${u.pathname}?${u.search.replace(/^\?/, '')}`;
|
|
13849
|
+
} catch {
|
|
13850
|
+
continue;
|
|
13851
|
+
}
|
|
13852
|
+
if (PAY_WORDS.test(String(action.label || '')) || PAY_WORDS.test(title) || PAY_PATH.test(path)) return true;
|
|
13853
|
+
}
|
|
13854
|
+
}
|
|
13855
|
+
return false;
|
|
13856
|
+
}
|
|
13857
|
+
|
|
13858
|
+
/** True when the newest agent reply in the transcript put a payment link on the screen. */
|
|
13859
|
+
function awaitsPayment(messages) {
|
|
13860
|
+
if (!Array.isArray(messages)) return false;
|
|
13861
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
13862
|
+
const m = messages[i];
|
|
13863
|
+
if (m?.role !== 'assistant') continue;
|
|
13864
|
+
if (m?.metadata?.contentType === 'payment_status') return false; // the outcome is in
|
|
13865
|
+
if (m?.isProcessing) continue;
|
|
13866
|
+
return hasPaymentLink(m.content);
|
|
13867
|
+
}
|
|
13868
|
+
return false;
|
|
13869
|
+
}
|
|
13870
|
+
|
|
13766
13871
|
// EV-4048: human-agent identification in the widget transcript.
|
|
13767
13872
|
//
|
|
13768
13873
|
// A message pushed by a human agent (inbox reply / takeover) carries
|
|
@@ -15058,6 +15163,14 @@
|
|
|
15058
15163
|
}
|
|
15059
15164
|
};
|
|
15060
15165
|
}, []);
|
|
15166
|
+
|
|
15167
|
+
// A reply's payment link is open: the conversation's stream is read for the
|
|
15168
|
+
// payment's outcome, so it shows the moment it lands (lib/paymentLink.js;
|
|
15169
|
+
// backend services/paymentEvents.ts). Dev, 13 Nov 2026, Aurelia: the customer
|
|
15170
|
+
// paid and was told only once they asked.
|
|
15171
|
+
reactExports.useEffect(() => {
|
|
15172
|
+
if (awaitsPayment(messages)) void startHandoffEventSource();
|
|
15173
|
+
}, [messages, startHandoffEventSource]);
|
|
15061
15174
|
const websocketUrl = reactExports.useMemo(() => {
|
|
15062
15175
|
if (!organizationId) return null;
|
|
15063
15176
|
const resolvedWsBaseUrl = getWebSocketUrl(apiBaseUrl, wsBaseUrl);
|
|
@@ -23780,6 +23893,7 @@
|
|
|
23780
23893
|
const lastAgent = latestLine(lines, "agent");
|
|
23781
23894
|
const lastCaller = latestLine(lines, "user");
|
|
23782
23895
|
const card = latestVoiceCard(lines);
|
|
23896
|
+
const cardAnswer = voiceCardAnswer(lines);
|
|
23783
23897
|
reactExports.useEffect(() => {
|
|
23784
23898
|
const el = scrollRef.current;
|
|
23785
23899
|
if (el) el.scrollTop = el.scrollHeight;
|
|
@@ -23851,13 +23965,16 @@
|
|
|
23851
23965
|
children: /*#__PURE__*/jsxRuntimeExports.jsx(CardBoundary, {
|
|
23852
23966
|
children: /*#__PURE__*/jsxRuntimeExports.jsx(reactExports.Suspense, {
|
|
23853
23967
|
fallback: null,
|
|
23854
|
-
children: /*#__PURE__*/jsxRuntimeExports.jsx(
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
|
|
23858
|
-
|
|
23859
|
-
|
|
23860
|
-
|
|
23968
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx(A2uiAnsweredContext.Provider, {
|
|
23969
|
+
value: cardAnswer,
|
|
23970
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx(MarkdownRenderer, {
|
|
23971
|
+
content: card,
|
|
23972
|
+
isDark: isDark,
|
|
23973
|
+
isRtl: isRtl,
|
|
23974
|
+
fontFamily: fontFamily,
|
|
23975
|
+
provideCitations: false,
|
|
23976
|
+
onButtonClick: (value, _label, extra) => onCardAction?.(String(value ?? ""), extra)
|
|
23977
|
+
})
|
|
23861
23978
|
})
|
|
23862
23979
|
})
|
|
23863
23980
|
}, card)
|
|
@@ -25674,7 +25791,7 @@
|
|
|
25674
25791
|
* value by its own test (that constant sat at 0.1.113 while this package was
|
|
25675
25792
|
* at 0.2.2 precisely because nothing enforced it - EV-2431).
|
|
25676
25793
|
*/
|
|
25677
|
-
const WIDGET_VERSION = '0.2.
|
|
25794
|
+
const WIDGET_VERSION = '0.2.56';
|
|
25678
25795
|
|
|
25679
25796
|
/**
|
|
25680
25797
|
* API utility functions
|