@webless/agent 0.9.3 → 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.
package/dist/embed.cjs CHANGED
@@ -1671,6 +1671,24 @@ function formatAgentError(error) {
1671
1671
  }
1672
1672
 
1673
1673
  // src/react/lib/composer-form.ts
1674
+ 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.";
1675
+ function visitorMessageDisplayText(message) {
1676
+ if (message.role !== "visitor") return message.text;
1677
+ const text2 = message.text.trim();
1678
+ if (!text2) return message.text;
1679
+ if (text2.startsWith(COMPOSER_FORM_SKIP_DISMISSAL)) {
1680
+ const afterDismissal = text2.slice(COMPOSER_FORM_SKIP_DISMISSAL.length).trim().replace(/^\n+/, "").trim();
1681
+ if (afterDismissal) return afterDismissal;
1682
+ }
1683
+ const runtime = message.runtimeText?.trim();
1684
+ if (runtime && text2 === runtime && runtime.includes(COMPOSER_FORM_SKIP_DISMISSAL)) {
1685
+ const afterDismissal = runtime.slice(
1686
+ runtime.indexOf(COMPOSER_FORM_SKIP_DISMISSAL) + COMPOSER_FORM_SKIP_DISMISSAL.length
1687
+ ).trim().replace(/^\n+/, "").trim();
1688
+ if (afterDismissal) return afterDismissal;
1689
+ }
1690
+ return message.text;
1691
+ }
1674
1692
  var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1675
1693
  var MIN_FORM_FIELDS = 2;
1676
1694
  var MAX_FORM_FIELDS = 5;
@@ -2924,7 +2942,8 @@ function createInitialState(greeting = DEFAULT_GREETING) {
2924
2942
  pendingOffer: null,
2925
2943
  pendingInputs: [],
2926
2944
  toolResults: [],
2927
- error: null
2945
+ error: null,
2946
+ declinedComposerFormIds: []
2928
2947
  };
2929
2948
  }
2930
2949
  function stateFromConversation(conversation, initialState) {
@@ -3344,6 +3363,7 @@ function useAgentChat({
3344
3363
  const trimmed = visitorText.trim();
3345
3364
  const outgoing = options?.runtimeText ?? visitorText;
3346
3365
  if (!outgoing.trim()) return null;
3366
+ const declinedComposerFormId = options?.declinedComposerFormId?.trim();
3347
3367
  const chatResponse = chatInputResponseForText(
3348
3368
  state.pendingInputs ?? [],
3349
3369
  outgoing.trim()
@@ -3377,7 +3397,15 @@ function useAgentChat({
3377
3397
  state: "active"
3378
3398
  }
3379
3399
  ],
3380
- error: null
3400
+ error: null,
3401
+ ...declinedComposerFormId ? {
3402
+ declinedComposerFormIds: [
3403
+ .../* @__PURE__ */ new Set([
3404
+ ...prev.declinedComposerFormIds ?? [],
3405
+ declinedComposerFormId
3406
+ ])
3407
+ ]
3408
+ } : {}
3381
3409
  }));
3382
3410
  return await runTurn({
3383
3411
  controller: controller2,
@@ -3399,9 +3427,9 @@ ${outgoing}` : outgoing;
3399
3427
  const visitorMessage = {
3400
3428
  id: `visitor-${Date.now()}`,
3401
3429
  role: "visitor",
3402
- text: visitorText,
3430
+ text: trimmed,
3403
3431
  createdAt: Date.now(),
3404
- ...runtimeText !== visitorText ? { runtimeText } : {}
3432
+ ...runtimeText.trim() !== trimmed ? { runtimeText } : {}
3405
3433
  };
3406
3434
  setState((prev) => ({
3407
3435
  ...prev,
@@ -3421,7 +3449,15 @@ ${outgoing}` : outgoing;
3421
3449
  pendingOffer: options?.preservePendingOffer ? prev.pendingOffer : null,
3422
3450
  pendingInputs: [],
3423
3451
  toolResults: [],
3424
- error: null
3452
+ error: null,
3453
+ ...declinedComposerFormId ? {
3454
+ declinedComposerFormIds: [
3455
+ .../* @__PURE__ */ new Set([
3456
+ ...prev.declinedComposerFormIds ?? [],
3457
+ declinedComposerFormId
3458
+ ])
3459
+ ]
3460
+ } : {}
3425
3461
  }));
