@webless/agent 0.9.3 → 0.10.1

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.
@@ -388,6 +388,24 @@ function parseAgentSearchDiscoveryOutput(value) {
388
388
  }
389
389
 
390
390
  // src/react/lib/composer-form.ts
391
+ var COMPOSER_FORM_SKIP_DISMISSAL = "I'd like to keep chatting without sharing the requested details for now. Please don't ask for them again unless I choose to proceed with something that needs them.";
392
+ function visitorMessageDisplayText(message) {
393
+ if (message.role !== "visitor") return message.text;
394
+ const text2 = message.text.trim();
395
+ if (!text2) return message.text;
396
+ if (text2.startsWith(COMPOSER_FORM_SKIP_DISMISSAL)) {
397
+ const afterDismissal = text2.slice(COMPOSER_FORM_SKIP_DISMISSAL.length).trim().replace(/^\n+/, "").trim();
398
+ if (afterDismissal) return afterDismissal;
399
+ }
400
+ const runtime = message.runtimeText?.trim();
401
+ if (runtime && text2 === runtime && runtime.includes(COMPOSER_FORM_SKIP_DISMISSAL)) {
402
+ const afterDismissal = runtime.slice(
403
+ runtime.indexOf(COMPOSER_FORM_SKIP_DISMISSAL) + COMPOSER_FORM_SKIP_DISMISSAL.length
404
+ ).trim().replace(/^\n+/, "").trim();
405
+ if (afterDismissal) return afterDismissal;
406
+ }
407
+ return message.text;
408
+ }
391
409
  var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
392
410
  var MIN_FORM_FIELDS = 2;
393
411
  var MAX_FORM_FIELDS = 5;
@@ -2779,7 +2797,8 @@ function createInitialState(greeting = DEFAULT_GREETING) {
2779
2797
  pendingOffer: null,
2780
2798
  pendingInputs: [],
2781
2799
  toolResults: [],
2782
- error: null
2800
+ error: null,
2801
+ declinedComposerFormIds: []
2783
2802
  };
2784
2803
  }
2785
2804
  function stateFromConversation(conversation, initialState) {
@@ -3199,6 +3218,7 @@ function useAgentChat({
3199
3218
  const trimmed = visitorText.trim();
3200
3219
  const outgoing = options?.runtimeText ?? visitorText;
3201
3220
  if (!outgoing.trim()) return null;
3221
+ const declinedComposerFormId = options?.declinedComposerFormId?.trim();
3202
3222
  const chatResponse = chatInputResponseForText(
3203
3223
  state.pendingInputs ?? [],
3204
3224
  outgoing.trim()
@@ -3232,7 +3252,15 @@ function useAgentChat({
3232
3252
  state: "active"
3233
3253
  }
3234
3254
  ],
3235
- error: null
3255
+ error: null,
3256
+ ...declinedComposerFormId ? {
3257
+ declinedComposerFormIds: [
3258
+ .../* @__PURE__ */ new Set([
3259
+ ...prev.declinedComposerFormIds ?? [],
3260
+ declinedComposerFormId
3261
+ ])
3262
+ ]
3263
+ } : {}
3236
3264
  }));
3237
3265
  return await runTurn({
3238
3266
  controller: controller2,
@@ -3254,9 +3282,9 @@ ${outgoing}` : outgoing;
3254
3282
  const visitorMessage = {
3255
3283
  id: `visitor-${Date.now()}`,
3256
3284
  role: "visitor",
3257
- text: visitorText,
3285
+ text: trimmed,
3258
3286
  createdAt: Date.now(),
3259
- ...runtimeText !== visitorText ? { runtimeText } : {}
3287
+ ...runtimeText.trim() !== trimmed ? { runtimeText } : {}
3260
3288
  };
3261
3289
  setState((prev) => ({
3262
3290
  ...prev,
@@ -3276,7 +3304,15 @@ ${outgoing}` : outgoing;
3276
3304
  pendingOffer: options?.preservePendingOffer ? prev.pendingOffer : null,
3277
3305
  pendingInputs: [],
3278
3306
  toolResults: [],
3279
- error: null
3307
+ error: null,
3308
+ ...declinedComposerFormId ? {
3309
+ declinedComposerFormIds: [
3310
+ .../* @__PURE__ */ new Set([
3311
+ ...prev.declinedComposerFormIds ?? [],
3312
+ declinedComposerFormId
3313
+ ])
3314
+ ]
3315
+ } : {}
3280
3316
  }));
