@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/react.cjs CHANGED
@@ -1653,6 +1653,24 @@ function formatAgentError(error) {
1653
1653
  }
1654
1654
 
1655
1655
  // src/react/lib/composer-form.ts
1656
+ 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.";
1657
+ function visitorMessageDisplayText(message) {
1658
+ if (message.role !== "visitor") return message.text;
1659
+ const text2 = message.text.trim();
1660
+ if (!text2) return message.text;
1661
+ if (text2.startsWith(COMPOSER_FORM_SKIP_DISMISSAL)) {
1662
+ const afterDismissal = text2.slice(COMPOSER_FORM_SKIP_DISMISSAL.length).trim().replace(/^\n+/, "").trim();
1663
+ if (afterDismissal) return afterDismissal;
1664
+ }
1665
+ const runtime = message.runtimeText?.trim();
1666
+ if (runtime && text2 === runtime && runtime.includes(COMPOSER_FORM_SKIP_DISMISSAL)) {
1667
+ const afterDismissal = runtime.slice(
1668
+ runtime.indexOf(COMPOSER_FORM_SKIP_DISMISSAL) + COMPOSER_FORM_SKIP_DISMISSAL.length
1669
+ ).trim().replace(/^\n+/, "").trim();
1670
+ if (afterDismissal) return afterDismissal;
1671
+ }
1672
+ return message.text;
1673
+ }
1656
1674
  var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1657
1675
  var MIN_FORM_FIELDS = 2;
1658
1676
  var MAX_FORM_FIELDS = 5;
@@ -2906,7 +2924,8 @@ function createInitialState(greeting = DEFAULT_GREETING) {
2906
2924
  pendingOffer: null,
2907
2925
  pendingInputs: [],
2908
2926
  toolResults: [],
2909
- error: null
2927
+ error: null,
2928
+ declinedComposerFormIds: []
2910
2929
  };
2911
2930
  }
2912
2931
  function stateFromConversation(conversation, initialState) {
@@ -3326,6 +3345,7 @@ function useAgentChat({
3326
3345
  const trimmed = visitorText.trim();
3327
3346
  const outgoing = options?.runtimeText ?? visitorText;
3328
3347
  if (!outgoing.trim()) return null;
3348
+ const declinedComposerFormId = options?.declinedComposerFormId?.trim();
3329
3349
  const chatResponse = chatInputResponseForText(
3330
3350
  state.pendingInputs ?? [],
3331
3351
  outgoing.trim()
@@ -3359,7 +3379,15 @@ function useAgentChat({
3359
3379
  state: "active"
3360
3380
  }
3361
3381
  ],
3362
- error: null
3382
+ error: null,
3383
+ ...declinedComposerFormId ? {
3384
+ declinedComposerFormIds: [
3385
+ .../* @__PURE__ */ new Set([
3386
+ ...prev.declinedComposerFormIds ?? [],
3387
+ declinedComposerFormId
3388
+ ])
3389
+ ]
3390
+ } : {}
3363
3391
  }));
3364
3392
  return await runTurn({
3365
3393
  controller: controller2,
@@ -3381,9 +3409,9 @@ ${outgoing}` : outgoing;
3381
3409
  const visitorMessage = {
3382
3410
  id: `visitor-${Date.now()}`,
3383
3411
  role: "visitor",
3384
- text: visitorText,
3412
+ text: trimmed,
3385
3413
  createdAt: Date.now(),
3386
- ...runtimeText !== visitorText ? { runtimeText } : {}
3414
+ ...runtimeText.trim() !== trimmed ? { runtimeText } : {}
3387
3415
  };
3388
3416
  setState((prev) => ({
3389
3417
  ...prev,
@@ -3403,7 +3431,15 @@ ${outgoing}` : outgoing;
3403
3431
  pendingOffer: options?.preservePendingOffer ? prev.pendingOffer : null,
3404
3432
  pendingInputs: [],
3405
3433
  toolResults: [],
3406
- error: null
3434
+ error: null,
3435
+ ...declinedComposerFormId ? {
3436
+ declinedComposerFormIds: [
3437
+ .../* @__PURE__ */ new Set([
3438
+ ...prev.declinedComposerFormIds ?? [],
3439
+ declinedComposerFormId
3440
+ ])
3441
+ ]
3442
+ } : {}
3407
3443
  }));