3426
3462
  return await runTurn({
3427
3463
  controller,
@@ -4032,6 +4068,7 @@ function AnswerReceiptDialog({
4032
4068
  // src/react/components/Composer/Composer.tsx
4033
4069
  var import_react8 = require("react");
4034
4070
  var import_jsx_runtime3 = require("react/jsx-runtime");
4071
+ var FORM_SUBMITTED_MESSAGE = "Shared my details";
4035
4072
  function SendIcon() {
4036
4073
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4037
4074
  "path",
@@ -4044,6 +4081,30 @@ function SendIcon() {
4044
4081
  }
4045
4082
  ) });
4046
4083
  }
4084
+ function CheckIcon() {
4085
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4086
+ "path",
4087
+ {
4088
+ d: "M2.5 6.2l2.3 2.3 4.7-5",
4089
+ stroke: "currentColor",
4090
+ strokeWidth: "1.6",
4091
+ strokeLinecap: "round",
4092
+ strokeLinejoin: "round"
4093
+ }
4094
+ ) });
4095
+ }
4096
+ function CollapseIcon() {
4097
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4098
+ "path",
4099
+ {
4100
+ d: "M4 10l4-4 4 4",
4101
+ stroke: "currentColor",
4102
+ strokeWidth: "1.6",
4103
+ strokeLinecap: "round",
4104
+ strokeLinejoin: "round"
4105
+ }
4106
+ ) });
4107
+ }
4047
4108
  function emptyValues(form) {
4048
4109
  const values = {};
4049
4110
  for (const field of form?.fields ?? []) values[field.id] = "";
@@ -4077,26 +4138,31 @@ function Composer({
4077
4138
  const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
4078
4139
  const activeForm = !disabled && draft.expanded ? savedForm : null;
4079
4140
  const hasDraft = Object.values(draft.values).some((value2) => value2.trim());
4141
+ const canSend = !disabled && Boolean(value.trim() || activeForm);
4080
4142
  (0, import_react8.useEffect)(() => {
4081
4143
  if (activeForm) firstFieldRef.current?.focus();
4082
4144
  else if ((savedForm || draft.submitted) && !disabled)
4083
4145
  inputRef.current?.focus();
4084
4146
  }, [activeForm?.id, disabled, savedForm?.id, draft.submitted]);
4147
+ function collapseForm() {
4148
+ setDraft((current) => ({ ...current, expanded: false }));
4149
+ }
4085
4150
  function submitChat() {
4086
4151
  const trimmed = value.trim();
4087
4152
  if (!trimmed || disabled) return;
4088
4153
  const shareDismissal = savedForm && !draft.dismissalSent;
4089
4154
  if (shareDismissal) {
4090
4155
  onSubmit?.(trimmed, {
4091
- 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.
4092
-
4093
- ${trimmed}`
4156
+ declinedComposerFormId: savedForm.id
4094
4157
  });
4095
4158
  } else {
4096
4159
  onSubmit?.(trimmed);
4097
4160
  }
4098
- if (shareDismissal)
4099
- setDraft((current) => ({ ...current, dismissalSent: true }));
4161
+ setDraft((current) => ({
4162
+ ...current,
4163
+ expanded: false,
4164
+ dismissalSent: shareDismissal ? true : current.dismissalSent
4165
+ }));
4100
4166
  setValue("");
4101
4167
  inputRef.current?.focus();
4102
4168
  }
@@ -4111,7 +4177,7 @@ ${trimmed}`
4111
4177
  if (control instanceof HTMLElement) control.focus();
4112
4178
  return;
4113
4179
  }
4114
- onSubmit?.("", {
4180
+ onSubmit?.(FORM_SUBMITTED_MESSAGE, {
4115
4181
  runtimeText: formatComposerFormMessage(activeForm, draft.values)
4116
4182
  });
4117
4183
  setDraft((current) => ({
@@ -4122,10 +4188,16 @@ ${trimmed}`
4122
4188
  attempted: false
4123
4189
  }));
4124
4190
  }
4191
+ function handleSend() {
4192
+ if (value.trim()) {
4193
+ submitChat();
4194
+ return;
4195
+ }
4196
+ if (activeForm) submitForm();
4197
+ }
4125
4198
  function handleSubmit(event) {
4126
4199
  event.preventDefault();
4127
- if (activeForm) submitForm();
4128
- else submitChat();
4200
+ handleSend();
4129
4201
  }
4130
4202
  function handleChatKeyDown(event) {
4131
4203
  if (event.key === "Enter" && !event.shiftKey) {
@@ -4141,7 +4213,34 @@ ${trimmed}`
4141
4213
  submitForm();
4142
4214
  }
4143
4215
  }
4144
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4216
+ const chatField = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
4217
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4218
+ "textarea",
4219
+ {
4220
+ ref: inputRef,
4221
+ className: "composer__input",
4222
+ rows: 1,
4223
+ value,
4224
+ placeholder,
4225
+ disabled,
4226
+ spellCheck: false,
4227
+ "aria-label": "Message",
4228
+ onChange: (event) => setValue(event.target.value),
4229
+ onKeyDown: handleChatKeyDown
4230
+ }
4231
+ ),
4232
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4233
+ "button",
4234
+ {
4235
+ type: "submit",
4236
+ className: "composer__send",
4237
+ disabled: !canSend,
4238
+ "aria-label": "Send message",
4239
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
4240
+ }
4241
+ )
4242
+ ] });
4243
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4145
4244
  "form",
4146
4245
  {
4147
4246
  ref: formRef,
@@ -4152,107 +4251,10 @@ ${trimmed}`
4152
4251
  activeForm ? "composer--form" : ""
4153
4252
  ].filter(Boolean).join(" "),
4154
4253
  onSubmit: handleSubmit,
4155
- children: activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4156
- "div",
4157
- {
4158
- className: "composer__sheet",
4159
- role: "group",
4160
- "aria-label": "Contact details",
4161
- children: [
4162
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__form-heading", children: [
4163
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Share your details" }),
4164
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Optional" }),
4165
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "You can also keep chatting." })
4166
- ] }),
4167
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
4168
- const fieldId = `${formId}-${field.id}`;
4169
- const invalid = draft.attempted && !isValidComposerFieldValue(field, draft.values[field.id] ?? "");
4170
- const controlProps = {
4171
- id: fieldId,
4172
- name: field.id,
4173
- disabled,
4174
- required: field.required,
4175
- autoComplete: field.autocomplete,
4176
- placeholder: field.placeholder,
4177
- spellCheck: false,
4178
- value: draft.values[field.id] ?? "",
4179
- "aria-invalid": invalid || void 0,
4180
- "aria-describedby": invalid ? `${fieldId}-error` : void 0,
4181
- onChange: (event) => {
4182
- const next = readComposerControlValue(event);
4183
- setDraft((current) => ({
4184
- ...current,
4185
- values: { ...current.values, [field.id]: next }
4186
- }));
4187
- },
4188
- onKeyDown: handleFormKeyDown
4189
- };
4190
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4191
- "div",
4192
- {
4193
- className: [
4194
- "composer__row",
4195
- field.kind === "textarea" ? "composer__row--grow" : ""
4196
- ].filter(Boolean).join(" "),
4197
- children: [
4198
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "composer__label", htmlFor: fieldId, children: [
4199
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "composer__field-label", children: field.label }),
4200
- field.kind === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4201
- "textarea",
4202
- {
4203
- ...controlProps,
4204
- ref: index === 0 ? (node) => {
4205
- firstFieldRef.current = node;
4206
- } : void 0,
4207
- className: "composer__control composer__control--area",
4208
- rows: 3
4209
- }
4210
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4211
- "input",
4212
- {
4213
- ...controlProps,
4214
- ref: index === 0 ? (node) => {
4215
- firstFieldRef.current = node;
4216
- } : void 0,
4217
- className: "composer__control",
4218
- type: field.kind,
4219
- inputMode: field.kind === "tel" ? "tel" : void 0
4220
- }
4221
- )
4222
- ] }),
4223
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("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
4224
- ]
4225
- },
4226
- field.id
4227
- );
4228
- }) }),
4229
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__toolbar", children: [
4230
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4231
- "button",
4232
- {
4233
- type: "submit",
4234
- className: "composer__action composer__action--primary",
4235
- disabled,
4236
- children: "Share details"
4237
- }
4238
- ),
4239
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4240
- "button",
4241
- {
4242
- type: "button",
4243
- className: "composer__action",
4244
- disabled,
4245
- onClick: () => setDraft((current) => ({ ...current, expanded: false })),
4246
- children: "Keep chatting"
4247
- }
4248
- )
4249
- ] })
4250
- ]
4251
- }
4252
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
4254
+ children: [
4253
4255
  savedForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__resume", children: [
4254
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Contact details are optional" }),
4255
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4256
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Share your details so we can follow up" }),
4257
+ !activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4256
4258
  "button",
4257
4259
  {
4258
4260
  type: "button",
@@ -4260,36 +4262,100 @@ ${trimmed}`
4260
4262
  onClick: () => setDraft((current) => ({ ...current, expanded: true })),
4261
4263
  children: hasDraft ? "Resume details" : "Add details"
4262
4264
  }
4263
- )
4265
+ ) : null
4264
4266
  ] }) : null,