3281
3317
  return await runTurn({
3282
3318
  controller,
@@ -4262,8 +4298,7 @@ function workSummary(steps, failed, brandLabel) {
4262
4298
  )}`;
4263
4299
  const active = [...steps].reverse().find((step) => step.state === "active");
4264
4300
  if (active?.kind === "search") return "Searching this site";
4265
- if (active)
4266
- return brandLabel ? `${brandLabel} is choosing the best way to help` : "Choosing the best way to help";
4301
+ if (active) return "Reviewing your details to find the best approach";
4267
4302
  if (failed) return "Couldn\u2019t complete this request";
4268
4303
  const hasError = steps.some((step) => step.state === "error");
4269
4304
  const specialists = steps.filter(
@@ -4372,7 +4407,7 @@ function AgentActivityBubble({
4372
4407
  }
4373
4408
  ),
4374
4409
  workSummary(steps, failed, brandLabel),
4375
- active ? "\u2026" : ""
4410
+ active ? "..." : ""
4376
4411
  ] }),
4377
4412
  !active ? /* @__PURE__ */ jsxs2("div", { className: "agent-activity-bubble__details", children: [
4378
4413
  /* @__PURE__ */ jsx2(
@@ -4519,6 +4554,7 @@ import {
4519
4554
  useState as useState4
4520
4555
  } from "react";
4521
4556
  import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
4557
+ var FORM_SUBMITTED_MESSAGE = "Shared my details";
4522
4558
  function SendIcon() {
4523
4559
  return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4524
4560
  "path",
@@ -4531,6 +4567,30 @@ function SendIcon() {
4531
4567
  }
4532
4568
  ) });
4533
4569
  }
4570
+ function CheckIcon2() {
4571
+ return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4572
+ "path",
4573
+ {
4574
+ d: "M2.5 6.2l2.3 2.3 4.7-5",
4575
+ stroke: "currentColor",
4576
+ strokeWidth: "1.6",
4577
+ strokeLinecap: "round",
4578
+ strokeLinejoin: "round"
4579
+ }
4580
+ ) });
4581
+ }
4582
+ function CollapseIcon() {
4583
+ return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4584
+ "path",
4585
+ {
4586
+ d: "M4 10l4-4 4 4",
4587
+ stroke: "currentColor",
4588
+ strokeWidth: "1.6",
4589
+ strokeLinecap: "round",
4590
+ strokeLinejoin: "round"
4591
+ }
4592
+ ) });
4593
+ }
4534
4594
  function emptyValues(form) {
4535
4595
  const values = {};
4536
4596
  for (const field of form?.fields ?? []) values[field.id] = "";
@@ -4564,26 +4624,31 @@ function Composer({
4564
4624
  const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
4565
4625
  const activeForm = !disabled && draft.expanded ? savedForm : null;
4566
4626
  const hasDraft = Object.values(draft.values).some((value2) => value2.trim());
4627
+ const canSend = !disabled && Boolean(value.trim() || activeForm);
4567
4628
  useEffect4(() => {
4568
4629
  if (activeForm) firstFieldRef.current?.focus();
4569
4630
  else if ((savedForm || draft.submitted) && !disabled)
4570
4631
  inputRef.current?.focus();
4571
4632
  }, [activeForm?.id, disabled, savedForm?.id, draft.submitted]);
4633
+ function collapseForm() {
4634
+ setDraft((current) => ({ ...current, expanded: false }));
4635
+ }
4572
4636
  function submitChat() {
4573
4637
  const trimmed = value.trim();
4574
4638
  if (!trimmed || disabled) return;
4575
4639
  const shareDismissal = savedForm && !draft.dismissalSent;
4576
4640
  if (shareDismissal) {
4577
4641
  onSubmit?.(trimmed, {
4578
- runtimeText: `I'd like to keep chatting without sharing the requested details for now. Please don't ask for them again unless I choose to proceed with something that needs them.
4579
-
4580
- ${trimmed}`
4642
+ declinedComposerFormId: savedForm.id
4581
4643
  });
4582
4644
  } else {
4583
4645
  onSubmit?.(trimmed);
4584
4646
  }
4585
- if (shareDismissal)
4586
- setDraft((current) => ({ ...current, dismissalSent: true }));
4647
+ setDraft((current) => ({
4648
+ ...current,
4649
+ expanded: false,
4650
+ dismissalSent: shareDismissal ? true : current.dismissalSent
4651
+ }));
4587
4652
  setValue("");
4588
4653
  inputRef.current?.focus();
4589
4654
  }
@@ -4598,7 +4663,7 @@ ${trimmed}`
4598
4663
  if (control instanceof HTMLElement) control.focus();
4599
4664
  return;
4600
4665
  }