3408
3444
  return await runTurn({
3409
3445
  controller,
@@ -4030,6 +4066,7 @@ function AnswerReceiptDialog({
4030
4066
  // src/react/components/Composer/Composer.tsx
4031
4067
  var import_react8 = require("react");
4032
4068
  var import_jsx_runtime3 = require("react/jsx-runtime");
4069
+ var FORM_SUBMITTED_MESSAGE = "Shared my details";
4033
4070
  function SendIcon() {
4034
4071
  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)(
4035
4072
  "path",
@@ -4042,6 +4079,30 @@ function SendIcon() {
4042
4079
  }
4043
4080
  ) });
4044
4081
  }
4082
+ function CheckIcon() {
4083
+ 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)(
4084
+ "path",
4085
+ {
4086
+ d: "M2.5 6.2l2.3 2.3 4.7-5",
4087
+ stroke: "currentColor",
4088
+ strokeWidth: "1.6",
4089
+ strokeLinecap: "round",
4090
+ strokeLinejoin: "round"
4091
+ }
4092
+ ) });
4093
+ }
4094
+ function CollapseIcon() {
4095
+ 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)(
4096
+ "path",
4097
+ {
4098
+ d: "M4 10l4-4 4 4",
4099
+ stroke: "currentColor",
4100
+ strokeWidth: "1.6",
4101
+ strokeLinecap: "round",
4102
+ strokeLinejoin: "round"
4103
+ }
4104
+ ) });
4105
+ }
4045
4106
  function emptyValues(form) {
4046
4107
  const values = {};
4047
4108
  for (const field of form?.fields ?? []) values[field.id] = "";
@@ -4075,26 +4136,31 @@ function Composer({
4075
4136
  const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
4076
4137
  const activeForm = !disabled && draft.expanded ? savedForm : null;
4077
4138
  const hasDraft = Object.values(draft.values).some((value2) => value2.trim());
4139
+ const canSend = !disabled && Boolean(value.trim() || activeForm);
4078
4140
  (0, import_react8.useEffect)(() => {
4079
4141
  if (activeForm) firstFieldRef.current?.focus();
4080
4142
  else if ((savedForm || draft.submitted) && !disabled)
4081
4143
  inputRef.current?.focus();
4082
4144
  }, [activeForm?.id, disabled, savedForm?.id, draft.submitted]);
4145
+ function collapseForm() {
4146
+ setDraft((current) => ({ ...current, expanded: false }));
4147
+ }
4083
4148
  function submitChat() {
4084
4149
  const trimmed = value.trim();
4085
4150
  if (!trimmed || disabled) return;
4086
4151
  const shareDismissal = savedForm && !draft.dismissalSent;
4087
4152
  if (shareDismissal) {
4088
4153
  onSubmit?.(trimmed, {
4089
- 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.
4090
-
4091
- ${trimmed}`
4154
+ declinedComposerFormId: savedForm.id
4092
4155
  });
4093
4156
  } else {
4094
4157
  onSubmit?.(trimmed);
4095
4158
  }
4096
- if (shareDismissal)
4097
- setDraft((current) => ({ ...current, dismissalSent: true }));
4159
+ setDraft((current) => ({
4160
+ ...current,
4161
+ expanded: false,
4162
+ dismissalSent: shareDismissal ? true : current.dismissalSent
4163
+ }));
4098
4164
  setValue("");
4099
4165
  inputRef.current?.focus();
4100
4166
  }
@@ -4109,7 +4175,7 @@ ${trimmed}`
4109
4175
  if (control instanceof HTMLElement) control.focus();
4110
4176
  return;
4111
4177
  }
4112
- onSubmit?.("", {
4178
+ onSubmit?.(FORM_SUBMITTED_MESSAGE, {
4113
4179
  runtimeText: formatComposerFormMessage(activeForm, draft.values)
4114
4180
  });
4115
4181
  setDraft((current) => ({
@@ -4120,10 +4186,16 @@ ${trimmed}`
4120
4186
  attempted: false
4121
4187
  }));
4122
4188
  }
4189
+ function handleSend() {
4190
+ if (value.trim()) {
4191
+ submitChat();
4192
+ return;
4193
+ }
4194
+ if (activeForm) submitForm();
4195
+ }
4123
4196
  function handleSubmit(event) {
4124
4197
  event.preventDefault();
4125
- if (activeForm) submitForm();
4126
- else submitChat();
4198
+ handleSend();
4127
4199
  }
4128
4200
  function handleChatKeyDown(event) {
4129
4201
  if (event.key === "Enter" && !event.shiftKey) {
@@ -4139,7 +4211,34 @@ ${trimmed}`
4139
4211
  submitForm();
4140
4212
  }
4141
4213
  }
4142
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4214
+ const chatField = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
4215
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4216
+ "textarea",
4217
+ {
4218
+ ref: inputRef,
4219
+ className: "composer__input",
4220
+ rows: 1,
4221
+ value,
4222
+ placeholder,
4223
+ disabled,
4224
+ spellCheck: false,
4225
+ "aria-label": "Message",
4226
+ onChange: (event) => setValue(event.target.value),
4227
+ onKeyDown: handleChatKeyDown
4228
+ }
4229
+ ),
4230
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4231
+ "button",
4232
+ {
4233
+ type: "submit",
4234
+ className: "composer__send",
4235
+ disabled: !canSend,
4236
+ "aria-label": "Send message",
4237
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
4238
+ }
4239
+ )
4240
+ ] });
4241
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4143
4242
  "form",
4144
4243
  {
4145
4244
  ref: formRef,
@@ -4150,107 +4249,10 @@ ${trimmed}`
4150
4249
  activeForm ? "composer--form" : ""
4151
4250
  ].filter(Boolean).join(" "),
4152
4251
  onSubmit: handleSubmit,
4153
- children: activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4154
- "div",
4155
- {
4156
- className: "composer__sheet",
4157
- role: "group",
4158
- "aria-label": "Contact details",
4159
- children: [
4160
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__form-heading", children: [
4161
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Share your details" }),
4162
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Optional" }),
4163
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "You can also keep chatting." })
4164
- ] }),
4165
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
4166
- const fieldId = `${formId}-${field.id}`;
4167
- const invalid = draft.attempted && !isValidComposerFieldValue(field, draft.values[field.id] ?? "");
4168
- const controlProps = {
4169
- id: fieldId,
4170
- name: field.id,
4171
- disabled,
4172
- required: field.required,
4173
- autoComplete: field.autocomplete,
4174
- placeholder: field.placeholder,
4175
- spellCheck: false,
4176
- value: draft.values[field.id] ?? "",
4177
- "aria-invalid": invalid || void 0,
4178
- "aria-describedby": invalid ? `${fieldId}-error` : void 0,
4179
- onChange: (event) => {
4180
- const next = readComposerControlValue(event);
4181
- setDraft((current) => ({
4182
- ...current,
4183
- values: { ...current.values, [field.id]: next }
4184
- }));
4185
- },
4186
- onKeyDown: handleFormKeyDown
4187
- };
4188
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4189
- "div",
4190
- {
4191
- className: [
4192
- "composer__row",
4193
- field.kind === "textarea" ? "composer__row--grow" : ""
4194
- ].filter(Boolean).join(" "),
4195
- children: [
4196
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "composer__label", htmlFor: fieldId, children: [
4197
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "composer__field-label", children: field.label }),
4198
- field.kind === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4199
- "textarea",
4200
- {
4201
- ...controlProps,
4202
- ref: index === 0 ? (node) => {
4203
- firstFieldRef.current = node;
4204
- } : void 0,
4205
- className: "composer__control composer__control--area",
4206
- rows: 3
4207
- }
4208
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4209
- "input",
4210
- {
4211
- ...controlProps,
4212
- ref: index === 0 ? (node) => {
4213
- firstFieldRef.current = node;
4214
- } : void 0,
4215
- className: "composer__control",
4216
- type: field.kind,
4217
- inputMode: field.kind === "tel" ? "tel" : void 0
4218
- }
4219
- )
4220
- ] }),
4221
- 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
4222
- ]
4223
- },
4224
- field.id
4225
- );
4226
- }) }),
4227
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__toolbar", children: [
4228
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4229
- "button",
4230
- {
4231
- type: "submit",
4232
- className: "composer__action composer__action--primary",
4233
- disabled,
4234
- children: "Share details"
4235
- }
4236
- ),
4237
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4238
- "button",
4239
- {
4240
- type: "button",
4241
- className: "composer__action",
4242
- disabled,
4243
- onClick: () => setDraft((current) => ({ ...current, expanded: false })),
4244
- children: "Keep chatting"
4245
- }
4246
- )
4247
- ] })
4248
- ]
4249
- }
4250
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
4252
+ children: [
4251
4253
  savedForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__resume", children: [
4252
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Contact details are optional" }),
4253
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4254
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Share your details so we can follow up" }),
4255
+ !activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4254
4256
  "button",
4255
4257
  {
4256
4258
  type: "button",
@@ -4258,36 +4260,100 @@ ${trimmed}`
4258
4260
  onClick: () => setDraft((current) => ({ ...current, expanded: true })),
4259
4261
  children: hasDraft ? "Resume details" : "Add details"
4260
4262
  }
4261
- )
4263
+ ) : null
4262
4264
  ] }) : null,
