@webless/agent 0.4.0 → 0.5.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/embed.cjs CHANGED
@@ -50,7 +50,7 @@ function closeAgentPanel(customerId) {
50
50
  }
51
51
 
52
52
  // src/react/components/AgentWidget/AgentWidget.tsx
53
- var import_react6 = require("react");
53
+ var import_react7 = 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
- if (received?.type !== "message.received" || received.data.message !== message) {
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,6 +875,246 @@ 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
1119
  var CONVERSATION_VERSION = 1;
843
1120
  function conversationKey(storageKeyPrefix, visitorSessionId) {
@@ -849,13 +1126,25 @@ 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: record.role,
1140
+ role: "agent",
855
1141
  text: record.text,
856
1142
  createdAt: record.createdAt
857
1143
  };
858
1144
  }
1145
+ function visitorTurnText(message) {
1146
+ return message.role === "visitor" && message.runtimeText ? message.runtimeText : message.text;
1147
+ }
859
1148
  function loadPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
860
1149
  if (typeof sessionStorage === "undefined") return null;
861
1150
  const raw = sessionStorage.getItem(conversationKey(storageKeyPrefix, visitorSessionId));
@@ -888,6 +1177,42 @@ function savePersistedAgentConversation(storageKeyPrefix, visitorSessionId, conv
888
1177
  function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
889
1178
  if (typeof sessionStorage === "undefined") return;
890
1179
  sessionStorage.removeItem(conversationKey(storageKeyPrefix, visitorSessionId));
1180
+ clearPendingWidgetBooking(storageKeyPrefix, visitorSessionId);
1181
+ }
1182
+ function pendingBookingKey(storageKeyPrefix, visitorSessionId) {
1183
+ return `${storageKeyPrefix}:pending-booking:${visitorSessionId}`;
1184
+ }
1185
+ function loadPendingWidgetBooking(storageKeyPrefix, visitorSessionId) {
1186
+ if (typeof sessionStorage === "undefined") return null;
1187
+ const raw = sessionStorage.getItem(
1188
+ pendingBookingKey(storageKeyPrefix, visitorSessionId)
1189
+ );
1190
+ if (!raw) return null;
1191
+ try {
1192
+ const value = JSON.parse(raw);
1193
+ if (typeof value !== "object" || value === null) return null;
1194
+ const record = value;
1195
+ if (typeof record.eventUri !== "string" || !record.eventUri) return null;
1196
+ return {
1197
+ eventUri: record.eventUri,
1198
+ ...typeof record.inviteeUri === "string" && record.inviteeUri ? { inviteeUri: record.inviteeUri } : {},
1199
+ ...typeof record.inviteeEmail === "string" && record.inviteeEmail ? { inviteeEmail: record.inviteeEmail } : {},
1200
+ ...typeof record.startTime === "string" && record.startTime ? { startTime: record.startTime } : {}
1201
+ };
1202
+ } catch {
1203
+ return null;
1204
+ }
1205
+ }
1206
+ function savePendingWidgetBooking(storageKeyPrefix, visitorSessionId, booking) {
1207
+ if (typeof sessionStorage === "undefined") return;
1208
+ sessionStorage.setItem(
1209
+ pendingBookingKey(storageKeyPrefix, visitorSessionId),
1210
+ JSON.stringify(booking)
1211
+ );
1212
+ }
1213
+ function clearPendingWidgetBooking(storageKeyPrefix, visitorSessionId) {
1214
+ if (typeof sessionStorage === "undefined") return;
1215
+ sessionStorage.removeItem(pendingBookingKey(storageKeyPrefix, visitorSessionId));
891
1216
  }
892
1217
 
893
1218
  // src/react/hooks/useAgentChat.ts
@@ -907,6 +1232,7 @@ function createInitialState(greeting = DEFAULT_GREETING) {
907
1232
  journey: null,
908
1233
  followUps: [],
909
1234
  streamingText: "",
1235
+ pendingOffer: null,
910
1236
  error: null
911
1237
  };
912
1238
  }
@@ -989,6 +1315,9 @@ function useAgentChat({
989
1315
  initialState
990
1316
  )
991
1317
  );
1318
+ const pendingBookingRef = (0, import_react2.useRef)(
1319
+ loadPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId)
1320
+ );
992
1321
  const runRef = (0, import_react2.useRef)(null);
