@webless/agent 0.6.9 → 0.6.11

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/react.cjs CHANGED
@@ -2278,6 +2278,30 @@ function bookingPresenter(kind) {
2278
2278
  }
2279
2279
  };
2280
2280
  }
2281
+ function providerErrorPresenter() {
2282
+ return {
2283
+ kind: "provider_error",
2284
+ present: ({ envelope }) => {
2285
+ const output = asRecord3(envelope.output);
2286
+ const providerError = asRecord3(output?.providerError);
2287
+ const message = safeText(providerError?.message);
2288
+ const action = safeText(providerError?.action);
2289
+ if (!message || !action) return null;
2290
+ const resourceLabels = Array.isArray(providerError?.resourceLabels) ? providerError.resourceLabels.map(safeText).filter(Boolean).slice(0, MAX_DETAILS) : [];
2291
+ return {
2292
+ kind: "summary",
2293
+ status: "failed",
2294
+ title: message,
2295
+ description: action,
2296
+ ...resourceLabels.length ? {
2297
+ details: [
2298
+ { label: "Affected", value: resourceLabels.join(", ") }
2299
+ ]
2300
+ } : {}
2301
+ };
2302
+ }
2303
+ };
2304
+ }
2281
2305
  function asRecord3(value) {
2282
2306
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
2283
2307
  }
@@ -2395,6 +2419,7 @@ function fallbackTitleFromKind(kind) {
2395
2419
  return "Saved";
2396
2420
  }