4263
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__field", children: [
4264
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4265
- "textarea",
4266
- {
4267
- ref: inputRef,
4268
- className: "composer__input",
4269
- rows: 1,
4270
- value,
4271
- placeholder,
4272
- disabled,
4273
- spellCheck: false,
4274
- "aria-label": "Message",
4275
- onChange: (event) => setValue(event.target.value),
4276
- onKeyDown: handleChatKeyDown
4277
- }
4278
- ),
4279
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4280
- "button",
4281
- {
4282
- type: "submit",
4283
- className: "composer__send",
4284
- disabled: disabled || !value.trim(),
4285
- "aria-label": "Send message",
4286
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
4287
- }
4288
- )
4289
- ] })
4290
- ] })
4265
+ activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4266
+ "div",
4267
+ {
4268
+ className: "composer__sheet",
4269
+ role: "group",
4270
+ "aria-label": "Contact details",
4271
+ children: [
4272
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__form-heading", children: [
4273
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Share your details" }),
4274
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Optional" }),
4275
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4276
+ "button",
4277
+ {
4278
+ type: "button",
4279
+ className: "composer__collapse",
4280
+ "aria-label": "Collapse form",
4281
+ disabled,
4282
+ onClick: collapseForm,
4283
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CollapseIcon, {})
4284
+ }
4285
+ )
4286
+ ] }),
4287
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
4288
+ const fieldId = `${formId}-${field.id}`;
4289
+ const fieldValue = draft.values[field.id] ?? "";
4290
+ const invalid = draft.attempted && !isValidComposerFieldValue(field, fieldValue);
4291
+ const complete = fieldValue.trim().length > 0 && isValidComposerFieldValue(field, fieldValue);
4292
+ const controlProps = {
4293
+ id: fieldId,
4294
+ name: field.id,
4295
+ disabled,
4296
+ required: field.required,
4297
+ autoComplete: field.autocomplete,
4298
+ placeholder: field.placeholder,
4299
+ spellCheck: false,
4300
+ value: fieldValue,
4301
+ "aria-invalid": invalid || void 0,
4302
+ "aria-describedby": invalid ? `${fieldId}-error` : void 0,
4303
+ onChange: (event) => {
4304
+ const next = readComposerControlValue(event);
4305
+ setDraft((current) => ({
4306
+ ...current,
4307
+ values: { ...current.values, [field.id]: next }
4308
+ }));
4309
+ },
4310
+ onKeyDown: handleFormKeyDown
4311
+ };
4312
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4313
+ "div",
4314
+ {
4315
+ className: [
4316
+ "composer__row",
4317
+ field.kind === "textarea" ? "composer__row--area" : ""
4318
+ ].filter(Boolean).join(" "),
4319
+ children: [
4320
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__line", children: [
4321
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "composer__label", htmlFor: fieldId, children: field.label }),
4322
+ field.kind === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4323
+ "textarea",
4324
+ {
4325
+ ...controlProps,
4326
+ ref: index === 0 ? (node) => {
4327
+ firstFieldRef.current = node;
4328
+ } : void 0,
4329
+ className: "composer__control composer__control--area",
4330
+ rows: 2
4331
+ }
4332
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4333
+ "input",
4334
+ {
4335
+ ...controlProps,
4336
+ ref: index === 0 ? (node) => {
4337
+ firstFieldRef.current = node;
4338
+ } : void 0,
4339
+ className: "composer__control",
4340
+ type: field.kind,
4341
+ inputMode: field.kind === "tel" ? "tel" : void 0
4342
+ }
4343
+ ),
4344
+ 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
4345
+ ] }),
4346
+ 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
4347
+ ]
4348
+ },
4349
+ field.id
4350
+ );
4351
+ }) }),
4352
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__field composer__field--inset", children: chatField })
4353
+ ]
4354
+ }
4355
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__field", children: chatField })
4356
+ ]
4291
4357
  }
