@webless/agent 0.9.2 → 0.10.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.
@@ -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,
@@ -4519,6 +4555,7 @@ import {
4519
4555
  useState as useState4
4520
4556
  } from "react";
4521
4557
  import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
4558
+ var FORM_SUBMITTED_MESSAGE = "Shared my details";
4522
4559
  function SendIcon() {
4523
4560
  return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4524
4561
  "path",
@@ -4531,6 +4568,30 @@ function SendIcon() {
4531
4568
  }
4532
4569
  ) });
4533
4570
  }
4571
+ function CheckIcon2() {
4572
+ return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4573
+ "path",
4574
+ {
4575
+ d: "M2.5 6.2l2.3 2.3 4.7-5",
4576
+ stroke: "currentColor",
4577
+ strokeWidth: "1.6",
4578
+ strokeLinecap: "round",
4579
+ strokeLinejoin: "round"
4580
+ }
4581
+ ) });
4582
+ }
4583
+ function CollapseIcon() {
4584
+ return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4585
+ "path",
4586
+ {
4587
+ d: "M4 10l4-4 4 4",
4588
+ stroke: "currentColor",
4589
+ strokeWidth: "1.6",
4590
+ strokeLinecap: "round",
4591
+ strokeLinejoin: "round"
4592
+ }
4593
+ ) });
4594
+ }
4534
4595
  function emptyValues(form) {
4535
4596
  const values = {};
4536
4597
  for (const field of form?.fields ?? []) values[field.id] = "";
@@ -4564,26 +4625,31 @@ function Composer({
4564
4625
  const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
4565
4626
  const activeForm = !disabled && draft.expanded ? savedForm : null;
4566
4627
  const hasDraft = Object.values(draft.values).some((value2) => value2.trim());
4628
+ const canSend = !disabled && Boolean(value.trim() || activeForm);
4567
4629
  useEffect4(() => {
4568
4630
  if (activeForm) firstFieldRef.current?.focus();
4569
4631
  else if ((savedForm || draft.submitted) && !disabled)
4570
4632
  inputRef.current?.focus();
4571
4633
  }, [activeForm?.id, disabled, savedForm?.id, draft.submitted]);
4634
+ function collapseForm() {
4635
+ setDraft((current) => ({ ...current, expanded: false }));
4636
+ }
4572
4637
  function submitChat() {
4573
4638
  const trimmed = value.trim();
4574
4639
  if (!trimmed || disabled) return;
4575
4640
  const shareDismissal = savedForm && !draft.dismissalSent;
4576
4641
  if (shareDismissal) {
4577
4642
  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}`
4643
+ declinedComposerFormId: savedForm.id
4581
4644
  });
4582
4645
  } else {
4583
4646
  onSubmit?.(trimmed);
4584
4647
  }
4585
- if (shareDismissal)
4586
- setDraft((current) => ({ ...current, dismissalSent: true }));
4648
+ setDraft((current) => ({
4649
+ ...current,
4650
+ expanded: false,
4651
+ dismissalSent: shareDismissal ? true : current.dismissalSent
4652
+ }));
4587
4653
  setValue("");
4588
4654
  inputRef.current?.focus();
4589
4655
  }
@@ -4598,7 +4664,7 @@ ${trimmed}`
4598
4664
  if (control instanceof HTMLElement) control.focus();
4599
4665
  return;
4600
4666
  }
4601
- onSubmit?.("", {
4667
+ onSubmit?.(FORM_SUBMITTED_MESSAGE, {
4602
4668
  runtimeText: formatComposerFormMessage(activeForm, draft.values)
4603
4669
  });
4604
4670
  setDraft((current) => ({
@@ -4609,10 +4675,16 @@ ${trimmed}`
4609
4675
  attempted: false
4610
4676
  }));
4611
4677
  }
4678
+ function handleSend() {
4679
+ if (value.trim()) {
4680
+ submitChat();
4681
+ return;
4682
+ }
4683
+ if (activeForm) submitForm();
4684
+ }
4612
4685
  function handleSubmit(event) {
4613
4686
  event.preventDefault();
4614
- if (activeForm) submitForm();
4615
- else submitChat();
4687
+ handleSend();
4616
4688
  }
4617
4689
  function handleChatKeyDown(event) {
4618
4690
  if (event.key === "Enter" && !event.shiftKey) {
@@ -4628,7 +4700,34 @@ ${trimmed}`
4628
4700
  submitForm();
4629
4701
  }
4630
4702
  }
4631
- return /* @__PURE__ */ jsx4(
4703
+ const chatField = /* @__PURE__ */ jsxs4(Fragment, { children: [
4704
+ /* @__PURE__ */ jsx4(
4705
+ "textarea",
4706
+ {
4707
+ ref: inputRef,
4708
+ className: "composer__input",
4709
+ rows: 1,
4710
+ value,
4711
+ placeholder,
4712
+ disabled,
4713
+ spellCheck: false,
4714
+ "aria-label": "Message",
4715
+ onChange: (event) => setValue(event.target.value),
4716
+ onKeyDown: handleChatKeyDown
4717
+ }
4718
+ ),
4719
+ /* @__PURE__ */ jsx4(
4720
+ "button",
4721
+ {
4722
+ type: "submit",
4723
+ className: "composer__send",
4724
+ disabled: !canSend,
4725
+ "aria-label": "Send message",
4726
+ children: /* @__PURE__ */ jsx4(SendIcon, {})
4727
+ }
4728
+ )
4729
+ ] });
4730
+ return /* @__PURE__ */ jsxs4(
4632
4731
  "form",
4633
4732
  {
4634
4733
  ref: formRef,
@@ -4639,107 +4738,10 @@ ${trimmed}`
4639
4738
  activeForm ? "composer--form" : ""
4640
4739
  ].filter(Boolean).join(" "),
4641
4740
  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: [
4741
+ children: [
4740
4742
  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(
4743
+ /* @__PURE__ */ jsx4("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Share your details so we can follow up" }),
4744
+ !activeForm ? /* @__PURE__ */ jsx4(
4743
4745
  "button",
4744
4746
  {
4745
4747
  type: "button",
@@ -4747,36 +4749,100 @@ ${trimmed}`
4747
4749
  onClick: () => setDraft((current) => ({ ...current, expanded: true })),
4748
4750
  children: hasDraft ? "Resume details" : "Add details"
4749
4751
  }
4750
- )
4752
+ ) : null
4751
4753
  ] }) : 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
- ] })
4754
+ activeForm ? /* @__PURE__ */ jsxs4(
4755
+ "div",
4756
+ {
4757
+ className: "composer__sheet",
4758
+ role: "group",
4759
+ "aria-label": "Contact details",
4760
+ children: [
4761
+ /* @__PURE__ */ jsxs4("div", { className: "composer__form-heading", children: [
4762
+ /* @__PURE__ */ jsx4("strong", { children: "Share your details" }),
4763
+ /* @__PURE__ */ jsx4("span", { children: "Optional" }),
4764
+ /* @__PURE__ */ jsx4(
4765
+ "button",
4766
+ {
4767
+ type: "button",
4768
+ className: "composer__collapse",
4769
+ "aria-label": "Collapse form",
4770
+ disabled,
4771
+ onClick: collapseForm,
4772
+ children: /* @__PURE__ */ jsx4(CollapseIcon, {})
4773
+ }
4774
+ )
4775
+ ] }),
4776
+ /* @__PURE__ */ jsx4("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
4777
+ const fieldId = `${formId}-${field.id}`;
4778
+ const fieldValue = draft.values[field.id] ?? "";
4779
+ const invalid = draft.attempted && !isValidComposerFieldValue(field, fieldValue);
4780
+ const complete = fieldValue.trim().length > 0 && isValidComposerFieldValue(field, fieldValue);
4781
+ const controlProps = {
4782
+ id: fieldId,
4783
+ name: field.id,
4784
+ disabled,
4785
+ required: field.required,
4786
+ autoComplete: field.autocomplete,
4787
+ placeholder: field.placeholder,
4788
+ spellCheck: false,
4789
+ value: fieldValue,
4790
+ "aria-invalid": invalid || void 0,
4791
+ "aria-describedby": invalid ? `${fieldId}-error` : void 0,
4792
+ onChange: (event) => {
4793
+ const next = readComposerControlValue(event);
4794
+ setDraft((current) => ({
4795
+ ...current,
4796
+ values: { ...current.values, [field.id]: next }
4797
+ }));
4798
+ },
4799
+ onKeyDown: handleFormKeyDown
4800
+ };
4801
+ return /* @__PURE__ */ jsxs4(
4802
+ "div",
4803
+ {
4804
+ className: [
4805
+ "composer__row",
4806
+ field.kind === "textarea" ? "composer__row--area" : ""
4807
+ ].filter(Boolean).join(" "),
4808
+ children: [
4809
+ /* @__PURE__ */ jsxs4("div", { className: "composer__line", children: [
4810
+ /* @__PURE__ */ jsx4("label", { className: "composer__label", htmlFor: fieldId, children: field.label }),
4811
+ field.kind === "textarea" ? /* @__PURE__ */ jsx4(
4812
+ "textarea",
4813
+ {
4814
+ ...controlProps,
4815
+ ref: index === 0 ? (node) => {
4816
+ firstFieldRef.current = node;
4817
+ } : void 0,
4818
+ className: "composer__control composer__control--area",
4819
+ rows: 2
4820
+ }
4821
+ ) : /* @__PURE__ */ jsx4(
4822
+ "input",
4823
+ {
4824
+ ...controlProps,
4825
+ ref: index === 0 ? (node) => {
4826
+ firstFieldRef.current = node;
4827
+ } : void 0,
4828
+ className: "composer__control",
4829
+ type: field.kind,
4830
+ inputMode: field.kind === "tel" ? "tel" : void 0
4831
+ }
4832
+ ),
4833
+ complete && field.kind !== "textarea" ? /* @__PURE__ */ jsx4("span", { className: "composer__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(CheckIcon2, {}) }) : null
4834
+ ] }),
4835
+ 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
4836
+ ]
4837
+ },
4838
+ field.id
4839
+ );
4840
+ }) }),
4841
+ /* @__PURE__ */ jsx4("div", { className: "composer__field composer__field--inset", children: chatField })
4842
+ ]
4843
+ }
4844
+ ) : /* @__PURE__ */ jsx4("div", { className: "composer__field", children: chatField })
4845
+ ]
4780
4846
  }