4265
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__field", children: [
4266
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4267
- "textarea",
4268
- {
4269
- ref: inputRef,
4270
- className: "composer__input",
4271
- rows: 1,
4272
- value,
4273
- placeholder,
4274
- disabled,
4275
- spellCheck: false,
4276
- "aria-label": "Message",
4277
- onChange: (event) => setValue(event.target.value),
4278
- onKeyDown: handleChatKeyDown
4279
- }
4280
- ),
4281
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4282
- "button",
4283
- {
4284
- type: "submit",
4285
- className: "composer__send",
4286
- disabled: disabled || !value.trim(),
4287
- "aria-label": "Send message",
4288
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
4289
- }
4290
- )
4291
- ] })
4292
- ] })
4267
+ activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4268
+ "div",
4269
+ {
4270
+ className: "composer__sheet",
4271
+ role: "group",
4272
+ "aria-label": "Contact details",
4273
+ children: [
4274
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__form-heading", children: [
4275
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Share your details" }),
4276
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Optional" }),
4277
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4278
+ "button",
4279
+ {
4280
+ type: "button",
4281
+ className: "composer__collapse",
4282
+ "aria-label": "Collapse form",
4283
+ disabled,
4284
+ onClick: collapseForm,
4285
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CollapseIcon, {})
4286
+ }
4287
+ )
4288
+ ] }),
4289
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
4290
+ const fieldId = `${formId}-${field.id}`;
4291
+ const fieldValue = draft.values[field.id] ?? "";
4292
+ const invalid = draft.attempted && !isValidComposerFieldValue(field, fieldValue);
4293
+ const complete = fieldValue.trim().length > 0 && isValidComposerFieldValue(field, fieldValue);
4294
+ const controlProps = {
4295
+ id: fieldId,
4296
+ name: field.id,
4297
+ disabled,
4298
+ required: field.required,
4299
+ autoComplete: field.autocomplete,
4300
+ placeholder: field.placeholder,
4301
+ spellCheck: false,
4302
+ value: fieldValue,
4303
+ "aria-invalid": invalid || void 0,
4304
+ "aria-describedby": invalid ? `${fieldId}-error` : void 0,
4305
+ onChange: (event) => {
4306
+ const next = readComposerControlValue(event);
4307
+ setDraft((current) => ({
4308
+ ...current,
4309
+ values: { ...current.values, [field.id]: next }
4310
+ }));
4311
+ },
4312
+ onKeyDown: handleFormKeyDown
4313
+ };
4314
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4315
+ "div",
4316
+ {
4317
+ className: [
4318
+ "composer__row",
4319
+ field.kind === "textarea" ? "composer__row--area" : ""
4320
+ ].filter(Boolean).join(" "),
4321
+ children: [
4322
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__line", children: [
4323
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "composer__label", htmlFor: fieldId, children: field.label }),
4324
+ field.kind === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4325
+ "textarea",
4326
+ {
4327
+ ...controlProps,
4328
+ ref: index === 0 ? (node) => {
4329
+ firstFieldRef.current = node;
4330
+ } : void 0,
4331
+ className: "composer__control composer__control--area",
4332
+ rows: 2
4333
+ }
4334
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4335
+ "input",
4336
+ {
4337
+ ...controlProps,
4338
+ ref: index === 0 ? (node) => {
4339
+ firstFieldRef.current = node;
4340
+ } : void 0,
4341
+ className: "composer__control",
4342
+ type: field.kind,
4343
+ inputMode: field.kind === "tel" ? "tel" : void 0
4344
+ }
4345
+ ),
4346
+ complete && field.kind !== "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "composer__check", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, {}) }) : null
4347
+ ] }),
4348
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("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
4349
+ ]
4350
+ },
4351
+ field.id
4352
+ );
4353
+ }) }),
4354
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__field composer__field--inset", children: chatField })
4355
+ ]
4356
+ }
4357
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__field", children: chatField })
4358
+ ]
4293
4359
  }