4292
4358
  );
4293
4359
  }
@@ -4872,8 +4938,9 @@ function MessageBubble({
4872
4938
  offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
4873
4939
  );
4874
4940
  if (message.role === "visitor") {
4875
- if (!message.text.trim()) return null;
4876
- 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 }) });
4941
+ const visitorText = visitorMessageDisplayText(message).trim();
4942
+ if (!visitorText) return null;
4943
+ 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 }) });
4877
4944
  }
4878
4945
  const citations = message.citations ?? [];
4879
4946
  const agentText = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__text", children: [
@@ -5111,7 +5178,7 @@ function CopyIcon() {
5111
5178
  )
5112
5179
  ] });
5113
5180
  }
5114
- function CheckIcon() {
5181
+ function CheckIcon2() {
5115
5182
  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)(
5116
5183
  "path",
5117
5184
  {
@@ -5486,7 +5553,7 @@ function MessageActions({
5486
5553
  title: copied ? "Copied" : "Copy answer",
5487
5554
  disabled,
5488
5555
  onClick: handleCopy,
5489
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CopyIcon, {})
5556
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon2, {}) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CopyIcon, {})
5490
5557
  }
5491
5558
  ),
5492
5559
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
@@ -6440,13 +6507,17 @@ function AgentRail({
6440
6507
  const hasPendingConfirmation = pendingInputRequests.some(
6441
6508
  (request) => request.kind === "tool-approval" || request.kind === "question" && (request.options?.length ?? 0) > 0
6442
6509
  );
6443
- const composerForm = resolveComposerForm({
6510
+ const inferredComposerForm = resolveComposerForm({
6444
6511
  agentText: lastAgentText,
6445
6512
  cards: extractToolCards(lastAgentText),
6446
6513
  hasBookingOffer: Boolean(state.pendingOffer) || waitingForBooking,
6447
6514
  hasPendingConfirmation,
6448
6515
  enabled: lastIsAgent && !isBusy
6449
6516
  });
6517
+ const declinedComposerFormIds = state.declinedComposerFormIds ?? [];
6518
+ const composerForm = inferredComposerForm && lastMessage?.role === "agent" && declinedComposerFormIds.includes(
6519
+ `${lastMessage.id}:${inferredComposerForm.id}`
6520
+ ) ? null : inferredComposerForm;
6450
6521
  const latestResultId = [
6451
6522
  ...visibleMessages.flatMap(
6452
6523
  (message) => message.role === "agent" ? message.toolResults ?? [] : []
@@ -6817,36 +6888,75 @@ function AgentRail({
6817
6888
 
6818
6889
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
6819
6890
  var import_jsx_runtime18 = require("react/jsx-runtime");
6820
- function SparklesIcon() {
6891
+ function ChatSparkIcon() {
6821
6892
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
6822
6893
  "svg",
6823
6894
  {
6824
- className: "assist-edge-tab__sparkles",
6825
- viewBox: "0 0 18 16",
6895
+ className: "assist-edge-tab__chat-spark",
6896
+ viewBox: "0 0 24 24",
6826
6897
  fill: "none",
6827
6898
  "aria-hidden": "true",
6828
6899
  children: [
6829
6900
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6830
6901
  "path",
6831
6902
  {
6832
- 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",
6903
+ className: "assist-edge-tab__spark assist-edge-tab__spark--a",
6904
+ 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",
6833
6905
  fill: "currentColor"
6834
6906
  }
6835
6907
  ),
6836
6908
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6837
6909
  "path",
6838
6910
  {
6839
- 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",
6911
+ className: "assist-edge-tab__spark assist-edge-tab__spark--b",
6912
+ 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",
6840
6913
  fill: "currentColor"
6841
6914
  }
6842
6915
  ),
6843
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6844
- "path",
6845
- {
6846
- 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",
6847
- fill: "currentColor"
6848
- }
6849
- )
6916
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { className: "assist-edge-tab__bot", children: [
6917
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6918
+ "path",
6919
+ {
6920
+ d: "M11.15 5.2V3.05",
6921
+ stroke: "currentColor",
6922
+ strokeWidth: "1.9",
6923
+ strokeLinecap: "round"
6924
+ }
6925
+ ),
6926
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "11.15", cy: "2.45", r: "0.85", fill: "currentColor" }),
6927
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6928
+ "rect",
6929
+ {
6930
+ x: "3.55",
6931
+ y: "5.35",
6932
+ width: "15.2",
6933
+ height: "11.15",
6934
+ rx: "3.9",
6935
+ stroke: "currentColor",
6936
+ strokeWidth: "1.9"
6937
+ }
6938
+ ),
6939
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6940
+ "circle",
6941
+ {
6942
+ className: "assist-edge-tab__eye",
6943
+ cx: "8.7",
6944
+ cy: "10.85",
6945
+ r: "1.28",
6946
+ fill: "currentColor"
6947
+ }
6948
+ ),
6949
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6950
+ "circle",
6951
+ {
6952
+ className: "assist-edge-tab__eye assist-edge-tab__eye--r",
6953
+ cx: "14.35",
6954
+ cy: "10.85",
6955
+ r: "1.28",
6956
+ fill: "currentColor"
6957
+ }
6958
+ )
6959
+ ] })
6850
6960
  ]
6851
6961
  }