993
1322
  const clientRef = (0, import_react2.useRef)(
994
1323
  createAgentClient({
@@ -1021,6 +1350,10 @@ function useAgentChat({
1021
1350
  visitorSessionId: visitorId,
1022
1351
  storageKeyPrefix: resolvedStorageKeyPrefix
1023
1352
  });
1353
+ pendingBookingRef.current = loadPendingWidgetBooking(
1354
+ resolvedStorageKeyPrefix,
1355
+ visitorId
1356
+ );
1024
1357
  setState(
1025
1358
  stateFromConversation(
1026
1359
  loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
@@ -1056,6 +1389,7 @@ function useAgentChat({
1056
1389
  runRef.current?.abort();
1057
1390
  runRef.current = null;
1058
1391
  clientRef.current.reset();
1392
+ pendingBookingRef.current = null;
1059
1393
  clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
1060
1394
  setState(initialState);
1061
1395
  }, [initialState, resolvedStorageKeyPrefix, visitorId]);
@@ -1067,6 +1401,7 @@ function useAgentChat({
1067
1401
  try {
1068
1402
  let streamStarted = Boolean(initialText);
1069
1403
  let streamed = initialText;
1404
+ const capturedOffers = [];
1070
1405
  const handlers = {
1071
1406
  onWork: (item) => {
1072
1407
  if (!isActiveRun()) return;
@@ -1076,6 +1411,12 @@ function useAgentChat({
1076
1411
  toolSteps: upsertToolStep(prev.toolSteps, item)
1077
1412
  }));
1078
1413
  },
1414
+ onActionResult: (output) => {
1415
+ const offer = bookingOfferFromActionOutput(output);
1416
+ if (!offer) return;
1417
+ capturedOffers.push(offer);
1418
+ setState((prev) => ({ ...prev, pendingOffer: offer }));
1419
+ },
1079
1420
  onDelta: (delta) => {
1080
1421
  if (!isActiveRun()) return;
1081
1422
  if (!streamStarted) {
@@ -1091,7 +1432,8 @@ function useAgentChat({
1091
1432
  setState((prev) => ({
1092
1433
  ...prev,
1093
1434
  phase: "streaming",
1094
- streamingText: streamed
1435
+ streamingText: hideToolCardFences(streamed),
1436
+ pendingOffer: prev.pendingOffer ?? capturedOffers.at(-1) ?? null
1095
1437
  }));
1096
1438
  },
1097
1439
  onComplete: () => {
@@ -1112,18 +1454,34 @@ function useAgentChat({
1112
1454
  });
1113
1455
  }
1114
1456
  if (!isActiveRun() || finalText === null) return;
1457
+ const displayText = ensureBookingOfferText(
1458
+ finalText,
1459
+ capturedOffers.at(-1) ?? null
1460
+ );
1115
1461
  const agentMessage = {
1116
1462
  id: `agent-${Date.now()}`,
1117
1463
  role: "agent",
1118
- text: finalText,
1464
+ text: displayText,
1119
1465
  createdAt: Date.now()
1120
1466
  };
1467
+ const parsedCards = extractToolCards(displayText);
1468
+ for (const card of parsedCards) {
1469
+ if (card.type === "booking_confirmed") {
1470
+ pendingBookingRef.current = card;
1471
+ savePendingWidgetBooking(resolvedStorageKeyPrefix, visitorId, card);
1472
+ }
1473
+ if (card.type === "booking_canceled" && pendingBookingRef.current?.eventUri === card.eventUri) {
1474
+ pendingBookingRef.current = null;
1475
+ clearPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId);
1476
+ }
1477
+ }
1121
1478
  setState((prev) => ({
1122
1479
  ...prev,
1123
1480
  phase: "complete",
1124
1481
  messages: [...prev.messages, agentMessage],
1125
1482
  toolSteps: completeActivePlanning(prev.toolSteps),
1126
1483
  streamingText: "",
1484
+ pendingOffer: null,
1127
1485
  followUps: [],
1128
1486
  journey: null
1129
1487
  }));
@@ -1145,26 +1503,54 @@ function useAgentChat({
1145
1503
  } : step
1146
1504
  ),
1147
1505
  streamingText: "",
1506
+ pendingOffer: null,
1148
1507
  error: message
1149
1508
  }));
1150
1509
  runRef.current = null;
1151
1510
  }
1152
1511
  },
1153
- []
1512
+ [resolvedStorageKeyPrefix, visitorId]
1513
+ );
1514
+ const rememberBooking = (0, import_react2.useCallback)(
1515
+ (booking) => {
1516
+ const current = pendingBookingRef.current;
1517
+ if (current?.eventUri === booking.eventUri && current.inviteeEmail === booking.inviteeEmail && current.inviteeUri === booking.inviteeUri) {
1518
+ return;
1519
+ }
1520
+ pendingBookingRef.current = booking;
1521
+ savePendingWidgetBooking(resolvedStorageKeyPrefix, visitorId, booking);
1522
+ },
1523
+ [resolvedStorageKeyPrefix, visitorId]
1524
+ );
1525
+ const forgetBooking = (0, import_react2.useCallback)(
1526
+ (eventUri) => {
1527
+ const current = pendingBookingRef.current;
1528
+ if (!current) return;
1529
+ if (eventUri && current.eventUri !== eventUri) return;
1530
+ pendingBookingRef.current = null;
1531
+ clearPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId);
1532
+ },
1533
+ [resolvedStorageKeyPrefix, visitorId]
1154
1534
  );
1155
1535
  const submit = (0, import_react2.useCallback)(
1156
- async (visitorText) => {
1536
+ async (visitorText, options) => {
1157
1537
  if (runRef.current) {
1158
1538
  runRef.current.abort();
1159
1539
  clientRef.current.cancelActive();
1160
1540
  }
1161
1541
  const controller = new AbortController();
1162
1542
  runRef.current = controller;
1543
+ const booking = pendingBookingRef.current;
1544
+ const outgoing = options?.runtimeText ?? visitorText;
1545
+ const runtimeText = booking ? `${visitorBookingPrefix(booking)}
1546
+
1547
+ ${outgoing}` : outgoing;
1163
1548
  const visitorMessage = {
1164
1549
  id: `visitor-${Date.now()}`,
1165
1550
  role: "visitor",
1166
1551
  text: visitorText,
1167
- createdAt: Date.now()
1552
+ createdAt: Date.now(),
1553
+ ...runtimeText !== visitorText ? { runtimeText } : {}
1168
1554
  };
1169
1555
  setState((prev) => ({
1170
1556
  ...prev,
@@ -1181,9 +1567,10 @@ function useAgentChat({
1181
1567
  journey: null,
1182
1568
  followUps: [],
1183
1569
  streamingText: "",
1570
+ pendingOffer: null,
1184
1571
  error: null
1185
1572
  }));
1186
- await runTurn({ controller, resume: false, visitorText });
1573
+ await runTurn({ controller, resume: false, visitorText: runtimeText });
1187
1574
  },
1188
1575
  [runTurn]
1189
1576
  );
@@ -1210,12 +1597,13 @@ function useAgentChat({
1210
1597
  journey: null,
1211
1598
  followUps: [],
1212
1599
  streamingText: "",
1600
+ pendingOffer: null,
1213
1601
  error: null
1214
1602
  }));
1215
1603
  await runTurn({
1216
1604
  controller,
1217
1605
  resume: false,
1218
- visitorText: visitorMessage.text
1606
+ visitorText: visitorTurnText(visitorMessage)
1219
1607
  });
1220
1608
  }, [runTurn, state.messages]);
1221
1609
  (0, import_react2.useEffect)(() => {
@@ -1232,7 +1620,7 @@ function useAgentChat({
1232
1620
  controller,
1233
1621
  initialText: conversation.streamingText,
1234
1622
  resume: true,
1235
- visitorText: visitorMessage.text
1623
+ visitorText: visitorTurnText(visitorMessage)
1236
1624
  });
1237
1625
  return () => {
1238
1626
  if (runRef.current === controller) {
@@ -1252,6 +1640,8 @@ function useAgentChat({
1252
1640
  reset,
1253
1641
  retry,
1254
1642
  submit,
1643
+ rememberBooking,
1644
+ forgetBooking,
1255
1645
  visitorSessionId: visitorId,
1256
1646
  sessionId: clientRef.current.getActiveSessionId()
1257
1647
  };
@@ -1259,13 +1649,6 @@ function useAgentChat({
1259
1649
  function hasVisitorMessages(messages) {
1260
1650
  return messages.some((message) => message.role === "visitor");
1261
1651
  }
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
1652
  function isAgentBusy(phase) {
1270
1653
  return phase === "thinking" || phase === "running-tools" || phase === "streaming";
1271
1654
  }
@@ -1304,7 +1687,7 @@ function normalizeAgentPlacement(placement) {
1304
1687
  }
1305
1688
 
1306
1689
  // src/react/components/AgentRail/AgentRail.tsx
1307
- var import_react5 = require("react");
1690
+ var import_react6 = require("react");
1308
1691
 
1309
1692
  // src/react/types/conversation.ts
1310
1693
  var defaultAgentRailTheme = {
@@ -1344,10 +1727,9 @@ function workSummary(steps, failed, brandLabel) {
1344
1727
  );
1345
1728
  if (hasError) return "Answered with available information";
1346
1729
  if (specialists.length > 1)
1347
- return `Answer prepared with ${specialists.length} specialists`;
1348
- if (specialists.length === 1)
1349
- return `Answer prepared with ${specialists[0]?.label}`;
1350
- if (searched) return "Answer prepared from this site";
1730
+ return `Consulted ${specialists.length} specialists`;
1731
+ if (specialists.length === 1) return `Consulted ${specialists[0]?.label}`;
1732
+ if (searched) return "Searched this site";
1351
1733
  return "Answer ready";
1352
1734
  }
1353
1735
  function stepLabel(step, brandLabel) {
@@ -1397,7 +1779,6 @@ function AgentActivityBubble({
1397
1779
  steps
1398
1780
  }) {
1399
1781
  const active = steps.some((step) => step.state === "active");
1400
- const delegated = steps.some((step) => step.kind === "specialist");
1401
1782
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", { className: "agent-activity-bubble", children: [
1402
1783
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "agent-activity-bubble__status", "aria-live": "polite", children: [
1403
1784
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1409,57 +1790,50 @@ function AgentActivityBubble({
1409
1790
  ),
1410
1791
  workSummary(steps, failed, brandLabel)
1411
1792
  ] }),
1412
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1413
- "details",
1414
- {
1415
- className: "agent-activity-bubble__details",
1416
- open: active || delegated,
1417
- children: [
1418
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: failed ? "What happened" : active ? "Working" : "How this answer was prepared" }),
1419
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => {
1420
- const detail = stepDetail(step, steps);
1421
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1422
- "li",
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
1458
- );
1459
- }) })
1460
- ]
1461
- }
1462
- )
1793
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "agent-activity-bubble__details", open: active, children: [
1794
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "Work details" }),
1795
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => {
1796
+ const detail = stepDetail(step, steps);
1797
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1798
+ "li",
1799
+ {
1800
+ className: "agent-activity-bubble__step",
1801
+ "data-kind": step.kind,
1802
+ "data-state": step.state,
1803
+ children: [
1804
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1805
+ "span",
1806
+ {
1807
+ className: "agent-activity-bubble__step-icon",
1808
+ "aria-hidden": "true",
1809
+ children: step.kind === "planning" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1810
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlanningIcon, {}),
1811
+ brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1812
+ "img",
1813
+ {
1814
+ src: brandLogoUrl,
1815
+ alt: "",
1816
+ onError: (event) => {
1817
+ event.currentTarget.hidden = true;
1818
+ }
1819
+ }
1820
+ ) : null
1821
+ ] }) : step.kind === "search" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) : step.label.slice(0, 1).toUpperCase()
1822
+ }
1823
+ ),
1824
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-copy", children: [
1825
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-heading", children: [
1826
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: stepLabel(step, brandLabel) }),
1827
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: step.kind === "specialist" ? "Specialist" : step.kind === "search" ? "Built-in capability" : "Supervisor" })
1828
+ ] }),
1829
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-activity-bubble__step-detail", children: detail }) : null
1830
+ ] })
1831
+ ]
1832
+ },
1833
+ step.id
1834
+ );
1835
+ }) })
1836
+ ] })
1463
1837
  ] });