4601
- onSubmit?.("", {
4666
+ onSubmit?.(FORM_SUBMITTED_MESSAGE, {
4602
4667
  runtimeText: formatComposerFormMessage(activeForm, draft.values)
4603
4668
  });
4604
4669
  setDraft((current) => ({
@@ -4609,10 +4674,16 @@ ${trimmed}`
4609
4674
  attempted: false
4610
4675
  }));
4611
4676
  }
4677
+ function handleSend() {
4678
+ if (value.trim()) {
4679
+ submitChat();
4680
+ return;
4681
+ }
4682
+ if (activeForm) submitForm();
4683
+ }
4612
4684
  function handleSubmit(event) {
4613
4685
  event.preventDefault();
4614
- if (activeForm) submitForm();
4615
- else submitChat();
4686
+ handleSend();
4616
4687
  }
4617
4688
  function handleChatKeyDown(event) {
4618
4689
  if (event.key === "Enter" && !event.shiftKey) {
@@ -4628,7 +4699,34 @@ ${trimmed}`
4628
4699
  submitForm();
4629
4700
  }
4630
4701
  }
4631
- return /* @__PURE__ */ jsx4(
4702
+ const chatField = /* @__PURE__ */ jsxs4(Fragment, { children: [
4703
+ /* @__PURE__ */ jsx4(
4704
+ "textarea",
4705
+ {
4706
+ ref: inputRef,
4707
+ className: "composer__input",
4708
+ rows: 1,
4709
+ value,
4710
+ placeholder,
4711
+ disabled,
4712
+ spellCheck: false,
4713
+ "aria-label": "Message",
4714
+ onChange: (event) => setValue(event.target.value),
4715
+ onKeyDown: handleChatKeyDown
4716
+ }
4717
+ ),
4718
+ /* @__PURE__ */ jsx4(
4719
+ "button",
4720
+ {
4721
+ type: "submit",
4722
+ className: "composer__send",
4723
+ disabled: !canSend,
4724
+ "aria-label": "Send message",
4725
+ children: /* @__PURE__ */ jsx4(SendIcon, {})
4726
+ }
4727
+ )
4728
+ ] });
4729
+ return /* @__PURE__ */ jsxs4(
4632
4730
  "form",
4633
4731
  {
4634
4732
  ref: formRef,
@@ -4639,107 +4737,10 @@ ${trimmed}`
4639
4737
  activeForm ? "composer--form" : ""
4640
4738
  ].filter(Boolean).join(" "),
4641
4739
  onSubmit: handleSubmit,
4642
- children: activeForm ? /* @__PURE__ */ jsxs4(
4643
- "div",
4644
- {
4645
- className: "composer__sheet",
4646
- role: "group",
4647
- "aria-label": "Contact details",
4648
- children: [
4649
- /* @__PURE__ */ jsxs4("div", { className: "composer__form-heading", children: [
4650
- /* @__PURE__ */ jsx4("strong", { children: "Share your details" }),
4651
- /* @__PURE__ */ jsx4("span", { children: "Optional" }),
4652
- /* @__PURE__ */ jsx4("p", { children: "You can also keep chatting." })
4653
- ] }),
4654
- /* @__PURE__ */ jsx4("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
4655
- const fieldId = `${formId}-${field.id}`;
4656
- const invalid = draft.attempted && !isValidComposerFieldValue(field, draft.values[field.id] ?? "");
4657
- const controlProps = {
4658
- id: fieldId,
4659
- name: field.id,
4660
- disabled,
4661
- required: field.required,
4662
- autoComplete: field.autocomplete,
4663
- placeholder: field.placeholder,
4664
- spellCheck: false,
4665
- value: draft.values[field.id] ?? "",
4666
- "aria-invalid": invalid || void 0,
4667
- "aria-describedby": invalid ? `${fieldId}-error` : void 0,
4668
- onChange: (event) => {
4669
- const next = readComposerControlValue(event);
4670
- setDraft((current) => ({
4671
- ...current,
4672
- values: { ...current.values, [field.id]: next }
4673
- }));
4674
- },
4675
- onKeyDown: handleFormKeyDown
4676
- };
4677
- return /* @__PURE__ */ jsxs4(
4678
- "div",
4679
- {
4680
- className: [
4681
- "composer__row",
4682
- field.kind === "textarea" ? "composer__row--grow" : ""
4683
- ].filter(Boolean).join(" "),
4684
- children: [
4685
- /* @__PURE__ */ jsxs4("label", { className: "composer__label", htmlFor: fieldId, children: [
4686
- /* @__PURE__ */ jsx4("span", { className: "composer__field-label", children: field.label }),
4687
- field.kind === "textarea" ? /* @__PURE__ */ jsx4(
4688
- "textarea",
4689
- {
4690
- ...controlProps,
4691
- ref: index === 0 ? (node) => {
4692
- firstFieldRef.current = node;
4693
- } : void 0,
4694
- className: "composer__control composer__control--area",
4695
- rows: 3
4696
- }
4697
- ) : /* @__PURE__ */ jsx4(
4698
- "input",
4699
- {
4700
- ...controlProps,
4701
- ref: index === 0 ? (node) => {
4702
- firstFieldRef.current = node;
4703
- } : void 0,
4704
- className: "composer__control",
4705
- type: field.kind,
4706
- inputMode: field.kind === "tel" ? "tel" : void 0
4707
- }
4708
- )
4709
- ] }),
4710
- invalid ? /* @__PURE__ */ jsx4("p", { className: "composer__error", id: `${fieldId}-error`, children: field.kind === "email" ? "Enter a valid email to share your details." : `Add your ${field.label.toLowerCase()} to share your details.` }) : null
4711
- ]
4712
- },
4713
- field.id
4714
- );
4715
- }) }),
4716
- /* @__PURE__ */ jsxs4("div", { className: "composer__toolbar", children: [
4717
- /* @__PURE__ */ jsx4(
4718
- "button",
4719
- {
4720
- type: "submit",
4721
- className: "composer__action composer__action--primary",
4722
- disabled,
4723
- children: "Share details"
4724
- }
4725
- ),
4726
- /* @__PURE__ */ jsx4(
4727
- "button",
4728
- {
4729
- type: "button",
4730
- className: "composer__action",
4731
- disabled,
4732
- onClick: () => setDraft((current) => ({ ...current, expanded: false })),
4733
- children: "Keep chatting"
4734
- }
4735
- )
4736
- ] })
4737
- ]
4738
- }
4739
- ) : /* @__PURE__ */ jsxs4(Fragment, { children: [
4740
+ children: [
4740
4741
  savedForm ? /* @__PURE__ */ jsxs4("div", { className: "composer__resume", children: [
4741
- /* @__PURE__ */ jsx4("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Contact details are optional" }),
4742
- /* @__PURE__ */ jsx4(
4742
+ /* @__PURE__ */ jsx4("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Share your details so we can follow up" }),
4743
+ !activeForm ? /* @__PURE__ */ jsx4(
4743
4744
  "button",
4744
4745
  {
4745
4746
  type: "button",
@@ -4747,36 +4748,100 @@ ${trimmed}`
4747
4748
  onClick: () => setDraft((current) => ({ ...current, expanded: true })),
4748
4749
  children: hasDraft ? "Resume details" : "Add details"
4749
4750
  }
4750
- )
4751
+ ) : null
4751
4752
  ] }) : null,