2397
2421
  var builtInVisitorToolResultRegistry = [
2422
+ providerErrorPresenter(),
2398
2423
  bookingPresenter("booking_offer"),
2399
2424
  bookingPresenter("booking_confirmed"),
2400
2425
  bookingPresenter("booking_canceled"),
@@ -2444,7 +2469,7 @@ function finalizeSummaryPresentation(result, proposed) {
2444
2469
  return {
2445
2470
  id: result.callId,
2446
2471
  toolName: result.toolName,
2447
- status: result.status,
2472
+ status: proposed.status ?? result.status,
2448
2473
  kind: "summary",
2449
2474
  title,
2450
2475
  ...description && description !== title ? { description } : {},
@@ -2453,7 +2478,7 @@ function finalizeSummaryPresentation(result, proposed) {
2453
2478
  };
2454
2479
  }
2455
2480
  function presentVisitorToolResult(result, registry = []) {
2456
- const envelope = parseAgentToolResultEnvelope(result.output) ?? legacyBookingEnvelope(result.output);
2481
+ const envelope = parseAgentToolResultEnvelope(result.output) ?? providerErrorEnvelope(result.output) ?? legacyBookingEnvelope(result.output);
2457
2482
  const proposed = envelope ? resolvePresenterOutput(result, envelope, registry) : null;
2458
2483
  if (proposed?.kind === "booking") {
2459
2484
  return {
@@ -2516,6 +2541,25 @@ function presentVisitorToolResult(result, registry = []) {
2516
2541
  }
2517
2542
  return finalizeSummaryPresentation(result, proposed);
2518
2543
  }
2544
+ function providerErrorEnvelope(output) {
2545
+ const record = asRecord3(output);
2546
+ const providerError = asRecord3(record?.providerError);
2547
+ const message = safeText(providerError?.message);
2548
+ const action = safeText(providerError?.action);
2549
+ if (!message || !action) return null;
2550
+ const resourceLabels = Array.isArray(providerError?.resourceLabels) ? providerError.resourceLabels.map(safeText).filter(Boolean).slice(0, MAX_DETAILS) : [];
2551
+ return {
2552
+ schemaVersion: "webless.tool-result.v1",
2553
+ output: {
2554
+ providerError: {
2555
+ action,
2556
+ message,
2557
+ ...resourceLabels.length ? { resourceLabels } : {}
2558
+ }
2559
+ },
2560
+ presentationKinds: ["provider_error"]
2561
+ };
2562
+ }
2519
2563
  function legacyBookingEnvelope(output) {
2520
2564
  const card = bookingCardFromActionOutput(output);
2521
2565
  return card ? {
@@ -2823,6 +2867,7 @@ function useAgentChat({
2823
2867
  let streamStarted = Boolean(initialText);
2824
2868
  let streamed = initialText;
2825
2869
  const capturedOffers = [];
2870
+ let bookingConfirmed = false;
2826
2871
  let capturedInputCount = 0;
2827
2872
  const handlers = {
2828
2873
  onWork: (item) => {
@@ -2847,6 +2892,7 @@ function useAgentChat({
2847
2892
  }
2848
2893
  if (!isActiveRun()) return;
2849
2894
  if (card.type === "booking_confirmed") {
2895
+ bookingConfirmed = true;
2850
2896
  pendingBookingRef.current = card;
2851
2897
  savePendingWidgetBooking(
2852
2898
  resolvedStorageKeyPrefix,
@@ -2922,7 +2968,10 @@ function useAgentChat({
2922
2968
  initialText,
2923
2969
  message: visitorText,
2924
2970
  signal
2925
- }) : await clientRef.current.sendTurn(visitorText, { handlers, signal });
2971
+ }) : await clientRef.current.sendTurn(visitorText, {
2972
+ handlers,
2973
+ signal
2974
+ });
2926
2975
  if (resume && finalText === null) {
2927
2976
  finalText = await clientRef.current.sendTurn(visitorText, {
2928
2977
  handlers,
@@ -2941,6 +2990,7 @@ function useAgentChat({
2941
2990
  const parsedCards = extractToolCards(displayText);
2942
2991
  for (const card of parsedCards) {
2943
2992
  if (card.type === "booking_confirmed") {
2993
+ bookingConfirmed = true;
2944
2994
  pendingBookingRef.current = card;
2945
2995
  savePendingWidgetBooking(resolvedStorageKeyPrefix, visitorId, card);
2946
2996
  }
@@ -2955,7 +3005,7 @@ function useAgentChat({
2955
3005
  messages: appendAgentTurnMessage(prev.messages, displayText),
2956
3006
  toolSteps: completeActivePlanning(prev.toolSteps),
2957
3007
  streamingText: "",
2958
- pendingOffer: capturedOffers.at(-1) ?? prev.pendingOffer,
3008
+ pendingOffer: bookingConfirmed ? null : capturedOffers.at(-1) ?? prev.pendingOffer,
2959
3009
  pendingInputs: (prev.pendingInputs ?? []).filter(
2960
3010
  isChatCollectibleInputRequest
2961
3011
  ),
@@ -2981,7 +3031,6 @@ function useAgentChat({
2981
3031
  } : step
2982
3032
  ),
2983
3033
  streamingText: "",
2984
- pendingOffer: null,
2985
3034
  error: message
2986
3035
  }));
2987
3036
  runRef.current = null;
@@ -3089,7 +3138,7 @@ ${outgoing}` : outgoing;
3089
3138
  journey: null,
3090
3139
  followUps: [],
3091
3140
  streamingText: "",
3092
- pendingOffer: null,
3141
+ pendingOffer: options?.preservePendingOffer ? prev.pendingOffer : null,
3093
3142
  pendingInputs: [],
3094
3143
  toolResults: [],
3095
3144
  error: null
@@ -3125,7 +3174,6 @@ ${outgoing}` : outgoing;
3125
3174
  journey: null,
3126
3175
  followUps: [],
3127
3176
  streamingText: "",
3128
- pendingOffer: null,
3129
3177
  pendingInputs: [],
3130
3178
  toolResults: [],
3131
3179
  error: null
@@ -3759,6 +3807,7 @@ function BookingCardLoader() {
3759
3807
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { className: "booking-card", "aria-label": "Book a meeting", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__loading", role: "status", children: "Finding available times\u2026" }) });
3760
3808
  }
3761
3809
  function BookingCard({
3810
+ disabled = false,
3762
3811
  offer,
3763
3812
  onBook
3764
3813
  }) {
@@ -3770,7 +3819,14 @@ function BookingCard({
3770
3819
  const [startTime, setStartTime] = (0, import_react7.useState)("");
3771
3820
  const [name, setName] = (0, import_react7.useState)("");
3772
3821
  const [email, setEmail] = (0, import_react7.useState)("");
3822
+ const activeStepRef = (0, import_react7.useRef)(null);
3823
+ const previousStepRef = (0, import_react7.useRef)(step);
3773
3824
  const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
3825
+ (0, import_react7.useEffect)(() => {
3826
+ if (previousStepRef.current === step) return;
3827
+ previousStepRef.current = step;
3828
+ activeStepRef.current?.scrollIntoView({ block: "nearest" });
3829
+ }, [step]);
3774
3830
  const slots = (0, import_react7.useMemo)(
3775
3831
  () => bookingSlotsForEventType(offer.slots, eventTypeUri),
3776
3832
  [eventTypeUri, offer.slots]
@@ -3847,216 +3903,230 @@ function BookingCard({
3847
3903
  })
3848
3904
  });
3849
3905
  }
3850
- 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: [
3851
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { className: "booking-card__steps", "aria-label": "Booking steps", children: BOOKING_STEPS.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3852
- "li",
3853
- {
3854
- className: [
3855
- "booking-card__step-indicator",
3856
- index === stepIndex ? "booking-card__step-indicator--active" : "",
3857
- index < stepIndex ? "booking-card__step-indicator--complete" : ""
3858
- ].filter(Boolean).join(" "),
3859
- "aria-current": index === stepIndex ? "step" : void 0,
3860
- children: [
3861
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", children: index + 1 }),
3862
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: item.label })
3863
- ]
3864
- },
3865
- item.id
3866
- )) }),
3867
- step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3868
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
3869
- timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
3870
- "Times in ",
3871
- timeZone
3872
- ] }) : null,
3873
- offer.eventTypes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3874
- "label",
3875
- {
3876
- className: "booking-card__field",
3877
- htmlFor: `${fieldId}-type`,
3878
- children: [
3879
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Meeting" }),
3906
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3907
+ "section",
3908
+ {
3909
+ className: "booking-card",
3910
+ "aria-busy": disabled || void 0,
3911
+ "aria-label": "Book a meeting",
3912
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { className: "booking-card__form", onSubmit: handleSubmit, children: [
3913
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { className: "booking-card__steps", "aria-label": "Booking steps", children: BOOKING_STEPS.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3914
+ "li",
3915
+ {
3916
+ className: [
3917
+ "booking-card__step-indicator",
3918
+ index === stepIndex ? "booking-card__step-indicator--active" : "",
3919
+ index < stepIndex ? "booking-card__step-indicator--complete" : ""
3920
+ ].filter(Boolean).join(" "),
3921
+ "aria-current": index === stepIndex ? "step" : void 0,
3922
+ children: [
3923
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", children: index + 1 }),
3924
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: item.label })
3925
+ ]
3926
+ },
3927
+ item.id
3928
+ )) }),
3929
+ step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
3930
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
3931
+ timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
3932
+ "Times in ",
3933
+ timeZone
3934
+ ] }) : null,
3935
+ offer.eventTypes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3936
+ "label",
3937
+ {
3938
+ className: "booking-card__field",
3939
+ htmlFor: `${fieldId}-type`,
3940
+ children: [
3941
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Meeting" }),
3942
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3943
+ "select",
3944
+ {
3945
+ id: `${fieldId}-type`,
3946
+ value: eventTypeUri,
3947
+ disabled,
3948
+ onChange: (event) => selectEventType(event.target.value),
3949
+ children: offer.eventTypes.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: item.uri, children: item.name }, item.uri))
3950
+ }
3951
+ )
3952
+ ]
3953
+ }
3954
+ ) : null,
3955
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__month", children: [
3880
3956
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3881
- "select",
3957
+ "button",
3882
3958
  {
3883
- id: `${fieldId}-type`,
3884
- value: eventTypeUri,
3885
- onChange: (event) => selectEventType(event.target.value),
3886
- children: offer.eventTypes.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: item.uri, children: item.name }, item.uri))
3959
+ type: "button",
3960
+ className: "booking-card__nav",
3961
+ "aria-label": "Previous month",
3962
+ disabled: disabled || !canPrevMonth,
3963
+ onClick: () => goToMonth(-1),
3964
+ children: "\u2039"
3965
+ }
3966
+ ),
3967
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__month-title", children: formatMonthTitle(visibleMonth.year, visibleMonth.month) }),
3968
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3969
+ "button",
3970
+ {
3971
+ type: "button",
3972
+ className: "booking-card__nav",
3973
+ "aria-label": "Next month",
3974
+ disabled: disabled || !canNextMonth,
3975
+ onClick: () => goToMonth(1),
3976
+ children: "\u203A"
3887
3977
  }