4294
4360
  );
4295
4361
  }
@@ -4874,8 +4940,9 @@ function MessageBubble({
4874
4940
  offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
4875
4941
  );
4876
4942
  if (message.role === "visitor") {
4877
- if (!message.text.trim()) return null;
4878
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "message-bubble__text", children: message.text }) });
4943
+ const visitorText = visitorMessageDisplayText(message).trim();
4944
+ if (!visitorText) return null;
4945
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "message-bubble__text", children: visitorText }) });
4879
4946
  }
4880
4947
  const citations = message.citations ?? [];
4881
4948
  const agentText = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__text", children: [
@@ -5113,7 +5180,7 @@ function CopyIcon() {
5113
5180
  )
5114
5181
  ] });
5115
5182
  }
5116
- function CheckIcon() {
5183
+ function CheckIcon2() {
5117
5184
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5118
5185
  "path",
5119
5186
  {
@@ -5488,7 +5555,7 @@ function MessageActions({
5488
5555
  title: copied ? "Copied" : "Copy answer",
5489
5556
  disabled,
5490
5557
  onClick: handleCopy,
5491
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CopyIcon, {})
5558
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon2, {}) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CopyIcon, {})
5492
5559
  }
5493
5560
  ),
5494
5561
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
@@ -6442,13 +6509,17 @@ function AgentRail({
6442
6509
  const hasPendingConfirmation = pendingInputRequests.some(
6443
6510
  (request) => request.kind === "tool-approval" || request.kind === "question" && (request.options?.length ?? 0) > 0
6444
6511
  );
6445
- const composerForm = resolveComposerForm({
6512
+ const inferredComposerForm = resolveComposerForm({
6446
6513
  agentText: lastAgentText,
6447
6514
  cards: extractToolCards(lastAgentText),
6448
6515
  hasBookingOffer: Boolean(state.pendingOffer) || waitingForBooking,
6449
6516
  hasPendingConfirmation,
6450
6517
  enabled: lastIsAgent && !isBusy
6451
6518
  });
6519
+ const declinedComposerFormIds = state.declinedComposerFormIds ?? [];
6520
+ const composerForm = inferredComposerForm && lastMessage?.role === "agent" && declinedComposerFormIds.includes(
6521
+ `${lastMessage.id}:${inferredComposerForm.id}`
6522
+ ) ? null : inferredComposerForm;
6452
6523
  const latestResultId = [
6453
6524
  ...visibleMessages.flatMap(
6454
6525
  (message) => message.role === "agent" ? message.toolResults ?? [] : []
@@ -6819,36 +6890,75 @@ function AgentRail({
6819
6890
 
6820
6891
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
6821
6892
  var import_jsx_runtime18 = require("react/jsx-runtime");
6822
- function SparklesIcon() {
6893
+ function ChatSparkIcon() {
6823
6894
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
6824
6895
  "svg",
6825
6896
  {
6826
- className: "assist-edge-tab__sparkles",
6827
- viewBox: "0 0 18 16",
6897
+ className: "assist-edge-tab__chat-spark",
6898
+ viewBox: "0 0 24 24",
6828
6899
  fill: "none",
6829
6900
  "aria-hidden": "true",
6830
6901
  children: [
6831
6902
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6832
6903
  "path",
6833
6904
  {
6834
- 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",
6905
+ className: "assist-edge-tab__spark assist-edge-tab__spark--a",
6906
+ 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",
6835
6907
  fill: "currentColor"
6836
6908
  }
6837
6909
  ),
6838
6910
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6839
6911
  "path",
6840
6912
  {
6841
- 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",
6913
+ className: "assist-edge-tab__spark assist-edge-tab__spark--b",
6914
+ 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",
6842
6915
  fill: "currentColor"
6843
6916
  }
6844
6917
  ),
6845
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6846
- "path",
6847
- {
6848
- 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",
6849
- fill: "currentColor"
6850
- }
6851
- )
6918
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { className: "assist-edge-tab__bot", children: [
6919
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6920
+ "path",
6921
+ {
6922
+ d: "M11.15 5.2V3.05",
6923
+ stroke: "currentColor",
6924
+ strokeWidth: "1.9",
6925
+ strokeLinecap: "round"
6926
+ }
6927
+ ),
6928
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "11.15", cy: "2.45", r: "0.85", fill: "currentColor" }),
6929
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6930
+ "rect",
6931
+ {
6932
+ x: "3.55",
6933
+ y: "5.35",
6934
+ width: "15.2",
6935
+ height: "11.15",
6936
+ rx: "3.9",
6937
+ stroke: "currentColor",
6938
+ strokeWidth: "1.9"
6939
+ }
6940
+ ),
6941
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6942
+ "circle",
6943
+ {
6944
+ className: "assist-edge-tab__eye",
6945
+ cx: "8.7",
6946
+ cy: "10.85",
6947
+ r: "1.28",
6948
+ fill: "currentColor"
6949
+ }
6950
+ ),
6951
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6952
+ "circle",
6953
+ {
6954
+ className: "assist-edge-tab__eye assist-edge-tab__eye--r",
6955
+ cx: "14.35",
6956
+ cy: "10.85",
6957
+ r: "1.28",
6958
+ fill: "currentColor"
6959
+ }
6960
+ )
6961
+ ] })
6852
6962
  ]
6853
6963
  }
