@webless/agent 0.4.1 → 0.6.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/{chunk-SVWXFDV3.js → chunk-Y7Z3ZIAQ.js} +1090 -281
- package/dist/chunk-Y7Z3ZIAQ.js.map +1 -0
- package/dist/embed.cjs +1100 -296
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.css +416 -205
- package/dist/embed.css.map +1 -1
- package/dist/embed.d.cts +2 -2
- package/dist/embed.d.ts +2 -2
- package/dist/embed.js +5 -2
- package/dist/embed.js.map +1 -1
- package/dist/index.cjs +39 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -2
- package/dist/index.js.map +1 -1
- package/dist/manifest-D9V3kLCd.d.cts +183 -0
- package/dist/manifest-D9V3kLCd.d.ts +183 -0
- package/dist/react.cjs +1094 -284
- package/dist/react.cjs.map +1 -1
- package/dist/react.css +416 -205
- package/dist/react.css.map +1 -1
- package/dist/react.d.cts +14 -73
- package/dist/react.d.ts +14 -73
- package/dist/react.js +3 -1
- package/package.json +1 -1
- package/dist/chunk-SVWXFDV3.js.map +0 -1
- package/dist/manifest-C8l7WUf6.d.cts +0 -84
- package/dist/manifest-C8l7WUf6.d.ts +0 -84
package/dist/react.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(react_exports, {
|
|
|
26
26
|
DEFAULT_AGENT_PLACEMENT: () => DEFAULT_AGENT_PLACEMENT,
|
|
27
27
|
createIdleSuggestions: () => createIdleSuggestions,
|
|
28
28
|
defaultAgentRailTheme: () => defaultAgentRailTheme,
|
|
29
|
+
defaultDarkAgentRailTheme: () => defaultDarkAgentRailTheme,
|
|
29
30
|
hasVisitorMessages: () => hasVisitorMessages,
|
|
30
31
|
isAgentBusy: () => isAgentBusy,
|
|
31
32
|
normalizeAgentPlacement: () => normalizeAgentPlacement,
|
|
@@ -34,7 +35,7 @@ __export(react_exports, {
|
|
|
34
35
|
module.exports = __toCommonJS(react_exports);
|
|
35
36
|
|
|
36
37
|
// src/react/components/AgentWidget/AgentWidget.tsx
|
|
37
|
-
var
|
|
38
|
+
var import_react10 = require("react");
|
|
38
39
|
|
|
39
40
|
// src/react/page-shift.ts
|
|
40
41
|
var import_react = require("react");
|
|
@@ -303,6 +304,9 @@ function runtimeSessionIdKey(visitorSessionId, prefix) {
|
|
|
303
304
|
function runtimeStreamIndexKey(visitorSessionId, prefix) {
|
|
304
305
|
return `${prefix}:eve:${visitorSessionId}:streamIndex`;
|
|
305
306
|
}
|
|
307
|
+
function runtimeLastMessageKey(visitorSessionId, prefix) {
|
|
308
|
+
return `${prefix}:eve:${visitorSessionId}:lastMessage`;
|
|
309
|
+
}
|
|
306
310
|
function loadPersistedAgentSession(visitorSessionId, options) {
|
|
307
311
|
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return null;
|
|
308
312
|
const prefix = resolvePrefix(options);
|
|
@@ -310,9 +314,11 @@ function loadPersistedAgentSession(visitorSessionId, options) {
|
|
|
310
314
|
if (!sessionId) return null;
|
|
311
315
|
const rawIndex = sessionStorage.getItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
312
316
|
const streamIndex = rawIndex ? Number.parseInt(rawIndex, 10) : 0;
|
|
317
|
+
const lastMessage = sessionStorage.getItem(runtimeLastMessageKey(visitorSessionId, prefix))?.trim();
|
|
313
318
|
return {
|
|
314
319
|
sessionId,
|
|
315
|
-
streamIndex: Number.isFinite(streamIndex) && streamIndex >= 0 ? streamIndex : 0
|
|
320
|
+
streamIndex: Number.isFinite(streamIndex) && streamIndex >= 0 ? streamIndex : 0,
|
|
321
|
+
...lastMessage ? { lastMessage } : {}
|
|
316
322
|
};
|
|
317
323
|
}
|
|
318
324
|
function savePersistedAgentSession(visitorSessionId, sessionId, streamIndex, options) {
|
|
@@ -326,11 +332,19 @@ function savePersistedAgentSession(visitorSessionId, sessionId, streamIndex, opt
|
|
|
326
332
|
String(Math.max(0, streamIndex))
|
|
327
333
|
);
|
|
328
334
|
}
|
|
335
|
+
function savePersistedAgentTurnMessage(visitorSessionId, message, options) {
|
|
336
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !message) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const prefix = resolvePrefix(options);
|
|
340
|
+
sessionStorage.setItem(runtimeLastMessageKey(visitorSessionId, prefix), message);
|
|
341
|
+
}
|
|
329
342
|
function clearPersistedAgentSession(visitorSessionId, options) {
|
|
330
343
|
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return;
|
|
331
344
|
const prefix = resolvePrefix(options);
|
|
332
345
|
sessionStorage.removeItem(runtimeSessionIdKey(visitorSessionId, prefix));
|
|
333
346
|
sessionStorage.removeItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
347
|
+
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
334
348
|
}
|
|
335
349
|
|
|
336
350
|
// src/runtime/client.ts
|
|
@@ -345,6 +359,12 @@ function applyMessageEvent(event, rendered, handlers, workItems) {
|
|
|
345
359
|
if (event.type === "message.completed") {
|
|
346
360
|
handlers.onComplete?.();
|
|
347
361
|
}
|
|
362
|
+
if (event.type === "action.result") {
|
|
363
|
+
const result = event.data.result;
|
|
364
|
+
if (result && typeof result === "object" && "output" in result) {
|
|
365
|
+
handlers.onActionResult?.(result.output);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
348
368
|
if (event.type !== "message.appended") return rendered;
|
|
349
369
|
const { messageDelta, messageSoFar } = event.data;
|
|
350
370
|
let delta = messageDelta;
|
|
@@ -358,6 +378,12 @@ function applyMessageEvent(event, rendered, handlers, workItems) {
|
|
|
358
378
|
if (delta) handlers.onDelta(delta);
|
|
359
379
|
return next;
|
|
360
380
|
}
|
|
381
|
+
function isResumeTurnMessage(received, candidate) {
|
|
382
|
+
if (received === candidate) return true;
|
|
383
|
+
return Boolean(candidate) && received.endsWith(`
|
|
384
|
+
|
|
385
|
+
${candidate}`);
|
|
386
|
+
}
|
|
361
387
|
function latestTurnEvents(events) {
|
|
362
388
|
let startIndex = -1;
|
|
363
389
|
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
@@ -589,6 +615,11 @@ var AgentSession = class {
|
|
|
589
615
|
this.session = session;
|
|
590
616
|
try {
|
|
591
617
|
const activeSession = session;
|
|
618
|
+
savePersistedAgentTurnMessage(
|
|
619
|
+
this.visitorSessionId,
|
|
620
|
+
message,
|
|
621
|
+
this.storeOptions
|
|
622
|
+
);
|
|
592
623
|
response = await withCapabilityRefresh(
|
|
593
624
|
this.capability,
|
|
594
625
|
() => activeSession.send(message, { signal })
|
|
@@ -604,6 +635,11 @@ var AgentSession = class {
|
|
|
604
635
|
}
|
|
605
636
|
}
|
|
606
637
|
if (!response) {
|
|
638
|
+
savePersistedAgentTurnMessage(
|
|
639
|
+
this.visitorSessionId,
|
|
640
|
+
message,
|
|
641
|
+
this.storeOptions
|
|
642
|
+
);
|
|
607
643
|
const created = await withCapabilityRefresh(
|
|
608
644
|
this.capability,
|
|
609
645
|
() => client.sessions.create({ message, signal })
|
|
@@ -658,7 +694,9 @@ var AgentSession = class {
|
|
|
658
694
|
);
|
|
659
695
|
const turnEvents = latestTurnEvents(snapshot.events);
|
|
660
696
|
const received = turnEvents[0];
|
|
661
|
-
|
|
697
|
+
const lastSent = persisted.lastMessage;
|
|
698
|
+
const inFlight = !turnEvents.some((event) => isTurnBoundary(event));
|
|
699
|
+
if (received?.type !== "message.received" || !(isResumeTurnMessage(received.data.message, message) || inFlight && lastSent !== void 0 && received.data.message === lastSent)) {
|
|
662
700
|
return null;
|
|
663
701
|
}
|
|
664
702
|
let rendered = renderTurn(turnEvents);
|
|
@@ -822,8 +860,248 @@ function formatAgentError(error) {
|
|
|
822
860
|
return TRANSIENT_AGENT_ERROR_MESSAGE;
|
|
823
861
|
}
|
|
824
862
|
|
|
863
|
+
// src/react/lib/tool-card.ts
|
|
864
|
+
function bookingOfferIdentityKey(offer) {
|
|
865
|
+
const eventTypes = offer.eventTypes.map(
|
|
866
|
+
(item) => `${item.uri}:${item.duration ?? ""}:${item.locationKind ?? ""}:${item.location ?? ""}`
|
|
867
|
+
).join("|");
|
|
868
|
+
const slots = offer.slots.map((slot) => `${slot.eventTypeUri ?? ""}:${slot.startTime}`).join("|");
|
|
869
|
+
return `${eventTypes}::${slots}` || "offer";
|
|
870
|
+
}
|
|
871
|
+
var FENCE_PATTERN = /```(?:webless-tool-card|json)\s*([\s\S]*?)```/gi;
|
|
872
|
+
function asRecord(value) {
|
|
873
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
874
|
+
}
|
|
875
|
+
function asString(value) {
|
|
876
|
+
return typeof value === "string" ? value.trim() : "";
|
|
877
|
+
}
|
|
878
|
+
function isEventUri(value) {
|
|
879
|
+
return /^https:\/\/api\.calendly\.com\/scheduled_events\/[^/]+$/i.test(value);
|
|
880
|
+
}
|
|
881
|
+
function isEventTypeUri(value) {
|
|
882
|
+
return /^https:\/\/api\.calendly\.com\/event_types\/[^/]+$/i.test(value);
|
|
883
|
+
}
|
|
884
|
+
function parseToolCard(value) {
|
|
885
|
+
const record = asRecord(value);
|
|
886
|
+
if (!record) return null;
|
|
887
|
+
if (record.booking_offer && asString(record.type) !== "booking_offer") {
|
|
888
|
+
const nested = parseToolCard(record.booking_offer);
|
|
889
|
+
if (nested) return nested;
|
|
890
|
+
}
|
|
891
|
+
const type = asString(record.type);
|
|
892
|
+
if (type === "booking_offer") {
|
|
893
|
+
const eventTypes = Array.isArray(record.eventTypes) ? record.eventTypes.flatMap((item) => {
|
|
894
|
+
const entry = asRecord(item);
|
|
895
|
+
const uri = asString(entry?.uri);
|
|
896
|
+
if (!entry || !isEventTypeUri(uri)) return [];
|
|
897
|
+
const duration = entry.duration;
|
|
898
|
+
const locationKind = asString(entry.locationKind);
|
|
899
|
+
const location = asString(entry.location);
|
|
900
|
+
return [
|
|
901
|
+
{
|
|
902
|
+
name: asString(entry.name) || "Meeting",
|
|
903
|
+
uri,
|
|
904
|
+
...typeof duration === "number" ? { duration } : {},
|
|
905
|
+
...locationKind ? { locationKind } : {},
|
|
906
|
+
...location ? { location } : {}
|
|
907
|
+
}
|
|
908
|
+
];
|
|
909
|
+
}) : [];
|
|
910
|
+
const slots = Array.isArray(record.slots) ? record.slots.flatMap((item) => {
|
|
911
|
+
const entry = asRecord(item);
|
|
912
|
+
const startTime = asString(entry?.startTime);
|
|
913
|
+
if (!entry || !startTime) return [];
|
|
914
|
+
const eventTypeUri = asString(entry.eventTypeUri);
|
|
915
|
+
return [
|
|
916
|
+
{
|
|
917
|
+
startTime,
|
|
918
|
+
...isEventTypeUri(eventTypeUri) ? { eventTypeUri } : {}
|
|
919
|
+
}
|
|
920
|
+
];
|
|
921
|
+
}) : [];
|
|
922
|
+
if (slots.length === 0) return null;
|
|
923
|
+
return { type: "booking_offer", eventTypes, slots };
|
|
924
|
+
}
|
|
925
|
+
if (type === "booking_confirmed") {
|
|
926
|
+
const eventUri = asString(record.eventUri);
|
|
927
|
+
if (!isEventUri(eventUri)) return null;
|
|
928
|
+
const inviteeUri = asString(record.inviteeUri);
|
|
929
|
+
const inviteeEmail = asString(record.inviteeEmail);
|
|
930
|
+
const startTime = asString(record.startTime);
|
|
931
|
+
return {
|
|
932
|
+
type: "booking_confirmed",
|
|
933
|
+
eventUri,
|
|
934
|
+
...inviteeUri ? { inviteeUri } : {},
|
|
935
|
+
...inviteeEmail ? { inviteeEmail } : {},
|
|
936
|
+
...startTime ? { startTime } : {}
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
if (type === "booking_canceled") {
|
|
940
|
+
const eventUri = asString(record.eventUri);
|
|
941
|
+
if (!isEventUri(eventUri)) return null;
|
|
942
|
+
return { type: "booking_canceled", eventUri };
|
|
943
|
+
}
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
function formatBookingOfferFence(offer) {
|
|
947
|
+
return [
|
|
948
|
+
"```webless-tool-card",
|
|
949
|
+
JSON.stringify({
|
|
950
|
+
type: "booking_offer",
|
|
951
|
+
eventTypes: offer.eventTypes,
|
|
952
|
+
slots: offer.slots
|
|
953
|
+
}),
|
|
954
|
+
"```"
|
|
955
|
+
].join("\n");
|
|
956
|
+
}
|
|
957
|
+
function bookingOfferFromActionOutput(output) {
|
|
958
|
+
const record = asRecord(output);
|
|
959
|
+
const data = asRecord(record?.data) ?? record;
|
|
960
|
+
const card = parseToolCard(data);
|
|
961
|
+
return card?.type === "booking_offer" ? card : null;
|
|
962
|
+
}
|
|
963
|
+
function ensureBookingOfferText(text, offer) {
|
|
964
|
+
if (!offer) return text;
|
|
965
|
+
if (extractToolCards(text).some((card) => card.type === "booking_offer")) {
|
|
966
|
+
return text;
|
|
967
|
+
}
|
|
968
|
+
const visible = stripToolCards(text).trim() || text.trim();
|
|
969
|
+
return `${visible}
|
|
970
|
+
|
|
971
|
+
${formatBookingOfferFence(offer)}`;
|
|
972
|
+
}
|
|
973
|
+
function hideToolCardFences(text) {
|
|
974
|
+
return text.replace(/```(?:webless-tool-card|json)\s*[\s\S]*?```/gi, "").replace(/```(?:webless-tool-card|json)[\s\S]*$/i, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
975
|
+
}
|
|
976
|
+
function visitorTimeZone() {
|
|
977
|
+
try {
|
|
978
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
979
|
+
} catch {
|
|
980
|
+
return "UTC";
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function extractToolCards(text) {
|
|
984
|
+
const cards = [];
|
|
985
|
+
for (const match of text.matchAll(FENCE_PATTERN)) {
|
|
986
|
+
try {
|
|
987
|
+
const card = parseToolCard(JSON.parse(match[1] ?? ""));
|
|
988
|
+
if (card) cards.push(card);
|
|
989
|
+
} catch {
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
return cards;
|
|
993
|
+
}
|
|
994
|
+
function stripToolCards(text) {
|
|
995
|
+
return text.replace(FENCE_PATTERN, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
996
|
+
}
|
|
997
|
+
function localDateKey(date) {
|
|
998
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
999
|
+
return [
|
|
1000
|
+
date.getFullYear(),
|
|
1001
|
+
String(date.getMonth() + 1).padStart(2, "0"),
|
|
1002
|
+
String(date.getDate()).padStart(2, "0")
|
|
1003
|
+
].join("-");
|
|
1004
|
+
}
|
|
1005
|
+
function slotDateKey(startTime) {
|
|
1006
|
+
return localDateKey(new Date(startTime)) || startTime;
|
|
1007
|
+
}
|
|
1008
|
+
function bookingSlotsForEventType(slots, eventTypeUri) {
|
|
1009
|
+
return slots.filter(
|
|
1010
|
+
(slot) => !eventTypeUri || !slot.eventTypeUri || slot.eventTypeUri === eventTypeUri
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
function firstAvailableBookingMonth(slots) {
|
|
1014
|
+
let earliest;
|
|
1015
|
+
for (const slot of slots) {
|
|
1016
|
+
const key = slotDateKey(slot.startTime);
|
|
1017
|
+
if (!earliest || key < earliest) earliest = key;
|
|
1018
|
+
}
|
|
1019
|
+
const [year, month] = (earliest ?? slotDateKey((/* @__PURE__ */ new Date()).toISOString())).split("-").map(Number);
|
|
1020
|
+
if (!year || !month) {
|
|
1021
|
+
const now = /* @__PURE__ */ new Date();
|
|
1022
|
+
return { year: now.getFullYear(), month: now.getMonth() };
|
|
1023
|
+
}
|
|
1024
|
+
return { year, month: month - 1 };
|
|
1025
|
+
}
|
|
1026
|
+
function formatMonthTitle(year, month) {
|
|
1027
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
1028
|
+
month: "long",
|
|
1029
|
+
year: "numeric"
|
|
1030
|
+
}).format(new Date(year, month, 1));
|
|
1031
|
+
}
|
|
1032
|
+
function formatLongDate(startTime) {
|
|
1033
|
+
const date = new Date(startTime);
|
|
1034
|
+
if (Number.isNaN(date.getTime())) return startTime;
|
|
1035
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
1036
|
+
weekday: "long",
|
|
1037
|
+
month: "long",
|
|
1038
|
+
day: "numeric"
|
|
1039
|
+
}).format(date);
|
|
1040
|
+
}
|
|
1041
|
+
function weekdayLabels() {
|
|
1042
|
+
return Array.from(
|
|
1043
|
+
{ length: 7 },
|
|
1044
|
+
(_, index) => new Intl.DateTimeFormat(void 0, { weekday: "short" }).format(
|
|
1045
|
+
new Date(2026, 7, 3 + index)
|
|
1046
|
+
)
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
function formatTimeChip(startTime) {
|
|
1050
|
+
const date = new Date(startTime);
|
|
1051
|
+
if (Number.isNaN(date.getTime())) return startTime;
|
|
1052
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
1053
|
+
hour: "numeric",
|
|
1054
|
+
minute: "2-digit"
|
|
1055
|
+
}).format(date);
|
|
1056
|
+
}
|
|
1057
|
+
function formatSlotTimeZone(startTime) {
|
|
1058
|
+
const date = new Date(startTime);
|
|
1059
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
1060
|
+
return new Intl.DateTimeFormat(void 0, { timeZoneName: "short" }).formatToParts(date).find((part) => part.type === "timeZoneName")?.value ?? "";
|
|
1061
|
+
}
|
|
1062
|
+
function formatSlotLabel(startTime) {
|
|
1063
|
+
const date = new Date(startTime);
|
|
1064
|
+
if (Number.isNaN(date.getTime())) return startTime;
|
|
1065
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
1066
|
+
weekday: "short",
|
|
1067
|
+
month: "short",
|
|
1068
|
+
day: "numeric",
|
|
1069
|
+
hour: "numeric",
|
|
1070
|
+
minute: "2-digit",
|
|
1071
|
+
timeZoneName: "short"
|
|
1072
|
+
}).format(date);
|
|
1073
|
+
}
|
|
1074
|
+
function formatBookingRequest(input) {
|
|
1075
|
+
return [
|
|
1076
|
+
"Book this meeting now with CALENDLY_POST_INVITEE.",
|
|
1077
|
+
"Do not open a Calendly URL and do not list other scheduled events.",
|
|
1078
|
+
"Do not invent a location kind. Use only the location fields below.",
|
|
1079
|
+
`event_type: ${input.eventTypeUri}`,
|
|
1080
|
+
`start_time: ${input.startTime}`,
|
|
1081
|
+
`invitee.name: ${input.inviteeName}`,
|
|
1082
|
+
`invitee.email: ${input.inviteeEmail}`,
|
|
1083
|
+
`invitee.timezone: ${input.timezone}`,
|
|
1084
|
+
...input.locationKind ? [
|
|
1085
|
+
`location.kind: ${input.locationKind}`,
|
|
1086
|
+
...input.location ? [`location.location: ${input.location}`] : []
|
|
1087
|
+
] : ["Do not send a location field."],
|
|
1088
|
+
"After it succeeds, reply with one short confirmation and a webless-tool-card booking_confirmed block using visitor_booking."
|
|
1089
|
+
].join("\n");
|
|
1090
|
+
}
|
|
1091
|
+
function visitorBookingPrefix(booking) {
|
|
1092
|
+
return [
|
|
1093
|
+
"This visitor already booked a meeting. Use only this meeting:",
|
|
1094
|
+
`- scheduled event URI: ${booking.eventUri}`,
|
|
1095
|
+
...booking.inviteeUri ? [`- invitee URI: ${booking.inviteeUri}`] : [],
|
|
1096
|
+
...booking.inviteeEmail ? [`- invitee email: ${booking.inviteeEmail}`] : [],
|
|
1097
|
+
"For details call CALENDLY_GET_EVENT or CALENDLY_GET_EVENT_INVITEE with those URIs.",
|
|
1098
|
+
"If you must list events, pass this invitee_email. Never describe any other scheduled event.",
|
|
1099
|
+
"start_time values from Calendly are UTC."
|
|
1100
|
+
].join("\n");
|
|
1101
|
+
}
|
|
1102
|
+
|
|
825
1103
|
// src/react/persisted-conversation.ts
|
|
826
|
-
var CONVERSATION_VERSION =
|
|
1104
|
+
var CONVERSATION_VERSION = 2;
|
|
827
1105
|
function conversationKey(storageKeyPrefix, visitorSessionId) {
|
|
828
1106
|
return `${storageKeyPrefix}:conversation:${visitorSessionId}`;
|
|
829
1107
|
}
|
|
@@ -833,13 +1111,39 @@ function parseMessage(value) {
|
|
|
833
1111
|
if (typeof record.id !== "string" || record.role !== "agent" && record.role !== "visitor" || typeof record.text !== "string" || typeof record.createdAt !== "number" || !Number.isFinite(record.createdAt)) {
|
|
834
1112
|
return null;
|
|
835
1113
|
}
|
|
1114
|
+
if (record.role === "visitor") {
|
|
1115
|
+
return {
|
|
1116
|
+
id: record.id,
|
|
1117
|
+
role: "visitor",
|
|
1118
|
+
text: record.text,
|
|
1119
|
+
createdAt: record.createdAt,
|
|
1120
|
+
...typeof record.runtimeText === "string" && record.runtimeText ? { runtimeText: record.runtimeText } : {}
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
836
1123
|
return {
|
|
837
1124
|
id: record.id,
|
|
838
|
-
role:
|
|
1125
|
+
role: "agent",
|
|
839
1126
|
text: record.text,
|
|
840
1127
|
createdAt: record.createdAt
|
|
841
1128
|
};
|
|
842
1129
|
}
|
|
1130
|
+
function parseToolStep(value) {
|
|
1131
|
+
if (typeof value !== "object" || value === null) return null;
|
|
1132
|
+
const record = value;
|
|
1133
|
+
if (typeof record.id !== "string" || record.kind !== "planning" && record.kind !== "search" && record.kind !== "specialist" || typeof record.label !== "string" || record.state !== "completed" && record.state !== "active" && record.state !== "pending" && record.state !== "error") {
|
|
1134
|
+
return null;
|
|
1135
|
+
}
|
|
1136
|
+
return {
|
|
1137
|
+
id: record.id,
|
|
1138
|
+
kind: record.kind,
|
|
1139
|
+
label: record.label,
|
|
1140
|
+
state: record.state,
|
|
1141
|
+
...typeof record.detail === "string" && record.detail ? { detail: record.detail } : {}
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
function visitorTurnText(message) {
|
|
1145
|
+
return message.role === "visitor" && message.runtimeText ? message.runtimeText : message.text;
|
|
1146
|
+
}
|
|
843
1147
|
function loadPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
|
|
844
1148
|
if (typeof sessionStorage === "undefined") return null;
|
|
845
1149
|
const raw = sessionStorage.getItem(conversationKey(storageKeyPrefix, visitorSessionId));
|
|
@@ -848,15 +1152,19 @@ function loadPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
|
|
|
848
1152
|
const value = JSON.parse(raw);
|
|
849
1153
|
if (typeof value !== "object" || value === null) return null;
|
|
850
1154
|
const record = value;
|
|
851
|
-
if (record.version !== CONVERSATION_VERSION || !Array.isArray(record.messages) || typeof record.pending !== "boolean" || typeof record.streamingText !== "string") {
|
|
1155
|
+
if (record.version !== 1 && record.version !== CONVERSATION_VERSION || !Array.isArray(record.messages) || typeof record.pending !== "boolean" || typeof record.streamingText !== "string" || record.version === CONVERSATION_VERSION && !Array.isArray(record.toolSteps)) {
|
|
852
1156
|
return null;
|
|
853
1157
|
}
|
|
854
1158
|
const messages = record.messages.map(parseMessage);
|
|
855
1159
|
if (messages.some((message) => message === null)) return null;
|
|
1160
|
+
const storedToolSteps = record.version === CONVERSATION_VERSION && Array.isArray(record.toolSteps) ? record.toolSteps : [];
|
|
1161
|
+
const toolSteps = storedToolSteps.map(parseToolStep);
|
|
1162
|
+
if (toolSteps.some((step) => step === null)) return null;
|
|
856
1163
|
return {
|
|
857
1164
|
messages: messages.filter((message) => message !== null),
|
|
858
1165
|
pending: record.pending,
|
|
859
|
-
streamingText: record.streamingText
|
|
1166
|
+
streamingText: record.streamingText,
|
|
1167
|
+
toolSteps: toolSteps.filter((step) => step !== null)
|
|
860
1168
|
};
|
|
861
1169
|
} catch {
|
|
862
1170
|
return null;
|
|
@@ -872,6 +1180,42 @@ function savePersistedAgentConversation(storageKeyPrefix, visitorSessionId, conv
|
|
|
872
1180
|
function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
|
|
873
1181
|
if (typeof sessionStorage === "undefined") return;
|
|
874
1182
|
sessionStorage.removeItem(conversationKey(storageKeyPrefix, visitorSessionId));
|
|
1183
|
+
clearPendingWidgetBooking(storageKeyPrefix, visitorSessionId);
|
|
1184
|
+
}
|
|
1185
|
+
function pendingBookingKey(storageKeyPrefix, visitorSessionId) {
|
|
1186
|
+
return `${storageKeyPrefix}:pending-booking:${visitorSessionId}`;
|
|
1187
|
+
}
|
|
1188
|
+
function loadPendingWidgetBooking(storageKeyPrefix, visitorSessionId) {
|
|
1189
|
+
if (typeof sessionStorage === "undefined") return null;
|
|
1190
|
+
const raw = sessionStorage.getItem(
|
|
1191
|
+
pendingBookingKey(storageKeyPrefix, visitorSessionId)
|
|
1192
|
+
);
|
|
1193
|
+
if (!raw) return null;
|
|
1194
|
+
try {
|
|
1195
|
+
const value = JSON.parse(raw);
|
|
1196
|
+
if (typeof value !== "object" || value === null) return null;
|
|
1197
|
+
const record = value;
|
|
1198
|
+
if (typeof record.eventUri !== "string" || !record.eventUri) return null;
|
|
1199
|
+
return {
|
|
1200
|
+
eventUri: record.eventUri,
|
|
1201
|
+
...typeof record.inviteeUri === "string" && record.inviteeUri ? { inviteeUri: record.inviteeUri } : {},
|
|
1202
|
+
...typeof record.inviteeEmail === "string" && record.inviteeEmail ? { inviteeEmail: record.inviteeEmail } : {},
|
|
1203
|
+
...typeof record.startTime === "string" && record.startTime ? { startTime: record.startTime } : {}
|
|
1204
|
+
};
|
|
1205
|
+
} catch {
|
|
1206
|
+
return null;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
function savePendingWidgetBooking(storageKeyPrefix, visitorSessionId, booking) {
|
|
1210
|
+
if (typeof sessionStorage === "undefined") return;
|
|
1211
|
+
sessionStorage.setItem(
|
|
1212
|
+
pendingBookingKey(storageKeyPrefix, visitorSessionId),
|
|
1213
|
+
JSON.stringify(booking)
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
function clearPendingWidgetBooking(storageKeyPrefix, visitorSessionId) {
|
|
1217
|
+
if (typeof sessionStorage === "undefined") return;
|
|
1218
|
+
sessionStorage.removeItem(pendingBookingKey(storageKeyPrefix, visitorSessionId));
|
|
875
1219
|
}
|
|
876
1220
|
|
|
877
1221
|
// src/react/hooks/useAgentChat.ts
|
|
@@ -891,6 +1235,7 @@ function createInitialState(greeting = DEFAULT_GREETING) {
|
|
|
891
1235
|
journey: null,
|
|
892
1236
|
followUps: [],
|
|
893
1237
|
streamingText: "",
|
|
1238
|
+
pendingOffer: null,
|
|
894
1239
|
error: null
|
|
895
1240
|
};
|
|
896
1241
|
}
|
|
@@ -900,7 +1245,8 @@ function stateFromConversation(conversation, initialState) {
|
|
|
900
1245
|
...initialState,
|
|
901
1246
|
messages: conversation.messages,
|
|
902
1247
|
phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
|
|
903
|
-
streamingText: conversation.streamingText
|
|
1248
|
+
streamingText: conversation.streamingText,
|
|
1249
|
+
toolSteps: conversation.toolSteps
|
|
904
1250
|
};
|
|
905
1251
|
}
|
|
906
1252
|
function upsertToolStep(steps, item) {
|
|
@@ -973,6 +1319,9 @@ function useAgentChat({
|
|
|
973
1319
|
initialState
|
|
974
1320
|
)
|
|
975
1321
|
);
|
|
1322
|
+
const pendingBookingRef = (0, import_react2.useRef)(
|
|
1323
|
+
loadPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId)
|
|
1324
|
+
);
|
|
976
1325
|
const runRef = (0, import_react2.useRef)(null);
|
|
977
1326
|
const clientRef = (0, import_react2.useRef)(
|
|
978
1327
|
createAgentClient({
|
|
@@ -1005,6 +1354,10 @@ function useAgentChat({
|
|
|
1005
1354
|
visitorSessionId: visitorId,
|
|
1006
1355
|
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
1007
1356
|
});
|
|
1357
|
+
pendingBookingRef.current = loadPendingWidgetBooking(
|
|
1358
|
+
resolvedStorageKeyPrefix,
|
|
1359
|
+
visitorId
|
|
1360
|
+
);
|
|
1008
1361
|
setState(
|
|
1009
1362
|
stateFromConversation(
|
|
1010
1363
|
loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
|
|
@@ -1027,19 +1380,22 @@ function useAgentChat({
|
|
|
1027
1380
|
savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
|
|
1028
1381
|
messages: state.messages,
|
|
1029
1382
|
pending: isAgentBusy(state.phase),
|
|
1030
|
-
streamingText: state.streamingText
|
|
1383
|
+
streamingText: state.streamingText,
|
|
1384
|
+
toolSteps: state.toolSteps
|
|
1031
1385
|
});
|
|
1032
1386
|
}, [
|
|
1033
1387
|
resolvedStorageKeyPrefix,
|
|
1034
1388
|
state.messages,
|
|
1035
1389
|
state.phase,
|
|
1036
1390
|
state.streamingText,
|
|
1391
|
+
state.toolSteps,
|
|
1037
1392
|
visitorId
|
|
1038
1393
|
]);
|
|
1039
1394
|
const reset = (0, import_react2.useCallback)(() => {
|
|
1040
1395
|
runRef.current?.abort();
|
|
1041
1396
|
runRef.current = null;
|
|
1042
1397
|
clientRef.current.reset();
|
|
1398
|
+
pendingBookingRef.current = null;
|
|
1043
1399
|
clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
|
|
1044
1400
|
setState(initialState);
|
|
1045
1401
|
}, [initialState, resolvedStorageKeyPrefix, visitorId]);
|
|
@@ -1051,6 +1407,7 @@ function useAgentChat({
|
|
|
1051
1407
|
try {
|
|
1052
1408
|
let streamStarted = Boolean(initialText);
|
|
1053
1409
|
let streamed = initialText;
|
|
1410
|
+
const capturedOffers = [];
|
|
1054
1411
|
const handlers = {
|
|
1055
1412
|
onWork: (item) => {
|
|
1056
1413
|
if (!isActiveRun()) return;
|
|
@@ -1060,6 +1417,12 @@ function useAgentChat({
|
|
|
1060
1417
|
toolSteps: upsertToolStep(prev.toolSteps, item)
|
|
1061
1418
|
}));
|
|
1062
1419
|
},
|
|
1420
|
+
onActionResult: (output) => {
|
|
1421
|
+
const offer = bookingOfferFromActionOutput(output);
|
|
1422
|
+
if (!offer) return;
|
|
1423
|
+
capturedOffers.push(offer);
|
|
1424
|
+
setState((prev) => ({ ...prev, pendingOffer: offer }));
|
|
1425
|
+
},
|
|
1063
1426
|
onDelta: (delta) => {
|
|
1064
1427
|
if (!isActiveRun()) return;
|
|
1065
1428
|
if (!streamStarted) {
|
|
@@ -1075,7 +1438,8 @@ function useAgentChat({
|
|
|
1075
1438
|
setState((prev) => ({
|
|
1076
1439
|
...prev,
|
|
1077
1440
|
phase: "streaming",
|
|
1078
|
-
streamingText: streamed
|
|
1441
|
+
streamingText: hideToolCardFences(streamed),
|
|
1442
|
+
pendingOffer: prev.pendingOffer ?? capturedOffers.at(-1) ?? null
|
|
1079
1443
|
}));
|
|
1080
1444
|
},
|
|
1081
1445
|
onComplete: () => {
|
|
@@ -1096,18 +1460,34 @@ function useAgentChat({
|
|
|
1096
1460
|
});
|
|
1097
1461
|
}
|
|
1098
1462
|
if (!isActiveRun() || finalText === null) return;
|
|
1463
|
+
const displayText = ensureBookingOfferText(
|
|
1464
|
+
finalText,
|
|
1465
|
+
capturedOffers.at(-1) ?? null
|
|
1466
|
+
);
|
|
1099
1467
|
const agentMessage = {
|
|
1100
1468
|
id: `agent-${Date.now()}`,
|
|
1101
1469
|
role: "agent",
|
|
1102
|
-
text:
|
|
1470
|
+
text: displayText,
|
|
1103
1471
|
createdAt: Date.now()
|
|
1104
1472
|
};
|
|
1473
|
+
const parsedCards = extractToolCards(displayText);
|
|
1474
|
+
for (const card of parsedCards) {
|
|
1475
|
+
if (card.type === "booking_confirmed") {
|
|
1476
|
+
pendingBookingRef.current = card;
|
|
1477
|
+
savePendingWidgetBooking(resolvedStorageKeyPrefix, visitorId, card);
|
|
1478
|
+
}
|
|
1479
|
+
if (card.type === "booking_canceled" && pendingBookingRef.current?.eventUri === card.eventUri) {
|
|
1480
|
+
pendingBookingRef.current = null;
|
|
1481
|
+
clearPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1105
1484
|
setState((prev) => ({
|
|
1106
1485
|
...prev,
|
|
1107
1486
|
phase: "complete",
|
|
1108
1487
|
messages: [...prev.messages, agentMessage],
|
|
1109
1488
|
toolSteps: completeActivePlanning(prev.toolSteps),
|
|
1110
1489
|
streamingText: "",
|
|
1490
|
+
pendingOffer: null,
|
|
1111
1491
|
followUps: [],
|
|
1112
1492
|
journey: null
|
|
1113
1493
|
}));
|
|
@@ -1129,26 +1509,54 @@ function useAgentChat({
|
|
|
1129
1509
|
} : step
|
|
1130
1510
|
),
|
|
1131
1511
|
streamingText: "",
|
|
1512
|
+
pendingOffer: null,
|
|
1132
1513
|
error: message
|
|
1133
1514
|
}));
|
|
1134
1515
|
runRef.current = null;
|
|
1135
1516
|
}
|
|
1136
1517
|
},
|
|
1137
|
-
[]
|
|
1518
|
+
[resolvedStorageKeyPrefix, visitorId]
|
|
1519
|
+
);
|
|
1520
|
+
const rememberBooking = (0, import_react2.useCallback)(
|
|
1521
|
+
(booking) => {
|
|
1522
|
+
const current = pendingBookingRef.current;
|
|
1523
|
+
if (current?.eventUri === booking.eventUri && current.inviteeEmail === booking.inviteeEmail && current.inviteeUri === booking.inviteeUri) {
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
pendingBookingRef.current = booking;
|
|
1527
|
+
savePendingWidgetBooking(resolvedStorageKeyPrefix, visitorId, booking);
|
|
1528
|
+
},
|
|
1529
|
+
[resolvedStorageKeyPrefix, visitorId]
|
|
1530
|
+
);
|
|
1531
|
+
const forgetBooking = (0, import_react2.useCallback)(
|
|
1532
|
+
(eventUri) => {
|
|
1533
|
+
const current = pendingBookingRef.current;
|
|
1534
|
+
if (!current) return;
|
|
1535
|
+
if (eventUri && current.eventUri !== eventUri) return;
|
|
1536
|
+
pendingBookingRef.current = null;
|
|
1537
|
+
clearPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId);
|
|
1538
|
+
},
|
|
1539
|
+
[resolvedStorageKeyPrefix, visitorId]
|
|
1138
1540
|
);
|
|
1139
1541
|
const submit = (0, import_react2.useCallback)(
|
|
1140
|
-
async (visitorText) => {
|
|
1542
|
+
async (visitorText, options) => {
|
|
1141
1543
|
if (runRef.current) {
|
|
1142
1544
|
runRef.current.abort();
|
|
1143
1545
|
clientRef.current.cancelActive();
|
|
1144
1546
|
}
|
|
1145
1547
|
const controller = new AbortController();
|
|
1146
1548
|
runRef.current = controller;
|
|
1549
|
+
const booking = pendingBookingRef.current;
|
|
1550
|
+
const outgoing = options?.runtimeText ?? visitorText;
|
|
1551
|
+
const runtimeText = booking ? `${visitorBookingPrefix(booking)}
|
|
1552
|
+
|
|
1553
|
+
${outgoing}` : outgoing;
|
|
1147
1554
|
const visitorMessage = {
|
|
1148
1555
|
id: `visitor-${Date.now()}`,
|
|
1149
1556
|
role: "visitor",
|
|
1150
1557
|
text: visitorText,
|
|
1151
|
-
createdAt: Date.now()
|
|
1558
|
+
createdAt: Date.now(),
|
|
1559
|
+
...runtimeText !== visitorText ? { runtimeText } : {}
|
|
1152
1560
|
};
|
|
1153
1561
|
setState((prev) => ({
|
|
1154
1562
|
...prev,
|
|
@@ -1165,9 +1573,10 @@ function useAgentChat({
|
|
|
1165
1573
|
journey: null,
|
|
1166
1574
|
followUps: [],
|
|
1167
1575
|
streamingText: "",
|
|
1576
|
+
pendingOffer: null,
|
|
1168
1577
|
error: null
|
|
1169
1578
|
}));
|
|
1170
|
-
await runTurn({ controller, resume: false, visitorText });
|
|
1579
|
+
await runTurn({ controller, resume: false, visitorText: runtimeText });
|
|
1171
1580
|
},
|
|
1172
1581
|
[runTurn]
|
|
1173
1582
|
);
|
|
@@ -1194,12 +1603,13 @@ function useAgentChat({
|
|
|
1194
1603
|
journey: null,
|
|
1195
1604
|
followUps: [],
|
|
1196
1605
|
streamingText: "",
|
|
1606
|
+
pendingOffer: null,
|
|
1197
1607
|
error: null
|
|
1198
1608
|
}));
|
|
1199
1609
|
await runTurn({
|
|
1200
1610
|
controller,
|
|
1201
1611
|
resume: false,
|
|
1202
|
-
visitorText: visitorMessage
|
|
1612
|
+
visitorText: visitorTurnText(visitorMessage)
|
|
1203
1613
|
});
|
|
1204
1614
|
}, [runTurn, state.messages]);
|
|
1205
1615
|
(0, import_react2.useEffect)(() => {
|
|
@@ -1216,7 +1626,7 @@ function useAgentChat({
|
|
|
1216
1626
|
controller,
|
|
1217
1627
|
initialText: conversation.streamingText,
|
|
1218
1628
|
resume: true,
|
|
1219
|
-
visitorText: visitorMessage
|
|
1629
|
+
visitorText: visitorTurnText(visitorMessage)
|
|
1220
1630
|
});
|
|
1221
1631
|
return () => {
|
|
1222
1632
|
if (runRef.current === controller) {
|
|
@@ -1236,6 +1646,8 @@ function useAgentChat({
|
|
|
1236
1646
|
reset,
|
|
1237
1647
|
retry,
|
|
1238
1648
|
submit,
|
|
1649
|
+
rememberBooking,
|
|
1650
|
+
forgetBooking,
|
|
1239
1651
|
visitorSessionId: visitorId,
|
|
1240
1652
|
sessionId: clientRef.current.getActiveSessionId()
|
|
1241
1653
|
};
|
|
@@ -1297,7 +1709,7 @@ function unregisterAgentPanelController(customerId) {
|
|
|
1297
1709
|
}
|
|
1298
1710
|
|
|
1299
1711
|
// src/react/components/AgentRail/AgentRail.tsx
|
|
1300
|
-
var
|
|
1712
|
+
var import_react9 = require("react");
|
|
1301
1713
|
|
|
1302
1714
|
// src/react/types/conversation.ts
|
|
1303
1715
|
var defaultAgentRailTheme = {
|
|
@@ -1318,15 +1730,62 @@ var defaultAgentRailTheme = {
|
|
|
1318
1730
|
fontBody: '"Mulish", "Avenir Next", "Segoe UI", sans-serif',
|
|
1319
1731
|
fontDisplay: '"Space Grotesk", sans-serif'
|
|
1320
1732
|
};
|
|
1733
|
+
var defaultDarkAgentRailTheme = {
|
|
1734
|
+
...defaultAgentRailTheme,
|
|
1735
|
+
brand: "#a77bff",
|
|
1736
|
+
brandSoft: "#2b2140",
|
|
1737
|
+
brandDeep: "#f5f0ff",
|
|
1738
|
+
surface: "#101218",
|
|
1739
|
+
surfaceMuted: "#1a1e27",
|
|
1740
|
+
text: "#f5f7fb",
|
|
1741
|
+
textMuted: "#b6bfce",
|
|
1742
|
+
textSubtle: "#919cad",
|
|
1743
|
+
border: "rgb(226 232 240 / 0.16)",
|
|
1744
|
+
visitorBubble: "#7c3aed",
|
|
1745
|
+
success: "#55cf91",
|
|
1746
|
+
danger: "#ff8da1"
|
|
1747
|
+
};
|
|
1748
|
+
|
|
1749
|
+
// src/react/hooks/useAgentColorScheme.ts
|
|
1750
|
+
var import_react4 = require("react");
|
|
1751
|
+
var DARK_MODE_QUERY = "(prefers-color-scheme: dark)";
|
|
1752
|
+
function subscribeToDarkMode(onChange) {
|
|
1753
|
+
if (typeof window === "undefined" || !window.matchMedia) {
|
|
1754
|
+
return () => void 0;
|
|
1755
|
+
}
|
|
1756
|
+
const mediaQuery = window.matchMedia(DARK_MODE_QUERY);
|
|
1757
|
+
if (typeof mediaQuery.addEventListener === "function") {
|
|
1758
|
+
mediaQuery.addEventListener("change", onChange);
|
|
1759
|
+
return () => mediaQuery.removeEventListener("change", onChange);
|
|
1760
|
+
}
|
|
1761
|
+
mediaQuery.addListener(onChange);
|
|
1762
|
+
return () => mediaQuery.removeListener(onChange);
|
|
1763
|
+
}
|
|
1764
|
+
function getPrefersDarkMode() {
|
|
1765
|
+
return typeof window !== "undefined" && Boolean(window.matchMedia?.(DARK_MODE_QUERY).matches);
|
|
1766
|
+
}
|
|
1767
|
+
function useAgentColorScheme(colorScheme = "auto") {
|
|
1768
|
+
const prefersDarkMode = (0, import_react4.useSyncExternalStore)(
|
|
1769
|
+
subscribeToDarkMode,
|
|
1770
|
+
getPrefersDarkMode,
|
|
1771
|
+
() => false
|
|
1772
|
+
);
|
|
1773
|
+
return resolveAgentColorScheme(colorScheme, prefersDarkMode);
|
|
1774
|
+
}
|
|
1775
|
+
function resolveAgentColorScheme(colorScheme = "auto", prefersDarkMode) {
|
|
1776
|
+
return colorScheme === "auto" ? prefersDarkMode ? "dark" : "light" : colorScheme;
|
|
1777
|
+
}
|
|
1321
1778
|
|
|
1322
1779
|
// src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
|
|
1780
|
+
var import_react5 = require("react");
|
|
1323
1781
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1324
1782
|
function workSummary(steps, failed, brandLabel) {
|
|
1325
1783
|
const active = [...steps].reverse().find((step) => step.state === "active");
|
|
1326
1784
|
if (active?.kind === "specialist")
|
|
1327
1785
|
return `${active.label} is reviewing your question`;
|
|
1328
1786
|
if (active?.kind === "search") return "Searching this site";
|
|
1329
|
-
if (active)
|
|
1787
|
+
if (active)
|
|
1788
|
+
return brandLabel ? `${brandLabel} is choosing the best way to help` : "Choosing the best way to help";
|
|
1330
1789
|
if (failed) return "Couldn\u2019t complete this request";
|
|
1331
1790
|
const hasError = steps.some((step) => step.state === "error");
|
|
1332
1791
|
const specialists = steps.filter(
|
|
@@ -1337,23 +1796,24 @@ function workSummary(steps, failed, brandLabel) {
|
|
|
1337
1796
|
);
|
|
1338
1797
|
if (hasError) return "Answered with available information";
|
|
1339
1798
|
if (specialists.length > 1)
|
|
1340
|
-
return `
|
|
1799
|
+
return `Brought in ${specialists.length} specialists`;
|
|
1341
1800
|
if (specialists.length === 1)
|
|
1342
|
-
return `
|
|
1343
|
-
if (searched) return "
|
|
1801
|
+
return `Brought in ${specialists[0]?.label}`;
|
|
1802
|
+
if (searched) return "Searched this site";
|
|
1344
1803
|
return "Answer ready";
|
|
1345
1804
|
}
|
|
1346
1805
|
function stepLabel(step, brandLabel) {
|
|
1347
|
-
return step.kind === "planning" ? brandLabel : step.label;
|
|
1806
|
+
return step.kind === "planning" ? brandLabel || "Supervisor" : step.label;
|
|
1348
1807
|
}
|
|
1349
1808
|
function stepDetail(step, steps) {
|
|
1350
1809
|
if (step.kind !== "planning" || step.state !== "completed") {
|
|
1351
1810
|
return step.detail;
|
|
1352
1811
|
}
|
|
1353
1812
|
const specialists = steps.filter((item) => item.kind === "specialist");
|
|
1354
|
-
if (specialists.length === 1)
|
|
1813
|
+
if (specialists.length === 1)
|
|
1814
|
+
return `Routed your question to ${specialists[0]?.label}`;
|
|
1355
1815
|
if (specialists.length > 1)
|
|
1356
|
-
return `
|
|
1816
|
+
return `Routed your question to ${specialists.length} specialists`;
|
|
1357
1817
|
if (steps.some((item) => item.kind === "search"))
|
|
1358
1818
|
return "Used built-in Search & Discovery";
|
|
1359
1819
|
return step.detail;
|
|
@@ -1384,13 +1844,17 @@ function PlanningIcon() {
|
|
|
1384
1844
|
) });
|
|
1385
1845
|
}
|
|
1386
1846
|
function AgentActivityBubble({
|
|
1387
|
-
brandLabel = "
|
|
1847
|
+
brandLabel = "",
|
|
1388
1848
|
brandLogoUrl,
|
|
1389
1849
|
failed = false,
|
|
1390
1850
|
steps
|
|
1391
1851
|
}) {
|
|
1392
1852
|
const active = steps.some((step) => step.state === "active");
|
|
1393
|
-
const
|
|
1853
|
+
const receiptId = steps.map((step) => step.id).join(":");
|
|
1854
|
+
const [expandedReceiptId, setExpandedReceiptId] = (0, import_react5.useState)(
|
|
1855
|
+
null
|
|
1856
|
+
);
|
|
1857
|
+
const detailsOpen = active || expandedReceiptId === receiptId;
|
|
1394
1858
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", { className: "agent-activity-bubble", children: [
|
|
1395
1859
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "agent-activity-bubble__status", "aria-live": "polite", children: [
|
|
1396
1860
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1402,62 +1866,69 @@ function AgentActivityBubble({
|
|
|
1402
1866
|
),
|
|
1403
1867
|
workSummary(steps, failed, brandLabel)
|
|
1404
1868
|
] }),
|
|
1405
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
{
|
|
1417
|
-
className: "agent-activity-bubble__step",
|
|
1418
|
-
"data-kind": step.kind,
|
|
1419
|
-
"data-state": step.state,
|
|
1420
|
-
children: [
|
|
1421
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1422
|
-
"span",
|
|
1423
|
-
{
|
|
1424
|
-
className: "agent-activity-bubble__step-icon",
|
|
1425
|
-
"aria-hidden": "true",
|
|
1426
|
-
children: step.kind === "planning" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1427
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlanningIcon, {}),
|
|
1428
|
-
brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1429
|
-
"img",
|
|
1430
|
-
{
|
|
1431
|
-
src: brandLogoUrl,
|
|
1432
|
-
alt: "",
|
|
1433
|
-
onError: (event) => {
|
|
1434
|
-
event.currentTarget.hidden = true;
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
) : null
|
|
1438
|
-
] }) : step.kind === "search" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) : step.label.slice(0, 1).toUpperCase()
|
|
1439
|
-
}
|
|
1440
|
-
),
|
|
1441
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-copy", children: [
|
|
1442
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-heading", children: [
|
|
1443
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: stepLabel(step, brandLabel) }),
|
|
1444
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: step.kind === "specialist" ? "Specialist" : step.kind === "search" ? "Built-in capability" : "Supervisor" })
|
|
1445
|
-
] }),
|
|
1446
|
-
detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-activity-bubble__step-detail", children: detail }) : null
|
|
1447
|
-
] })
|
|
1448
|
-
]
|
|
1449
|
-
},
|
|
1450
|
-
step.id
|
|
1869
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-activity-bubble__details", children: [
|
|
1870
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1871
|
+
"button",
|
|
1872
|
+
{
|
|
1873
|
+
type: "button",
|
|
1874
|
+
className: "agent-activity-bubble__summary",
|
|
1875
|
+
"aria-expanded": detailsOpen,
|
|
1876
|
+
onClick: () => {
|
|
1877
|
+
if (active) return;
|
|
1878
|
+
setExpandedReceiptId(
|
|
1879
|
+
(current) => current === receiptId ? null : receiptId
|
|
1451
1880
|
);
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1881
|
+
},
|
|
1882
|
+
children: "How this answer was made"
|
|
1883
|
+
}
|
|
1884
|
+
),
|
|
1885
|
+
detailsOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => {
|
|
1886
|
+
const detail = stepDetail(step, steps);
|
|
1887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1888
|
+
"li",
|
|
1889
|
+
{
|
|
1890
|
+
className: "agent-activity-bubble__step",
|
|
1891
|
+
"data-kind": step.kind,
|
|
1892
|
+
"data-state": step.state,
|
|
1893
|
+
children: [
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1895
|
+
"span",
|
|
1896
|
+
{
|
|
1897
|
+
className: "agent-activity-bubble__step-icon",
|
|
1898
|
+
"aria-hidden": "true",
|
|
1899
|
+
children: step.kind === "planning" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1900
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlanningIcon, {}),
|
|
1901
|
+
brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1902
|
+
"img",
|
|
1903
|
+
{
|
|
1904
|
+
src: brandLogoUrl,
|
|
1905
|
+
alt: "",
|
|
1906
|
+
onError: (event) => {
|
|
1907
|
+
event.currentTarget.hidden = true;
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
) : null
|
|
1911
|
+
] }) : step.kind === "search" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) : step.label.slice(0, 1).toUpperCase()
|
|
1912
|
+
}
|
|
1913
|
+
),
|
|
1914
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-copy", children: [
|
|
1915
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-heading", children: [
|
|
1916
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: stepLabel(step, brandLabel) }),
|
|
1917
|
+
step.kind === "planning" && !brandLabel ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: step.kind === "specialist" ? "Specialist" : step.kind === "search" ? "Built-in capability" : "Supervisor" })
|
|
1918
|
+
] }),
|
|
1919
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-activity-bubble__step-detail", children: detail }) : null
|
|
1920
|
+
] })
|
|
1921
|
+
]
|
|
1922
|
+
},
|
|
1923
|
+
step.id
|
|
1924
|
+
);
|
|
1925
|
+
}) }) : null
|
|
1926
|
+
] })
|
|
1456
1927
|
] });
|
|
1457
1928
|
}
|
|
1458
1929
|
|
|
1459
1930
|
// src/react/components/Composer/Composer.tsx
|
|
1460
|
-
var
|
|
1931
|
+
var import_react6 = require("react");
|
|
1461
1932
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1462
1933
|
function SendIcon() {
|
|
1463
1934
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 12V4M8 4l-3 3M8 4l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
@@ -1468,8 +1939,8 @@ function Composer({
|
|
|
1468
1939
|
variant = "default",
|
|
1469
1940
|
onSubmit
|
|
1470
1941
|
}) {
|
|
1471
|
-
const [value, setValue] = (0,
|
|
1472
|
-
const inputRef = (0,
|
|
1942
|
+
const [value, setValue] = (0, import_react6.useState)("");
|
|
1943
|
+
const inputRef = (0, import_react6.useRef)(null);
|
|
1473
1944
|
function submitCurrent() {
|
|
1474
1945
|
const trimmed = value.trim();
|
|
1475
1946
|
if (!trimmed || disabled) return;
|
|
@@ -1554,34 +2025,338 @@ function FollowUpChips({
|
|
|
1554
2025
|
] });
|
|
1555
2026
|
}
|
|
1556
2027
|
|
|
2028
|
+
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
2029
|
+
var import_react8 = require("react");
|
|
2030
|
+
|
|
2031
|
+
// src/react/components/BookingCard/BookingCard.tsx
|
|
2032
|
+
var import_react7 = require("react");
|
|
2033
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2034
|
+
function monthFromKey(key) {
|
|
2035
|
+
const [year, month] = key.split("-").map(Number);
|
|
2036
|
+
if (!year || !month) return { year: (/* @__PURE__ */ new Date()).getFullYear(), month: (/* @__PURE__ */ new Date()).getMonth() };
|
|
2037
|
+
return { year, month: month - 1 };
|
|
2038
|
+
}
|
|
2039
|
+
function dateKeyFromParts(year, month, day) {
|
|
2040
|
+
return [
|
|
2041
|
+
year,
|
|
2042
|
+
String(month + 1).padStart(2, "0"),
|
|
2043
|
+
String(day).padStart(2, "0")
|
|
2044
|
+
].join("-");
|
|
2045
|
+
}
|
|
2046
|
+
function calendarCells(year, month) {
|
|
2047
|
+
const firstWeekday = (new Date(year, month, 1).getDay() + 6) % 7;
|
|
2048
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
2049
|
+
const cells = [];
|
|
2050
|
+
for (let index = 0; index < firstWeekday; index += 1) cells.push(null);
|
|
2051
|
+
for (let day = 1; day <= daysInMonth; day += 1) {
|
|
2052
|
+
cells.push({ day, key: dateKeyFromParts(year, month, day) });
|
|
2053
|
+
}
|
|
2054
|
+
while (cells.length < 42) cells.push(null);
|
|
2055
|
+
return cells;
|
|
2056
|
+
}
|
|
2057
|
+
function BookingCard({
|
|
2058
|
+
offer,
|
|
2059
|
+
onBook
|
|
2060
|
+
}) {
|
|
2061
|
+
const fieldId = (0, import_react7.useId)();
|
|
2062
|
+
const defaultType = offer.eventTypes[0]?.uri ?? offer.slots[0]?.eventTypeUri ?? "";
|
|
2063
|
+
const [step, setStep] = (0, import_react7.useState)("date");
|
|
2064
|
+
const [eventTypeUri, setEventTypeUri] = (0, import_react7.useState)(defaultType);
|
|
2065
|
+
const [selectedDate, setSelectedDate] = (0, import_react7.useState)("");
|
|
2066
|
+
const [startTime, setStartTime] = (0, import_react7.useState)("");
|
|
2067
|
+
const [name, setName] = (0, import_react7.useState)("");
|
|
2068
|
+
const [email, setEmail] = (0, import_react7.useState)("");
|
|
2069
|
+
const slots = (0, import_react7.useMemo)(
|
|
2070
|
+
() => bookingSlotsForEventType(offer.slots, eventTypeUri),
|
|
2071
|
+
[eventTypeUri, offer.slots]
|
|
2072
|
+
);
|
|
2073
|
+
const availableByDate = (0, import_react7.useMemo)(() => {
|
|
2074
|
+
const next = /* @__PURE__ */ new Map();
|
|
2075
|
+
for (const slot of slots) {
|
|
2076
|
+
const key = slotDateKey(slot.startTime);
|
|
2077
|
+
if (!next.has(key)) next.set(key, slot.startTime);
|
|
2078
|
+
}
|
|
2079
|
+
return next;
|
|
2080
|
+
}, [slots]);
|
|
2081
|
+
const [visibleMonth, setVisibleMonth] = (0, import_react7.useState)(
|
|
2082
|
+
() => firstAvailableBookingMonth(slots)
|
|
2083
|
+
);
|
|
2084
|
+
function selectEventType(nextType) {
|
|
2085
|
+
setEventTypeUri(nextType);
|
|
2086
|
+
setSelectedDate("");
|
|
2087
|
+
setStartTime("");
|
|
2088
|
+
setVisibleMonth(
|
|
2089
|
+
firstAvailableBookingMonth(bookingSlotsForEventType(offer.slots, nextType))
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
const daySlots = (0, import_react7.useMemo)(
|
|
2093
|
+
() => slots.filter((slot) => slotDateKey(slot.startTime) === selectedDate),
|
|
2094
|
+
[selectedDate, slots]
|
|
2095
|
+
);
|
|
2096
|
+
const selectedType = offer.eventTypes.find((item) => item.uri === eventTypeUri);
|
|
2097
|
+
const selectedSample = availableByDate.get(selectedDate) ?? startTime;
|
|
2098
|
+
const timeZone = formatSlotTimeZone(slots[0]?.startTime ?? selectedSample);
|
|
2099
|
+
const weekdays = (0, import_react7.useMemo)(() => weekdayLabels(), []);
|
|
2100
|
+
const cells = calendarCells(visibleMonth.year, visibleMonth.month);
|
|
2101
|
+
const canPrevMonth = [...availableByDate.keys()].some((key) => {
|
|
2102
|
+
const month = monthFromKey(key);
|
|
2103
|
+
return month.year < visibleMonth.year || month.year === visibleMonth.year && month.month < visibleMonth.month;
|
|
2104
|
+
});
|
|
2105
|
+
const canNextMonth = [...availableByDate.keys()].some((key) => {
|
|
2106
|
+
const month = monthFromKey(key);
|
|
2107
|
+
return month.year > visibleMonth.year || month.year === visibleMonth.year && month.month > visibleMonth.month;
|
|
2108
|
+
});
|
|
2109
|
+
function goToMonth(offset) {
|
|
2110
|
+
setVisibleMonth((current) => {
|
|
2111
|
+
const next = new Date(current.year, current.month + offset, 1);
|
|
2112
|
+
return { year: next.getFullYear(), month: next.getMonth() };
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
function selectDate(key) {
|
|
2116
|
+
if (!availableByDate.has(key)) return;
|
|
2117
|
+
setSelectedDate(key);
|
|
2118
|
+
setStartTime("");
|
|
2119
|
+
setStep("time");
|
|
2120
|
+
}
|
|
2121
|
+
function selectTime(value) {
|
|
2122
|
+
setStartTime(value);
|
|
2123
|
+
setStep("details");
|
|
2124
|
+
}
|
|
2125
|
+
function handleSubmit(event) {
|
|
2126
|
+
event.preventDefault();
|
|
2127
|
+
if (!eventTypeUri || !startTime || !name.trim() || !email.trim()) return;
|
|
2128
|
+
onBook?.({
|
|
2129
|
+
displayText: `Book the ${formatSlotLabel(startTime)} demo`,
|
|
2130
|
+
runtimeText: formatBookingRequest({
|
|
2131
|
+
eventTypeUri,
|
|
2132
|
+
inviteeEmail: email.trim(),
|
|
2133
|
+
inviteeName: name.trim(),
|
|
2134
|
+
startTime,
|
|
2135
|
+
timezone: visitorTimeZone(),
|
|
2136
|
+
locationKind: selectedType?.locationKind,
|
|
2137
|
+
location: selectedType?.location
|
|
2138
|
+
})
|
|
2139
|
+
});
|
|
2140
|
+
}
|
|
2141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { className: "booking-card", "aria-label": "Book a meeting", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { className: "booking-card__form", onSubmit: handleSubmit, children: [
|
|
2142
|
+
step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
2143
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
|
|
2144
|
+
timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
|
|
2145
|
+
"Times in ",
|
|
2146
|
+
timeZone
|
|
2147
|
+
] }) : null,
|
|
2148
|
+
offer.eventTypes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "booking-card__field", htmlFor: `${fieldId}-type`, children: [
|
|
2149
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Meeting" }),
|
|
2150
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2151
|
+
"select",
|
|
2152
|
+
{
|
|
2153
|
+
id: `${fieldId}-type`,
|
|
2154
|
+
value: eventTypeUri,
|
|
2155
|
+
onChange: (event) => selectEventType(event.target.value),
|
|
2156
|
+
children: offer.eventTypes.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: item.uri, children: item.name }, item.uri))
|
|
2157
|
+
}
|
|
2158
|
+
)
|
|
2159
|
+
] }) : null,
|
|
2160
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__month", children: [
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2162
|
+
"button",
|
|
2163
|
+
{
|
|
2164
|
+
type: "button",
|
|
2165
|
+
className: "booking-card__nav",
|
|
2166
|
+
"aria-label": "Previous month",
|
|
2167
|
+
disabled: !canPrevMonth,
|
|
2168
|
+
onClick: () => goToMonth(-1),
|
|
2169
|
+
children: "\u2039"
|
|
2170
|
+
}
|
|
2171
|
+
),
|
|
2172
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__month-title", children: formatMonthTitle(visibleMonth.year, visibleMonth.month) }),
|
|
2173
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2174
|
+
"button",
|
|
2175
|
+
{
|
|
2176
|
+
type: "button",
|
|
2177
|
+
className: "booking-card__nav",
|
|
2178
|
+
"aria-label": "Next month",
|
|
2179
|
+
disabled: !canNextMonth,
|
|
2180
|
+
onClick: () => goToMonth(1),
|
|
2181
|
+
children: "\u203A"
|
|
2182
|
+
}
|
|
2183
|
+
)
|
|
2184
|
+
] }),
|
|
2185
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "booking-card__weekdays", children: weekdays.map((label) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: label }, label)) }),
|
|
2186
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "booking-card__calendar", role: "grid", "aria-label": "Available dates", children: cells.map((cell, index) => {
|
|
2187
|
+
if (!cell) {
|
|
2188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "booking-card__day" }, `empty-${index}`);
|
|
2189
|
+
}
|
|
2190
|
+
const available = availableByDate.has(cell.key);
|
|
2191
|
+
const selected = cell.key === selectedDate;
|
|
2192
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2193
|
+
"button",
|
|
2194
|
+
{
|
|
2195
|
+
type: "button",
|
|
2196
|
+
className: [
|
|
2197
|
+
"booking-card__day",
|
|
2198
|
+
available ? "booking-card__day--available" : "",
|
|
2199
|
+
selected ? "booking-card__day--selected" : ""
|
|
2200
|
+
].filter(Boolean).join(" "),
|
|
2201
|
+
disabled: !available,
|
|
2202
|
+
"aria-pressed": selected,
|
|
2203
|
+
onClick: () => selectDate(cell.key),
|
|
2204
|
+
children: cell.day
|
|
2205
|
+
},
|
|
2206
|
+
cell.key
|
|
2207
|
+
);
|
|
2208
|
+
}) })
|
|
2209
|
+
] }, "date") : null,
|
|
2210
|
+
step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2213
|
+
"button",
|
|
2214
|
+
{
|
|
2215
|
+
type: "button",
|
|
2216
|
+
className: "booking-card__nav",
|
|
2217
|
+
"aria-label": "Back to dates",
|
|
2218
|
+
onClick: () => setStep("date"),
|
|
2219
|
+
children: "\u2039"
|
|
2220
|
+
}
|
|
2221
|
+
),
|
|
2222
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
2223
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedSample ? formatLongDate(selectedSample) : "Pick a time" }),
|
|
2224
|
+
timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
|
|
2225
|
+
"Times in ",
|
|
2226
|
+
timeZone
|
|
2227
|
+
] }) : null
|
|
2228
|
+
] })
|
|
2229
|
+
] }),
|
|
2230
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "booking-card__times", children: daySlots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2231
|
+
"button",
|
|
2232
|
+
{
|
|
2233
|
+
type: "button",
|
|
2234
|
+
className: startTime === slot.startTime ? "booking-card__time booking-card__time--selected" : "booking-card__time",
|
|
2235
|
+
onClick: () => selectTime(slot.startTime),
|
|
2236
|
+
children: formatTimeChip(slot.startTime)
|
|
2237
|
+
},
|
|
2238
|
+
slot.startTime
|
|
2239
|
+
)) })
|
|
2240
|
+
] }, "time") : null,
|
|
2241
|
+
step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
|
|
2243
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2244
|
+
"button",
|
|
2245
|
+
{
|
|
2246
|
+
type: "button",
|
|
2247
|
+
className: "booking-card__nav",
|
|
2248
|
+
"aria-label": "Back to times",
|
|
2249
|
+
onClick: () => setStep("time"),
|
|
2250
|
+
children: "\u2039"
|
|
2251
|
+
}
|
|
2252
|
+
),
|
|
2253
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
2254
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: "Enter details" }),
|
|
2255
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: formatSlotLabel(startTime) }),
|
|
2256
|
+
selectedType?.location ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: selectedType.location }) : null
|
|
2257
|
+
] })
|
|
2258
|
+
] }),
|
|
2259
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__identity", children: [
|
|
2260
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "booking-card__field", htmlFor: `${fieldId}-name`, children: [
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Name" }),
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2263
|
+
"input",
|
|
2264
|
+
{
|
|
2265
|
+
id: `${fieldId}-name`,
|
|
2266
|
+
autoComplete: "name",
|
|
2267
|
+
value: name,
|
|
2268
|
+
onChange: (event) => setName(event.target.value),
|
|
2269
|
+
required: true
|
|
2270
|
+
}
|
|
2271
|
+
)
|
|
2272
|
+
] }),
|
|
2273
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "booking-card__field", htmlFor: `${fieldId}-email`, children: [
|
|
2274
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Email" }),
|
|
2275
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2276
|
+
"input",
|
|
2277
|
+
{
|
|
2278
|
+
id: `${fieldId}-email`,
|
|
2279
|
+
type: "email",
|
|
2280
|
+
autoComplete: "email",
|
|
2281
|
+
value: email,
|
|
2282
|
+
onChange: (event) => setEmail(event.target.value),
|
|
2283
|
+
required: true
|
|
2284
|
+
}
|
|
2285
|
+
)
|
|
2286
|
+
] })
|
|
2287
|
+
] }),
|
|
2288
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "submit", className: "booking-card__submit", children: "Book this time" })
|
|
2289
|
+
] }, "details") : null
|
|
2290
|
+
] }) });
|
|
2291
|
+
}
|
|
2292
|
+
|
|
1557
2293
|
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
1558
2294
|
var import_streamdown = require("streamdown");
|
|
1559
2295
|
var import_styles = require("streamdown/styles.css");
|
|
1560
|
-
var
|
|
1561
|
-
function MessageBubble({
|
|
2296
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2297
|
+
function MessageBubble({
|
|
2298
|
+
message,
|
|
2299
|
+
brandLogoUrl,
|
|
2300
|
+
offer,
|
|
2301
|
+
onBook
|
|
2302
|
+
}) {
|
|
2303
|
+
const resolvedLogoUrl = brandLogoUrl?.trim();
|
|
2304
|
+
const [failedLogoUrl, setFailedLogoUrl] = (0, import_react8.useState)(null);
|
|
2305
|
+
const showBrandLogo = Boolean(resolvedLogoUrl) && failedLogoUrl !== resolvedLogoUrl;
|
|
2306
|
+
const cards = message.role === "agent" ? extractToolCards(message.text) : [];
|
|
2307
|
+
const extractedOffers = cards.filter(
|
|
2308
|
+
(card) => card.type === "booking_offer"
|
|
2309
|
+
);
|
|
2310
|
+
const offers = offer ? [offer] : extractedOffers;
|
|
2311
|
+
const visibleText = hideToolCardFences(message.text);
|
|
2312
|
+
const isStreaming = message.role === "agent" && Boolean(message.streaming);
|
|
2313
|
+
const displayText = offers.length > 0 ? visibleText || "Pick a date and time that works for you." : visibleText || (isStreaming ? "" : message.text);
|
|
1562
2314
|
if (message.role === "visitor") {
|
|
1563
|
-
return /* @__PURE__ */ (0,
|
|
2315
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "message-bubble__text", children: message.text }) });
|
|
1564
2316
|
}
|
|
1565
|
-
|
|
2317
|
+
const agentText = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1566
2318
|
import_streamdown.Streamdown,
|
|
1567
2319
|
{
|
|
1568
2320
|
animated: true,
|
|
1569
2321
|
caret: "circle",
|
|
1570
2322
|
className: "message-bubble__markdown",
|
|
1571
2323
|
controls: false,
|
|
1572
|
-
isAnimating:
|
|
2324
|
+
isAnimating: isStreaming,
|
|
1573
2325
|
linkSafety: { enabled: false },
|
|
1574
|
-
mode:
|
|
2326
|
+
mode: isStreaming ? "streaming" : "static",
|
|
1575
2327
|
skipHtml: true,
|
|
1576
|
-
children:
|
|
2328
|
+
children: displayText
|
|
1577
2329
|
}
|
|
1578
|
-
) })
|
|
2330
|
+
) });
|
|
2331
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
|
|
2332
|
+
displayText ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "message-bubble__agent-row", children: [
|
|
2333
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2334
|
+
"img",
|
|
2335
|
+
{
|
|
2336
|
+
src: resolvedLogoUrl,
|
|
2337
|
+
alt: "",
|
|
2338
|
+
onError: () => {
|
|
2339
|
+
setFailedLogoUrl(resolvedLogoUrl ?? null);
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
) }),
|
|
2343
|
+
agentText
|
|
2344
|
+
] }) : agentText : null,
|
|
2345
|
+
offers.map((nextOffer, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2346
|
+
BookingCard,
|
|
2347
|
+
{
|
|
2348
|
+
offer: nextOffer,
|
|
2349
|
+
onBook
|
|
2350
|
+
},
|
|
2351
|
+
`${bookingOfferIdentityKey(nextOffer)}-${index}`
|
|
2352
|
+
))
|
|
2353
|
+
] });
|
|
1579
2354
|
}
|
|
1580
2355
|
|
|
1581
2356
|
// src/react/components/AgentRail/AgentRail.tsx
|
|
1582
|
-
var
|
|
2357
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1583
2358
|
function MinimizeIcon() {
|
|
1584
|
-
return /* @__PURE__ */ (0,
|
|
2359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1585
2360
|
"path",
|
|
1586
2361
|
{
|
|
1587
2362
|
d: "M3.5 8h9",
|
|
@@ -1592,7 +2367,7 @@ function MinimizeIcon() {
|
|
|
1592
2367
|
) });
|
|
1593
2368
|
}
|
|
1594
2369
|
function CloseIcon() {
|
|
1595
|
-
return /* @__PURE__ */ (0,
|
|
2370
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1596
2371
|
"path",
|
|
1597
2372
|
{
|
|
1598
2373
|
d: "M4 4l8 8M12 4l-8 8",
|
|
@@ -1603,7 +2378,7 @@ function CloseIcon() {
|
|
|
1603
2378
|
) });
|
|
1604
2379
|
}
|
|
1605
2380
|
function NewChatIcon() {
|
|
1606
|
-
return /* @__PURE__ */ (0,
|
|
2381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1607
2382
|
"path",
|
|
1608
2383
|
{
|
|
1609
2384
|
d: "M9.5 3.5h3v3M12.25 3.75 8 8M7 4H4.5A1.5 1.5 0 0 0 3 5.5v6A1.5 1.5 0 0 0 4.5 13h6a1.5 1.5 0 0 0 1.5-1.5V9",
|
|
@@ -1615,7 +2390,7 @@ function NewChatIcon() {
|
|
|
1615
2390
|
) });
|
|
1616
2391
|
}
|
|
1617
2392
|
function ExpandIcon() {
|
|
1618
|
-
return /* @__PURE__ */ (0,
|
|
2393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1619
2394
|
"path",
|
|
1620
2395
|
{
|
|
1621
2396
|
d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
|
|
@@ -1627,7 +2402,7 @@ function ExpandIcon() {
|
|
|
1627
2402
|
) });
|
|
1628
2403
|
}
|
|
1629
2404
|
function RestoreIcon() {
|
|
1630
|
-
return /* @__PURE__ */ (0,
|
|
2405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1631
2406
|
"path",
|
|
1632
2407
|
{
|
|
1633
2408
|
d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
|
|
@@ -1641,7 +2416,8 @@ function RestoreIcon() {
|
|
|
1641
2416
|
function AgentRail({
|
|
1642
2417
|
state,
|
|
1643
2418
|
theme,
|
|
1644
|
-
|
|
2419
|
+
colorScheme = "auto",
|
|
2420
|
+
brandLabel = "",
|
|
1645
2421
|
brandLogoUrl,
|
|
1646
2422
|
poweredByLabel = "Powered by Webless",
|
|
1647
2423
|
composerPlaceholder = "Ask anything\u2026",
|
|
@@ -1653,11 +2429,31 @@ function AgentRail({
|
|
|
1653
2429
|
onReset,
|
|
1654
2430
|
onRetry,
|
|
1655
2431
|
onSubmit,
|
|
1656
|
-
onFollowUpSelect
|
|
2432
|
+
onFollowUpSelect,
|
|
2433
|
+
onBook
|
|
1657
2434
|
}) {
|
|
1658
|
-
const transcriptRef = (0,
|
|
1659
|
-
const
|
|
1660
|
-
const
|
|
2435
|
+
const transcriptRef = (0, import_react9.useRef)(null);
|
|
2436
|
+
const resolvedBrandLabel = brandLabel.trim();
|
|
2437
|
+
const resolvedBrandLogoUrl = brandLogoUrl?.trim();
|
|
2438
|
+
const [failedLogoUrl, setFailedLogoUrl] = (0, import_react9.useState)(null);
|
|
2439
|
+
const showBrandLogo = Boolean(resolvedBrandLogoUrl) && failedLogoUrl !== resolvedBrandLogoUrl;
|
|
2440
|
+
const resolvedColorScheme = useAgentColorScheme(colorScheme);
|
|
2441
|
+
const brandedTheme = { ...defaultAgentRailTheme, ...theme };
|
|
2442
|
+
const resolvedTheme = resolvedColorScheme === "dark" ? {
|
|
2443
|
+
...brandedTheme,
|
|
2444
|
+
brand: theme?.brand ?? defaultDarkAgentRailTheme.brand,
|
|
2445
|
+
brandDeep: defaultDarkAgentRailTheme.brandDeep,
|
|
2446
|
+
brandSoft: `color-mix(in srgb, ${theme?.brand ?? defaultDarkAgentRailTheme.brand} 18%, ${defaultDarkAgentRailTheme.surface})`,
|
|
2447
|
+
border: defaultDarkAgentRailTheme.border,
|
|
2448
|
+
danger: defaultDarkAgentRailTheme.danger,
|
|
2449
|
+
success: defaultDarkAgentRailTheme.success,
|
|
2450
|
+
surface: defaultDarkAgentRailTheme.surface,
|
|
2451
|
+
surfaceMuted: defaultDarkAgentRailTheme.surfaceMuted,
|
|
2452
|
+
text: defaultDarkAgentRailTheme.text,
|
|
2453
|
+
textMuted: defaultDarkAgentRailTheme.textMuted,
|
|
2454
|
+
textSubtle: defaultDarkAgentRailTheme.textSubtle,
|
|
2455
|
+
visitorBubble: theme?.visitorBubble ?? theme?.brand ?? defaultDarkAgentRailTheme.visitorBubble
|
|
2456
|
+
} : brandedTheme;
|
|
1661
2457
|
const railStyle = {
|
|
1662
2458
|
"--rail-width": resolvedTheme.railMaxWidth,
|
|
1663
2459
|
"--as-rail-max-width": resolvedTheme.railMaxWidth,
|
|
@@ -1675,7 +2471,8 @@ function AgentRail({
|
|
|
1675
2471
|
"--as-success": resolvedTheme.success,
|
|
1676
2472
|
"--as-danger": resolvedTheme.danger,
|
|
1677
2473
|
"--as-font-body": resolvedTheme.fontBody,
|
|
1678
|
-
"--as-font-display": resolvedTheme.fontDisplay
|
|
2474
|
+
"--as-font-display": resolvedTheme.fontDisplay,
|
|
2475
|
+
colorScheme: resolvedColorScheme
|
|
1679
2476
|
};
|
|
1680
2477
|
const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
|
|
1681
2478
|
const showActivity = state.toolSteps.length > 0;
|
|
@@ -1686,7 +2483,7 @@ function AgentRail({
|
|
|
1686
2483
|
const greeting = state.messages.find(
|
|
1687
2484
|
(message) => message.role === "agent" && message.id === "greeting"
|
|
1688
2485
|
);
|
|
1689
|
-
const visibleMessages = hasVisitorMessages2 ? state.messages
|
|
2486
|
+
const visibleMessages = hasVisitorMessages2 ? state.messages : [];
|
|
1690
2487
|
const lastMessage = visibleMessages.at(-1);
|
|
1691
2488
|
const completedAnswer = showActivity && state.phase === "complete" && lastMessage?.role === "agent" ? lastMessage : null;
|
|
1692
2489
|
const transcriptMessages = completedAnswer ? visibleMessages.slice(0, -1) : visibleMessages;
|
|
@@ -1696,8 +2493,14 @@ function AgentRail({
|
|
|
1696
2493
|
role: "agent",
|
|
1697
2494
|
streaming: true,
|
|
1698
2495
|
text: state.streamingText
|
|
2496
|
+
} : state.pendingOffer ? {
|
|
2497
|
+
createdAt: 0,
|
|
2498
|
+
id: "pending-booking",
|
|
2499
|
+
role: "agent",
|
|
2500
|
+
streaming: false,
|
|
2501
|
+
text: "Pick a date and time that works for you."
|
|
1699
2502
|
} : null;
|
|
1700
|
-
(0,
|
|
2503
|
+
(0, import_react9.useEffect)(() => {
|
|
1701
2504
|
const node = transcriptRef.current;
|
|
1702
2505
|
if (!node) return;
|
|
1703
2506
|
node.scrollTop = node.scrollHeight;
|
|
@@ -1708,10 +2511,11 @@ function AgentRail({
|
|
|
1708
2511
|
state.followUps,
|
|
1709
2512
|
state.journey
|
|
1710
2513
|
]);
|
|
1711
|
-
return /* @__PURE__ */ (0,
|
|
2514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1712
2515
|
"aside",
|
|
1713
2516
|
{
|
|
1714
2517
|
className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
|
|
2518
|
+
"data-color-scheme": resolvedColorScheme,
|
|
1715
2519
|
style: railStyle,
|
|
1716
2520
|
"aria-label": "Agent conversation",
|
|
1717
2521
|
"aria-modal": mobileFullscreen || expanded ? true : void 0,
|
|
@@ -1719,45 +2523,42 @@ function AgentRail({
|
|
|
1719
2523
|
role: mobileFullscreen || expanded ? "dialog" : void 0,
|
|
1720
2524
|
tabIndex: mobileFullscreen || expanded ? -1 : void 0,
|
|
1721
2525
|
children: [
|
|
1722
|
-
/* @__PURE__ */ (0,
|
|
1723
|
-
onCollapse ? /* @__PURE__ */ (0,
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__brand-row", children: [
|
|
2527
|
+
onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1724
2528
|
"button",
|
|
1725
2529
|
{
|
|
1726
2530
|
type: "button",
|
|
1727
2531
|
className: "agent-rail__collapse",
|
|
1728
2532
|
"aria-label": "Collapse assist",
|
|
1729
2533
|
onClick: onCollapse,
|
|
1730
|
-
children: /* @__PURE__ */ (0,
|
|
2534
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
|
|
1731
2535
|
}
|
|
1732
|
-
) : onClose ? /* @__PURE__ */ (0,
|
|
2536
|
+
) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1733
2537
|
"button",
|
|
1734
2538
|
{
|
|
1735
2539
|
type: "button",
|
|
1736
2540
|
className: "agent-rail__close",
|
|
1737
2541
|
"aria-label": "Close agent",
|
|
1738
2542
|
onClick: onClose,
|
|
1739
|
-
children: /* @__PURE__ */ (0,
|
|
2543
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, {})
|
|
1740
2544
|
}
|
|
1741
|
-
) : /* @__PURE__ */ (0,
|
|
1742
|
-
/* @__PURE__ */ (0,
|
|
1743
|
-
/* @__PURE__ */ (0,
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
"
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
onError: (event) => {
|
|
1752
|
-
event.currentTarget.hidden = true;
|
|
1753
|
-
}
|
|
2545
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
|
|
2546
|
+
resolvedBrandLabel || showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "agent-rail__identity", children: [
|
|
2547
|
+
showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2548
|
+
"img",
|
|
2549
|
+
{
|
|
2550
|
+
className: "agent-rail__brand-logo",
|
|
2551
|
+
src: resolvedBrandLogoUrl,
|
|
2552
|
+
alt: "",
|
|
2553
|
+
onError: () => {
|
|
2554
|
+
setFailedLogoUrl(resolvedBrandLogoUrl ?? null);
|
|
1754
2555
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
/* @__PURE__ */ (0,
|
|
1758
|
-
] }),
|
|
1759
|
-
/* @__PURE__ */ (0,
|
|
1760
|
-
onReset ? /* @__PURE__ */ (0,
|
|
2556
|
+
}
|
|
2557
|
+
) }) : null,
|
|
2558
|
+
resolvedBrandLabel ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: resolvedBrandLabel }) : null
|
|
2559
|
+
] }) : null,
|
|
2560
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "agent-rail__actions", children: [
|
|
2561
|
+
onReset ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1761
2562
|
"button",
|
|
1762
2563
|
{
|
|
1763
2564
|
type: "button",
|
|
@@ -1765,80 +2566,86 @@ function AgentRail({
|
|
|
1765
2566
|
"aria-label": "Start a new conversation",
|
|
1766
2567
|
disabled: !hasVisitorMessages2,
|
|
1767
2568
|
onClick: onReset,
|
|
1768
|
-
children: /* @__PURE__ */ (0,
|
|
2569
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NewChatIcon, {})
|
|
1769
2570
|
}
|
|
1770
2571
|
) : null,
|
|
1771
|
-
onExpandToggle ? /* @__PURE__ */ (0,
|
|
2572
|
+
onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1772
2573
|
"button",
|
|
1773
2574
|
{
|
|
1774
2575
|
type: "button",
|
|
1775
2576
|
className: "agent-rail__expand",
|
|
1776
|
-
"aria-label": expanded ? "Exit
|
|
2577
|
+
"aria-label": expanded ? "Exit full screen" : "Open full screen",
|
|
1777
2578
|
onClick: onExpandToggle,
|
|
1778
|
-
children: expanded ? /* @__PURE__ */ (0,
|
|
2579
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
|
|
1779
2580
|
}
|
|
1780
2581
|
) : null
|
|
1781
2582
|
] })
|
|
1782
2583
|
] }) }),
|
|
1783
|
-
/* @__PURE__ */ (0,
|
|
1784
|
-
!hasVisitorMessages2 ? /* @__PURE__ */ (0,
|
|
1785
|
-
"
|
|
2584
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__thread", children: [
|
|
2585
|
+
!hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
2586
|
+
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2587
|
+
MessageBubble,
|
|
2588
|
+
{
|
|
2589
|
+
message: greeting,
|
|
2590
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
2591
|
+
onBook
|
|
2592
|
+
}
|
|
2593
|
+
) : null,
|
|
2594
|
+
showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2595
|
+
FollowUpChips,
|
|
2596
|
+
{
|
|
2597
|
+
suggestions: state.followUps,
|
|
2598
|
+
disabled: isBusy,
|
|
2599
|
+
label: "Start here",
|
|
2600
|
+
onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
|
|
2601
|
+
}
|
|
2602
|
+
) }) : null
|
|
2603
|
+
] }) : null,
|
|
2604
|
+
transcriptMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2605
|
+
MessageBubble,
|
|
1786
2606
|
{
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
{
|
|
1795
|
-
className: "agent-rail__welcome-logo",
|
|
1796
|
-
src: brandLogoUrl,
|
|
1797
|
-
alt: "",
|
|
1798
|
-
onError: (event) => {
|
|
1799
|
-
event.currentTarget.hidden = true;
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
) : null
|
|
1803
|
-
] }),
|
|
1804
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__welcome-copy", children: [
|
|
1805
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { id: welcomeTitleId, children: "What can I help you find?" }),
|
|
1806
|
-
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: greeting.text }) : null
|
|
1807
|
-
] }),
|
|
1808
|
-
showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1809
|
-
FollowUpChips,
|
|
1810
|
-
{
|
|
1811
|
-
suggestions: state.followUps,
|
|
1812
|
-
disabled: isBusy,
|
|
1813
|
-
label: "Start here",
|
|
1814
|
-
onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
|
|
1815
|
-
}
|
|
1816
|
-
) }) : null
|
|
1817
|
-
]
|
|
1818
|
-
}
|
|
1819
|
-
) : null,
|
|
1820
|
-
transcriptMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message }, message.id)),
|
|
1821
|
-
showActivity ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2607
|
+
message,
|
|
2608
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
2609
|
+
onBook
|
|
2610
|
+
},
|
|
2611
|
+
message.id
|
|
2612
|
+
)),
|
|
2613
|
+
showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1822
2614
|
AgentActivityBubble,
|
|
1823
2615
|
{
|
|
1824
|
-
brandLabel,
|
|
1825
|
-
brandLogoUrl,
|
|
2616
|
+
brandLabel: resolvedBrandLabel,
|
|
2617
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
1826
2618
|
failed: state.phase === "error",
|
|
1827
2619
|
steps: state.toolSteps
|
|
1828
2620
|
}
|
|
1829
2621
|
) : null,
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
2622
|
+
completedAnswer ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2623
|
+
MessageBubble,
|
|
2624
|
+
{
|
|
2625
|
+
message: completedAnswer,
|
|
2626
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
2627
|
+
onBook
|
|
2628
|
+
}
|
|
2629
|
+
) : null,
|
|
2630
|
+
streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2631
|
+
MessageBubble,
|
|
2632
|
+
{
|
|
2633
|
+
message: streamingMessage,
|
|
2634
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
2635
|
+
offer: state.pendingOffer,
|
|
2636
|
+
onBook
|
|
2637
|
+
}
|
|
2638
|
+
) : null,
|
|
2639
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
2641
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "Something went wrong" }),
|
|
2642
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: state.error })
|
|
1836
2643
|
] }),
|
|
1837
|
-
onRetry ? /* @__PURE__ */ (0,
|
|
2644
|
+
onRetry ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
|
|
1838
2645
|
] }) : null
|
|
1839
2646
|
] }) }),
|
|
1840
|
-
/* @__PURE__ */ (0,
|
|
1841
|
-
/* @__PURE__ */ (0,
|
|
2647
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
|
|
2648
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1842
2649
|
Composer,
|
|
1843
2650
|
{
|
|
1844
2651
|
variant: expanded || mobileFullscreen ? "dock" : "default",
|
|
@@ -1847,10 +2654,9 @@ function AgentRail({
|
|
|
1847
2654
|
onSubmit
|
|
1848
2655
|
}
|
|
1849
2656
|
),
|
|
1850
|
-
/* @__PURE__ */ (0,
|
|
1851
|
-
/* @__PURE__ */ (0,
|
|
1852
|
-
/* @__PURE__ */ (0,
|
|
1853
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: poweredByLabel })
|
|
2657
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
|
|
2658
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "AI can make mistakes. Check important info." }),
|
|
2659
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: poweredByLabel })
|
|
1854
2660
|
] }) })
|
|
1855
2661
|
] })
|
|
1856
2662
|
]
|
|
@@ -1859,9 +2665,9 @@ function AgentRail({
|
|
|
1859
2665
|
}
|
|
1860
2666
|
|
|
1861
2667
|
// src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
|
|
1862
|
-
var
|
|
2668
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1863
2669
|
function SparklesIcon() {
|
|
1864
|
-
return /* @__PURE__ */ (0,
|
|
2670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1865
2671
|
"svg",
|
|
1866
2672
|
{
|
|
1867
2673
|
className: "assist-edge-tab__sparkles",
|
|
@@ -1869,21 +2675,21 @@ function SparklesIcon() {
|
|
|
1869
2675
|
fill: "none",
|
|
1870
2676
|
"aria-hidden": "true",
|
|
1871
2677
|
children: [
|
|
1872
|
-
/* @__PURE__ */ (0,
|
|
2678
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1873
2679
|
"path",
|
|
1874
2680
|
{
|
|
1875
2681
|
d: "M8 1.2l.95 2.7 2.85.05-2.25 1.75.8 2.75L8 6.7 5.65 8.45l.8-2.75L4.2 3.95l2.85-.05L8 1.2z",
|
|
1876
2682
|
fill: "currentColor"
|
|
1877
2683
|
}
|
|
1878
2684
|
),
|
|
1879
|
-
/* @__PURE__ */ (0,
|
|
2685
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1880
2686
|
"path",
|
|
1881
2687
|
{
|
|
1882
2688
|
d: "M14.2 6.4l.55 1.55 1.65.03-1.3 1 .46 1.58-1.36-1-1.36 1 .46-1.58-1.3-1 1.65-.03.55-1.55z",
|
|
1883
2689
|
fill: "currentColor"
|
|
1884
2690
|
}
|
|
1885
2691
|
),
|
|
1886
|
-
/* @__PURE__ */ (0,
|
|
2692
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1887
2693
|
"path",
|
|
1888
2694
|
{
|
|
1889
2695
|
d: "M3.1 9.1l.4 1.15 1.22.02-.96.74.34 1.17-1-.74-1 .74.34-1.17-.96-.74 1.22-.02.4-1.15z",
|
|
@@ -1894,8 +2700,23 @@ function SparklesIcon() {
|
|
|
1894
2700
|
}
|
|
1895
2701
|
);
|
|
1896
2702
|
}
|
|
2703
|
+
function TabMarkIcon({ customIconUrl }) {
|
|
2704
|
+
const url = customIconUrl?.trim();
|
|
2705
|
+
if (url) {
|
|
2706
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2707
|
+
"img",
|
|
2708
|
+
{
|
|
2709
|
+
alt: "",
|
|
2710
|
+
"aria-hidden": true,
|
|
2711
|
+
className: "assist-edge-tab__custom-icon",
|
|
2712
|
+
src: url
|
|
2713
|
+
}
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2716
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {});
|
|
2717
|
+
}
|
|
1897
2718
|
function ChevronLeftIcon() {
|
|
1898
|
-
return /* @__PURE__ */ (0,
|
|
2719
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1899
2720
|
"path",
|
|
1900
2721
|
{
|
|
1901
2722
|
d: "M10 4L6 8l4 4",
|
|
@@ -1907,7 +2728,7 @@ function ChevronLeftIcon() {
|
|
|
1907
2728
|
) });
|
|
1908
2729
|
}
|
|
1909
2730
|
function ChevronDownIcon() {
|
|
1910
|
-
return /* @__PURE__ */ (0,
|
|
2731
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1911
2732
|
"path",
|
|
1912
2733
|
{
|
|
1913
2734
|
d: "M4 6l4 4 4-4",
|
|
@@ -1919,12 +2740,12 @@ function ChevronDownIcon() {
|
|
|
1919
2740
|
) });
|
|
1920
2741
|
}
|
|
1921
2742
|
function DragDots() {
|
|
1922
|
-
return /* @__PURE__ */ (0,
|
|
2743
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("i", {}, index)) });
|
|
1923
2744
|
}
|
|
1924
2745
|
var VARIANT_COPY = {
|
|
1925
|
-
outline: { label: "
|
|
2746
|
+
outline: { label: "Ask anything", aria: "Ask anything" },
|
|
1926
2747
|
ask: { label: "Ask anything", aria: "Ask anything" },
|
|
1927
|
-
fill: { label: "
|
|
2748
|
+
fill: { label: "Ask anything", aria: "Ask anything" }
|
|
1928
2749
|
};
|
|
1929
2750
|
function AssistEdgeTab({
|
|
1930
2751
|
variant,
|
|
@@ -1933,6 +2754,7 @@ function AssistEdgeTab({
|
|
|
1933
2754
|
inset,
|
|
1934
2755
|
visible,
|
|
1935
2756
|
label,
|
|
2757
|
+
customIconUrl,
|
|
1936
2758
|
logoUrl,
|
|
1937
2759
|
brandColor,
|
|
1938
2760
|
brandForeground,
|
|
@@ -1941,40 +2763,49 @@ function AssistEdgeTab({
|
|
|
1941
2763
|
mobile = false,
|
|
1942
2764
|
surfaceColor,
|
|
1943
2765
|
textColor,
|
|
2766
|
+
colorScheme = "auto",
|
|
1944
2767
|
onOpen
|
|
1945
2768
|
}) {
|
|
2769
|
+
const resolvedColorScheme = useAgentColorScheme(colorScheme);
|
|
1946
2770
|
const copy = VARIANT_COPY[variant];
|
|
1947
2771
|
const visibleLabel = label?.trim() || copy.label;
|
|
2772
|
+
const showLogo = Boolean(logoUrl?.trim()) && !customIconUrl?.trim();
|
|
2773
|
+
const resolvedBrandColor = brandColor ?? (resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.brand : void 0);
|
|
2774
|
+
const resolvedBorderColor = resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.border : borderColor;
|
|
2775
|
+
const resolvedSurfaceColor = resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.surface : surfaceColor;
|
|
2776
|
+
const resolvedTextColor = resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.text : textColor;
|
|
1948
2777
|
const style = {
|
|
1949
2778
|
"--tab-along": `${along}%`,
|
|
1950
2779
|
"--tab-inset": `${inset}px`,
|
|
1951
|
-
...
|
|
2780
|
+
...resolvedBrandColor ? { "--as-brand": resolvedBrandColor } : {},
|
|
1952
2781
|
...brandForeground ? { "--as-visitor-text": brandForeground } : {},
|
|
1953
|
-
...
|
|
2782
|
+
...resolvedBorderColor ? { "--as-border": resolvedBorderColor } : {},
|
|
1954
2783
|
...fontFamily ? { "--as-font-display": fontFamily } : {},
|
|
1955
|
-
...
|
|
1956
|
-
...
|
|
2784
|
+
...resolvedSurfaceColor ? { "--as-surface": resolvedSurfaceColor } : {},
|
|
2785
|
+
...resolvedTextColor ? { "--as-text": resolvedTextColor } : {},
|
|
2786
|
+
colorScheme: resolvedColorScheme
|
|
1957
2787
|
};
|
|
1958
|
-
return /* @__PURE__ */ (0,
|
|
2788
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1959
2789
|
"button",
|
|
1960
2790
|
{
|
|
1961
2791
|
type: "button",
|
|
1962
2792
|
className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${mobile ? " assist-edge-tab--mobile" : ""}${visible ? " is-visible" : ""}`,
|
|
2793
|
+
"data-color-scheme": resolvedColorScheme,
|
|
1963
2794
|
style,
|
|
1964
2795
|
"aria-label": `Open ${visibleLabel}`,
|
|
1965
2796
|
"aria-hidden": !visible,
|
|
1966
2797
|
tabIndex: visible ? 0 : -1,
|
|
1967
2798
|
onClick: onOpen,
|
|
1968
2799
|
children: [
|
|
1969
|
-
mobile ? /* @__PURE__ */ (0,
|
|
1970
|
-
/* @__PURE__ */ (0,
|
|
2800
|
+
mobile ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2801
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1971
2802
|
"span",
|
|
1972
2803
|
{
|
|
1973
2804
|
className: "assist-edge-tab__mark assist-edge-tab__mark--mobile",
|
|
1974
2805
|
"aria-hidden": "true",
|
|
1975
2806
|
children: [
|
|
1976
|
-
|
|
1977
|
-
|
|
2807
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabMarkIcon, { customIconUrl }),
|
|
2808
|
+
showLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1978
2809
|
"img",
|
|
1979
2810
|
{
|
|
1980
2811
|
className: "assist-edge-tab__logo",
|
|
@@ -1988,14 +2819,11 @@ function AssistEdgeTab({
|
|
|
1988
2819
|
]
|
|
1989
2820
|
}
|
|
1990
2821
|
),
|
|
1991
|
-
/* @__PURE__ */ (0,
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
|
|
1997
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
|
|
1998
|
-
logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2822
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel })
|
|
2823
|
+
] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2824
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
|
|
2825
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabMarkIcon, { customIconUrl }),
|
|
2826
|
+
showLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1999
2827
|
"img",
|
|
2000
2828
|
{
|
|
2001
2829
|
className: "assist-edge-tab__logo",
|
|
@@ -2007,18 +2835,18 @@ function AssistEdgeTab({
|
|
|
2007
2835
|
}
|
|
2008
2836
|
) : null
|
|
2009
2837
|
] }),
|
|
2010
|
-
/* @__PURE__ */ (0,
|
|
2011
|
-
/* @__PURE__ */ (0,
|
|
2838
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
2839
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
|
|
2012
2840
|
] }) : null,
|
|
2013
|
-
variant === "ask" ? /* @__PURE__ */ (0,
|
|
2014
|
-
/* @__PURE__ */ (0,
|
|
2015
|
-
/* @__PURE__ */ (0,
|
|
2016
|
-
/* @__PURE__ */ (0,
|
|
2841
|
+
variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2842
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
|
|
2843
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
2844
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
|
|
2017
2845
|
] }) : null,
|
|
2018
|
-
variant === "fill" ? /* @__PURE__ */ (0,
|
|
2019
|
-
/* @__PURE__ */ (0,
|
|
2020
|
-
/* @__PURE__ */ (0,
|
|
2021
|
-
|
|
2846
|
+
variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2847
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
|
|
2848
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabMarkIcon, { customIconUrl }),
|
|
2849
|
+
showLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2022
2850
|
"img",
|
|
2023
2851
|
{
|
|
2024
2852
|
className: "assist-edge-tab__logo",
|
|
@@ -2030,8 +2858,8 @@ function AssistEdgeTab({
|
|
|
2030
2858
|
}
|
|
2031
2859
|
) : null
|
|
2032
2860
|
] }),
|
|
2033
|
-
/* @__PURE__ */ (0,
|
|
2034
|
-
/* @__PURE__ */ (0,
|
|
2861
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
2862
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
|
|
2035
2863
|
] }) : null
|
|
2036
2864
|
]
|
|
2037
2865
|
}
|
|
@@ -2039,7 +2867,7 @@ function AssistEdgeTab({
|
|
|
2039
2867
|
}
|
|
2040
2868
|
|
|
2041
2869
|
// src/react/components/AgentWidget/AgentWidget.tsx
|
|
2042
|
-
var
|
|
2870
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2043
2871
|
function AgentWidget({
|
|
2044
2872
|
indexId,
|
|
2045
2873
|
customerId,
|
|
@@ -2055,9 +2883,9 @@ function AgentWidget({
|
|
|
2055
2883
|
}) {
|
|
2056
2884
|
const isMobile = useIsMobile();
|
|
2057
2885
|
const placement = normalizeAgentPlacement(placementInput);
|
|
2058
|
-
const railSlotRef = (0,
|
|
2059
|
-
const [railCollapsed, setRailCollapsed] = (0,
|
|
2060
|
-
const [railExpanded, setRailExpanded] = (0,
|
|
2886
|
+
const railSlotRef = (0, import_react10.useRef)(null);
|
|
2887
|
+
const [railCollapsed, setRailCollapsed] = (0, import_react10.useState)(defaultCollapsed);
|
|
2888
|
+
const [railExpanded, setRailExpanded] = (0, import_react10.useState)(false);
|
|
2061
2889
|
const pageShiftActive = shouldApplyPageShift({
|
|
2062
2890
|
pageShift,
|
|
2063
2891
|
isMobile,
|
|
@@ -2077,7 +2905,8 @@ function AgentWidget({
|
|
|
2077
2905
|
runtimeOrigin,
|
|
2078
2906
|
greeting: branding?.greeting
|
|
2079
2907
|
});
|
|
2080
|
-
const agentName = branding?.agentName ?? "
|
|
2908
|
+
const agentName = branding?.agentName ?? "";
|
|
2909
|
+
const tabLabel = branding?.tabLabel ?? agentName;
|
|
2081
2910
|
const theme = {
|
|
2082
2911
|
...branding?.fontFamily ? { fontBody: branding.fontFamily, fontDisplay: branding.fontFamily } : {},
|
|
2083
2912
|
...branding?.colors?.primary ? {
|
|
@@ -2095,8 +2924,7 @@ function AgentWidget({
|
|
|
2095
2924
|
} : {},
|
|
2096
2925
|
...branding?.colors?.border ? { border: branding.colors.border } : {}
|
|
2097
2926
|
};
|
|
2098
|
-
|
|
2099
|
-
(0, import_react6.useEffect)(() => {
|
|
2927
|
+
(0, import_react10.useEffect)(() => {
|
|
2100
2928
|
if (!registerPanelController) return;
|
|
2101
2929
|
registerAgentPanelController(customerId, {
|
|
2102
2930
|
open: () => setRailCollapsed(false),
|
|
@@ -2111,7 +2939,7 @@ function AgentWidget({
|
|
|
2111
2939
|
if (isMobile) setRailCollapsed(false);
|
|
2112
2940
|
await submit(message);
|
|
2113
2941
|
}
|
|
2114
|
-
(0,
|
|
2942
|
+
(0, import_react10.useEffect)(() => {
|
|
2115
2943
|
if (railCollapsed) return;
|
|
2116
2944
|
const handleKeyDown = (event) => {
|
|
2117
2945
|
if (event.key === "Tab" && (isMobile || railExpanded)) {
|
|
@@ -2145,64 +2973,44 @@ function AgentWidget({
|
|
|
2145
2973
|
window.addEventListener("keydown", handleKeyDown);
|
|
2146
2974
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
2147
2975
|
}, [isMobile, railCollapsed, railExpanded]);
|
|
2148
|
-
return /* @__PURE__ */ (0,
|
|
2149
|
-
/* @__PURE__ */ (0,
|
|
2976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "webless-agent-root", children: [
|
|
2977
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2150
2978
|
"div",
|
|
2151
2979
|
{
|
|
2152
2980
|
className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
|
|
2153
|
-
children:
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
onReset: reset,
|
|
2180
|
-
onRetry: () => void retry(),
|
|
2181
|
-
onFollowUpSelect: (label) => void handleSubmit(label)
|
|
2182
|
-
}
|
|
2183
|
-
)
|
|
2184
|
-
}
|
|
2185
|
-
),
|
|
2186
|
-
!railCollapsed && isMobile || !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2187
|
-
"button",
|
|
2188
|
-
{
|
|
2189
|
-
type: "button",
|
|
2190
|
-
className: `webless-agent-root__backdrop${isMobile ? " webless-agent-root__backdrop--mobile" : ""}`,
|
|
2191
|
-
tabIndex: -1,
|
|
2192
|
-
"aria-label": isMobile ? "Close agent" : "Exit focus view",
|
|
2193
|
-
onClick: () => {
|
|
2194
|
-
if (isMobile) {
|
|
2195
|
-
setRailCollapsed(true);
|
|
2196
|
-
} else {
|
|
2197
|
-
setRailExpanded(false);
|
|
2198
|
-
}
|
|
2981
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2982
|
+
"div",
|
|
2983
|
+
{
|
|
2984
|
+
ref: railSlotRef,
|
|
2985
|
+
className: "webless-agent-root__rail-slot",
|
|
2986
|
+
inert: railCollapsed || void 0,
|
|
2987
|
+
"aria-hidden": railCollapsed,
|
|
2988
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2989
|
+
AgentRail,
|
|
2990
|
+
{
|
|
2991
|
+
theme,
|
|
2992
|
+
brandLabel: agentName,
|
|
2993
|
+
brandLogoUrl: branding?.logoUrl,
|
|
2994
|
+
composerPlaceholder: branding?.composerPlaceholder ?? "Ask a question\u2026",
|
|
2995
|
+
poweredByLabel: branding?.poweredByLabel ?? "Powered by Webless",
|
|
2996
|
+
state,
|
|
2997
|
+
mobileFullscreen: isMobile && !railCollapsed,
|
|
2998
|
+
expanded: railExpanded,
|
|
2999
|
+
onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
|
|
3000
|
+
onClose: isMobile ? () => setRailCollapsed(true) : void 0,
|
|
3001
|
+
onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
|
|
3002
|
+
onSubmit: handleSubmit,
|
|
3003
|
+
onReset: reset,
|
|
3004
|
+
onRetry: () => void retry(),
|
|
3005
|
+
onFollowUpSelect: (label) => void handleSubmit(label),
|
|
3006
|
+
onBook: (input) => void submit(input.displayText, { runtimeText: input.runtimeText })
|
|
2199
3007
|
}
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
3008
|
+
)
|
|
3009
|
+
}
|
|
3010
|
+
)
|
|
2203
3011
|
}
|
|
2204
3012
|
),
|
|
2205
|
-
railCollapsed ? /* @__PURE__ */ (0,
|
|
3013
|
+
railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2206
3014
|
AssistEdgeTab,
|
|
2207
3015
|
{
|
|
2208
3016
|
variant: placement.variant,
|
|
@@ -2210,7 +3018,8 @@ function AgentWidget({
|
|
|
2210
3018
|
along: placement.along,
|
|
2211
3019
|
inset: placement.inset,
|
|
2212
3020
|
visible: true,
|
|
2213
|
-
label:
|
|
3021
|
+
label: tabLabel,
|
|
3022
|
+
customIconUrl: branding?.tabIconUrl,
|
|
2214
3023
|
logoUrl: branding?.logoUrl,
|
|
2215
3024
|
brandColor: branding?.colors?.primary,
|
|
2216
3025
|
brandForeground: branding?.colors?.primaryForeground,
|
|
@@ -2232,6 +3041,7 @@ function AgentWidget({
|
|
|
2232
3041
|
DEFAULT_AGENT_PLACEMENT,
|
|
2233
3042
|
createIdleSuggestions,
|
|
2234
3043
|
defaultAgentRailTheme,
|
|
3044
|
+
defaultDarkAgentRailTheme,
|
|
2235
3045
|
hasVisitorMessages,
|
|
2236
3046
|
isAgentBusy,
|
|
2237
3047
|
normalizeAgentPlacement,
|