4752
- /* @__PURE__ */ jsxs4("div", { className: "composer__field", children: [
4753
- /* @__PURE__ */ jsx4(
4754
- "textarea",
4755
- {
4756
- ref: inputRef,
4757
- className: "composer__input",
4758
- rows: 1,
4759
- value,
4760
- placeholder,
4761
- disabled,
4762
- spellCheck: false,
4763
- "aria-label": "Message",
4764
- onChange: (event) => setValue(event.target.value),
4765
- onKeyDown: handleChatKeyDown
4766
- }
4767
- ),
4768
- /* @__PURE__ */ jsx4(
4769
- "button",
4770
- {
4771
- type: "submit",
4772
- className: "composer__send",
4773
- disabled: disabled || !value.trim(),
4774
- "aria-label": "Send message",
4775
- children: /* @__PURE__ */ jsx4(SendIcon, {})
4776
- }
4777
- )
4778
- ] })
4779
- ] })
4753
+ activeForm ? /* @__PURE__ */ jsxs4(
4754
+ "div",
4755
+ {
4756
+ className: "composer__sheet",
4757
+ role: "group",
4758
+ "aria-label": "Contact details",
4759
+ children: [
4760
+ /* @__PURE__ */ jsxs4("div", { className: "composer__form-heading", children: [
4761
+ /* @__PURE__ */ jsx4("strong", { children: "Share your details" }),
4762
+ /* @__PURE__ */ jsx4("span", { children: "Optional" }),
4763
+ /* @__PURE__ */ jsx4(
4764
+ "button",
4765
+ {
4766
+ type: "button",
4767
+ className: "composer__collapse",
4768
+ "aria-label": "Collapse form",
4769
+ disabled,
4770
+ onClick: collapseForm,
4771
+ children: /* @__PURE__ */ jsx4(CollapseIcon, {})
4772
+ }
4773
+ )
4774
+ ] }),
4775
+ /* @__PURE__ */ jsx4("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
4776
+ const fieldId = `${formId}-${field.id}`;
4777
+ const fieldValue = draft.values[field.id] ?? "";
4778
+ const invalid = draft.attempted && !isValidComposerFieldValue(field, fieldValue);
4779
+ const complete = fieldValue.trim().length > 0 && isValidComposerFieldValue(field, fieldValue);
4780
+ const controlProps = {
4781
+ id: fieldId,
4782
+ name: field.id,
4783
+ disabled,
4784
+ required: field.required,
4785
+ autoComplete: field.autocomplete,
4786
+ placeholder: field.placeholder,
4787
+ spellCheck: false,
4788
+ value: fieldValue,
4789
+ "aria-invalid": invalid || void 0,
4790
+ "aria-describedby": invalid ? `${fieldId}-error` : void 0,
4791
+ onChange: (event) => {
4792
+ const next = readComposerControlValue(event);
4793
+ setDraft((current) => ({
4794
+ ...current,
4795
+ values: { ...current.values, [field.id]: next }
4796
+ }));
4797
+ },
4798
+ onKeyDown: handleFormKeyDown
4799
+ };
4800
+ return /* @__PURE__ */ jsxs4(
4801
+ "div",
4802
+ {
4803
+ className: [
4804
+ "composer__row",
4805
+ field.kind === "textarea" ? "composer__row--area" : ""
4806
+ ].filter(Boolean).join(" "),
4807
+ children: [
4808
+ /* @__PURE__ */ jsxs4("div", { className: "composer__line", children: [
4809
+ /* @__PURE__ */ jsx4("label", { className: "composer__label", htmlFor: fieldId, children: field.label }),
4810
+ field.kind === "textarea" ? /* @__PURE__ */ jsx4(
4811
+ "textarea",
4812
+ {
4813
+ ...controlProps,
4814
+ ref: index === 0 ? (node) => {
4815
+ firstFieldRef.current = node;
4816
+ } : void 0,
4817
+ className: "composer__control composer__control--area",
4818
+ rows: 2
4819
+ }
4820
+ ) : /* @__PURE__ */ jsx4(
4821
+ "input",
4822
+ {
4823
+ ...controlProps,
4824
+ ref: index === 0 ? (node) => {
4825
+ firstFieldRef.current = node;
4826
+ } : void 0,
4827
+ className: "composer__control",
4828
+ type: field.kind,
4829
+ inputMode: field.kind === "tel" ? "tel" : void 0
4830
+ }
4831
+ ),
4832
+ complete && field.kind !== "textarea" ? /* @__PURE__ */ jsx4("span", { className: "composer__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(CheckIcon2, {}) }) : null
4833
+ ] }),
4834
+ invalid ? /* @__PURE__ */ jsx4("p", { className: "composer__error", id: `${fieldId}-error`, children: field.kind === "email" ? "Enter a valid email to share your details." : `Add your ${field.label.toLowerCase()} to share your details.` }) : null
4835
+ ]
4836
+ },
4837
+ field.id
4838
+ );
4839
+ }) }),
4840
+ /* @__PURE__ */ jsx4("div", { className: "composer__field composer__field--inset", children: chatField })
4841
+ ]
4842
+ }
4843
+ ) : /* @__PURE__ */ jsx4("div", { className: "composer__field", children: chatField })
4844
+ ]
4780
4845
  }