3888
3978
  )
3889
- ]
3890
- }
3891
- ) : null,
3892
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__month", children: [
3893
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3894
- "button",
3895
- {
3896
- type: "button",
3897
- className: "booking-card__nav",
3898
- "aria-label": "Previous month",
3899
- disabled: !canPrevMonth,
3900
- onClick: () => goToMonth(-1),
3901
- children: "\u2039"
3902
- }
3903
- ),
3904
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__month-title", children: formatMonthTitle(visibleMonth.year, visibleMonth.month) }),
3905
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3906
- "button",
3907
- {
3908
- type: "button",
3909
- className: "booking-card__nav",
3910
- "aria-label": "Next month",
3911
- disabled: !canNextMonth,
3912
- onClick: () => goToMonth(1),
3913
- children: "\u203A"
3914
- }
3915
- )
3916
- ] }),
3917
- /* @__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)) }),
3918
- offer.slots.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__loading", role: "status", children: "Finding available times\u2026" }) : null,
3919
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3920
- "div",
3921
- {
3922
- className: "booking-card__calendar",
3923
- role: "grid",
3924
- "aria-label": "Available dates",
3925
- children: cells.map((cell, index) => {
3926
- if (!cell) {
3927
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3928
- "span",
3929
- {
3930
- className: "booking-card__day"
3931
- },
3932
- `empty-${index}`
3933
- );
3979
+ ] }),
3980
+ /* @__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)) }),
3981
+ offer.slots.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__loading", role: "status", children: "Finding available times\u2026" }) : null,
3982
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3983
+ "div",
3984
+ {
3985
+ className: "booking-card__calendar",
3986
+ role: "grid",
3987
+ "aria-label": "Available dates",
3988
+ children: cells.map((cell, index) => {
3989
+ if (!cell) {
3990
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3991
+ "span",
3992
+ {
3993
+ className: "booking-card__day"
3994
+ },
3995
+ `empty-${index}`
3996
+ );
3997
+ }
3998
+ const available = availableByDate.has(cell.key);
3999
+ const selected = cell.key === selectedDate;
4000
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4001
+ "button",
4002
+ {
4003
+ type: "button",
4004
+ className: [
4005
+ "booking-card__day",
4006
+ available ? "booking-card__day--available" : "",
4007
+ selected ? "booking-card__day--selected" : ""
4008
+ ].filter(Boolean).join(" "),
4009
+ disabled: disabled || !available,
4010
+ "aria-pressed": selected,
4011
+ onClick: () => selectDate(cell.key),
4012
+ children: cell.day
4013
+ },
4014
+ cell.key
4015
+ );
4016
+ })
3934
4017
  }
3935
- const available = availableByDate.has(cell.key);
3936
- const selected = cell.key === selectedDate;
3937
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4018
+ )
4019
+ ] }, "date") : null,
4020
+ step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
4021
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
4022
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3938
4023
  "button",
3939
4024
  {
3940
4025
  type: "button",
3941
- className: [
3942
- "booking-card__day",
3943
- available ? "booking-card__day--available" : "",
3944
- selected ? "booking-card__day--selected" : ""
3945
- ].filter(Boolean).join(" "),
3946
- disabled: !available,
3947
- "aria-pressed": selected,
3948
- onClick: () => selectDate(cell.key),
3949
- children: cell.day
3950
- },
3951
- cell.key
3952
- );
3953
- })
3954
- }
3955
- )
3956
- ] }, "date") : null,
3957
- step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3958
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
3959
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3960
- "button",
3961
- {
3962
- type: "button",
3963
- className: "booking-card__nav",
3964
- "aria-label": "Back to dates",
3965
- onClick: () => setStep("date"),
3966
- children: "\u2039"
3967
- }
3968
- ),
3969
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
3970
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedSample ? formatLongDate(selectedSample) : "Pick a time" }),
3971
- timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
3972
- "Times in ",
3973
- timeZone
3974
- ] }) : null
3975
- ] })
3976
- ] }),
3977
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "booking-card__times", children: daySlots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3978
- "button",
3979
- {
3980
- type: "button",
3981
- className: startTime === slot.startTime ? "booking-card__time booking-card__time--selected" : "booking-card__time",
3982
- onClick: () => selectTime(slot.startTime),
3983
- children: formatTimeChip(slot.startTime)
3984
- },
3985
- slot.startTime
3986
- )) })
3987
- ] }, "time") : null,
3988
- step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3989
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
3990
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3991
- "button",
3992
- {
3993
- type: "button",
3994
- className: "booking-card__nav",
3995
- "aria-label": "Back to times",
3996
- onClick: () => setStep("time"),
3997
- children: "\u2039"
3998
- }
3999
- ),
4000
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
4001
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: "Enter details" }),
4002
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: formatSlotLabel(startTime) }),
4003
- selectedType?.location ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: selectedType.location }) : null
4004
- ] })
4005
- ] }),
4006
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__identity", children: [
4007
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
4008
- "label",
4009
- {
4010
- className: "booking-card__field",
4011
- htmlFor: `${fieldId}-name`,
4012
- children: [
4013
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Name" }),
4014
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4015
- "input",
4016
- {
4017
- id: `${fieldId}-name`,
4018
- autoComplete: "name",
4019
- value: name,
4020
- onChange: (event) => setName(event.target.value),
4021
- required: true
4022
- }
4023
- )
4024
- ]
4025
- }
4026
- ),
4027
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
4028
- "label",
4029
- {
4030
- className: "booking-card__field",
4031
- htmlFor: `${fieldId}-email`,
4032
- children: [
4033
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Email" }),
4034
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4035
- "input",
4036
- {
4037
- id: `${fieldId}-email`,
4038
- type: "email",
4039
- autoComplete: "email",
4040
- value: email,
4041
- onChange: (event) => setEmail(event.target.value),
4042
- required: true
4043
- }
4044
- )
4045
- ]
4046
- }
4047
- )
4048
- ] }),
4049
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4050
- "button",
4051
- {
4052
- type: "submit",
4053
- className: "booking-card__submit",
4054
- disabled: !name.trim() || !email.trim(),
4055
- children: "Book this time"
4056
- }
4057
- )
4058
- ] }, "details") : null
4059
- ] }) });
4026
+ className: "booking-card__nav",
4027
+ "aria-label": "Back to dates",
4028
+ disabled,
4029
+ onClick: () => setStep("date"),
4030
+ children: "\u2039"
4031
+ }
4032
+ ),
4033
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
4034
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedSample ? formatLongDate(selectedSample) : "Pick a time" }),
4035
+ timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
4036
+ "Times in ",
4037
+ timeZone
4038
+ ] }) : null
4039
+ ] })
4040
+ ] }),
4041
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "booking-card__times", children: daySlots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4042
+ "button",
4043
+ {
4044
+ type: "button",
4045
+ className: startTime === slot.startTime ? "booking-card__time booking-card__time--selected" : "booking-card__time",
4046
+ disabled,
4047
+ onClick: () => selectTime(slot.startTime),
4048
+ children: formatTimeChip(slot.startTime)
4049
+ },
4050
+ slot.startTime
4051
+ )) })
4052
+ ] }, "time") : null,
4053
+ step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
4054
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
4055
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4056
+ "button",
4057
+ {
4058
+ type: "button",
4059
+ className: "booking-card__nav",
4060
+ "aria-label": "Back to times",
4061
+ disabled,
4062
+ onClick: () => setStep("time"),
4063
+ children: "\u2039"
4064
+ }
4065
+ ),
4066
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
4067
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: "Enter details" }),
4068
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: formatSlotLabel(startTime) }),
4069
+ selectedType?.location ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__tz", children: selectedType.location }) : null
4070
+ ] })
4071
+ ] }),
4072
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__identity", children: [
4073
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
4074
+ "label",
4075
+ {
4076
+ className: "booking-card__field",
4077
+ htmlFor: `${fieldId}-name`,
4078
+ children: [
4079
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Name" }),
4080
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4081
+ "input",
4082
+ {
4083
+ id: `${fieldId}-name`,
4084
+ autoComplete: "name",
4085
+ disabled,
4086
+ value: name,
4087
+ onChange: (event) => setName(event.target.value),
4088
+ required: true
4089
+ }
4090
+ )
4091
+ ]
4092
+ }
4093
+ ),
4094
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
4095
+ "label",
4096
+ {
4097
+ className: "booking-card__field",
4098
+ htmlFor: `${fieldId}-email`,
4099
+ children: [
4100
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Email" }),
4101
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4102
+ "input",
4103
+ {
4104
+ id: `${fieldId}-email`,
4105
+ type: "email",
4106
+ autoComplete: "email",
4107
+ disabled,
4108
+ value: email,
4109
+ onChange: (event) => setEmail(event.target.value),
4110
+ required: true
4111
+ }
4112
+ )
4113
+ ]
4114
+ }
4115
+ )
4116
+ ] }),
4117
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4118
+ "button",
4119
+ {
4120
+ type: "submit",
4121
+ className: "booking-card__submit",
4122
+ disabled: disabled || !name.trim() || !email.trim(),
4123
+ children: disabled ? "Booking\u2026" : "Book this time"
4124
+ }
4125
+ )
4126
+ ] }, "details") : null
4127
+ ] })
4128
+ }
4129
+ );
4060
4130
  }
4061
4131
 
4062
4132
  // src/react/components/MessageBubble/MessageBubble.tsx
@@ -4073,9 +4143,7 @@ function paragraphsAreNearDuplicates(first, second) {
4073
4143
  if (left === right) return true;
4074
4144
  const shorter = left.length <= right.length ? left : right;
4075
4145
  const longer = left.length <= right.length ? right : left;
4076
- return longer.startsWith(
4077
- shorter.slice(0, Math.floor(shorter.length * 0.85))
4078
- );
4146
+ return longer.startsWith(shorter.slice(0, Math.floor(shorter.length * 0.85)));
4079
4147
  }
4080
4148
  function paragraphsShareOpening(first, second) {
4081
4149
  const opening = first.split("\n")[0]?.trim();
@@ -4103,6 +4171,7 @@ function collapseRepeatedText(text) {
4103
4171
  function MessageBubble({
4104
4172
  message,
4105
4173
  brandLogoUrl,
4174
+ bookingDisabled = false,
4106
4175
  offer,
4107
4176
  onBook
4108
4177
  }) {
@@ -4138,18 +4207,17 @@ function MessageBubble({
4138
4207
  children: displayText
4139
4208
  }
4140
4209
  ),
4141
- citations.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "message-bubble__sources", "aria-label": "Sources", children: citations.map((citation) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
4142
- "a",
4143
- {
4144
- href: citation.url,
4145
- target: "_blank",
4146
- rel: "noreferrer",
4147
- children: [
4148
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "message-bubble__source-icon", "aria-hidden": "true", children: "\u25A6" }),
4149
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: citation.label })
4150
- ]
4151
- }
4152
- ) }, citation.id)) }) : null
4210
+ citations.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "message-bubble__sources", "aria-label": "Sources", children: citations.map((citation) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("a", { href: citation.url, target: "_blank", rel: "noreferrer", children: [
4211
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4212
+ "span",
4213
+ {
4214
+ className: "message-bubble__source-icon",
4215
+ "aria-hidden": "true",
4216
+ children: "\u25A6"
4217
+ }
4218
+ ),
4219
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: citation.label })
4220
+ ] }) }, citation.id)) }) : null
4153
4221
  ] });
4154
4222
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
4155
4223
  displayText ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "message-bubble__agent-row", children: [
@@ -4168,6 +4236,7 @@ function MessageBubble({
4168
4236
  offers.map((nextOffer, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4169
4237
  BookingCard,
4170
4238
  {
4239
+ disabled: bookingDisabled,
4171
4240
  offer: nextOffer,
4172
4241
  onBook
4173
4242
  },
@@ -5147,6 +5216,7 @@ function AgentRail({
5147
5216
  MessageBubble,
5148
5217
  {
5149
5218
  message: greeting,
5219
+ bookingDisabled: isBusy,
5150
5220
  brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
5151
5221
  onBook
5152
5222
  }
@@ -5192,6 +5262,7 @@ function AgentRail({
5192
5262
  MessageBubble,
5193
5263
  {
5194
5264
  message,
5265
+ bookingDisabled: isBusy,
5195
5266
  brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
5196
5267
  offer: index === lastAgentIndex ? state.pendingOffer : void 0,
5197
5268
  onBook
@@ -5230,6 +5301,7 @@ function AgentRail({
5230
5301
  MessageBubble,
5231
5302
  {
5232
5303
  message: streamingMessage,
5304
+ bookingDisabled: isBusy,
5233
5305
  brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
5234
5306
  offer: state.pendingOffer,
5235
5307
  onBook
@@ -5616,7 +5688,10 @@ function AgentWidget({
5616
5688
  onInputResponse: (response) => void respondToInput(response),
5617
5689
  onToolInput: (surface, values) => void respondToToolInput(surface, values),
5618
5690
  onFollowUpSelect: (label) => void handleSubmit(label),
5619
- onBook: (input) => void submit(input.displayText, { runtimeText: input.runtimeText })
5691
+ onBook: (input) => void submit(input.displayText, {
5692
+ preservePendingOffer: true,
5693
+ runtimeText: input.runtimeText
5694
+ })
5620
5695
  }
5621
5696
  )
5622
5697
  }