6854
6964
  );
@@ -6866,7 +6976,7 @@ function TabMarkIcon({ customIconUrl }) {
6866
6976
  }
6867
6977
  );
6868
6978
  }
6869
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SparklesIcon, {});
6979
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChatSparkIcon, {});
6870
6980
  }
6871
6981
  function ChevronLeftIcon() {
6872
6982
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
@@ -6907,6 +7017,7 @@ function AssistEdgeTab({
6907
7017
  inset,
6908
7018
  visible,
6909
7019
  label,
7020
+ subLabel,
6910
7021
  customIconUrl,
6911
7022
  logoUrl,
6912
7023
  brandColor,
@@ -6922,6 +7033,9 @@ function AssistEdgeTab({
6922
7033
  const resolvedColorScheme = useAgentColorScheme(colorScheme);
6923
7034
  const copy = VARIANT_COPY[variant];
6924
7035
  const visibleLabel = label?.trim() || copy.label;
7036
+ const visibleSubLabel = subLabel?.trim() || "";
7037
+ const pill = mobile || side === "bottom";
7038
+ const ariaLabel = visibleSubLabel ? `Open ${visibleLabel} \u2014 ${visibleSubLabel}` : `Open ${visibleLabel}`;
6925
7039
  const alignment = along < 50 ? "start" : along > 50 ? "end" : "center";
6926
7040
  const showLogo = Boolean(logoUrl?.trim()) && !customIconUrl?.trim();
6927
7041
  const resolvedBrandColor = brandColor ?? (resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.brand : void 0);
@@ -6946,18 +7060,20 @@ function AssistEdgeTab({
6946
7060
  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" : ""}`,
6947
7061
  "data-color-scheme": resolvedColorScheme,
6948
7062
  style,
6949
- "aria-label": `Open ${visibleLabel}`,
7063
+ "aria-label": ariaLabel,
6950
7064
  "aria-hidden": !visible,
6951
7065
  tabIndex: visible ? 0 : -1,
6952
7066
  onClick: onOpen,
6953
7067
  children: [
6954
- mobile ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7068
+ pill ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
6955
7069
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
6956
7070
  "span",
6957
7071
  {
6958
- className: "assist-edge-tab__mark assist-edge-tab__mark--mobile",
7072
+ className: `assist-edge-tab__mark assist-edge-tab__mark--chip${mobile ? " assist-edge-tab__mark--mobile" : ""}`,
6959
7073
  "aria-hidden": "true",
6960
7074
  children: [
7075
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--light" }),
7076
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--cool" }),
6961
7077
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TabMarkIcon, { customIconUrl }),
6962
7078
  showLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6963
7079
  "img",
@@ -6973,7 +7089,10 @@ function AssistEdgeTab({
6973
7089
  ]
6974
7090
  }
6975
7091
  ),
6976
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel })
7092
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "assist-edge-tab__text", children: [
7093
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7094
+ visibleSubLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
7095
+ ] })
6977
7096
  ] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
6978
7097
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
6979
7098
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TabMarkIcon, { customIconUrl }),
@@ -6992,12 +7111,12 @@ function AssistEdgeTab({
6992
7111
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6993
7112
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronDownIcon2, {})
6994
7113
  ] }) : null,