4781
4846
  );
4782
4847
  }
@@ -5367,8 +5432,9 @@ function MessageBubble({
5367
5432
  offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
5368
5433
  );
5369
5434
  if (message.role === "visitor") {
5370
- if (!message.text.trim()) return null;
5371
- return /* @__PURE__ */ jsx8("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ jsx8("p", { className: "message-bubble__text", children: message.text }) });
5435
+ const visitorText = visitorMessageDisplayText(message).trim();
5436
+ if (!visitorText) return null;
5437
+ return /* @__PURE__ */ jsx8("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ jsx8("p", { className: "message-bubble__text", children: visitorText }) });
5372
5438
  }
5373
5439
  const citations = message.citations ?? [];
5374
5440
  const agentText = /* @__PURE__ */ jsxs8("div", { className: "message-bubble__text", children: [
@@ -6324,13 +6390,17 @@ function AgentRail({
6324
6390
  const hasPendingConfirmation = pendingInputRequests.some(
6325
6391
  (request) => request.kind === "tool-approval" || request.kind === "question" && (request.options?.length ?? 0) > 0
6326
6392
  );
6327
- const composerForm = resolveComposerForm({
6393
+ const inferredComposerForm = resolveComposerForm({
6328
6394
  agentText: lastAgentText,
6329
6395
  cards: extractToolCards(lastAgentText),
6330
6396
  hasBookingOffer: Boolean(state.pendingOffer) || waitingForBooking,
6331
6397
  hasPendingConfirmation,
6332
6398
  enabled: lastIsAgent && !isBusy
6333
6399
  });
6400
+ const declinedComposerFormIds = state.declinedComposerFormIds ?? [];
6401
+ const composerForm = inferredComposerForm && lastMessage?.role === "agent" && declinedComposerFormIds.includes(
6402
+ `${lastMessage.id}:${inferredComposerForm.id}`
6403
+ ) ? null : inferredComposerForm;
6334
6404
  const latestResultId = [
6335
6405
  ...visibleMessages.flatMap(
6336
6406
  (message) => message.role === "agent" ? message.toolResults ?? [] : []
@@ -6700,55 +6770,114 @@ function AgentRail({
6700
6770
  }
6701
6771
 
6702
6772
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
6773
+ import { useState as useState10 } from "react";
6703
6774
  import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
6704
- function SparklesIcon() {
6775
+ function ChatSparkIcon() {
6705
6776
  return /* @__PURE__ */ jsxs17(
6706
6777
  "svg",
6707
6778
  {
6708
- className: "assist-edge-tab__sparkles",
6709
- viewBox: "0 0 18 16",
6779
+ className: "assist-edge-tab__chat-spark",
6780
+ viewBox: "0 0 24 24",
6710
6781
  fill: "none",
6711
6782
  "aria-hidden": "true",
6712
6783
  children: [
6713
6784
  /* @__PURE__ */ jsx18(
6714
6785
  "path",
6715
6786
  {
6716
- 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",
6787
+ className: "assist-edge-tab__spark assist-edge-tab__spark--a",
6788
+ d: "M19.55 1.55l.78 1.82 1.82.78-1.82.78-.78 1.82-.78-1.82-1.82-.78 1.82-.78.78-1.82z",
6717
6789
  fill: "currentColor"
6718
6790
  }
6719
6791
  ),
6720
6792
  /* @__PURE__ */ jsx18(
6721
6793
  "path",
6722
6794
  {
6723
- 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",
6795
+ className: "assist-edge-tab__spark assist-edge-tab__spark--b",
6796
+ d: "M4.15 17.35l.48 1.12 1.12.48-1.12.48-.48 1.12-.48-1.12-1.12-.48 1.12-.48.48-1.12z",
6724
6797
  fill: "currentColor"
6725
6798
  }
6726
6799
  ),
6727
- /* @__PURE__ */ jsx18(
6728
- "path",
6729
- {
6730
- 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",
6731
- fill: "currentColor"
6732
- }
6733
- )
6800
+ /* @__PURE__ */ jsxs17("g", { className: "assist-edge-tab__bot", children: [
6801
+ /* @__PURE__ */ jsx18(
6802
+ "path",
6803
+ {
6804
+ d: "M11.15 5.2V3.05",
6805
+ stroke: "currentColor",
6806
+ strokeWidth: "1.9",
6807
+ strokeLinecap: "round"
6808
+ }
6809
+ ),
6810
+ /* @__PURE__ */ jsx18("circle", { cx: "11.15", cy: "2.45", r: "0.85", fill: "currentColor" }),
6811
+ /* @__PURE__ */ jsx18(
6812
+ "rect",
6813
+ {
6814
+ x: "3.55",
6815
+ y: "5.35",
6816
+ width: "15.2",
6817
+ height: "11.15",
6818
+ rx: "3.9",
6819
+ stroke: "currentColor",
6820
+ strokeWidth: "1.9"
6821
+ }
6822
+ ),
6823
+ /* @__PURE__ */ jsx18(
6824
+ "circle",
6825
+ {
6826
+ className: "assist-edge-tab__eye",
6827
+ cx: "8.7",
6828
+ cy: "10.85",
6829
+ r: "1.28",
6830
+ fill: "currentColor"
6831
+ }
6832
+ ),
6833
+ /* @__PURE__ */ jsx18(
6834
+ "circle",
6835
+ {
6836
+ className: "assist-edge-tab__eye assist-edge-tab__eye--r",
6837
+ cx: "14.35",
6838
+ cy: "10.85",
6839
+ r: "1.28",
6840
+ fill: "currentColor"
6841
+ }
6842
+ )
6843
+ ] })
6734
6844
  ]
6735
6845
  }
6736
6846
  );
6737
6847
  }
6738
- function TabMarkIcon({ customIconUrl }) {
6739
- const url = customIconUrl?.trim();
6740
- if (url) {
6848
+ function TabMarkIcon({
6849
+ customIconUrl,
6850
+ logoUrl
6851
+ }) {
6852
+ const custom = customIconUrl?.trim();
6853
+ const logo = logoUrl?.trim();
6854
+ const [customFailed, setCustomFailed] = useState10(false);
6855
+ const [logoFailed, setLogoFailed] = useState10(false);
6856
+ if (custom && !customFailed) {
6741
6857
  return /* @__PURE__ */ jsx18(
6742
6858
  "img",
6743
6859
  {
6744
6860
  alt: "",
6745
6861
  "aria-hidden": true,
6746
6862
  className: "assist-edge-tab__custom-icon",
6747
- src: url
6863
+ src: custom,
6864
+ onError: () => setCustomFailed(true)
6748
6865
  }
6749
6866
  );
6750
6867
  }
6751
- return /* @__PURE__ */ jsx18(SparklesIcon, {});
6868
+ if (logo && !logoFailed) {
6869
+ return /* @__PURE__ */ jsx18(
6870
+ "img",
6871
+ {
6872
+ alt: "",
6873
+ "aria-hidden": true,
6874
+ className: "assist-edge-tab__logo",
6875
+ src: logo,
6876
+ onError: () => setLogoFailed(true)
6877
+ }
6878
+ );
6879
+ }
6880
+ return /* @__PURE__ */ jsx18(ChatSparkIcon, {});
6752
6881
  }
6753
6882
  function ChevronLeftIcon() {
6754
6883
  return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
@@ -6789,6 +6918,7 @@ function AssistEdgeTab({
6789
6918
  inset,
6790
6919
  visible,
6791
6920
  label,
6921
+ subLabel,
6792
6922
  customIconUrl,
6793
6923
  logoUrl,
6794
6924
  brandColor,
@@ -6804,12 +6934,16 @@ function AssistEdgeTab({
6804
6934
  const resolvedColorScheme = useAgentColorScheme(colorScheme);
6805
6935
  const copy = VARIANT_COPY[variant];
6806
6936
  const visibleLabel = label?.trim() || copy.label;
6937
+ const visibleSubLabel = subLabel?.trim() || "";
6938
+ const pill = mobile || side === "bottom";
6939
+ const chromeScheme = pill ? "light" : resolvedColorScheme;
6940
+ const ariaLabel = visibleSubLabel ? `Open ${visibleLabel} \u2014 ${visibleSubLabel}` : `Open ${visibleLabel}`;
6807
6941
  const alignment = along < 50 ? "start" : along > 50 ? "end" : "center";
6808
- const showLogo = Boolean(logoUrl?.trim()) && !customIconUrl?.trim();
6809
- const resolvedBrandColor = brandColor ?? (resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.brand : void 0);
6810
- const resolvedBorderColor = resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.border : borderColor;
6811
- const resolvedSurfaceColor = resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.surface : surfaceColor;
6812
- const resolvedTextColor = resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.text : textColor;
6942
+ const resolvedBrandColor = brandColor ?? (chromeScheme === "dark" ? defaultDarkAgentRailTheme.brand : void 0);
6943
+ const resolvedBorderColor = chromeScheme === "dark" ? defaultDarkAgentRailTheme.border : borderColor;
6944
+ const resolvedSurfaceColor = chromeScheme === "dark" ? defaultDarkAgentRailTheme.surface : surfaceColor;
6945
+ const resolvedTextColor = chromeScheme === "dark" ? defaultDarkAgentRailTheme.text : textColor;
6946
+ const markSourceKey = `${customIconUrl?.trim() ?? ""}|${logoUrl?.trim() ?? ""}`;
6813
6947
  const style = {
6814
6948
  "--tab-along": `${along}%`,
6815
6949
  "--tab-inset": `${inset}px`,
@@ -6817,83 +6951,72 @@ function AssistEdgeTab({
6817
6951
  ...brandForeground ? { "--as-visitor-text": brandForeground } : {},
6818
6952
  ...resolvedBorderColor ? { "--as-border": resolvedBorderColor } : {},
6819
6953
  ...fontFamily ? { "--as-font-display": fontFamily } : {},
6820
- ...resolvedSurfaceColor ? { "--as-surface": resolvedSurfaceColor } : {},
6821
- ...resolvedTextColor ? { "--as-text": resolvedTextColor } : {},
6822
- colorScheme: resolvedColorScheme
6954
+ ...pill ? { "--as-surface": "#ffffff", "--as-text": "#171717" } : resolvedSurfaceColor ? { "--as-surface": resolvedSurfaceColor } : {},
6955
+ ...!pill && resolvedTextColor ? { "--as-text": resolvedTextColor } : {},
6956
+ colorScheme: chromeScheme
6823
6957
  };
6824
6958
  return /* @__PURE__ */ jsxs17(
6825
6959
  "button",
6826
6960
  {
6827
6961
  type: "button",
6828
6962
  className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side} assist-edge-tab--align-${alignment}${mobile ? " assist-edge-tab--mobile" : ""}${visible ? " is-visible" : ""}`,
6829
- "data-color-scheme": resolvedColorScheme,
6963
+ "data-color-scheme": chromeScheme,
6830
6964
  style,
6831
- "aria-label": `Open ${visibleLabel}`,
6965
+ "aria-label": ariaLabel,
6832
6966
  "aria-hidden": !visible,
6833
6967
  tabIndex: visible ? 0 : -1,
6834
6968
  onClick: onOpen,
6835
6969
  children: [
6836
- mobile ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6970
+ pill ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6837
6971
  /* @__PURE__ */ jsxs17(
6838
6972
  "span",
6839
6973
  {
6840
- className: "assist-edge-tab__mark assist-edge-tab__mark--mobile",
6974
+ className: `assist-edge-tab__mark assist-edge-tab__mark--chip${mobile ? " assist-edge-tab__mark--mobile" : ""}`,
6841
6975
  "aria-hidden": "true",
6842
6976
  children: [
6843
- /* @__PURE__ */ jsx18(TabMarkIcon, { customIconUrl }),
6844
- showLogo ? /* @__PURE__ */ jsx18(
6845
- "img",
6977
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--light" }),
6978
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--cool" }),
6979
+ /* @__PURE__ */ jsx18(
6980
+ TabMarkIcon,
6846
6981
  {
6847
- className: "assist-edge-tab__logo",
6848
- src: logoUrl,
6849
- alt: "",
6850
- onError: (event) => {
6851
- event.currentTarget.hidden = true;
6852
- }
6853
- }
6854
- ) : null
6982
+ customIconUrl,
6983
+ logoUrl
6984
+ },
6985
+ markSourceKey
6986
+ )
6855
6987
  ]
6856
6988
  }
6857
6989
  ),
6858
- /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel })
6990
+ /* @__PURE__ */ jsxs17("span", { className: "assist-edge-tab__text", children: [
6991
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6992
+ visibleSubLabel ? /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
6993
+ ] })
6859
6994
  ] }) : variant === "outline" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6860
- /* @__PURE__ */ jsxs17("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
6861
- /* @__PURE__ */ jsx18(TabMarkIcon, { customIconUrl }),
6862
- showLogo ? /* @__PURE__ */ jsx18(
6863
- "img",
6864
- {
6865
- className: "assist-edge-tab__logo",
6866
- src: logoUrl,
6867
- alt: "",
6868
- onError: (event) => {
6869
- event.currentTarget.hidden = true;
6870
- }
6871
- }
6872
- ) : null
6873
- ] }),
6995
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
6996
+ TabMarkIcon,
6997
+ {
6998
+ customIconUrl,
6999
+ logoUrl
7000
+ },
7001
+ markSourceKey
7002
+ ) }),
6874
7003
  /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6875
7004
  /* @__PURE__ */ jsx18(ChevronDownIcon2, {})
6876
7005
  ] }) : null,
6877
- variant === "ask" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
7006
+ !pill && variant === "ask" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6878
7007
  /* @__PURE__ */ jsx18(ChevronLeftIcon, {}),
6879
7008
  /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6880
7009
  /* @__PURE__ */ jsx18(DragDots, {})
6881
7010
  ] }) : null,
6882
- variant === "fill" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6883
- /* @__PURE__ */ jsxs17("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
6884
- /* @__PURE__ */ jsx18(TabMarkIcon, { customIconUrl }),
6885
- showLogo ? /* @__PURE__ */ jsx18(
6886
- "img",
6887
- {
6888
- className: "assist-edge-tab__logo",
6889
- src: logoUrl,
6890
- alt: "",
6891
- onError: (event) => {
6892
- event.currentTarget.hidden = true;
6893
- }
6894
- }
6895
- ) : null
6896
- ] }),
7011
+ !pill && variant === "fill" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
7012
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
7013
+ TabMarkIcon,
7014
+ {
7015
+ customIconUrl,
7016
+ logoUrl
7017
+ },
7018
+ markSourceKey
7019
+ ) }),
6897
7020
  /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6898
7021
  /* @__PURE__ */ jsx18(ChevronLeftIcon, {})
6899
7022
  ] }) : null
@@ -6959,7 +7082,7 @@ function sendAgentAnswerFeedback(eventUrl, event) {
6959
7082
  }
6960
7083
 
6961
7084
  // src/react/components/AgentWidget/AgentWidget.tsx
6962
- import { useEffect as useEffect9, useRef as useRef7, useState as useState11 } from "react";
7085
+ import { useEffect as useEffect9, useRef as useRef7, useState as useState12 } from "react";
6963
7086
 
6964
7087
  // src/react/page-shift.ts
6965
7088
  import { useEffect as useEffect7 } from "react";
@@ -7042,9 +7165,9 @@ function usePageShift(input) {
7042
7165
  }
7043
7166
 
7044
7167
  // src/react/hooks/useIsMobile.ts
7045
- import { useEffect as useEffect8, useState as useState10 } from "react";
7168
+ import { useEffect as useEffect8, useState as useState11 } from "react";
7046
7169
  function useIsMobile(breakpoint = 767) {
7047
- const [isMobile, setIsMobile] = useState10(
7170
+ const [isMobile, setIsMobile] = useState11(
7048
7171
  () => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
7049
7172
  );
7050
7173
  useEffect8(() => {
@@ -7078,8 +7201,8 @@ function AgentWidget({
7078
7201
  const isMobile = useIsMobile();
7079
7202
  const placement = normalizeAgentPlacement(placementInput);
7080
7203
  const railSlotRef = useRef7(null);
7081
- const [railCollapsed, setRailCollapsed] = useState11(defaultCollapsed);
7082
- const [railExpanded, setRailExpanded] = useState11(false);
7204
+ const [railCollapsed, setRailCollapsed] = useState12(defaultCollapsed);
7205
+ const [railExpanded, setRailExpanded] = useState12(false);
7083
7206
  const pageShiftActive = shouldApplyPageShift({
7084
7207
  pageShift,
7085
7208
  isMobile,
@@ -7259,6 +7382,7 @@ function AgentWidget({
7259
7382
  inset: placement.inset,
7260
7383
  visible: true,
7261
7384
  label: tabLabel,
7385
+ subLabel: branding?.tabSubLabel,
7262
7386
  customIconUrl: branding?.tabIconUrl,
7263
7387
  logoUrl: branding?.logoUrl,
7264
7388
  brandColor: branding?.colors?.primary,
@@ -7310,4 +7434,4 @@ export {
7310
7434
  sendAgentAnswerFeedback,
7311
7435
  AgentWidget
7312
7436
  };
7313
- //# sourceMappingURL=chunk-JIM5AOVC.js.map
7437
+ //# sourceMappingURL=chunk-ZYTNNMZS.js.map