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