6995
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7114
+ !pill && variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
6996
7115
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronLeftIcon, {}),
6997
7116
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6998
7117
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DragDots, {})
6999
7118
  ] }) : null,
7000
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7119
+ !pill && variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7001
7120
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
7002
7121
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TabMarkIcon, { customIconUrl }),
7003
7122
  showLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
@@ -7278,6 +7397,7 @@ function AgentWidget({
7278
7397
  inset: placement.inset,
7279
7398
  visible: true,
7280
7399
  label: tabLabel,
7400
+ subLabel: branding?.tabSubLabel,
7281
7401
  customIconUrl: branding?.tabIconUrl,
7282
7402
  logoUrl: branding?.logoUrl,
7283
7403
  brandColor: branding?.colors?.primary,
@@ -7421,6 +7541,7 @@ function normalizeAgentBranding(branding) {
7421
7541
  const normalized = {
7422
7542
  agentName: normalizeOptionalValue(branding.agentName),
7423
7543
  tabLabel: normalizeOptionalValue(branding.tabLabel),
7544
+ tabSubLabel: normalizeOptionalValue(branding.tabSubLabel),
7424
7545
  tabIconUrl: normalizeOptionalValue(branding.tabIconUrl),
7425
7546
  logoUrl: normalizeOptionalValue(branding.logoUrl),
7426
7547
  greeting: normalizeOptionalValue(branding.greeting),