1464
1838
  }
1465
1839
 
@@ -1561,34 +1935,318 @@ function FollowUpChips({
1561
1935
  ] });
1562
1936
  }
1563
1937
 
1938
+ // src/react/components/BookingCard/BookingCard.tsx
1939
+ var import_react5 = require("react");
1940
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1941
+ function monthFromKey(key) {
1942
+ const [year, month] = key.split("-").map(Number);
1943
+ if (!year || !month) return { year: (/* @__PURE__ */ new Date()).getFullYear(), month: (/* @__PURE__ */ new Date()).getMonth() };
1944
+ return { year, month: month - 1 };
1945
+ }
1946
+ function dateKeyFromParts(year, month, day) {
1947
+ return [
1948
+ year,
1949
+ String(month + 1).padStart(2, "0"),
1950
+ String(day).padStart(2, "0")
1951
+ ].join("-");
1952
+ }
1953
+ function calendarCells(year, month) {
1954
+ const firstWeekday = (new Date(year, month, 1).getDay() + 6) % 7;
1955
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
1956
+ const cells = [];
1957
+ for (let index = 0; index < firstWeekday; index += 1) cells.push(null);
1958
+ for (let day = 1; day <= daysInMonth; day += 1) {
1959
+ cells.push({ day, key: dateKeyFromParts(year, month, day) });
1960
+ }
1961
+ while (cells.length < 42) cells.push(null);
1962
+ return cells;
1963
+ }
1964
+ function BookingCard({
1965
+ offer,
1966
+ onBook
1967
+ }) {
1968
+ const fieldId = (0, import_react5.useId)();
1969
+ const defaultType = offer.eventTypes[0]?.uri ?? offer.slots[0]?.eventTypeUri ?? "";
1970
+ const [step, setStep] = (0, import_react5.useState)("date");
1971
+ const [eventTypeUri, setEventTypeUri] = (0, import_react5.useState)(defaultType);
1972
+ const [selectedDate, setSelectedDate] = (0, import_react5.useState)("");
1973
+ const [startTime, setStartTime] = (0, import_react5.useState)("");
1974
+ const [name, setName] = (0, import_react5.useState)("");
1975
+ const [email, setEmail] = (0, import_react5.useState)("");
1976
+ const slots = (0, import_react5.useMemo)(
1977
+ () => bookingSlotsForEventType(offer.slots, eventTypeUri),
1978
+ [eventTypeUri, offer.slots]
1979
+ );
1980
+ const availableByDate = (0, import_react5.useMemo)(() => {
1981
+ const next = /* @__PURE__ */ new Map();
1982
+ for (const slot of slots) {
1983
+ const key = slotDateKey(slot.startTime);
1984
+ if (!next.has(key)) next.set(key, slot.startTime);
1985
+ }
1986
+ return next;
1987
+ }, [slots]);
1988
+ const [visibleMonth, setVisibleMonth] = (0, import_react5.useState)(
1989
+ () => firstAvailableBookingMonth(slots)
1990
+ );
1991
+ function selectEventType(nextType) {
1992
+ setEventTypeUri(nextType);
1993
+ setSelectedDate("");
1994
+ setStartTime("");
1995
+ setVisibleMonth(
1996
+ firstAvailableBookingMonth(bookingSlotsForEventType(offer.slots, nextType))
1997
+ );
1998
+ }
1999
+ const daySlots = (0, import_react5.useMemo)(
2000
+ () => slots.filter((slot) => slotDateKey(slot.startTime) === selectedDate),
2001
+ [selectedDate, slots]
2002
+ );
2003
+ const selectedType = offer.eventTypes.find((item) => item.uri === eventTypeUri);
2004
+ const selectedSample = availableByDate.get(selectedDate) ?? startTime;
2005
+ const timeZone = formatSlotTimeZone(slots[0]?.startTime ?? selectedSample);
2006
+ const weekdays = (0, import_react5.useMemo)(() => weekdayLabels(), []);
2007
+ const cells = calendarCells(visibleMonth.year, visibleMonth.month);
2008
+ const canPrevMonth = [...availableByDate.keys()].some((key) => {
2009
+ const month = monthFromKey(key);
2010
+ return month.year < visibleMonth.year || month.year === visibleMonth.year && month.month < visibleMonth.month;
2011
+ });
2012
+ const canNextMonth = [...availableByDate.keys()].some((key) => {
2013
+ const month = monthFromKey(key);
2014
+ return month.year > visibleMonth.year || month.year === visibleMonth.year && month.month > visibleMonth.month;
2015
+ });
2016
+ function goToMonth(offset) {
2017
+ setVisibleMonth((current) => {
2018
+ const next = new Date(current.year, current.month + offset, 1);
2019
+ return { year: next.getFullYear(), month: next.getMonth() };
2020
+ });
2021
+ }
2022
+ function selectDate(key) {
2023
+ if (!availableByDate.has(key)) return;
2024
+ setSelectedDate(key);
2025
+ setStartTime("");
2026
+ setStep("time");
2027
+ }
2028
+ function selectTime(value) {
2029
+ setStartTime(value);
2030
+ setStep("details");
2031
+ }
2032
+ function handleSubmit(event) {
2033
+ event.preventDefault();
2034
+ if (!eventTypeUri || !startTime || !name.trim() || !email.trim()) return;
2035
+ onBook?.({
2036
+ displayText: `Book the ${formatSlotLabel(startTime)} demo`,
2037
+ runtimeText: formatBookingRequest({
2038
+ eventTypeUri,
2039
+ inviteeEmail: email.trim(),
2040
+ inviteeName: name.trim(),
2041
+ startTime,
2042
+ timezone: visitorTimeZone(),
2043
+ locationKind: selectedType?.locationKind,
2044
+ location: selectedType?.location
2045
+ })
2046
+ });
2047
+ }
2048
+ 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: [
2049
+ step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
2050
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
2051
+ timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
2052
+ "Times in ",
2053
+ timeZone
2054
+ ] }) : null,
2055
+ offer.eventTypes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "booking-card__field", htmlFor: `${fieldId}-type`, children: [
2056
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Meeting" }),
2057
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2058
+ "select",
2059
+ {
2060
+ id: `${fieldId}-type`,
2061
+ value: eventTypeUri,
2062
+ onChange: (event) => selectEventType(event.target.value),
2063
+ children: offer.eventTypes.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: item.uri, children: item.name }, item.uri))
2064
+ }
2065
+ )
2066
+ ] }) : null,
2067
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__month", children: [
2068
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2069
+ "button",
2070
+ {
2071
+ type: "button",
2072
+ className: "booking-card__nav",
2073
+ "aria-label": "Previous month",
2074
+ disabled: !canPrevMonth,
2075
+ onClick: () => goToMonth(-1),
2076
+ children: "\u2039"
2077
+ }
2078
+ ),
2079
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__month-title", children: formatMonthTitle(visibleMonth.year, visibleMonth.month) }),
2080
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2081
+ "button",
2082
+ {
2083
+ type: "button",
2084
+ className: "booking-card__nav",
2085
+ "aria-label": "Next month",
2086
+ disabled: !canNextMonth,
2087
+ onClick: () => goToMonth(1),
2088
+ children: "\u203A"
2089
+ }
2090
+ )
2091
+ ] }),
2092
+ /* @__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)) }),
2093
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "booking-card__calendar", role: "grid", "aria-label": "Available dates", children: cells.map((cell, index) => {
2094
+ if (!cell) {
2095
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "booking-card__day" }, `empty-${index}`);
2096
+ }
2097
+ const available = availableByDate.has(cell.key);
2098
+ const selected = cell.key === selectedDate;
2099
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2100
+ "button",
2101
+ {
2102
+ type: "button",
2103
+ className: [
2104
+ "booking-card__day",
2105
+ available ? "booking-card__day--available" : "",
2106
+ selected ? "booking-card__day--selected" : ""
2107
+ ].filter(Boolean).join(" "),
2108
+ disabled: !available,
2109
+ "aria-pressed": selected,
2110
+ onClick: () => selectDate(cell.key),
2111
+ children: cell.day
2112
+ },
2113
+ cell.key
2114
+ );
2115
+ }) })
2116
+ ] }, "date") : null,
2117
+ step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
2118
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
2119
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2120
+ "button",
2121
+ {
2122
+ type: "button",
2123
+ className: "booking-card__nav",
2124
+ "aria-label": "Back to dates",
2125
+ onClick: () => setStep("date"),
2126
+ children: "\u2039"
2127
+ }
2128
+ ),
2129
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
2130
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedSample ? formatLongDate(selectedSample) : "Pick a time" }),
2131
+ timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
2132
+ "Times in ",
2133
+ timeZone
2134
+ ] }) : null
2135
+ ] })
2136
+ ] }),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "booking-card__times", children: daySlots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2138
+ "button",
2139
+ {
2140
+ type: "button",
2141
+ className: startTime === slot.startTime ? "booking-card__time booking-card__time--selected" : "booking-card__time",
2142
+ onClick: () => selectTime(slot.startTime),
2143
+ children: formatTimeChip(slot.startTime)
2144
+ },
2145
+ slot.startTime
2146
+ )) })
2147
+ ] }, "time") : null,
2148
+ step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
2149
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
2150
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2151
+ "button",
2152
+ {
2153
+ type: "button",
2154
+ className: "booking-card__nav",
2155
+ "aria-label": "Back to times",
2156
+ onClick: () => setStep("time"),
2157
+ children: "\u2039"
2158
+ }
2159
+ ),
2160
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
2161
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: "Enter details" }),
2162
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: formatSlotLabel(startTime) }),
2163
+ selectedType?.location ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: selectedType.location }) : null
2164
+ ] })
2165
+ ] }),
2166
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__identity", children: [
2167
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "booking-card__field", htmlFor: `${fieldId}-name`, children: [
2168
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Name" }),
2169
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2170
+ "input",
2171
+ {
2172
+ id: `${fieldId}-name`,
2173
+ autoComplete: "name",
2174
+ value: name,
2175
+ onChange: (event) => setName(event.target.value),
2176
+ required: true
2177
+ }
2178
+ )
2179
+ ] }),
2180
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "booking-card__field", htmlFor: `${fieldId}-email`, children: [
2181
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Email" }),
2182
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2183
+ "input",
2184
+ {
2185
+ id: `${fieldId}-email`,
2186
+ type: "email",
2187
+ autoComplete: "email",
2188
+ value: email,
2189
+ onChange: (event) => setEmail(event.target.value),
2190
+ required: true
2191
+ }
2192
+ )
2193
+ ] })
2194
+ ] }),
2195
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "submit", className: "booking-card__submit", children: "Book this time" })
2196
+ ] }, "details") : null
2197
+ ] }) });
2198
+ }
2199
+
1564
2200
  // src/react/components/MessageBubble/MessageBubble.tsx
1565
2201
  var import_streamdown = require("streamdown");
1566
2202
  var import_styles = require("streamdown/styles.css");
1567
- var import_jsx_runtime4 = require("react/jsx-runtime");
1568
- function MessageBubble({ message }) {
2203
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2204
+ function MessageBubble({
2205
+ message,
2206
+ offer,
2207
+ onBook
2208
+ }) {
2209
+ const cards = message.role === "agent" ? extractToolCards(message.text) : [];
2210
+ const extractedOffers = cards.filter(
2211
+ (card) => card.type === "booking_offer"
2212
+ );
2213
+ const offers = offer ? [offer] : extractedOffers;
2214
+ const visibleText = hideToolCardFences(message.text);
2215
+ const isStreaming = message.role === "agent" && Boolean(message.streaming);
2216
+ const displayText = offers.length > 0 ? visibleText || "Pick a date and time that works for you." : visibleText || (isStreaming ? "" : message.text);
1569
2217
  if (message.role === "visitor") {
1570
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "message-bubble__text", children: message.text }) });
2218
+ 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
2219
  }
1572
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1573
- import_streamdown.Streamdown,
1574
- {
1575
- animated: true,
1576
- caret: "circle",
1577
- className: "message-bubble__markdown",
1578
- controls: false,
1579
- isAnimating: message.streaming,
1580
- linkSafety: { enabled: false },
1581
- mode: message.streaming ? "streaming" : "static",
1582
- skipHtml: true,
1583
- children: message.text
1584
- }
1585
- ) }) });
2220
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
2221
+ displayText ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2222
+ import_streamdown.Streamdown,
2223
+ {
2224
+ animated: true,
2225
+ caret: "circle",
2226
+ className: "message-bubble__markdown",
2227
+ controls: false,
2228
+ isAnimating: isStreaming,
2229
+ linkSafety: { enabled: false },
2230
+ mode: isStreaming ? "streaming" : "static",
2231
+ skipHtml: true,
2232
+ children: displayText
2233
+ }
2234
+ ) }) : null,
2235
+ offers.map((nextOffer, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2236
+ BookingCard,
2237
+ {
2238
+ offer: nextOffer,
2239
+ onBook
2240
+ },
2241
+ `${bookingOfferIdentityKey(nextOffer)}-${index}`
2242
+ ))
2243
+ ] });
1586
2244
  }
1587
2245
 
1588
2246
  // src/react/components/AgentRail/AgentRail.tsx
1589
- var import_jsx_runtime5 = require("react/jsx-runtime");
2247
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1590
2248
  function MinimizeIcon() {
1591
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2249
+ 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
2250
  "path",
1593
2251
  {
1594
2252
  d: "M3.5 8h9",
@@ -1599,7 +2257,7 @@ function MinimizeIcon() {
1599
2257
  ) });
1600
2258
  }
1601
2259
  function CloseIcon() {
1602
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2260
+ 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
2261
  "path",
1604
2262
  {
1605
2263
  d: "M4 4l8 8M12 4l-8 8",
@@ -1610,7 +2268,7 @@ function CloseIcon() {
1610
2268
  ) });
1611
2269
  }
1612
2270
  function NewChatIcon() {
1613
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2271
+ 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
2272
  "path",
1615
2273
  {
1616
2274
  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 +2280,7 @@ function NewChatIcon() {
1622
2280
  ) });
1623
2281
  }
1624
2282
  function ExpandIcon() {
1625
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2283
+ 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
2284
  "path",
1627
2285
  {
1628
2286
  d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
@@ -1634,7 +2292,7 @@ function ExpandIcon() {
1634
2292
  ) });
1635
2293
  }
1636
2294
  function RestoreIcon() {
1637
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2295
+ 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
2296
  "path",
1639
2297
  {
1640
2298
  d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
@@ -1660,10 +2318,10 @@ function AgentRail({
1660
2318
  onReset,
1661
2319
  onRetry,
1662
2320
  onSubmit,
1663
- onFollowUpSelect
2321
+ onFollowUpSelect,
2322
+ onBook
1664
2323
  }) {
1665
- const transcriptRef = (0, import_react5.useRef)(null);
1666
- const welcomeTitleId = (0, import_react5.useId)();
2324
+ const transcriptRef = (0, import_react6.useRef)(null);
1667
2325
  const resolvedTheme = { ...defaultAgentRailTheme, ...theme };
1668
2326
  const railStyle = {
1669
2327
  "--rail-width": resolvedTheme.railMaxWidth,
@@ -1703,8 +2361,14 @@ function AgentRail({
1703
2361
  role: "agent",
1704
2362
  streaming: true,
1705
2363
  text: state.streamingText
2364
+ } : state.pendingOffer ? {
2365
+ createdAt: 0,
2366
+ id: "pending-booking",
2367
+ role: "agent",
2368
+ streaming: false,
2369
+ text: "Pick a date and time that works for you."
1706
2370
  } : null;
1707
- (0, import_react5.useEffect)(() => {
2371
+ (0, import_react6.useEffect)(() => {
1708
2372
  const node = transcriptRef.current;
1709
2373
  if (!node) return;
1710
2374
  node.scrollTop = node.scrollHeight;
@@ -1715,7 +2379,7 @@ function AgentRail({
1715
2379
  state.followUps,
1716
2380
  state.journey
1717
2381
  ]);
1718
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2382
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1719
2383
  "aside",
1720
2384
  {
1721
2385
  className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
@@ -1726,30 +2390,30 @@ function AgentRail({
1726
2390
  role: mobileFullscreen || expanded ? "dialog" : void 0,
1727
2391
  tabIndex: mobileFullscreen || expanded ? -1 : void 0,
1728
2392
  children: [
1729
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__brand-row", children: [
1730
- onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2393
+ /* @__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: [
2394
+ onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1731
2395
  "button",
1732
2396
  {
1733
2397
  type: "button",
1734
2398
  className: "agent-rail__collapse",
1735
2399
  "aria-label": "Collapse assist",
1736
2400
  onClick: onCollapse,
1737
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
2401
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
1738
2402
  }
1739
- ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2403
+ ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1740
2404
  "button",
1741
2405
  {
1742
2406
  type: "button",
1743
2407
  className: "agent-rail__close",
1744
2408
  "aria-label": "Close agent",
1745
2409
  onClick: onClose,
1746
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseIcon, {})
2410
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, {})
1747
2411
  }
1748
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
1749
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__identity", children: [
1750
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: [
2412
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
2413
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "agent-rail__identity", children: [
2414
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: [
1751
2415
  brandLabel.slice(0, 1).toUpperCase(),
1752
- brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2416
+ brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1753
2417
  "img",
1754
2418
  {
1755
2419
  className: "agent-rail__brand-logo",
@@ -1761,10 +2425,10 @@ function AgentRail({
1761
2425
  }
1762
2426
  ) : null
1763
2427
  ] }),
1764
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel })
2428
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel })
1765
2429
  ] }),
1766
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__actions", children: [
1767
- onReset ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2430
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "agent-rail__actions", children: [
2431
+ onReset ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1768
2432
  "button",
1769
2433
  {
1770
2434
  type: "button",
@@ -1772,60 +2436,37 @@ function AgentRail({
1772
2436
  "aria-label": "Start a new conversation",
1773
2437
  disabled: !hasVisitorMessages2,
1774
2438
  onClick: onReset,
1775
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(NewChatIcon, {})
2439
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NewChatIcon, {})
1776
2440
  }
1777
2441
  ) : null,
1778
- onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2442
+ onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1779
2443
  "button",
1780
2444
  {
1781
2445
  type: "button",
1782
2446
  className: "agent-rail__expand",
1783
2447
  "aria-label": expanded ? "Exit focus view" : "Open focus view",
1784
2448
  onClick: onExpandToggle,
1785
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpandIcon, {})
2449
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
1786
2450
  }
1787
2451
  ) : null
1788
2452
  ] })
1789
2453
  ] }) }),
1790
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__thread", children: [
1791
- !hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1792
- "section",
1793
- {
1794
- className: "agent-rail__welcome",
1795
- "aria-labelledby": welcomeTitleId,
1796
- children: [
1797
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__welcome-mark", "aria-hidden": "true", children: [
1798
- brandLabel.slice(0, 1).toUpperCase(),
1799
- brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1800
- "img",
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)(
2454
+ /* @__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: [
2455
+ !hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
2456
+ greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message: greeting, onBook }) : null,
2457
+ showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2458
+ FollowUpChips,
2459
+ {
2460
+ suggestions: state.followUps,
2461
+ disabled: isBusy,
2462
+ label: "Start here",
2463
+ onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
2464
+ }
2465
+ ) }) : null
2466
+ ] }) : null,
2467
+ transcriptMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message, onBook }, message.id)),
2468
+ completedAnswer ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message: completedAnswer, onBook }) : null,
2469
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1829
2470
  AgentActivityBubble,
1830
2471
  {
1831
2472
  brandLabel,
@@ -1834,18 +2475,24 @@ function AgentRail({
1834
2475
  steps: state.toolSteps
1835
2476
  }
1836
2477
  ) : null,
1837
- streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message: streamingMessage }) : null,
1838
- completedAnswer ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message: completedAnswer }) : null,
1839
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
1840
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1841
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Something went wrong" }),
1842
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: state.error })
2478
+ streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2479
+ MessageBubble,
2480
+ {
2481
+ message: streamingMessage,
2482
+ offer: state.pendingOffer,
2483
+ onBook
2484
+ }
2485
+ ) : null,
2486
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
2487
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
2488
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "Something went wrong" }),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: state.error })
1843
2490
  ] }),
1844
- onRetry ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
2491
+ onRetry ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
1845
2492
  ] }) : null
1846
2493
  ] }) }),
1847
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1848
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2494
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
2495
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1849
2496
  Composer,
1850
2497
  {
1851
2498
  variant: expanded || mobileFullscreen ? "dock" : "default",
@@ -1854,10 +2501,9 @@ function AgentRail({
1854
2501
  onSubmit
1855
2502
  }
1856
2503
  ),
1857
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
1858
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "AI can make mistakes." }),
1859
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": "true", children: " \xB7 " }),
1860
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: poweredByLabel })
2504
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
2505
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "AI can make mistakes. Check important info." }),
2506
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: poweredByLabel })
1861
2507
  ] }) })
1862
2508
  ] })
1863
2509
  ]
@@ -1866,9 +2512,9 @@ function AgentRail({
1866
2512
  }
1867
2513
 
1868
2514
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
1869
- var import_jsx_runtime6 = require("react/jsx-runtime");
2515
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1870
2516
  function SparklesIcon() {
1871
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2517
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1872
2518
  "svg",
1873
2519
  {
1874
2520
  className: "assist-edge-tab__sparkles",
@@ -1876,21 +2522,21 @@ function SparklesIcon() {
1876
2522
  fill: "none",
1877
2523
  "aria-hidden": "true",
1878
2524
  children: [
1879
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2525
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1880
2526
  "path",
1881
2527
  {
1882
2528
  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
2529
  fill: "currentColor"
1884
2530
  }
1885
2531
  ),
1886
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2532
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1887
2533
  "path",
1888
2534
  {
1889
2535
  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
2536
  fill: "currentColor"
1891
2537
  }
1892
2538
  ),
1893
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2539
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1894
2540
  "path",
1895
2541
  {
1896
2542
  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 +2547,23 @@ function SparklesIcon() {
1901
2547
  }
1902
2548
  );
1903
2549
  }
2550
+ function TabMarkIcon({ customIconUrl }) {
2551
+ const url = customIconUrl?.trim();
2552
+ if (url) {
2553
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2554
+ "img",
2555
+ {
2556
+ alt: "",
2557
+ "aria-hidden": true,
2558
+ className: "assist-edge-tab__custom-icon",
2559
+ src: url
2560
+ }
2561
+ );
2562
+ }
2563
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {});
2564
+ }
1904
2565
  function ChevronLeftIcon() {
1905
- 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)(
2566
+ 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
2567
  "path",
1907
2568
  {
1908
2569
  d: "M10 4L6 8l4 4",
@@ -1914,7 +2575,7 @@ function ChevronLeftIcon() {
1914
2575
  ) });
1915
2576
  }
1916
2577
  function ChevronDownIcon() {
1917
- 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)(
2578
+ 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
2579
  "path",
1919
2580
  {
1920
2581
  d: "M4 6l4 4 4-4",
@@ -1926,7 +2587,7 @@ function ChevronDownIcon() {
1926
2587
  ) });
1927
2588
  }
1928
2589
  function DragDots() {
1929
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("i", {}, index)) });
2590
+ 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
2591
  }
1931
2592
  var VARIANT_COPY = {
1932
2593
  outline: { label: "Assist", aria: "Open Assist" },
@@ -1940,6 +2601,7 @@ function AssistEdgeTab({
1940
2601
  inset,
1941
2602
  visible,
1942
2603
  label,
2604
+ customIconUrl,
1943
2605
  logoUrl,
1944
2606
  brandColor,
1945
2607
  brandForeground,
@@ -1952,6 +2614,7 @@ function AssistEdgeTab({
1952
2614
  }) {
1953
2615
  const copy = VARIANT_COPY[variant];
1954
2616
  const visibleLabel = label?.trim() || copy.label;
2617
+ const showLogo = Boolean(logoUrl?.trim()) && !customIconUrl?.trim();
1955
2618
  const style = {
1956
2619
  "--tab-along": `${along}%`,
1957
2620
  "--tab-inset": `${inset}px`,
@@ -1962,7 +2625,7 @@ function AssistEdgeTab({
1962
2625
  ...surfaceColor ? { "--as-surface": surfaceColor } : {},
1963
2626
  ...textColor ? { "--as-text": textColor } : {}
1964
2627
  };
1965
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2628
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1966
2629
  "button",
1967
2630
  {
1968
2631
  type: "button",
@@ -1973,15 +2636,15 @@ function AssistEdgeTab({
1973
2636
  tabIndex: visible ? 0 : -1,
1974
2637
  onClick: onOpen,
1975
2638
  children: [
1976
- mobile ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1977
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2639
+ mobile ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2640
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1978
2641
  "span",
1979
2642
  {
1980
2643
  className: "assist-edge-tab__mark assist-edge-tab__mark--mobile",
1981
2644
  "aria-hidden": "true",
1982
2645
  children: [
1983
- visibleLabel.slice(0, 1).toUpperCase(),
1984
- logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2646
+ customIconUrl?.trim() ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabMarkIcon, { customIconUrl }) : visibleLabel.slice(0, 1).toUpperCase(),
2647
+ showLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1985
2648
  "img",
1986
2649
  {
1987
2650
  className: "assist-edge-tab__logo",
@@ -1995,14 +2658,14 @@ function AssistEdgeTab({
1995
2658
  ]
1996
2659
  }
1997
2660
  ),
1998
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__label", children: [
2661
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "assist-edge-tab__label", children: [
1999
2662
  "Ask ",
2000
2663
  visibleLabel
2001
2664
  ] })
2002
- ] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
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)(
2665
+ ] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2666
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
2667
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabMarkIcon, { customIconUrl }),
2668
+ showLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2006
2669
  "img",
2007
2670
  {
2008
2671
  className: "assist-edge-tab__logo",
@@ -2014,18 +2677,18 @@ function AssistEdgeTab({
2014
2677
  }
2015
2678
  ) : null
2016
2679
  ] }),
2017
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
2018
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDownIcon, {})
2680
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
2681
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
2019
2682
  ] }) : null,
2020
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2021
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {}),
2022
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
2023
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DragDots, {})
2683
+ variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2684
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
2685
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
2686
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
2024
2687
  ] }) : null,
2025
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2026
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
2027
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
2028
- logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2688
+ variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2689
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
2690
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TabMarkIcon, { customIconUrl }),
2691
+ showLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2029
2692
  "img",
2030
2693
  {
2031
2694
  className: "assist-edge-tab__logo",
@@ -2037,8 +2700,8 @@ function AssistEdgeTab({
2037
2700
  }
2038
2701
  ) : null
2039
2702
  ] }),
2040
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
2041
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {})
2703
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
2704
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
2042
2705
  ] }) : null
2043
2706
  ]
2044
2707
  }
@@ -2046,7 +2709,7 @@ function AssistEdgeTab({
2046
2709
  }
2047
2710
 
2048
2711
  // src/react/components/AgentWidget/AgentWidget.tsx
2049
- var import_jsx_runtime7 = require("react/jsx-runtime");
2712
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2050
2713
  function AgentWidget({
2051
2714
  indexId,
2052
2715
  customerId,
@@ -2062,9 +2725,9 @@ function AgentWidget({
2062
2725
  }) {
2063
2726
  const isMobile = useIsMobile();
2064
2727
  const placement = normalizeAgentPlacement(placementInput);
2065
- const railSlotRef = (0, import_react6.useRef)(null);
2066
- const [railCollapsed, setRailCollapsed] = (0, import_react6.useState)(defaultCollapsed);
2067
- const [railExpanded, setRailExpanded] = (0, import_react6.useState)(false);
2728
+ const railSlotRef = (0, import_react7.useRef)(null);
2729
+ const [railCollapsed, setRailCollapsed] = (0, import_react7.useState)(defaultCollapsed);
2730
+ const [railExpanded, setRailExpanded] = (0, import_react7.useState)(false);
2068
2731
  const pageShiftActive = shouldApplyPageShift({
2069
2732
  pageShift,
2070
2733
  isMobile,
@@ -2085,6 +2748,7 @@ function AgentWidget({
2085
2748
  greeting: branding?.greeting
2086
2749
  });
2087
2750
  const agentName = branding?.agentName ?? "Webless Guide";
2751
+ const tabLabel = branding?.tabLabel ?? agentName;
2088
2752
  const theme = {
2089
2753
  ...branding?.fontFamily ? { fontBody: branding.fontFamily, fontDisplay: branding.fontFamily } : {},
2090
2754
  ...branding?.colors?.primary ? {
@@ -2102,8 +2766,7 @@ function AgentWidget({
2102
2766
  } : {},
2103
2767
  ...branding?.colors?.border ? { border: branding.colors.border } : {}
2104
2768
  };
2105
- const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
2106
- (0, import_react6.useEffect)(() => {
2769
+ (0, import_react7.useEffect)(() => {
2107
2770
  if (!registerPanelController) return;
2108
2771
  registerAgentPanelController(customerId, {
2109
2772
  open: () => setRailCollapsed(false),
@@ -2118,7 +2781,7 @@ function AgentWidget({
2118
2781
  if (isMobile) setRailCollapsed(false);
2119
2782
  await submit(message);
2120
2783
  }
2121
- (0, import_react6.useEffect)(() => {
2784
+ (0, import_react7.useEffect)(() => {
2122
2785
  if (railCollapsed) return;
2123
2786
  const handleKeyDown = (event) => {
2124
2787
  if (event.key === "Tab" && (isMobile || railExpanded)) {
@@ -2152,31 +2815,28 @@ function AgentWidget({
2152
2815
  window.addEventListener("keydown", handleKeyDown);
2153
2816
  return () => window.removeEventListener("keydown", handleKeyDown);
2154
2817
  }, [isMobile, railCollapsed, railExpanded]);
2155
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "webless-agent-root", children: [
2156
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2818
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "webless-agent-root", children: [
2819
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2157
2820
  "div",
2158
2821
  {
2159
2822
  className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
2160
2823
  children: [
2161
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2824
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2162
2825
  "div",
2163
2826
  {
2164
2827
  ref: railSlotRef,
2165
2828
  className: "webless-agent-root__rail-slot",
2166
2829
  inert: railCollapsed || void 0,
2167
2830
  "aria-hidden": railCollapsed,
2168
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2831
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2169
2832
  AgentRail,
2170
2833
  {
2171
2834
  theme,
2172
2835
  brandLabel: agentName,
2173
2836
  brandLogoUrl: branding?.logoUrl,
2174
- composerPlaceholder: branding?.composerPlaceholder ?? `Ask ${agentName}\u2026`,
2837
+ composerPlaceholder: branding?.composerPlaceholder ?? "Ask as a visitor\u2026",
2175
2838
  poweredByLabel: branding?.poweredByLabel ?? "Powered by Webless",
2176
- state: idle ? {
2177
- ...state,
2178
- followUps: createIdleSuggestions()
2179
- } : state,
2839
+ state,
2180
2840
  mobileFullscreen: isMobile && !railCollapsed,
2181
2841
  expanded: railExpanded,
2182
2842
  onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
@@ -2185,12 +2845,13 @@ function AgentWidget({
2185
2845
  onSubmit: handleSubmit,
2186
2846
  onReset: reset,
2187
2847
  onRetry: () => void retry(),
2188
- onFollowUpSelect: (label) => void handleSubmit(label)
2848
+ onFollowUpSelect: (label) => void handleSubmit(label),
2849
+ onBook: (input) => void submit(input.displayText, { runtimeText: input.runtimeText })
2189
2850
  }
2190
2851
  )
2191
2852
  }
2192
2853
  ),
2193
- !railCollapsed && isMobile || !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2854
+ !railCollapsed && isMobile || !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2194
2855
  "button",
2195
2856
  {
2196
2857
  type: "button",
@@ -2209,7 +2870,7 @@ function AgentWidget({
2209
2870
  ]
2210
2871
  }
2211
2872
  ),
2212
- railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2873
+ railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2213
2874
  AssistEdgeTab,
2214
2875
  {
2215
2876
  variant: placement.variant,
@@ -2217,7 +2878,8 @@ function AgentWidget({
2217
2878
  along: placement.along,
2218
2879
  inset: placement.inset,
2219
2880
  visible: true,
2220
- label: agentName,
2881
+ label: tabLabel,
2882
+ customIconUrl: branding?.tabIconUrl,
2221
2883
  logoUrl: branding?.logoUrl,
2222
2884
  brandColor: branding?.colors?.primary,
2223
2885
  brandForeground: branding?.colors?.primaryForeground,
@@ -2246,11 +2908,12 @@ function readUnpublishedPreviewBuildId(href) {
2246
2908
  }
2247
2909
 
2248
2910
  // src/embed/AgentWidget.tsx
2249
- var import_jsx_runtime8 = require("react/jsx-runtime");
2911
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2250
2912
  function AgentWidget2({
2251
2913
  manifest
2252
2914
  }) {
2253
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2915
+ const defaultCollapsed = manifest.version !== "unpublished";
2916
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2254
2917
  AgentWidget,
2255
2918
  {
2256
2919
  indexId: manifest.indexId,
@@ -2261,7 +2924,7 @@ function AgentWidget2({
2261
2924
  placement: manifest.placement,
2262
2925
  pageShift: manifest.pageShift,
2263
2926
  branding: manifest.branding,
2264
- defaultCollapsed: true,
2927
+ defaultCollapsed,
2265
2928
  registerPanelController: true
2266
2929
  }
2267
2930
  );
@@ -2315,6 +2978,8 @@ function normalizeAgentBranding(branding) {
2315
2978
  ) : void 0;
2316
2979
  const normalized = {
2317
2980
  agentName: normalizeOptionalValue(branding.agentName),
2981
+ tabLabel: normalizeOptionalValue(branding.tabLabel),
2982
+ tabIconUrl: normalizeOptionalValue(branding.tabIconUrl),
2318
2983
  logoUrl: normalizeOptionalValue(branding.logoUrl),
2319
2984
  greeting: normalizeOptionalValue(branding.greeting),
2320
2985
  composerPlaceholder: normalizeOptionalValue(branding.composerPlaceholder),
@@ -2326,7 +2991,7 @@ function normalizeAgentBranding(branding) {
2326
2991
  }
2327
2992
 
2328
2993
  // src/embed/mount.tsx
2329
- var import_jsx_runtime9 = require("react/jsx-runtime");
2994
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2330
2995
  var mountedHandles = /* @__PURE__ */ new Map();
2331
2996
  var latestCustomerId = null;
2332
2997
  function resolveMountHost(manifest, script) {
@@ -2356,7 +3021,7 @@ function mountAgent(input) {
2356
3021
  const host = createHost(manifest.customerId);
2357
3022
  mountTarget.append(host);
2358
3023
  const root = (0, import_client5.createRoot)(host);
2359
- root.render(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentWidget2, { manifest }));
3024
+ root.render(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentWidget2, { manifest }));
2360
3025
  const handle = {
2361
3026
  customerId: manifest.customerId,
2362
3027
  manifest,