4781
4847
  );
4782
4848
  }
@@ -5292,7 +5358,21 @@ function InteractiveBookingCard({
5292
5358
  }
5293
5359
 
5294
5360
  // src/react/components/MessageBubble/MessageBubble.tsx
5295
- import { Streamdown } from "streamdown";
5361
+ import { Streamdown, defaultUrlTransform } from "streamdown";
5362
+
5363
+ // src/react/lib/resolve-message-url.ts
5364
+ function resolveMessageUrl(safeUrl, baseUrl) {
5365
+ if (!safeUrl || !baseUrl) return safeUrl;
5366
+ try {
5367
+ const base = new URL(baseUrl);
5368
+ if (base.protocol !== "https:" && base.protocol !== "http:") return "";
5369
+ return new URL(safeUrl, base).href;
5370
+ } catch {
5371
+ return "";
5372
+ }
5373
+ }
5374
+
5375
+ // src/react/components/MessageBubble/MessageBubble.tsx
5296
5376
  import "streamdown/styles.css";
5297
5377
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
5298
5378
  function normalizeDedupeText(text2) {
@@ -5335,6 +5415,7 @@ function MessageBubble({
5335
5415
  brandLogoUrl,
5336
5416
  bookingDisabled = false,
5337
5417
  bookingReadOnly = false,
5418
+ linkBaseUrl,
5338
5419
  offer,
5339
5420
  onBook
5340
5421
  }) {
@@ -5352,8 +5433,9 @@ function MessageBubble({
5352
5433
  offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
5353
5434
  );
5354
5435
  if (message.role === "visitor") {
5355
- if (!message.text.trim()) return null;
5356
- return /* @__PURE__ */ jsx8("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ jsx8("p", { className: "message-bubble__text", children: message.text }) });
5436
+ const visitorText = visitorMessageDisplayText(message).trim();
5437
+ if (!visitorText) return null;
5438
+ return /* @__PURE__ */ jsx8("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ jsx8("p", { className: "message-bubble__text", children: visitorText }) });
5357
5439
  }
5358
5440
  const citations = message.citations ?? [];
5359
5441
  const agentText = /* @__PURE__ */ jsxs8("div", { className: "message-bubble__text", children: [
@@ -5367,6 +5449,10 @@ function MessageBubble({
5367
5449
  isAnimating: isStreaming,
5368
5450
  linkSafety: { enabled: false },
5369
5451
  mode: isStreaming ? "streaming" : "static",
5452
+ urlTransform: (url, key, node) => resolveMessageUrl(
5453
+ defaultUrlTransform(url, key, node) ?? "",
5454
+ key === "href" ? linkBaseUrl : void 0
5455
+ ),
5370
5456
  skipHtml: true,
5371
5457
  children: displayText
5372
5458
  }
@@ -5384,7 +5470,8 @@ function MessageBubble({
5384
5470
  /* @__PURE__ */ jsx8("span", { children: citation.label })
5385
5471
  ] }) }, citation.id)) }) : null
5386
5472
  ] });
5387
- if (!displayText && !message.searchResults?.length && offers.length === 0) return null;
5473
+ if (!displayText && !message.searchResults?.length && offers.length === 0)
5474
+ return null;
5388
5475
  return /* @__PURE__ */ jsxs8("article", { className: "message-bubble message-bubble--agent", children: [
5389
5476
  displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ jsxs8("div", { className: "message-bubble__agent-row", children: [
5390
5477
  /* @__PURE__ */ jsx8("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsx8(
@@ -6304,13 +6391,17 @@ function AgentRail({
6304
6391
  const hasPendingConfirmation = pendingInputRequests.some(
6305
6392
  (request) => request.kind === "tool-approval" || request.kind === "question" && (request.options?.length ?? 0) > 0
6306
6393
  );
6307
- const composerForm = resolveComposerForm({
6394
+ const inferredComposerForm = resolveComposerForm({
6308
6395
  agentText: lastAgentText,
6309
6396
  cards: extractToolCards(lastAgentText),
6310
6397
  hasBookingOffer: Boolean(state.pendingOffer) || waitingForBooking,
6311
6398
  hasPendingConfirmation,
6312
6399
  enabled: lastIsAgent && !isBusy
6313
6400
  });
6401
+ const declinedComposerFormIds = state.declinedComposerFormIds ?? [];
6402
+ const composerForm = inferredComposerForm && lastMessage?.role === "agent" && declinedComposerFormIds.includes(
6403
+ `${lastMessage.id}:${inferredComposerForm.id}`
6404
+ ) ? null : inferredComposerForm;
6314
6405
  const latestResultId = [
6315
6406
  ...visibleMessages.flatMap(
6316
6407
  (message) => message.role === "agent" ? message.toolResults ?? [] : []
@@ -6681,36 +6772,75 @@ function AgentRail({
6681
6772
 
6682
6773
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
6683
6774
  import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
6684
- function SparklesIcon() {
6775
+ function ChatSparkIcon() {
6685
6776
  return /* @__PURE__ */ jsxs17(
6686
6777
  "svg",
6687
6778
  {
6688
- className: "assist-edge-tab__sparkles",
6689
- viewBox: "0 0 18 16",
6779
+ className: "assist-edge-tab__chat-spark",
6780
+ viewBox: "0 0 24 24",
6690
6781
  fill: "none",
6691
6782
  "aria-hidden": "true",
6692
6783
  children: [
6693
6784
  /* @__PURE__ */ jsx18(
6694
6785
  "path",
6695
6786
  {
6696
- 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",
6697
6789
  fill: "currentColor"
6698
6790
  }
6699
6791
  ),
6700
6792
  /* @__PURE__ */ jsx18(
6701
6793
  "path",
6702
6794
  {
6703
- 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",
6704
6797
  fill: "currentColor"
6705
6798
  }
6706
6799
  ),
6707
- /* @__PURE__ */ jsx18(
6708
- "path",
6709
- {
6710
- 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",
6711
- fill: "currentColor"
6712
- }
6713
- )
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
+ ] })
6714
6844
  ]
6715
6845
  }
6716
6846
  );
@@ -6728,7 +6858,7 @@ function TabMarkIcon({ customIconUrl }) {
6728
6858
  }
6729
6859
  );
6730
6860
  }
6731
- return /* @__PURE__ */ jsx18(SparklesIcon, {});
6861
+ return /* @__PURE__ */ jsx18(ChatSparkIcon, {});
6732
6862
  }
6733
6863
  function ChevronLeftIcon() {
6734
6864
  return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
@@ -6769,6 +6899,7 @@ function AssistEdgeTab({
6769
6899
  inset,
6770
6900
  visible,
6771
6901
  label,
6902
+ subLabel,
6772
6903
  customIconUrl,
6773
6904
  logoUrl,
6774
6905
  brandColor,
@@ -6784,6 +6915,9 @@ function AssistEdgeTab({
6784
6915
  const resolvedColorScheme = useAgentColorScheme(colorScheme);
6785
6916
  const copy = VARIANT_COPY[variant];
6786
6917
  const visibleLabel = label?.trim() || copy.label;
6918
+ const visibleSubLabel = subLabel?.trim() || "";
6919
+ const pill = mobile || side === "bottom";
6920
+ const ariaLabel = visibleSubLabel ? `Open ${visibleLabel} \u2014 ${visibleSubLabel}` : `Open ${visibleLabel}`;
6787
6921
  const alignment = along < 50 ? "start" : along > 50 ? "end" : "center";
6788
6922
  const showLogo = Boolean(logoUrl?.trim()) && !customIconUrl?.trim();
6789
6923
  const resolvedBrandColor = brandColor ?? (resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.brand : void 0);
@@ -6808,18 +6942,20 @@ function AssistEdgeTab({
6808
6942
  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" : ""}`,
6809
6943
  "data-color-scheme": resolvedColorScheme,
6810
6944
  style,
6811
- "aria-label": `Open ${visibleLabel}`,
6945
+ "aria-label": ariaLabel,
6812
6946
  "aria-hidden": !visible,
6813
6947
  tabIndex: visible ? 0 : -1,
6814
6948
  onClick: onOpen,
6815
6949
  children: [
6816
- mobile ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6950
+ pill ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6817
6951
  /* @__PURE__ */ jsxs17(
6818
6952
  "span",
6819
6953
  {
6820
- className: "assist-edge-tab__mark assist-edge-tab__mark--mobile",
6954
+ className: `assist-edge-tab__mark assist-edge-tab__mark--chip${mobile ? " assist-edge-tab__mark--mobile" : ""}`,
6821
6955
  "aria-hidden": "true",
6822
6956
  children: [
6957
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--light" }),
6958
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--cool" }),
6823
6959
  /* @__PURE__ */ jsx18(TabMarkIcon, { customIconUrl }),
6824
6960
  showLogo ? /* @__PURE__ */ jsx18(
6825
6961
  "img",
@@ -6835,7 +6971,10 @@ function AssistEdgeTab({
6835
6971
  ]
6836
6972
  }
6837
6973
  ),
6838
- /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel })
6974
+ /* @__PURE__ */ jsxs17("span", { className: "assist-edge-tab__text", children: [
6975
+ /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6976
+ visibleSubLabel ? /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
6977
+ ] })
6839
6978
  ] }) : variant === "outline" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6840
6979
  /* @__PURE__ */ jsxs17("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
6841
6980
  /* @__PURE__ */ jsx18(TabMarkIcon, { customIconUrl }),
@@ -6854,12 +6993,12 @@ function AssistEdgeTab({
6854
6993
  /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6855
6994
  /* @__PURE__ */ jsx18(ChevronDownIcon2, {})
6856
6995
  ] }) : null,
6857
- variant === "ask" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6996
+ !pill && variant === "ask" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6858
6997
  /* @__PURE__ */ jsx18(ChevronLeftIcon, {}),
6859
6998
  /* @__PURE__ */ jsx18("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6860
6999
  /* @__PURE__ */ jsx18(DragDots, {})
6861
7000
  ] }) : null,
6862
- variant === "fill" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
7001
+ !pill && variant === "fill" ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6863
7002
  /* @__PURE__ */ jsxs17("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
6864
7003
  /* @__PURE__ */ jsx18(TabMarkIcon, { customIconUrl }),
6865
7004
  showLogo ? /* @__PURE__ */ jsx18(
@@ -7239,6 +7378,7 @@ function AgentWidget({
7239
7378
  inset: placement.inset,
7240
7379
  visible: true,
7241
7380
  label: tabLabel,
7381
+ subLabel: branding?.tabSubLabel,
7242
7382
  customIconUrl: branding?.tabIconUrl,
7243
7383
  logoUrl: branding?.logoUrl,
7244
7384
  brandColor: branding?.colors?.primary,
@@ -7290,4 +7430,4 @@ export {
7290
7430
  sendAgentAnswerFeedback,
7291
7431
  AgentWidget
7292
7432
  };
7293
- //# sourceMappingURL=chunk-3E632FNE.js.map
7433
+ //# sourceMappingURL=chunk-6OCODDRO.js.map