6852
6962
  );
@@ -6864,7 +6974,7 @@ function TabMarkIcon({ customIconUrl }) {
6864
6974
  }
6865
6975
  );
6866
6976
  }
6867
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SparklesIcon, {});
6977
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChatSparkIcon, {});
6868
6978
  }
6869
6979
  function ChevronLeftIcon() {
6870
6980
  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)(
@@ -6905,6 +7015,7 @@ function AssistEdgeTab({
6905
7015
  inset,
6906
7016
  visible,
6907
7017
  label,
7018
+ subLabel,
6908
7019
  customIconUrl,
6909
7020
  logoUrl,
6910
7021
  brandColor,
@@ -6920,6 +7031,9 @@ function AssistEdgeTab({
6920
7031
  const resolvedColorScheme = useAgentColorScheme(colorScheme);
6921
7032
  const copy = VARIANT_COPY[variant];
6922
7033
  const visibleLabel = label?.trim() || copy.label;
7034
+ const visibleSubLabel = subLabel?.trim() || "";
7035
+ const pill = mobile || side === "bottom";
7036
+ const ariaLabel = visibleSubLabel ? `Open ${visibleLabel} \u2014 ${visibleSubLabel}` : `Open ${visibleLabel}`;
6923
7037
  const alignment = along < 50 ? "start" : along > 50 ? "end" : "center";
6924
7038
  const showLogo = Boolean(logoUrl?.trim()) && !customIconUrl?.trim();
6925
7039
  const resolvedBrandColor = brandColor ?? (resolvedColorScheme === "dark" ? defaultDarkAgentRailTheme.brand : void 0);
@@ -6944,18 +7058,20 @@ function AssistEdgeTab({
6944
7058
  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" : ""}`,
6945
7059
  "data-color-scheme": resolvedColorScheme,
6946
7060
  style,
6947
- "aria-label": `Open ${visibleLabel}`,
7061
+ "aria-label": ariaLabel,
6948
7062
  "aria-hidden": !visible,
6949
7063
  tabIndex: visible ? 0 : -1,
6950
7064
  onClick: onOpen,
6951
7065
  children: [
6952
- mobile ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7066
+ pill ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
6953
7067
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
6954
7068
  "span",
6955
7069
  {
6956
- className: "assist-edge-tab__mark assist-edge-tab__mark--mobile",
7070
+ className: `assist-edge-tab__mark assist-edge-tab__mark--chip${mobile ? " assist-edge-tab__mark--mobile" : ""}`,
6957
7071
  "aria-hidden": "true",
6958
7072
  children: [
7073
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--light" }),
7074
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__wash assist-edge-tab__wash--cool" }),
6959
7075
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TabMarkIcon, { customIconUrl }),
6960
7076
  showLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6961
7077
  "img",
@@ -6971,7 +7087,10 @@ function AssistEdgeTab({
6971
7087
  ]
6972
7088
  }
6973
7089
  ),
6974
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel })
7090
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "assist-edge-tab__text", children: [
7091
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7092
+ visibleSubLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
7093
+ ] })
6975
7094
  ] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
6976
7095
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
6977
7096
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TabMarkIcon, { customIconUrl }),
@@ -6990,12 +7109,12 @@ function AssistEdgeTab({
6990
7109
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6991
7110
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronDownIcon2, {})
6992
7111
  ] }) : null,
6993
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7112
+ !pill && variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
6994
7113
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronLeftIcon, {}),
6995
7114
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
6996
7115
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DragDots, {})
6997
7116
  ] }) : null,
6998
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7117
+ !pill && variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
6999
7118
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
7000
7119
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TabMarkIcon, { customIconUrl }),
7001
7120
  showLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
@@ -7276,6 +7395,7 @@ function AgentWidget({
7276
7395
  inset: placement.inset,
7277
7396
  visible: true,
7278
7397
  label: tabLabel,
7398
+ subLabel: branding?.tabSubLabel,
7279
7399
  customIconUrl: branding?.tabIconUrl,
7280
7400
  logoUrl: branding?.logoUrl,
7281
7401
  brandColor: branding?.colors?.primary,