@webless/agent 0.10.4 → 0.12.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
@@ -46,7 +46,7 @@ __export(react_exports, {
46
46
  module.exports = __toCommonJS(react_exports);
47
47
 
48
48
  // src/react/components/AgentWidget/AgentWidget.tsx
49
- var import_react16 = require("react");
49
+ var import_react18 = require("react");
50
50
 
51
51
  // src/react/page-shift.ts
52
52
  var import_react = require("react");
@@ -128,8 +128,168 @@ function usePageShift(input) {
128
128
  }, [active, railSlotRef]);
129
129
  }
130
130
 
131
- // src/react/hooks/useAgentChat.ts
131
+ // src/react/hooks/useAgentHandoff.ts
132
+ var import_client = require("eve/client");
132
133
  var import_react2 = require("react");
134
+ function useAgentHandoff(options) {
135
+ const [page, setPage] = (0, import_react2.useState)(null);
136
+ const [busy, setBusy] = (0, import_react2.useState)(false);
137
+ const [rejected, setRejected] = (0, import_react2.useState)(false);
138
+ const [error, setError] = (0, import_react2.useState)(null);
139
+ const callbacks = (0, import_react2.useRef)(options);
140
+ callbacks.current = options;
141
+ const pending = (0, import_react2.useRef)(null);
142
+ const inFlight = (0, import_react2.useRef)(null);
143
+ const pageRef = (0, import_react2.useRef)(null);
144
+ const refreshRef = (0, import_react2.useRef)(null);
145
+ const generation = (0, import_react2.useRef)(0);
146
+ (0, import_react2.useEffect)(() => {
147
+ const token = ++generation.current;
148
+ const controller = new AbortController();
149
+ let timer;
150
+ let reading = null;
151
+ let cursor = 0;
152
+ pageRef.current = null;
153
+ pending.current = null;
154
+ inFlight.current?.abort();
155
+ inFlight.current = null;
156
+ setRejected(false);
157
+ setPage(null);
158
+ setError(null);
159
+ setBusy(false);
160
+ if (!options.enabled || !options.sessionId) return;
161
+ const active = () => !controller.signal.aborted && generation.current === token;
162
+ const refresh = () => {
163
+ reading ??= (async () => {
164
+ do {
165
+ const next = await options.client.handoff.read({
166
+ after: cursor,
167
+ signal: AbortSignal.any([
168
+ controller.signal,
169
+ AbortSignal.timeout(15e3)
170
+ ])
171
+ });
172
+ if (!active()) return;
173
+ callbacks.current.onEvents(next.events);
174
+ if (next.status !== "ai") callbacks.current.onOwnership();
175
+ cursor = next.cursor;
176
+ pageRef.current = next;
177
+ setPage(next);
178
+ setRejected(false);
179
+ if (!pending.current) setError(null);
180
+ if (!next.hasMore) break;
181
+ } while (active());
182
+ })().finally(() => {
183
+ reading = null;
184
+ });
185
+ return reading;
186
+ };
187
+ refreshRef.current = refresh;
188
+ const poll = async () => {
189
+ try {
190
+ await refresh();
191
+ } catch (cause) {
192
+ if (active()) {
193
+ const denied = cause instanceof import_client.ClientError && cause.status === 403;
194
+ setRejected(denied);
195
+ setError(
196
+ denied ? "This preview has changed. Restart the preview chat to test the current version." : "Reconnecting to your conversation\u2026"
197
+ );
198
+ }
199
+ } finally {
200
+ if (active()) timer = setTimeout(() => void poll(), 1500);
201
+ }
202
+ };
203
+ void poll();
204
+ return () => {
205
+ controller.abort();
206
+ inFlight.current?.abort();
207
+ clearTimeout(timer);
208
+ refreshRef.current = null;
209
+ };
210
+ }, [options.client, options.enabled, options.sessionId]);
211
+ async function execute(operation) {
212
+ if (inFlight.current) return;
213
+ const controller = new AbortController();
214
+ inFlight.current = controller;
215
+ const signal = AbortSignal.any([
216
+ controller.signal,
217
+ AbortSignal.timeout(15e3)
218
+ ]);
219
+ const token = generation.current;
220
+ pending.current = operation;
221
+ setBusy(true);
222
+ setError(null);
223
+ try {
224
+ if (operation.type === "start")
225
+ await options.client.handoff.start(operation.operationId, signal);
226
+ else if (operation.type === "message") {
227
+ const { type: _, ...command } = operation;
228
+ await options.client.handoff.send(command, signal);
229
+ } else {
230
+ const { type: _, ...command } = operation;
231
+ await options.client.handoff.returnToAI(command, signal);
232
+ }
233
+ if (token !== generation.current) return;
234
+ pending.current = null;
235
+ await refreshRef.current?.();
236
+ } catch {
237
+ if (token === generation.current)
238
+ setError(
239
+ "Could not confirm delivery. Retry to check the same request."
240
+ );
241
+ } finally {
242
+ if (inFlight.current === controller) inFlight.current = null;
243
+ if (token === generation.current) setBusy(false);
244
+ }
245
+ }
246
+ const binding = () => {
247
+ const current = pageRef.current;
248
+ if (!current?.handoffId) throw new Error("No active human conversation.");
249
+ return { handoffId: current.handoffId, epoch: current.epoch };
250
+ };
251
+ return {
252
+ page,
253
+ busy,
254
+ error,
255
+ hasPending: Boolean(pending.current),
256
+ canReset: !busy && !pending.current && (rejected || page?.status === "ai" || page?.status === "failed" || !options.sessionId),
257
+ blocksAI: Boolean(options.enabled && options.sessionId && !page) || busy || Boolean(pending.current) || Boolean(page && page.status !== "ai"),
258
+ start: () => execute(
259
+ pending.current ?? { type: "start", operationId: crypto.randomUUID() }
260
+ ),
261
+ send: (message) => {
262
+ if (pending.current)
263
+ throw new Error(
264
+ "Retry the pending request before sending another message."
265
+ );
266
+ return execute({
267
+ type: "message",
268
+ operationId: crypto.randomUUID(),
269
+ ...binding(),
270
+ message
271
+ });
272
+ },
273
+ returnToAI: () => execute(
274
+ pending.current ?? {
275
+ type: "return",
276
+ operationId: crypto.randomUUID(),
277
+ ...binding()
278
+ }
279
+ ),
280
+ retry: async () => {
281
+ if (pending.current) return execute(pending.current);
282
+ try {
283
+ await refreshRef.current?.();
284
+ } catch {
285
+ setError("Reconnecting to your conversation\u2026");
286
+ }
287
+ }
288
+ };
289
+ }
290
+
291
+ // src/react/hooks/useAgentChat.ts
292
+ var import_react3 = require("react");
133
293
 
134
294
  // src/runtime/tool-ui.ts
135
295
  var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
@@ -271,16 +431,16 @@ function parseStep(value) {
271
431
  if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
272
432
  return null;
273
433
  }
274
- const id = boundedString(value.id, 80);
434
+ const id2 = boundedString(value.id, 80);
275
435
  const label = boundedString(value.label, 160);
276
436
  const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
277
- if (!id || !/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(id) || !label || value.description !== void 0 && !description || !Array.isArray(value.fieldPaths) || value.fieldPaths.length < 1 || value.fieldPaths.length > 32 || value.fieldPaths.some(
437
+ if (!id2 || !/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(id2) || !label || value.description !== void 0 && !description || !Array.isArray(value.fieldPaths) || value.fieldPaths.length < 1 || value.fieldPaths.length > 32 || value.fieldPaths.some(
278
438
  (path) => typeof path !== "string" || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || path.length > 160
279
439
  )) {
280
440
  return null;
281
441
  }
282
442
  return {
283
- id,
443
+ id: id2,
284
444
  label,
285
445
  fieldPaths: value.fieldPaths,
286
446
  ...description ? { description } : {}
@@ -317,14 +477,14 @@ function parseAgentToolUiSurface(value) {
317
477
  ])) {
318
478
  return null;
319
479
  }
320
- const id = boundedString(value.id, 200);
480
+ const id2 = boundedString(value.id, 200);
321
481
  const title = boundedString(value.title, 200);
322
482
  const toolSlug = boundedString(value.toolSlug, 200);
323
483
  const description = value.description === void 0 ? void 0 : boundedString(value.description, 800);
324
484
  const operationId = value.operationId === void 0 ? void 0 : boundedString(value.operationId, 200);
325
485
  const requestId = value.requestId === void 0 ? void 0 : boundedString(value.requestId, 200);
326
486
  const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
327
- if (!id || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
487
+ if (!id2 || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
328
488
  return null;
329
489
  }
330
490
  const fields = value.fields.map(parseField);
@@ -344,7 +504,7 @@ function parseAgentToolUiSurface(value) {
344
504
  }
345
505
  return {
346
506
  schemaVersion: AGENT_TOOL_UI_SCHEMA_VERSION,
347
- id,
507
+ id: id2,
348
508
  title,
349
509
  toolSlug,
350
510
  fields,
@@ -455,10 +615,205 @@ function completeConnectedToolWork(item, result) {
455
615
  }
456
616
 
457
617
  // src/runtime/client.ts
458
- var import_client2 = require("eve/client");
618
+ var import_client4 = require("eve/client");
619
+
620
+ // src/runtime/handoff.ts
621
+ var import_client3 = require("eve/client");
622
+
623
+ // src/runtime/generated/handoff-contract.ts
624
+ var import_zod = require("zod");
625
+ var id = import_zod.z.string().min(1).max(200);
626
+ var sequence = import_zod.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
627
+ var text = import_zod.z.string().trim().min(1).max(16e3);
628
+ var agentRuntimeHandoffVersion = "webless.ai/agent-runtime-handoff/v1";
629
+ var agentRuntimeHandoffStatusSchema = import_zod.z.enum([
630
+ "ai",
631
+ "requesting",
632
+ "queued",
633
+ "human",
634
+ "resolved",
635
+ "failed"
636
+ ]);
637
+ var agentRuntimeHandoffActorSchema = import_zod.z.strictObject({
638
+ id,
639
+ name: import_zod.z.string().trim().min(1).max(200)
640
+ });
641
+ var eventBase = {
642
+ id,
643
+ sequence: sequence.refine((value) => value > 0),
644
+ handoffId: id,
645
+ epoch: sequence.refine((value) => value > 0),
646
+ createdAt: import_zod.z.iso.datetime()
647
+ };
648
+ var agentRuntimeHandoffEventSchema = import_zod.z.discriminatedUnion("type", [
649
+ import_zod.z.strictObject({
650
+ ...eventBase,
651
+ type: import_zod.z.literal("status"),
652
+ status: agentRuntimeHandoffStatusSchema,
653
+ actor: agentRuntimeHandoffActorSchema.nullable()
654
+ }),
655
+ import_zod.z.strictObject({
656
+ ...eventBase,
657
+ type: import_zod.z.literal("visitor.message"),
658
+ message: text,
659
+ operationId: id
660
+ }),
661
+ import_zod.z.strictObject({
662
+ ...eventBase,
663
+ type: import_zod.z.literal("human.message"),
664
+ message: text,
665
+ actor: agentRuntimeHandoffActorSchema
666
+ })
667
+ ]);
668
+ var agentRuntimeHandoffReadRequestSchema = import_zod.z.strictObject({
669
+ after: sequence.default(0)
670
+ });
671
+ var agentRuntimeHandoffPageSchema = import_zod.z.strictObject({
672
+ apiVersion: import_zod.z.literal(agentRuntimeHandoffVersion),
673
+ sessionId: id,
674
+ enabled: import_zod.z.boolean(),
675
+ status: agentRuntimeHandoffStatusSchema,
676
+ handoffId: id.nullable(),
677
+ epoch: sequence,
678
+ after: sequence,
679
+ cursor: sequence,
680
+ hasMore: import_zod.z.boolean(),
681
+ events: import_zod.z.array(agentRuntimeHandoffEventSchema).max(100)
682
+ }).superRefine((page, ctx) => {
683
+ let cursor = page.after;
684
+ let previousEpoch = 0;
685
+ const statuses = /* @__PURE__ */ new Map();
686
+ const ids = /* @__PURE__ */ new Set();
687
+ const handoffs = /* @__PURE__ */ new Map();
688
+ const terminalEpochs = /* @__PURE__ */ new Set();
689
+ let currentStatus;
690
+ for (const event of page.events) {
691
+ if (event.epoch < previousEpoch)
692
+ ctx.addIssue({
693
+ code: "custom",
694
+ message: "Handoff epochs cannot decrease."
695
+ });
696
+ previousEpoch = event.epoch;
697
+ if (ids.has(event.id))
698
+ ctx.addIssue({
699
+ code: "custom",
700
+ message: "Duplicate handoff event ID."
701
+ });
702
+ ids.add(event.id);
703
+ const handoffId = handoffs.get(event.epoch);
704
+ if (handoffId !== void 0 && handoffId !== event.handoffId || event.epoch === page.epoch && event.handoffId !== page.handoffId)
705
+ ctx.addIssue({
706
+ code: "custom",
707
+ message: "Inconsistent handoff epoch identity."
708
+ });
709
+ handoffs.set(event.epoch, event.handoffId);
710
+ if (terminalEpochs.has(event.epoch) && (event.type !== "status" || event.status !== "ai"))
711
+ ctx.addIssue({
712
+ code: "custom",
713
+ message: "Handoff event follows resolution."
714
+ });
715
+ if (event.type === "status") {
716
+ if (event.status === "human" && event.actor === null)
717
+ ctx.addIssue({
718
+ code: "custom",
719
+ message: "Human ownership requires a representative."
720
+ });
721
+ const previous = statuses.get(event.epoch);
722
+ const transitions = {
723
+ ai: [],
724
+ requesting: ["queued", "resolved", "failed"],
725
+ queued: ["human", "resolved", "failed"],
726
+ human: ["resolved", "failed"],
727
+ resolved: ["ai"],
728
+ failed: []
729
+ };
730
+ if (previous !== void 0 && !transitions[previous].includes(event.status))
731
+ ctx.addIssue({
732
+ code: "custom",
733
+ message: "Invalid handoff ownership transition."
734
+ });
735
+ statuses.set(event.epoch, event.status);
736
+ if (["resolved", "failed", "ai"].includes(event.status))
737
+ terminalEpochs.add(event.epoch);
738
+ if (event.epoch === page.epoch) currentStatus = event.status;
739
+ }
740
+ if (event.sequence !== cursor + 1) {
741
+ ctx.addIssue({
742
+ code: "custom",
743
+ message: "Handoff event gap or replay."
744
+ });
745
+ }
746
+ cursor = event.sequence;
747
+ if (event.epoch > page.epoch) {
748
+ ctx.addIssue({
749
+ code: "custom",
750
+ message: "Event exceeds current epoch."
751
+ });
752
+ }
753
+ }
754
+ if (!page.hasMore && currentStatus !== void 0 && currentStatus !== page.status)
755
+ ctx.addIssue({
756
+ code: "custom",
757
+ message: "Handoff ownership contradicts its final status event."
758
+ });
759
+ if (page.cursor !== cursor || page.hasMore && page.events.length === 0) {
760
+ ctx.addIssue({ code: "custom", message: "Invalid handoff page cursor." });
761
+ }
762
+ if (page.epoch === 0 !== (page.handoffId === null)) {
763
+ ctx.addIssue({ code: "custom", message: "Invalid handoff identity." });
764
+ }
765
+ if (page.handoffId === null && page.status !== "ai") {
766
+ ctx.addIssue({
767
+ code: "custom",
768
+ message: "Handoff identity is required."
769
+ });
770
+ }
771
+ });
772
+ var agentRuntimeHandoffStartSchema = import_zod.z.strictObject({
773
+ operationId: id
774
+ });
775
+ var agentRuntimeHandoffCommandSchema = import_zod.z.strictObject({
776
+ operationId: id,
777
+ handoffId: id,
778
+ epoch: sequence.refine((value) => value > 0)
779
+ });
780
+ var agentRuntimeHandoffMessageSchema = agentRuntimeHandoffCommandSchema.extend({ message: text });
781
+ var agentRuntimeHandoffBindingSchema = import_zod.z.strictObject({
782
+ tenantId: id,
783
+ indexId: id,
784
+ visitorSubject: id,
785
+ sessionId: id,
786
+ handoffId: id,
787
+ epoch: sequence.refine((value) => value > 0)
788
+ });
789
+ var providerEventBase = {
790
+ apiVersion: import_zod.z.literal(agentRuntimeHandoffVersion),
791
+ binding: agentRuntimeHandoffBindingSchema,
792
+ eventId: id,
793
+ sequence: sequence.refine((value) => value > 0)
794
+ };
795
+ var agentRuntimeHandoffProviderEventSchema = import_zod.z.discriminatedUnion(
796
+ "type",
797
+ [
798
+ import_zod.z.strictObject({ ...providerEventBase, type: import_zod.z.literal("queued") }),
799
+ import_zod.z.strictObject({
800
+ ...providerEventBase,
801
+ type: import_zod.z.literal("assigned"),
802
+ actor: agentRuntimeHandoffActorSchema
803
+ }),
804
+ import_zod.z.strictObject({
805
+ ...providerEventBase,
806
+ type: import_zod.z.literal("human.message"),
807
+ actor: agentRuntimeHandoffActorSchema,
808
+ message: text
809
+ }),
810
+ import_zod.z.strictObject({ ...providerEventBase, type: import_zod.z.literal("resolved") }),
811
+ import_zod.z.strictObject({ ...providerEventBase, type: import_zod.z.literal("failed") })
812
+ ]
813
+ );
459
814
 
460
815
  // src/runtime/capability.ts
461
- var import_client = require("eve/client");
816
+ var import_client2 = require("eve/client");
462
817
  var MAX_REFRESH_SKEW_MS = 3e4;
463
818
  var LOCAL_LOOPBACK_ORIGINS = [
464
819
  "http://127.0.0.1:3010",
@@ -526,18 +881,26 @@ function createAgentRuntimeCapability(options) {
526
881
  );
527
882
  }
528
883
  }
529
- const bootstrapBody = JSON.stringify({
884
+ const bootstrapBody = {
530
885
  clientSessionId: options.visitorSessionId,
531
886
  indexId: options.indexId,
532
887
  ...previewBuildId ? { previewBuildId } : {},
533
888
  ...previewGrant ? { previewGrant } : {},
534
889
  version: options.version
535
- });
536
- const postBootstrap = (origin) => fetchImplementation(`${origin}/webless/v1/bootstrap`, {
537
- body: bootstrapBody,
538
- headers: { "content-type": "application/json" },
539
- method: "POST"
540
- });
890
+ };
891
+ const postBootstrap = async (origin) => {
892
+ const send = (advertiseLocation) => fetchImplementation(`${origin}/webless/v1/bootstrap`, {
893
+ body: JSON.stringify({ ...bootstrapBody, ...advertiseLocation ? { locationConsent: "v1" } : {} }),
894
+ headers: { "content-type": "application/json" },
895
+ method: "POST"
896
+ });
897
+ const response2 = await send(Boolean(options.locationConsent));
898
+ if (options.locationConsent && response2.status === 400) {
899
+ const error = await response2.clone().json().catch(() => null);
900
+ if (isRecord3(error) && error.code === "invalid_request") return send(false);
901
+ }
902
+ return response2;
903
+ };
541
904
  let response;
542
905
  let lastError;
543
906
  for (const origin of localBootstrapOrigins(options.runtimeOrigin)) {
@@ -595,7 +958,7 @@ async function withCapabilityRefresh(capability, request) {
595
958
  try {
596
959
  return await request();
597
960
  } catch (error) {
598
- if (!(error instanceof import_client.ClientError) || error.status !== 401) {
961
+ if (!(error instanceof import_client2.ClientError) || error.status !== 401) {
599
962
  throw error;
600
963
  }
601
964
  capability.invalidate();
@@ -603,6 +966,75 @@ async function withCapabilityRefresh(capability, request) {
603
966
  }
604
967
  }
605
968
 
969
+ // src/runtime/handoff.ts
970
+ function createHandoffClient(options) {
971
+ const target = () => {
972
+ const sessionId = options.getSessionId();
973
+ if (!sessionId)
974
+ throw new Error(
975
+ "Start a conversation before requesting a representative."
976
+ );
977
+ return {
978
+ sessionId,
979
+ path: `/webless/v1/session/${encodeURIComponent(sessionId)}/handoff`
980
+ };
981
+ };
982
+ const request = (path, init) => withCapabilityRefresh(options.capability, async () => {
983
+ const response = await options.getClient().fetch(path, {
984
+ ...init,
985
+ cache: "no-store",
986
+ redirect: "error"
987
+ });
988
+ if (!response.ok) {
989
+ throw new import_client3.ClientError(
990
+ response.status,
991
+ await response.text(),
992
+ response.headers
993
+ );
994
+ }
995
+ return response;
996
+ });
997
+ const command = async (suffix, body, signal) => {
998
+ const { path } = target();
999
+ await request(path + suffix, {
1000
+ method: "POST",
1001
+ headers: { "content-type": "application/json" },
1002
+ body: JSON.stringify(body),
1003
+ signal
1004
+ });
1005
+ };
1006
+ return {
1007
+ async read(input = {}) {
1008
+ const { after } = agentRuntimeHandoffReadRequestSchema.parse({
1009
+ after: input.after
1010
+ });
1011
+ const { sessionId, path } = target();
1012
+ const response = await request(`${path}?after=${after}`, {
1013
+ signal: input.signal
1014
+ });
1015
+ const value = await response.json();
1016
+ const page = agentRuntimeHandoffPageSchema.parse(value);
1017
+ if (page.sessionId !== sessionId || page.after !== after) {
1018
+ throw new Error(
1019
+ "The handoff response does not belong to this conversation or cursor."
1020
+ );
1021
+ }
1022
+ return page;
1023
+ },
1024
+ start: (operationId, signal) => command(
1025
+ "",
1026
+ agentRuntimeHandoffStartSchema.parse({ operationId }),
1027
+ signal
1028
+ ),
1029
+ send: (input, signal) => command(
1030
+ "/messages",
1031
+ agentRuntimeHandoffMessageSchema.parse(input),
1032
+ signal
1033
+ ),
1034
+ returnToAI: (input, signal) => command("/return", agentRuntimeHandoffCommandSchema.parse(input), signal)
1035
+ };
1036
+ }
1037
+
606
1038
  // src/runtime/config.ts
607
1039
  var DEFAULT_RUNTIME_ORIGIN = "https://runtime.staging.webless.ai";
608
1040
  var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
@@ -1072,6 +1504,7 @@ function specialistNameFromInput(input) {
1072
1504
  return match?.[1]?.trim() || void 0;
1073
1505
  }
1074
1506
  function requestedWorkItem(action) {
1507
+ if (action.kind === "tool-call" && action.toolName === "request_location") return null;
1075
1508
  if (action.kind === "tool-call" && action.toolName === "search_discovery") {
1076
1509
  return {
1077
1510
  id: action.callId,
@@ -1177,13 +1610,14 @@ function applyWorkEvent(event, handlers, workItems) {
1177
1610
  );
1178
1611
  }
1179
1612
  var AgentSession = class {
1180
- constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, previewBuildId, getUnpublishedPreviewGrant) {
1613
+ constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, previewBuildId, getUnpublishedPreviewGrant, locationConsent) {
1181
1614
  this.indexId = indexId;
1182
1615
  this.version = version;
1183
1616
  this.runtimeOrigin = runtimeOrigin;
1184
1617
  this.visitorSessionId = visitorSessionId;
1185
1618
  this.storeOptions = storeOptions;
1186
1619
  this.capability = createAgentRuntimeCapability({
1620
+ locationConsent,
1187
1621
  getUnpublishedPreviewGrant,
1188
1622
  indexId,
1189
1623
  previewBuildId,
@@ -1191,6 +1625,11 @@ var AgentSession = class {
1191
1625
  version,
1192
1626
  visitorSessionId
1193
1627
  });
1628
+ this.handoff = createHandoffClient({
1629
+ getClient: () => this.ensureClient(),
1630
+ getSessionId: () => this.getActiveSessionId(),
1631
+ capability: this.capability
1632
+ });
1194
1633
  }
1195
1634
  indexId;
1196
1635
  version;
@@ -1203,6 +1642,7 @@ var AgentSession = class {
1203
1642
  activeResponse;
1204
1643
  childStreams;
1205
1644
  capability;
1645
+ handoff;
1206
1646
  getActiveSessionId() {
1207
1647
  return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
1208
1648
  }
@@ -1277,7 +1717,7 @@ var AgentSession = class {
1277
1717
  }
1278
1718
  this.activeResponse = void 0;
1279
1719
  this.session = void 0;
1280
- this.client = new import_client2.Client({
1720
+ this.client = new import_client4.Client({
1281
1721
  auth: { bearer: () => this.capability.getAccessToken() },
1282
1722
  host: config.host,
1283
1723
  redirect: "error"
@@ -1313,7 +1753,7 @@ var AgentSession = class {
1313
1753
  () => activeSession.send(message, { signal })
1314
1754
  );
1315
1755
  } catch (error) {
1316
- if (error instanceof import_client2.ClientError && error.status === 409 && error.code === "session_not_active") {
1756
+ if (error instanceof import_client4.ClientError && error.status === 409 && error.code === "session_not_active") {
1317
1757
  clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
1318
1758
  this.session = void 0;
1319
1759
  session = void 0;
@@ -1487,10 +1927,10 @@ var AgentSession = class {
1487
1927
  }
1488
1928
  this.session = session;
1489
1929
  const inputResponses = responses.map(
1490
- ({ requestId, optionId, text: text2 }) => ({
1930
+ ({ requestId, optionId, text: text3 }) => ({
1491
1931
  requestId,
1492
1932
  ...optionId ? { optionId } : {},
1493
- ...text2 ? { text: text2 } : {}
1933
+ ...text3 ? { text: text3 } : {}
1494
1934
  })
1495
1935
  );
1496
1936
  const response = await withCapabilityRefresh(
@@ -1575,10 +2015,12 @@ function createAgentClient(options) {
1575
2015
  visitorSessionId,
1576
2016
  storeOptions,
1577
2017
  options.previewBuildId,
1578
- options.getUnpublishedPreviewGrant
2018
+ options.getUnpublishedPreviewGrant,
2019
+ options.locationConsent
1579
2020
  );
1580
2021
  return {
1581
2022
  indexId,
2023
+ handoff: session.handoff,
1582
2024
  version,
1583
2025
  runtimeOrigin,
1584
2026
  visitorSessionId,
@@ -1610,7 +2052,7 @@ function createAgentClient(options) {
1610
2052
  }
1611
2053
 
1612
2054
  // src/runtime/errors.ts
1613
- var import_client3 = require("eve/client");
2055
+ var import_client5 = require("eve/client");
1614
2056
  var TRANSIENT_AGENT_ERROR_MESSAGE = "The agent run stopped before the action finished. Please try again.";
1615
2057
  var PREVIEW_AUTHORIZATION_ERROR_MESSAGE = "This preview could not be authorized. Open the latest preview from Webless.";
1616
2058
  function isTransientRuntimeMessage(message) {
@@ -1622,7 +2064,7 @@ function isPreviewAuthorizationMessage(message) {
1622
2064
  return normalized.includes("unpublished preview authorization") || normalized.includes("unpublished preview grant") || normalized.includes("agent studio preview grant") || normalized.includes("preview authorization");
1623
2065
  }
1624
2066
  function formatAgentError(error) {
1625
- if (error instanceof import_client3.ClientError) {
2067
+ if (error instanceof import_client5.ClientError) {
1626
2068
  if (error.status === 401 && error.code === "index_required") {
1627
2069
  return "Missing indexId \u2014 pass a published index id to createAgentClient().";
1628
2070
  }
@@ -1656,14 +2098,14 @@ function formatAgentError(error) {
1656
2098
  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
2099
  function visitorMessageDisplayText(message) {
1658
2100
  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();
2101
+ const text3 = message.text.trim();
2102
+ if (!text3) return message.text;
2103
+ if (text3.startsWith(COMPOSER_FORM_SKIP_DISMISSAL)) {
2104
+ const afterDismissal = text3.slice(COMPOSER_FORM_SKIP_DISMISSAL.length).trim().replace(/^\n+/, "").trim();
1663
2105
  if (afterDismissal) return afterDismissal;
1664
2106
  }
1665
2107
  const runtime = message.runtimeText?.trim();
1666
- if (runtime && text2 === runtime && runtime.includes(COMPOSER_FORM_SKIP_DISMISSAL)) {
2108
+ if (runtime && text3 === runtime && runtime.includes(COMPOSER_FORM_SKIP_DISMISSAL)) {
1667
2109
  const afterDismissal = runtime.slice(
1668
2110
  runtime.indexOf(COMPOSER_FORM_SKIP_DISMISSAL) + COMPOSER_FORM_SKIP_DISMISSAL.length
1669
2111
  ).trim().replace(/^\n+/, "").trim();
@@ -1737,13 +2179,13 @@ function parseVisitorFormFields(value) {
1737
2179
  const seen = /* @__PURE__ */ new Set();
1738
2180
  for (const item of value) {
1739
2181
  const record2 = asRecord(item);
1740
- const id = asString(record2?.id).toLowerCase().replace(/[^a-z0-9_-]/g, "");
2182
+ const id2 = asString(record2?.id).toLowerCase().replace(/[^a-z0-9_-]/g, "");
1741
2183
  const kind = asString(record2?.kind);
1742
- if (!record2 || !id || seen.has(id) || !isFieldKind2(kind)) continue;
1743
- seen.add(id);
1744
- const label = asString(record2.label) || id;
2184
+ if (!record2 || !id2 || seen.has(id2) || !isFieldKind2(kind)) continue;
2185
+ seen.add(id2);
2186
+ const label = asString(record2.label) || id2;
1745
2187
  fields.push({
1746
- id,
2188
+ id: id2,
1747
2189
  kind,
1748
2190
  label,
1749
2191
  placeholder: asString(record2.placeholder) || label,
@@ -1779,52 +2221,52 @@ function formatComposerFormMessage(form, values) {
1779
2221
  return value ? `${field.label}: ${value}` : "";
1780
2222
  }).filter(Boolean).join("\n");
1781
2223
  }
1782
- function looksLikeFieldCollection(text2) {
2224
+ function looksLikeFieldCollection(text3) {
1783
2225
  return /\b(please|need|send|share|enter|provide|add|collect|what|which|use)\b/i.test(
1784
- text2
1785
- ) || /:\s*$/m.test(text2) || /^[-*•]\s+/m.test(text2);
2226
+ text3
2227
+ ) || /:\s*$/m.test(text3) || /^[-*•]\s+/m.test(text3);
1786
2228
  }
1787
- function looksLikeBookingCopy(text2) {
2229
+ function looksLikeBookingCopy(text3) {
1788
2230
  return /book(ing)? (card|a demo|this time)|pick a (date|time)|available (times|slots)|calendly/i.test(
1789
- text2
2231
+ text3
1790
2232
  );
1791
2233
  }
1792
- function echoedLabeledFieldIds(text2) {
2234
+ function echoedLabeledFieldIds(text3) {
1793
2235
  const ids = /* @__PURE__ */ new Set();
1794
- if (/\bname\s*:\s+\S+/i.test(text2)) ids.add("name");
1795
- if (/\be-?mail\s*:\s+\S+/i.test(text2)) ids.add("email");
1796
- if (/\bphone\s*:\s+\S+/i.test(text2)) ids.add("phone");
1797
- if (/\bcompany\s*:\s+\S+/i.test(text2)) ids.add("company");
2236
+ if (/\bname\s*:\s+\S+/i.test(text3)) ids.add("name");
2237
+ if (/\be-?mail\s*:\s+\S+/i.test(text3)) ids.add("email");
2238
+ if (/\bphone\s*:\s+\S+/i.test(text3)) ids.add("phone");
2239
+ if (/\bcompany\s*:\s+\S+/i.test(text3)) ids.add("company");
1798
2240
  return ids;
1799
2241
  }
1800
- function matchLibraryFields(text2) {
2242
+ function matchLibraryFields(text3) {
1801
2243
  return FIELD_LIBRARY.flatMap((field) => {
1802
- if (field.exclude?.test(text2)) {
1803
- const leftover = text2.replace(field.exclude, " ");
2244
+ if (field.exclude?.test(text3)) {
2245
+ const leftover = text3.replace(field.exclude, " ");
1804
2246
  if (!field.patterns.some((pattern) => pattern.test(leftover))) return [];
1805
- } else if (!field.patterns.some((pattern) => pattern.test(text2))) {
2247
+ } else if (!field.patterns.some((pattern) => pattern.test(text3))) {
1806
2248
  return [];
1807
2249
  }
1808
2250
  const { patterns: _patterns, exclude: _exclude, ...next } = field;
1809
2251
  return [next];
1810
2252
  }).slice(0, MAX_FORM_FIELDS);
1811
2253
  }
1812
- function looksLikeCompletedActionRecap(text2) {
1813
- const confirmingCreate = /\bshould i create this\b/i.test(text2);
1814
- const echoingFilledFields = /\b(?:name|email|phone|company)\s*:\s+\S+/i.test(text2) && /[^\s@]+@[^\s@]+\.[^\s@]+/i.test(text2);
2254
+ function looksLikeCompletedActionRecap(text3) {
2255
+ const confirmingCreate = /\bshould i create this\b/i.test(text3);
2256
+ const echoingFilledFields = /\b(?:name|email|phone|company)\s*:\s+\S+/i.test(text3) && /[^\s@]+@[^\s@]+\.[^\s@]+/i.test(text3);
1815
2257
  if (echoingFilledFields) {
1816
- if (looksLikeFieldCollection(text2)) {
1817
- const echoed = echoedLabeledFieldIds(text2);
1818
- if (matchLibraryFields(text2).some((field) => !echoed.has(field.id))) {
2258
+ if (looksLikeFieldCollection(text3)) {
2259
+ const echoed = echoedLabeledFieldIds(text3);
2260
+ if (matchLibraryFields(text3).some((field) => !echoed.has(field.id))) {
1819
2261
  return false;
1820
2262
  }
1821
2263
  }
1822
2264
  return true;
1823
2265
  }
1824
- return confirmingCreate && !looksLikeFieldCollection(text2);
2266
+ return confirmingCreate && !looksLikeFieldCollection(text3);
1825
2267
  }
1826
- function inferComposerForm(text2) {
1827
- const cleaned = text2.trim();
2268
+ function inferComposerForm(text3) {
2269
+ const cleaned = text3.trim();
1828
2270
  if (!cleaned || looksLikeBookingCopy(cleaned) || looksLikeCompletedActionRecap(cleaned) || !looksLikeFieldCollection(cleaned)) {
1829
2271
  return null;
1830
2272
  }
@@ -1839,8 +2281,8 @@ function resolveComposerForm(input) {
1839
2281
  if (input.enabled === false || input.hasBookingOffer || input.hasPendingConfirmation) {
1840
2282
  return null;
1841
2283
  }
1842
- const text2 = input.agentText.trim();
1843
- if (!text2) return null;
2284
+ const text3 = input.agentText.trim();
2285
+ if (!text3) return null;
1844
2286
  const card = input.cards?.find((item) => item.type === "visitor_form");
1845
2287
  if (card?.fields && card.fields.length >= MIN_FORM_FIELDS) {
1846
2288
  return {
@@ -1848,7 +2290,7 @@ function resolveComposerForm(input) {
1848
2290
  fields: card.fields.slice(0, MAX_FORM_FIELDS)
1849
2291
  };
1850
2292
  }
1851
- return inferComposerForm(text2);
2293
+ return inferComposerForm(text3);
1852
2294
  }
1853
2295
 
1854
2296
  // src/react/lib/tool-card.ts
@@ -1862,9 +2304,9 @@ function preferBookingOffer(current, next) {
1862
2304
  }
1863
2305
  return next;
1864
2306
  }
1865
- function looksLikeBookingReady(text2) {
2307
+ function looksLikeBookingReady(text3) {
1866
2308
  return /demo option|options are ready|pick a (date|time)|available (times|slots)|book(ing)? (card|the demo)|\bschedule\b/i.test(
1867
- text2
2309
+ text3
1868
2310
  );
1869
2311
  }
1870
2312
  function bookingOfferIdentityKey(offer) {
@@ -1974,29 +2416,29 @@ function bookingCardFromActionOutput(output) {
1974
2416
  const data = asRecord2(record2?.output) ?? asRecord2(record2?.data) ?? record2;
1975
2417
  return parseToolCard(data);
1976
2418
  }
1977
- function ensureBookingOfferText(text2, offer) {
1978
- if (!offer) return text2;
1979
- if (extractToolCards(text2).some((card) => card.type === "booking_offer")) {
1980
- return text2;
2419
+ function ensureBookingOfferText(text3, offer) {
2420
+ if (!offer) return text3;
2421
+ if (extractToolCards(text3).some((card) => card.type === "booking_offer")) {
2422
+ return text3;
1981
2423
  }
1982
- const visible = stripToolCards(text2).trim() || text2.trim();
2424
+ const visible = stripToolCards(text3).trim() || text3.trim();
1983
2425
  return `${visible}
1984
2426
 
1985
2427
  ${formatBookingOfferFence(offer)}`;
1986
2428
  }
1987
- function hideToolCardFences(text2) {
1988
- return text2.replace(/```(?:webless-tool-card|json)\s*[\s\S]*?```/gi, "").replace(/```(?:webless-tool-card|json)[\s\S]*$/i, "").replace(/\n{3,}/g, "\n\n").trim();
2429
+ function hideToolCardFences(text3) {
2430
+ return text3.replace(/```(?:webless-tool-card|json)\s*[\s\S]*?```/gi, "").replace(/```(?:webless-tool-card|json)[\s\S]*$/i, "").replace(/\n{3,}/g, "\n\n").trim();
1989
2431
  }
1990
2432
  var BOOKING_CARD_FALLBACK = "Pick a date and time that works for you.";
1991
- function looksLikeBookingAvailabilityDump(text2) {
1992
- const cleaned = text2.trim();
2433
+ function looksLikeBookingAvailabilityDump(text3) {
2434
+ const cleaned = text3.trim();
1993
2435
  if (!cleaned) return false;
1994
2436
  const isoCount = (cleaned.match(/\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/g) ?? []).length;
1995
2437
  const utcCount = (cleaned.match(/\bUTC\b/g) ?? []).length;
1996
2438
  return isoCount >= 2 || utcCount >= 2 || /api\.calendly\.com|calendly\.com\//i.test(cleaned) || /webless-tool-card/i.test(cleaned);
1997
2439
  }
1998
- function sanitizeBookingOfferCopy(text2) {
1999
- const cleaned = hideToolCardFences(text2);
2440
+ function sanitizeBookingOfferCopy(text3) {
2441
+ const cleaned = hideToolCardFences(text3);
2000
2442
  if (!cleaned || looksLikeBookingAvailabilityDump(cleaned)) {
2001
2443
  return BOOKING_CARD_FALLBACK;
2002
2444
  }
@@ -2009,9 +2451,9 @@ function visitorTimeZone() {
2009
2451
  return "UTC";
2010
2452
  }
2011
2453
  }
2012
- function extractToolCards(text2) {
2454
+ function extractToolCards(text3) {
2013
2455
  const cards = [];
2014
- for (const match of text2.matchAll(FENCE_PATTERN)) {
2456
+ for (const match of text3.matchAll(FENCE_PATTERN)) {
2015
2457
  try {
2016
2458
  const card = parseToolCard(JSON.parse(match[1] ?? ""));
2017
2459
  if (card) cards.push(card);
@@ -2020,8 +2462,8 @@ function extractToolCards(text2) {
2020
2462
  }
2021
2463
  return cards;
2022
2464
  }
2023
- function stripToolCards(text2) {
2024
- return text2.replace(FENCE_PATTERN, "").replace(/\n{3,}/g, "\n\n").trim();
2465
+ function stripToolCards(text3) {
2466
+ return text3.replace(FENCE_PATTERN, "").replace(/\n{3,}/g, "\n\n").trim();
2025
2467
  }
2026
2468
  function localDateKey(date) {
2027
2469
  if (Number.isNaN(date.getTime())) return "";
@@ -2134,7 +2576,7 @@ function visitorBookingPrefix(booking) {
2134
2576
  function record(value) {
2135
2577
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
2136
2578
  }
2137
- function text(value, max = 500) {
2579
+ function text2(value, max = 500) {
2138
2580
  return typeof value === "string" && value.trim().length > 0 && value.trim().length <= max;
2139
2581
  }
2140
2582
  function safeSearchUrl(value) {
@@ -2155,7 +2597,7 @@ function parseAgentSearchReferences(value) {
2155
2597
  const source = record(value2);
2156
2598
  if (!source || Object.keys(source).some(
2157
2599
  (key) => !["id", "title", "url"].includes(key)
2158
- ) || !text(source.id, Infinity) || !text(source.title) || source.url !== void 0 && typeof source.url !== "string")
2600
+ ) || !text2(source.id, Infinity) || !text2(source.title) || source.url !== void 0 && typeof source.url !== "string")
2159
2601
  return null;
2160
2602
  const url = safeSearchUrl(source.url);
2161
2603
  sources.push({
@@ -2167,7 +2609,7 @@ function parseAgentSearchReferences(value) {
2167
2609
  let cta;
2168
2610
  if (data.cta !== void 0) {
2169
2611
  const action = record(data.cta);
2170
- if (!action || Object.keys(action).some((key) => !["label", "url"].includes(key)) || !text(action.label) || action.url !== void 0 && typeof action.url !== "string")
2612
+ if (!action || Object.keys(action).some((key) => !["label", "url"].includes(key)) || !text2(action.label) || action.url !== void 0 && typeof action.url !== "string")
2171
2613
  return null;
2172
2614
  const url = safeSearchUrl(action.url);
2173
2615
  cta = { label: action.label.trim(), ...url ? { url } : {} };
@@ -2186,7 +2628,7 @@ function parseAgentSearchDiscoveryOutput(value) {
2186
2628
  const data = record(decoded);
2187
2629
  if (!data || Object.keys(data).some(
2188
2630
  (key) => !["answer", "sources", "cta", "suggestions"].includes(key)
2189
- ) || !text(data.answer, 5e4) || !Array.isArray(data.suggestions) || data.suggestions.length > 8 || !data.suggestions.every((item) => text(item)))
2631
+ ) || !text2(data.answer, 5e4) || !Array.isArray(data.suggestions) || data.suggestions.length > 8 || !data.suggestions.every((item) => text2(item)))
2190
2632
  return null;
2191
2633
  const references = parseAgentSearchReferences(data);
2192
2634
  return references ? {
@@ -2204,9 +2646,21 @@ function conversationKey(storageKeyPrefix, visitorSessionId) {
2204
2646
  function parseMessage(value) {
2205
2647
  if (typeof value !== "object" || value === null) return null;
2206
2648
  const record2 = value;
2207
- if (typeof record2.id !== "string" || record2.role !== "agent" && record2.role !== "visitor" || typeof record2.text !== "string" || typeof record2.createdAt !== "number" || !Number.isFinite(record2.createdAt)) {
2649
+ if (typeof record2.id !== "string" || record2.role !== "agent" && record2.role !== "visitor" && record2.role !== "human" || typeof record2.text !== "string" || typeof record2.createdAt !== "number" || !Number.isFinite(record2.createdAt)) {
2208
2650
  return null;
2209
2651
  }
2652
+ if (record2.role === "human") {
2653
+ const person = record2.representative;
2654
+ if (typeof person !== "object" || person === null || !("id" in person) || !("name" in person) || typeof person.id !== "string" || typeof person.name !== "string")
2655
+ return null;
2656
+ return {
2657
+ id: record2.id,
2658
+ role: "human",
2659
+ text: record2.text,
2660
+ createdAt: record2.createdAt,
2661
+ representative: { id: person.id, name: person.name }
2662
+ };
2663
+ }
2210
2664
  if (record2.role === "visitor") {
2211
2665
  return {
2212
2666
  id: record2.id,
@@ -2501,10 +2955,10 @@ function safeText(value) {
2501
2955
  return value.trim().slice(0, MAX_TEXT_LENGTH);
2502
2956
  }
2503
2957
  function safeHref(value) {
2504
- const text2 = safeText(value);
2505
- if (!text2) return "";
2958
+ const text3 = safeText(value);
2959
+ if (!text3) return "";
2506
2960
  try {
2507
- const url = new URL(text2);
2961
+ const url = new URL(text3);
2508
2962
  return url.protocol === "https:" ? url.toString() : "";
2509
2963
  } catch {
2510
2964
  return "";
@@ -2724,6 +3178,9 @@ function finalizeSummaryPresentation(result, proposed) {
2724
3178
  };
2725
3179
  }
2726
3180
  function presentVisitorToolResult(result, registry = []) {
3181
+ if (result.toolName === "request_location") {
3182
+ return { id: result.callId, toolName: result.toolName, status: result.status, kind: "hidden" };
3183
+ }
2727
3184
  if (result.status === "completed" && toolResultFailed(result)) {
2728
3185
  result = { ...result, status: "failed" };
2729
3186
  }
@@ -2864,15 +3321,15 @@ function appendChatCollectiblePrompts(messages, requests) {
2864
3321
  }
2865
3322
  return next;
2866
3323
  }
2867
- function chatInputResponseForText(requests, text2) {
2868
- const trimmed = text2.trim();
3324
+ function chatInputResponseForText(requests, text3) {
3325
+ const trimmed = text3.trim();
2869
3326
  if (!trimmed) return null;
2870
3327
  const pending = requests.find(isChatCollectibleInputRequest);
2871
3328
  if (!pending) return null;
2872
3329
  return { requestId: pending.requestId, text: trimmed };
2873
3330
  }
2874
- function normalizeAssistantDedupeKey(text2) {
2875
- return text2.trim().replace(/\s+/g, " ").toLowerCase();
3331
+ function normalizeAssistantDedupeKey(text3) {
3332
+ return text3.trim().replace(/\s+/g, " ").toLowerCase();
2876
3333
  }
2877
3334
  function isNearDuplicateAssistantText(left, right) {
2878
3335
  const a = normalizeAssistantDedupeKey(left);
@@ -2985,6 +3442,7 @@ function isJsonRecord(value) {
2985
3442
  return value !== null && typeof value === "object" && !Array.isArray(value);
2986
3443
  }
2987
3444
  function useAgentChat({
3445
+ handoffEnabled = false,
2988
3446
  customerId,
2989
3447
  getUnpublishedPreviewGrant,
2990
3448
  indexId,
@@ -2996,13 +3454,13 @@ function useAgentChat({
2996
3454
  greeting,
2997
3455
  toolResultRegistry
2998
3456
  }) {
2999
- const initialState = (0, import_react2.useMemo)(
3457
+ const initialState = (0, import_react3.useMemo)(
3000
3458
  () => createInitialState(greeting?.trim() || DEFAULT_GREETING),
3001
3459
  [greeting]
3002
3460
  );
3003
- const previewGrantProviderRef = (0, import_react2.useRef)(getUnpublishedPreviewGrant);
3461
+ const previewGrantProviderRef = (0, import_react3.useRef)(getUnpublishedPreviewGrant);
3004
3462
  previewGrantProviderRef.current = getUnpublishedPreviewGrant;
3005
- const toolResultRegistryRef = (0, import_react2.useRef)(toolResultRegistry);
3463
+ const toolResultRegistryRef = (0, import_react3.useRef)(toolResultRegistry);
3006
3464
  toolResultRegistryRef.current = toolResultRegistry;
3007
3465
  const resolveUnpublishedPreviewGrant = () => {
3008
3466
  const provider = previewGrantProviderRef.current;
@@ -3015,7 +3473,7 @@ function useAgentChat({
3015
3473
  }
3016
3474
  return provider();
3017
3475
  };
3018
- const resolvedStorageKeyPrefix = (0, import_react2.useMemo)(
3476
+ const resolvedStorageKeyPrefix = (0, import_react3.useMemo)(
3019
3477
  () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({
3020
3478
  customerId,
3021
3479
  indexId,
@@ -3024,24 +3482,25 @@ function useAgentChat({
3024
3482
  }),
3025
3483
  [customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
3026
3484
  );
3027
- const visitorId = (0, import_react2.useMemo)(
3485
+ const visitorId = (0, import_react3.useMemo)(
3028
3486
  () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({
3029
3487
  storageKeyPrefix: resolvedStorageKeyPrefix
3030
3488
  }),
3031
3489
  [resolvedStorageKeyPrefix, visitorSessionId]
3032
3490
  );
3033
- const [state, setState] = (0, import_react2.useState)(
3491
+ const [state, setState] = (0, import_react3.useState)(
3034
3492
  () => stateFromConversation(
3035
3493
  loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
3036
3494
  initialState
3037
3495
  )
3038
3496
  );
3039
- const pendingBookingRef = (0, import_react2.useRef)(
3497
+ const pendingBookingRef = (0, import_react3.useRef)(
3040
3498
  loadPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId)
3041
3499
  );
3042
- const runRef = (0, import_react2.useRef)(null);
3043
- const clientRef = (0, import_react2.useRef)(
3500
+ const runRef = (0, import_react3.useRef)(null);
3501
+ const clientRef = (0, import_react3.useRef)(
3044
3502
  createAgentClient({
3503
+ locationConsent: true,
3045
3504
  customerId,
3046
3505
  getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
3047
3506
  indexId,
@@ -3053,8 +3512,8 @@ function useAgentChat({
3053
3512
  })
3054
3513
  );
3055
3514
  const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${previewBuildId ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
3056
- const identityRef = (0, import_react2.useRef)(identityKey);
3057
- (0, import_react2.useEffect)(() => {
3515
+ const identityRef = (0, import_react3.useRef)(identityKey);
3516
+ (0, import_react3.useEffect)(() => {
3058
3517
  if (identityRef.current === identityKey) {
3059
3518
  return;
3060
3519
  }
@@ -3062,6 +3521,7 @@ function useAgentChat({
3062
3521
  runRef.current?.abort();
3063
3522
  runRef.current = null;
3064
3523
  clientRef.current = createAgentClient({
3524
+ locationConsent: true,
3065
3525
  customerId,
3066
3526
  getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
3067
3527
  indexId,
@@ -3092,7 +3552,7 @@ function useAgentChat({
3092
3552
  version,
3093
3553
  visitorId
3094
3554
  ]);
3095
- (0, import_react2.useEffect)(() => {
3555
+ (0, import_react3.useEffect)(() => {
3096
3556
  if (!hasVisitorMessages(state.messages)) return;
3097
3557
  savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
3098
3558
  messages: state.messages,
@@ -3112,16 +3572,77 @@ function useAgentChat({
3112
3572
  state.toolResults,
3113
3573
  visitorId
3114
3574
  ]);
3115
- const reset = (0, import_react2.useCallback)(() => {
3575
+ const handoff = useAgentHandoff({
3576
+ enabled: handoffEnabled,
3577
+ client: clientRef.current,
3578
+ sessionId: clientRef.current.getActiveSessionId(),
3579
+ onOwnership: () => {
3580
+ runRef.current?.abort();
3581
+ runRef.current = null;
3582
+ setState(
3583
+ (prev) => prev.phase === "complete" && !prev.streamingText && !prev.pendingInputs?.length && !prev.toolSteps.length ? prev : {
3584
+ ...prev,
3585
+ phase: "complete",
3586
+ streamingText: "",
3587
+ pendingInputs: [],
3588
+ toolSteps: [],
3589
+ toolResults: [],
3590
+ pendingOffer: null,
3591
+ error: null
3592
+ }
3593
+ );
3594
+ },
3595
+ onEvents: (events) => {
3596
+ setState((prev) => {
3597
+ const seen = new Set(prev.messages.map((message) => message.id));
3598
+ const messages = [];
3599
+ for (const event of events) {
3600
+ if (event.type === "status" || seen.has(`handoff-${event.id}`))
3601
+ continue;
3602
+ messages.push(
3603
+ event.type === "human.message" ? {
3604
+ id: `handoff-${event.id}`,
3605
+ role: "human",
3606
+ text: event.message,
3607
+ createdAt: Date.parse(event.createdAt),
3608
+ representative: event.actor
3609
+ } : {
3610
+ id: `handoff-${event.id}`,
3611
+ role: "visitor",
3612
+ text: event.message,
3613
+ createdAt: Date.parse(event.createdAt)
3614
+ }
3615
+ );
3616
+ }
3617
+ return messages.length ? {
3618
+ ...prev,
3619
+ messages: [...prev.messages, ...messages].sort(
3620
+ (a, b) => a.createdAt - b.createdAt
3621
+ )
3622
+ } : prev;
3623
+ });
3624
+ }
3625
+ });
3626
+ const handoffBlocksAI = (0, import_react3.useRef)(handoff.blocksAI);
3627
+ handoffBlocksAI.current = handoff.blocksAI;
3628
+ const reset = (0, import_react3.useCallback)(() => {
3629
+ if (handoff.blocksAI && !handoff.canReset) return;
3116
3630
  runRef.current?.abort();
3117
3631
  runRef.current = null;
3118
3632
  clientRef.current.reset();
3119
3633
  pendingBookingRef.current = null;
3120
3634
  clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
3121
3635
  setState(initialState);
3122
- }, [initialState, resolvedStorageKeyPrefix, visitorId]);
3123
- const runTurn = (0, import_react2.useCallback)(
3636
+ }, [
3637
+ handoff.blocksAI,
3638
+ handoff.canReset,
3639
+ initialState,
3640
+ resolvedStorageKeyPrefix,
3641
+ visitorId
3642
+ ]);
3643
+ const runTurn = (0, import_react3.useCallback)(
3124
3644
  async (input) => {
3645
+ if (handoffBlocksAI.current) return null;
3125
3646
  const {
3126
3647
  controller,
3127
3648
  initialText = "",
@@ -3245,6 +3766,7 @@ function useAgentChat({
3245
3766
  signal
3246
3767
  });
3247
3768
  if (resume && finalText === null) {
3769
+ if (!isActiveRun() || handoffBlocksAI.current) return null;
3248
3770
  finalText = await clientRef.current.sendTurn(visitorText, {
3249
3771
  handlers,
3250
3772
  signal
@@ -3277,8 +3799,12 @@ function useAgentChat({
3277
3799
  messages: appendAgentTurnMessage(
3278
3800
  prev.messages,
3279
3801
  displayText,
3280
- (prev.toolResults ?? []).filter((result) => result.kind === "search"),
3281
- (prev.toolResults ?? []).filter((result) => result.kind !== "search" && result.kind !== "input")
3802
+ (prev.toolResults ?? []).filter(
3803
+ (result) => result.kind === "search"
3804
+ ),
3805
+ (prev.toolResults ?? []).filter(
3806
+ (result) => result.kind !== "search" && result.kind !== "input"
3807
+ )
3282
3808
  ),
3283
3809
  toolResults: (prev.toolResults ?? []).filter(
3284
3810
  (result) => result.kind === "input"
@@ -3319,7 +3845,7 @@ function useAgentChat({
3319
3845
  },
3320
3846
  [resolvedStorageKeyPrefix, visitorId]
3321
3847
  );
3322
- const rememberBooking = (0, import_react2.useCallback)(
3848
+ const rememberBooking = (0, import_react3.useCallback)(
3323
3849
  (booking) => {
3324
3850
  const current = pendingBookingRef.current;
3325
3851
  if (current?.eventUri === booking.eventUri && current.inviteeEmail === booking.inviteeEmail && current.inviteeUri === booking.inviteeUri) {
@@ -3330,7 +3856,7 @@ function useAgentChat({
3330
3856
  },
3331
3857
  [resolvedStorageKeyPrefix, visitorId]
3332
3858
  );
3333
- const forgetBooking = (0, import_react2.useCallback)(
3859
+ const forgetBooking = (0, import_react3.useCallback)(
3334
3860
  (eventUri) => {
3335
3861
  const current = pendingBookingRef.current;
3336
3862
  if (!current) return;
@@ -3340,12 +3866,21 @@ function useAgentChat({
3340
3866
  },
3341
3867
  [resolvedStorageKeyPrefix, visitorId]
3342
3868
  );
3343
- const submit = (0, import_react2.useCallback)(
3869
+ const submit = (0, import_react3.useCallback)(
3344
3870
  async (visitorText, options) => {
3345
3871
  const trimmed = visitorText.trim();
3346
3872
  const outgoing = options?.runtimeText ?? visitorText;
3347
3873
  if (!outgoing.trim()) return null;
3348
3874
  const declinedComposerFormId = options?.declinedComposerFormId?.trim();
3875
+ if (handoff.blocksAI) {
3876
+ if (!["requesting", "queued", "human"].includes(
3877
+ handoff.page?.status ?? ""
3878
+ ) || handoff.busy)
3879
+ return null;
3880
+ if (!trimmed) return null;
3881
+ await handoff.send(trimmed);
3882
+ return null;
3883
+ }
3349
3884
  const chatResponse = chatInputResponseForText(
3350
3885
  state.pendingInputs ?? [],
3351
3886
  outgoing.trim()
@@ -3447,9 +3982,10 @@ ${outgoing}` : outgoing;
3447
3982
  visitorText: runtimeText
3448
3983
  });
3449
3984
  },
3450
- [runTurn, state.pendingInputs]
3985
+ [handoff, runTurn, state.pendingInputs]
3451
3986
  );
3452
- const retry = (0, import_react2.useCallback)(async () => {
3987
+ const retry = (0, import_react3.useCallback)(async () => {
3988
+ if (handoffBlocksAI.current) return;
3453
3989
  const visitorMessage = [...state.messages].reverse().find((message) => message.role === "visitor");
3454
3990
  if (!visitorMessage) return;
3455
3991
  if (runRef.current) {
@@ -3482,7 +4018,8 @@ ${outgoing}` : outgoing;
3482
4018
  visitorText: visitorTurnText(visitorMessage)
3483
4019
  });
3484
4020
  }, [runTurn, state.messages]);
3485
- const regenerate = (0, import_react2.useCallback)(async () => {
4021
+ const regenerate = (0, import_react3.useCallback)(async () => {
4022
+ if (handoffBlocksAI.current) return null;
3486
4023
  let lastVisitorIndex = -1;
3487
4024
  for (let index = state.messages.length - 1; index >= 0; index -= 1) {
3488
4025
  if (state.messages[index]?.role === "visitor") {
@@ -3525,7 +4062,7 @@ ${outgoing}` : outgoing;
3525
4062
  visitorText: visitorTurnText(visitorMessage)
3526
4063
  });
3527
4064
  }, [runTurn, state.messages]);
3528
- const respondToToolInput = (0, import_react2.useCallback)(
4065
+ const respondToToolInput = (0, import_react3.useCallback)(
3529
4066
  async (surface, values) => {
3530
4067
  await submit(`${surface.title} submitted`, {
3531
4068
  runtimeText: [
@@ -3538,9 +4075,9 @@ ${outgoing}` : outgoing;
3538
4075
  },
3539
4076
  [submit]
3540
4077
  );
3541
- const respondToInput = (0, import_react2.useCallback)(
4078
+ const respondToInput = (0, import_react3.useCallback)(
3542
4079
  async (response) => {
3543
- if (runRef.current) return;
4080
+ if (handoffBlocksAI.current || runRef.current) return;
3544
4081
  const pending = state.pendingInputs?.find(
3545
4082
  (request) => request.requestId === response.requestId
3546
4083
  );
@@ -3568,7 +4105,8 @@ ${outgoing}` : outgoing;
3568
4105
  },
3569
4106
  [respondToToolInput, runTurn, state.pendingInputs]
3570
4107
  );
3571
- (0, import_react2.useEffect)(() => {
4108
+ (0, import_react3.useEffect)(() => {
4109
+ if (handoff.blocksAI) return;
3572
4110
  const conversation = loadPersistedAgentConversation(
3573
4111
  resolvedStorageKeyPrefix,
3574
4112
  visitorId
@@ -3590,14 +4128,21 @@ ${outgoing}` : outgoing;
3590
4128
  }
3591
4129
  controller.abort();
3592
4130
  };
3593
- }, [identityKey, resolvedStorageKeyPrefix, runTurn, visitorId]);
3594
- (0, import_react2.useEffect)(() => {
4131
+ }, [
4132
+ handoff.blocksAI,
4133
+ identityKey,
4134
+ resolvedStorageKeyPrefix,
4135
+ runTurn,
4136
+ visitorId
4137
+ ]);
4138
+ (0, import_react3.useEffect)(() => {
3595
4139
  return () => {
3596
4140
  runRef.current?.abort();
3597
4141
  runRef.current = null;
3598
4142
  };
3599
4143
  }, []);
3600
4144
  return {
4145
+ handoff,
3601
4146
  state,
3602
4147
  reset,
3603
4148
  retry,
@@ -3626,12 +4171,12 @@ function isAgentBusy(phase) {
3626
4171
  }
3627
4172
 
3628
4173
  // src/react/hooks/useIsMobile.ts
3629
- var import_react3 = require("react");
4174
+ var import_react4 = require("react");
3630
4175
  function useIsMobile(breakpoint = 767) {
3631
- const [isMobile, setIsMobile] = (0, import_react3.useState)(
4176
+ const [isMobile, setIsMobile] = (0, import_react4.useState)(
3632
4177
  () => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
3633
4178
  );
3634
- (0, import_react3.useEffect)(() => {
4179
+ (0, import_react4.useEffect)(() => {
3635
4180
  const media = window.matchMedia(`(max-width: ${breakpoint}px)`);
3636
4181
  const onChange = () => setIsMobile(media.matches);
3637
4182
  onChange();
@@ -3668,7 +4213,7 @@ function unregisterAgentPanelController(customerId) {
3668
4213
  }
3669
4214
 
3670
4215
  // src/react/components/AgentRail/AgentRail.tsx
3671
- var import_react14 = require("react");
4216
+ var import_react16 = require("react");
3672
4217
 
3673
4218
  // src/react/types/conversation.ts
3674
4219
  var defaultAgentRailTheme = {
@@ -3751,7 +4296,7 @@ function agentThemeStyle(theme, resolvedColorScheme) {
3751
4296
  }
3752
4297
 
3753
4298
  // src/react/hooks/useAgentColorScheme.ts
3754
- var import_react4 = require("react");
4299
+ var import_react5 = require("react");
3755
4300
  var DARK_MODE_QUERY = "(prefers-color-scheme: dark)";
3756
4301
  function subscribeToDarkMode(onChange) {
3757
4302
  if (typeof window === "undefined" || !window.matchMedia) {
@@ -3769,7 +4314,7 @@ function getPrefersDarkMode() {
3769
4314
  return typeof window !== "undefined" && Boolean(window.matchMedia?.(DARK_MODE_QUERY).matches);
3770
4315
  }
3771
4316
  function useAgentColorScheme(colorScheme = "auto") {
3772
- const prefersDarkMode = (0, import_react4.useSyncExternalStore)(
4317
+ const prefersDarkMode = (0, import_react5.useSyncExternalStore)(
3773
4318
  subscribeToDarkMode,
3774
4319
  getPrefersDarkMode,
3775
4320
  () => false
@@ -3781,7 +4326,7 @@ function resolveAgentColorScheme(colorScheme = "auto", prefersDarkMode) {
3781
4326
  }
3782
4327
 
3783
4328
  // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
3784
- var import_react5 = require("react");
4329
+ var import_react6 = require("react");
3785
4330
  var import_jsx_runtime = require("react/jsx-runtime");
3786
4331
  function joinLabels(labels) {
3787
4332
  if (labels.length <= 1) return labels[0] ?? "";
@@ -3900,7 +4445,7 @@ function AgentActivityBubble({
3900
4445
  const statusText = workSummary(steps, failed, brandLabel);
3901
4446
  const softReview = statusText === AGENT_SOFT_REVIEW_STATUS;
3902
4447
  const receiptId = steps.map((step) => step.id).join(":");
3903
- const [expandedReceiptId, setExpandedReceiptId] = (0, import_react5.useState)(
4448
+ const [expandedReceiptId, setExpandedReceiptId] = (0, import_react6.useState)(
3904
4449
  null
3905
4450
  );
3906
4451
  const detailsOpen = !active && expandedReceiptId === receiptId;
@@ -3951,17 +4496,17 @@ function AgentActivityBubble({
3951
4496
  }
3952
4497
 
3953
4498
  // src/react/components/AnswerReceiptDialog/AnswerReceiptDialog.tsx
3954
- var import_react7 = require("react");
4499
+ var import_react8 = require("react");
3955
4500
  var import_react_dom = require("react-dom");
3956
4501
 
3957
4502
  // src/react/components/AgentRail/AgentRailOverlayContext.tsx
3958
- var import_react6 = require("react");
3959
- var AgentRailOverlayContext = (0, import_react6.createContext)(null);
4503
+ var import_react7 = require("react");
4504
+ var AgentRailOverlayContext = (0, import_react7.createContext)(null);
3960
4505
  function useAgentRailPortalRoots() {
3961
- return (0, import_react6.useContext)(AgentRailOverlayContext);
4506
+ return (0, import_react7.useContext)(AgentRailOverlayContext);
3962
4507
  }
3963
4508
  function useAgentRailMenuPortalRoot() {
3964
- return (0, import_react6.useContext)(AgentRailOverlayContext)?.railRef ?? null;
4509
+ return (0, import_react7.useContext)(AgentRailOverlayContext)?.railRef ?? null;
3965
4510
  }
3966
4511
 
3967
4512
  // src/react/components/AnswerReceiptDialog/AnswerReceiptDialog.tsx
@@ -3985,10 +4530,10 @@ function AnswerReceiptDialog({
3985
4530
  }) {
3986
4531
  const portalRoots = useAgentRailPortalRoots();
3987
4532
  const overlayRoot = portalRoots?.overlayRef ?? null;
3988
- const cardRef = (0, import_react7.useRef)(null);
3989
- const closeButtonRef = (0, import_react7.useRef)(null);
3990
- const previouslyFocusedRef = (0, import_react7.useRef)(null);
3991
- (0, import_react7.useEffect)(() => {
4533
+ const cardRef = (0, import_react8.useRef)(null);
4534
+ const closeButtonRef = (0, import_react8.useRef)(null);
4535
+ const previouslyFocusedRef = (0, import_react8.useRef)(null);
4536
+ (0, import_react8.useEffect)(() => {
3992
4537
  previouslyFocusedRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
3993
4538
  closeButtonRef.current?.focus({ preventScroll: true });
3994
4539
  const handleKeyDown = (event) => {
@@ -4073,7 +4618,7 @@ function AnswerReceiptDialog({
4073
4618
  }
4074
4619
 
4075
4620
  // src/react/components/Composer/Composer.tsx
4076
- var import_react8 = require("react");
4621
+ var import_react9 = require("react");
4077
4622
  var import_jsx_runtime3 = require("react/jsx-runtime");
4078
4623
  var FORM_SUBMITTED_MESSAGE = "Shared my details";
4079
4624
  function SendIcon() {
@@ -4135,17 +4680,17 @@ function Composer({
4135
4680
  allowFormResume = true,
4136
4681
  onSubmit
4137
4682
  }) {
4138
- const [value, setValue] = (0, import_react8.useState)("");
4139
- const [draft, setDraft] = (0, import_react8.useState)(() => createDraft(form));
4140
- const inputRef = (0, import_react8.useRef)(null);
4141
- const firstFieldRef = (0, import_react8.useRef)(null);
4142
- const formRef = (0, import_react8.useRef)(null);
4143
- const formId = (0, import_react8.useId)();
4683
+ const [value, setValue] = (0, import_react9.useState)("");
4684
+ const [draft, setDraft] = (0, import_react9.useState)(() => createDraft(form));
4685
+ const inputRef = (0, import_react9.useRef)(null);
4686
+ const firstFieldRef = (0, import_react9.useRef)(null);
4687
+ const formRef = (0, import_react9.useRef)(null);
4688
+ const formId = (0, import_react9.useId)();
4144
4689
  if (form && form.id !== draft.form?.id) setDraft(createDraft(form));
4145
4690
  const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
4146
4691
  const activeForm = !disabled && draft.expanded ? savedForm : null;
4147
4692
  const canSend = !disabled && Boolean(value.trim() || activeForm);
4148
- (0, import_react8.useEffect)(() => {
4693
+ (0, import_react9.useEffect)(() => {
4149
4694
  if (activeForm) firstFieldRef.current?.focus();
4150
4695
  else if ((savedForm || draft.submitted) && !disabled)
4151
4696
  inputRef.current?.focus();
@@ -4406,7 +4951,7 @@ function FollowUpChips({
4406
4951
  }
4407
4952
 
4408
4953
  // src/react/components/MessageBubble/MessageBubble.tsx
4409
- var import_react10 = require("react");
4954
+ var import_react11 = require("react");
4410
4955
 
4411
4956
  // src/react/components/SearchReferences/SearchReferences.tsx
4412
4957
  var import_jsx_runtime5 = require("react/jsx-runtime");
@@ -4497,7 +5042,7 @@ function SearchReferences({
4497
5042
  }
4498
5043
 
4499
5044
  // src/react/components/BookingCard/BookingCard.tsx
4500
- var import_react9 = require("react");
5045
+ var import_react10 = require("react");
4501
5046
  var import_jsx_runtime6 = require("react/jsx-runtime");
4502
5047
  var BOOKING_STEPS = [
4503
5048
  { id: "date", label: "Date" },
@@ -4552,27 +5097,27 @@ function InteractiveBookingCard({
4552
5097
  offer,
4553
5098
  onBook
4554
5099
  }) {
4555
- const fieldId = (0, import_react9.useId)();
5100
+ const fieldId = (0, import_react10.useId)();
4556
5101
  const defaultType = offer.eventTypes[0]?.uri ?? offer.slots[0]?.eventTypeUri ?? "";
4557
- const [step, setStep] = (0, import_react9.useState)("date");
4558
- const [eventTypeUri, setEventTypeUri] = (0, import_react9.useState)(defaultType);
4559
- const [selectedDate, setSelectedDate] = (0, import_react9.useState)("");
4560
- const [startTime, setStartTime] = (0, import_react9.useState)("");
4561
- const [name, setName] = (0, import_react9.useState)("");
4562
- const [email, setEmail] = (0, import_react9.useState)("");
4563
- const activeStepRef = (0, import_react9.useRef)(null);
4564
- const previousStepRef = (0, import_react9.useRef)(step);
5102
+ const [step, setStep] = (0, import_react10.useState)("date");
5103
+ const [eventTypeUri, setEventTypeUri] = (0, import_react10.useState)(defaultType);
5104
+ const [selectedDate, setSelectedDate] = (0, import_react10.useState)("");
5105
+ const [startTime, setStartTime] = (0, import_react10.useState)("");
5106
+ const [name, setName] = (0, import_react10.useState)("");
5107
+ const [email, setEmail] = (0, import_react10.useState)("");
5108
+ const activeStepRef = (0, import_react10.useRef)(null);
5109
+ const previousStepRef = (0, import_react10.useRef)(step);
4565
5110
  const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
4566
- (0, import_react9.useEffect)(() => {
5111
+ (0, import_react10.useEffect)(() => {
4567
5112
  if (previousStepRef.current === step) return;
4568
5113
  previousStepRef.current = step;
4569
5114
  activeStepRef.current?.scrollIntoView({ block: "nearest" });
4570
5115
  }, [step]);
4571
- const slots = (0, import_react9.useMemo)(
5116
+ const slots = (0, import_react10.useMemo)(
4572
5117
  () => bookingSlotsForEventType(offer.slots, eventTypeUri),
4573
5118
  [eventTypeUri, offer.slots]
4574
5119
  );
4575
- const availableByDate = (0, import_react9.useMemo)(() => {
5120
+ const availableByDate = (0, import_react10.useMemo)(() => {
4576
5121
  const next = /* @__PURE__ */ new Map();
4577
5122
  for (const slot of slots) {
4578
5123
  const key = slotDateKey(slot.startTime);
@@ -4580,7 +5125,7 @@ function InteractiveBookingCard({
4580
5125
  }
4581
5126
  return next;
4582
5127
  }, [slots]);
4583
- const [visibleMonth, setVisibleMonth] = (0, import_react9.useState)(
5128
+ const [visibleMonth, setVisibleMonth] = (0, import_react10.useState)(
4584
5129
  () => firstAvailableBookingMonth(slots)
4585
5130
  );
4586
5131
  function selectEventType(nextType) {
@@ -4593,7 +5138,7 @@ function InteractiveBookingCard({
4593
5138
  )
4594
5139
  );
4595
5140
  }
4596
- const daySlots = (0, import_react9.useMemo)(
5141
+ const daySlots = (0, import_react10.useMemo)(
4597
5142
  () => slots.filter((slot) => slotDateKey(slot.startTime) === selectedDate),
4598
5143
  [selectedDate, slots]
4599
5144
  );
@@ -4602,7 +5147,7 @@ function InteractiveBookingCard({
4602
5147
  );
4603
5148
  const selectedSample = availableByDate.get(selectedDate) ?? startTime;
4604
5149
  const timeZone = formatSlotTimeZone(slots[0]?.startTime ?? selectedSample);
4605
- const weekdays = (0, import_react9.useMemo)(() => weekdayLabels(), []);
5150
+ const weekdays = (0, import_react10.useMemo)(() => weekdayLabels(), []);
4606
5151
  const cells = calendarCells(visibleMonth.year, visibleMonth.month);
4607
5152
  const canPrevMonth = [...availableByDate.keys()].some((key) => {
4608
5153
  const month = monthFromKey(key);
@@ -4888,8 +5433,8 @@ function resolveMessageUrl(safeUrl, baseUrl) {
4888
5433
  // src/react/components/MessageBubble/MessageBubble.tsx
4889
5434
  var import_styles = require("streamdown/styles.css");
4890
5435
  var import_jsx_runtime7 = require("react/jsx-runtime");
4891
- function normalizeDedupeText(text2) {
4892
- return text2.trim().replace(/\s+/g, " ").toLowerCase();
5436
+ function normalizeDedupeText(text3) {
5437
+ return text3.trim().replace(/\s+/g, " ").toLowerCase();
4893
5438
  }
4894
5439
  function paragraphsAreNearDuplicates(first, second) {
4895
5440
  const left = normalizeDedupeText(first);
@@ -4905,8 +5450,8 @@ function paragraphsShareOpening(first, second) {
4905
5450
  if (!opening || opening.length < 20) return false;
4906
5451
  return second.trim().startsWith(opening);
4907
5452
  }
4908
- function collapseRepeatedText(text2) {
4909
- const trimmed = text2.trim();
5453
+ function collapseRepeatedText(text3) {
5454
+ const trimmed = text3.trim();
4910
5455
  if (trimmed.length < 40) return trimmed;
4911
5456
  const paragraphs = trimmed.split(/\n{2,}/u).map((part) => part.trim()).filter(Boolean);
4912
5457
  if (paragraphs.length === 2 && (paragraphsAreNearDuplicates(paragraphs[0], paragraphs[1]) || paragraphsShareOpening(paragraphs[0], paragraphs[1]))) {
@@ -4927,13 +5472,14 @@ function MessageBubble({
4927
5472
  message,
4928
5473
  brandLogoUrl,
4929
5474
  bookingDisabled = false,
5475
+ showProvenance = false,
4930
5476
  bookingReadOnly = false,
4931
5477
  linkBaseUrl,
4932
5478
  offer,
4933
5479
  onBook
4934
5480
  }) {
4935
5481
  const resolvedLogoUrl = brandLogoUrl?.trim();
4936
- const [failedLogoUrl, setFailedLogoUrl] = (0, import_react10.useState)(null);
5482
+ const [failedLogoUrl, setFailedLogoUrl] = (0, import_react11.useState)(null);
4937
5483
  const showBrandLogo = Boolean(resolvedLogoUrl) && failedLogoUrl !== resolvedLogoUrl;
4938
5484
  const cards = message.role === "agent" ? extractToolCards(message.text) : [];
4939
5485
  const extractedOffers = cards.filter(
@@ -4948,7 +5494,34 @@ function MessageBubble({
4948
5494
  if (message.role === "visitor") {
4949
5495
  const visitorText = visitorMessageDisplayText(message).trim();
4950
5496
  if (!visitorText) return null;
4951
- 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 }) });
5497
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
5498
+ "article",
5499
+ {
5500
+ className: "message-bubble message-bubble--visitor",
5501
+ "aria-label": "Message from visitor",
5502
+ children: [
5503
+ showProvenance ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__speaker", children: "You \xB7 Visitor" }) : null,
5504
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "message-bubble__text", children: visitorText })
5505
+ ]
5506
+ }
5507
+ );
5508
+ }
5509
+ if (message.role === "human") {
5510
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
5511
+ "article",
5512
+ {
5513
+ className: "message-bubble message-bubble--human",
5514
+ "aria-label": `Message from ${message.representative.name}`,
5515
+ children: [
5516
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("strong", { className: "message-bubble__representative", children: [
5517
+ message.representative.name,
5518
+ " ",
5519
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Human representative" })
5520
+ ] }),
5521
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "message-bubble__text", children: message.text })
5522
+ ]
5523
+ }
5524
+ );
4952
5525
  }
4953
5526
  const citations = message.citations ?? [];
4954
5527
  const agentText = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__text", children: [
@@ -4985,40 +5558,48 @@ function MessageBubble({
4985
5558
  ] });
4986
5559
  if (!displayText && !message.searchResults?.length && offers.length === 0)
4987
5560
  return null;
4988
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
4989
- displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__agent-row", children: [
4990
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4991
- "img",
4992
- {
4993
- src: resolvedLogoUrl,
4994
- alt: "",
4995
- onError: () => {
4996
- setFailedLogoUrl(resolvedLogoUrl ?? null);
4997
- }
4998
- }
4999
- ) }),
5000
- agentText
5001
- ] }) : agentText : null,
5002
- offers.map((nextOffer, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5003
- BookingCard,
5004
- {
5005
- disabled: bookingDisabled,
5006
- readOnly: bookingReadOnly,
5007
- offer: nextOffer,
5008
- onBook
5009
- },
5010
- `${bookingOfferIdentityKey(nextOffer)}-${index}`
5011
- ))
5012
- ] });
5561
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
5562
+ "article",
5563
+ {
5564
+ className: "message-bubble message-bubble--agent",
5565
+ "aria-label": "Message from AI assistant",
5566
+ children: [
5567
+ showProvenance ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__speaker", children: "AI assistant" }) : null,
5568
+ displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__agent-row", children: [
5569
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5570
+ "img",
5571
+ {
5572
+ src: resolvedLogoUrl,
5573
+ alt: "",
5574
+ onError: () => {
5575
+ setFailedLogoUrl(resolvedLogoUrl ?? null);
5576
+ }
5577
+ }
5578
+ ) }),
5579
+ agentText
5580
+ ] }) : agentText : null,
5581
+ offers.map((nextOffer, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5582
+ BookingCard,
5583
+ {
5584
+ disabled: bookingDisabled,
5585
+ readOnly: bookingReadOnly,
5586
+ offer: nextOffer,
5587
+ onBook
5588
+ },
5589
+ `${bookingOfferIdentityKey(nextOffer)}-${index}`
5590
+ ))
5591
+ ]
5592
+ }
5593
+ );
5013
5594
  }
5014
5595
 
5015
5596
  // src/react/components/MessageActions/MessageActions.tsx
5016
- var import_react11 = require("react");
5597
+ var import_react12 = require("react");
5017
5598
  var import_react_dom2 = require("react-dom");
5018
5599
 
5019
5600
  // src/react/lib/speech.ts
5020
- function toSpeechText(text2) {
5021
- let out = hideToolCardFences(text2);
5601
+ function toSpeechText(text3) {
5602
+ let out = hideToolCardFences(text3);
5022
5603
  out = out.replace(/```[\s\S]*?```/g, " ");
5023
5604
  out = out.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
5024
5605
  out = out.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1");
@@ -5353,12 +5934,12 @@ function StopIcon() {
5353
5934
  }
5354
5935
  ) });
5355
5936
  }
5356
- async function writeToClipboard(text2) {
5937
+ async function writeToClipboard(text3) {
5357
5938
  try {
5358
- await navigator.clipboard.writeText(text2);
5939
+ await navigator.clipboard.writeText(text3);
5359
5940
  } catch {
5360
5941
  const textarea = document.createElement("textarea");
5361
- textarea.value = text2;
5942
+ textarea.value = text3;
5362
5943
  textarea.style.position = "fixed";
5363
5944
  textarea.style.opacity = "0";
5364
5945
  document.body.appendChild(textarea);
@@ -5409,26 +5990,26 @@ function MessageActions({
5409
5990
  speechText
5410
5991
  }) {
5411
5992
  const menuPortalRoot = useAgentRailMenuPortalRoot();
5412
- const [copied, setCopied] = (0, import_react11.useState)(false);
5413
- const [rating, setRating] = (0, import_react11.useState)(null);
5414
- const [menuOpen, setMenuOpen] = (0, import_react11.useState)(false);
5415
- const [menuPosition, setMenuPosition] = (0, import_react11.useState)(null);
5416
- const [speaking, setSpeaking] = (0, import_react11.useState)(false);
5417
- const [speechSupported, setSpeechSupported] = (0, import_react11.useState)(null);
5418
- const copyTimerRef = (0, import_react11.useRef)(null);
5419
- const menuRef = (0, import_react11.useRef)(null);
5420
- const portaledMenuRef = (0, import_react11.useRef)(null);
5421
- const moreButtonRef = (0, import_react11.useRef)(null);
5993
+ const [copied, setCopied] = (0, import_react12.useState)(false);
5994
+ const [rating, setRating] = (0, import_react12.useState)(null);
5995
+ const [menuOpen, setMenuOpen] = (0, import_react12.useState)(false);
5996
+ const [menuPosition, setMenuPosition] = (0, import_react12.useState)(null);
5997
+ const [speaking, setSpeaking] = (0, import_react12.useState)(false);
5998
+ const [speechSupported, setSpeechSupported] = (0, import_react12.useState)(null);
5999
+ const copyTimerRef = (0, import_react12.useRef)(null);
6000
+ const menuRef = (0, import_react12.useRef)(null);
6001
+ const portaledMenuRef = (0, import_react12.useRef)(null);
6002
+ const moreButtonRef = (0, import_react12.useRef)(null);
5422
6003
  const answeredLabel = formatAnsweredAt(answeredAt ?? 0);
5423
6004
  const resolvedSpeechText = speechText ?? toSpeechText(copyText);
5424
6005
  const canOpenReceipt = Boolean(receiptSteps) && Boolean(onOpenReceipt);
5425
6006
  const readAloudEligible = Boolean(readAloud && resolvedSpeechText);
5426
6007
  const canReadAloud = readAloudEligible && speechSupported === true;
5427
6008
  const showMenu = canOpenReceipt || (speechSupported === null ? readAloudEligible : canReadAloud);
5428
- (0, import_react11.useLayoutEffect)(() => {
6009
+ (0, import_react12.useLayoutEffect)(() => {
5429
6010
  setSpeechSupported(isSpeechSupported());
5430
6011
  }, []);
5431
- (0, import_react11.useLayoutEffect)(() => {
6012
+ (0, import_react12.useLayoutEffect)(() => {
5432
6013
  if (!menuOpen || !moreButtonRef.current || !portaledMenuRef.current) {
5433
6014
  setMenuPosition(null);
5434
6015
  return;
@@ -5445,7 +6026,7 @@ function MessageActions({
5445
6026
  })
5446
6027
  );
5447
6028
  }, [menuOpen, menuPortalRoot]);
5448
- (0, import_react11.useEffect)(() => {
6029
+ (0, import_react12.useEffect)(() => {
5449
6030
  const unsubscribe = subscribeSpeechInterrupts(() => setSpeaking(false));
5450
6031
  return () => {
5451
6032
  unsubscribe();
@@ -5455,7 +6036,7 @@ function MessageActions({
5455
6036
  stopSpeech();
5456
6037
  };
5457
6038
  }, []);
5458
- (0, import_react11.useEffect)(() => {
6039
+ (0, import_react12.useEffect)(() => {
5459
6040
  if (!menuOpen) return;
5460
6041
  const handlePointerDown = (event) => {
5461
6042
  const target = event.target;
@@ -5624,7 +6205,7 @@ function MessageActions({
5624
6205
  }
5625
6206
 
5626
6207
  // src/react/components/HumanInputCard/HumanInputCard.tsx
5627
- var import_react13 = require("react");
6208
+ var import_react14 = require("react");
5628
6209
 
5629
6210
  // src/react/components/ConfirmationCard/ConfirmationCard.tsx
5630
6211
  var import_jsx_runtime9 = require("react/jsx-runtime");
@@ -5666,7 +6247,7 @@ function ConfirmationCard({
5666
6247
  }
5667
6248
 
5668
6249
  // src/react/components/ToolInputCard/ToolInputCard.tsx
5669
- var import_react12 = require("react");
6250
+ var import_react13 = require("react");
5670
6251
  var import_jsx_runtime10 = require("react/jsx-runtime");
5671
6252
  function isRecord5(value) {
5672
6253
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -5789,13 +6370,13 @@ function valuesMatch(left, right) {
5789
6370
  }
5790
6371
  function FieldDescription({
5791
6372
  field,
5792
- id
6373
+ id: id2
5793
6374
  }) {
5794
- return field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id, className: "tool-input-card__description", children: field.description }) : null;
6375
+ return field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: id2, className: "tool-input-card__description", children: field.description }) : null;
5795
6376
  }
5796
6377
  function ChoiceField({
5797
6378
  field,
5798
- id,
6379
+ id: id2,
5799
6380
  value,
5800
6381
  disabled,
5801
6382
  describedBy,
@@ -5813,7 +6394,7 @@ function ChoiceField({
5813
6394
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5814
6395
  "select",
5815
6396
  {
5816
- id,
6397
+ id: id2,
5817
6398
  value: selectedIndex >= 0 ? String(selectedIndex) : "",
5818
6399
  disabled,
5819
6400
  required: field.required,
@@ -5836,7 +6417,7 @@ function ChoiceField({
5836
6417
  {
5837
6418
  className: "tool-input-card__choices",
5838
6419
  role: multiple ? "group" : "radiogroup",
5839
- "aria-labelledby": `${id}-label`,
6420
+ "aria-labelledby": `${id2}-label`,
5840
6421
  "aria-describedby": describedBy,
5841
6422
  "aria-invalid": Boolean(error),
5842
6423
  "aria-required": field.required,
@@ -5847,7 +6428,7 @@ function ChoiceField({
5847
6428
  "input",
5848
6429
  {
5849
6430
  type: multiple ? "checkbox" : "radio",
5850
- name: id,
6431
+ name: id2,
5851
6432
  value: String(index),
5852
6433
  checked,
5853
6434
  disabled,
@@ -5875,22 +6456,22 @@ function ToolField({
5875
6456
  disabled,
5876
6457
  error,
5877
6458
  field,
5878
- id,
6459
+ id: id2,
5879
6460
  value,
5880
6461
  onBlur,
5881
6462
  onChange
5882
6463
  }) {
5883
6464
  const describedBy = [
5884
- field.description ? `${id}-description` : "",
5885
- error ? `${id}-error` : ""
6465
+ field.description ? `${id2}-description` : "",
6466
+ error ? `${id2}-error` : ""
5886
6467
  ].filter(Boolean).join(" ");
5887
6468
  if (field.kind === "checkbox" || field.kind === "confirmation") {
5888
6469
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "tool-input-card__field", children: [
5889
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "tool-input-card__check", htmlFor: id, children: [
6470
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "tool-input-card__check", htmlFor: id2, children: [
5890
6471
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5891
6472
  "input",
5892
6473
  {
5893
- id,
6474
+ id: id2,
5894
6475
  type: "checkbox",
5895
6476
  checked: value === true,
5896
6477
  disabled,
@@ -5902,18 +6483,18 @@ function ToolField({
5902
6483
  ),
5903
6484
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
5904
6485
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: field.label }),
5905
- field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id}-description`, children: field.description }) : null
6486
+ field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id2}-description`, children: field.description }) : null
5906
6487
  ] })
5907
6488
  ] }),
5908
- error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id}-error`, className: "tool-input-card__error", children: error }) : null
6489
+ error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id2}-error`, className: "tool-input-card__error", children: error }) : null
5909
6490
  ] });
5910
6491
  }
5911
- const label = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { id: `${id}-label`, htmlFor: id, children: [
6492
+ const label = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { id: `${id2}-label`, htmlFor: id2, children: [
5912
6493
  field.label,
5913
6494
  field.required ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { "aria-hidden": "true", children: " *" }) : null
5914
6495
  ] });
5915
6496
  const common = {
5916
- id,
6497
+ id: id2,
5917
6498
  disabled,
5918
6499
  required: field.required,
5919
6500
  "aria-describedby": describedBy || void 0,
@@ -5926,7 +6507,7 @@ function ToolField({
5926
6507
  ChoiceField,
5927
6508
  {
5928
6509
  field,
5929
- id,
6510
+ id: id2,
5930
6511
  value,
5931
6512
  disabled,
5932
6513
  describedBy: describedBy || void 0,
@@ -5963,7 +6544,7 @@ function ToolField({
5963
6544
  onChange: (event) => onChange(Number(event.target.value))
5964
6545
  }
5965
6546
  ),
5966
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("output", { htmlFor: id, children: numericValue })
6547
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("output", { htmlFor: id2, children: numericValue })
5967
6548
  ] });
5968
6549
  } else {
5969
6550
  const type = field.kind === "date-time" ? "datetime-local" : field.kind === "calendar" ? "date" : field.kind;
@@ -5987,9 +6568,9 @@ function ToolField({
5987
6568
  }
5988
6569
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "tool-input-card__field", children: [
5989
6570
  label,
5990
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldDescription, { field, id: `${id}-description` }),
6571
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldDescription, { field, id: `${id2}-description` }),
5991
6572
  control,
5992
- error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id}-error`, className: "tool-input-card__error", children: error }) : null
6573
+ error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id2}-error`, className: "tool-input-card__error", children: error }) : null
5993
6574
  ] });
5994
6575
  }
5995
6576
  function ToolInputCard({
@@ -5997,11 +6578,11 @@ function ToolInputCard({
5997
6578
  surface,
5998
6579
  onSubmit
5999
6580
  }) {
6000
- const [values, setValues] = (0, import_react12.useState)(
6581
+ const [values, setValues] = (0, import_react13.useState)(
6001
6582
  () => initialValues(surface)
6002
6583
  );
6003
- const [touched, setTouched] = (0, import_react12.useState)(() => /* @__PURE__ */ new Set());
6004
- const [submitted, setSubmitted] = (0, import_react12.useState)(false);
6584
+ const [touched, setTouched] = (0, import_react13.useState)(() => /* @__PURE__ */ new Set());
6585
+ const [submitted, setSubmitted] = (0, import_react13.useState)(false);
6005
6586
  const errors = Object.fromEntries(
6006
6587
  surface.fields.map((field) => [
6007
6588
  field.path,
@@ -6094,7 +6675,7 @@ function HumanInputCard({
6094
6675
  request,
6095
6676
  onRespond
6096
6677
  }) {
6097
- const [text2, setText] = (0, import_react13.useState)("");
6678
+ const [text3, setText] = (0, import_react14.useState)("");
6098
6679
  const options = request.options ?? [];
6099
6680
  const showText = request.display === "text" || request.allowFreeform && options.length === 0;
6100
6681
  if (request.ui) {
@@ -6119,7 +6700,7 @@ function HumanInputCard({
6119
6700
  }
6120
6701
  function submitText(event) {
6121
6702
  event.preventDefault();
6122
- const value = text2.trim();
6703
+ const value = text3.trim();
6123
6704
  if (!value || disabled) return;
6124
6705
  onRespond?.({ requestId: request.requestId, text: value });
6125
6706
  }
@@ -6137,12 +6718,12 @@ function HumanInputCard({
6137
6718
  "input",
6138
6719
  {
6139
6720
  id: `human-input-text-${request.requestId}`,
6140
- value: text2,
6721
+ value: text3,
6141
6722
  disabled,
6142
6723
  onChange: (event) => setText(event.target.value)
6143
6724
  }
6144
6725
  ),
6145
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", disabled: disabled || !text2.trim(), children: "Send" })
6726
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", disabled: disabled || !text3.trim(), children: "Send" })
6146
6727
  ] })
6147
6728
  ] }) : null,
6148
6729
  !showText && options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "human-input-card__unavailable", role: "status", children: "This request can\u2019t be answered here." }) : null
@@ -6151,31 +6732,173 @@ function HumanInputCard({
6151
6732
  );
6152
6733
  }
6153
6734
 
6154
- // src/react/components/CollectionResultCard/CollectionResultCard.tsx
6735
+ // src/react/components/LocationConsent/LocationConsent.tsx
6736
+ var import_react15 = require("react");
6737
+
6738
+ // src/runtime/location-consent.ts
6739
+ function isLocationConsentRequest(request) {
6740
+ return request.kind === "tool-approval" && request.action.toolName === "request_location";
6741
+ }
6742
+ function preciseLocationResponse(requestId, position) {
6743
+ const { latitude, longitude, accuracy } = position.coords;
6744
+ if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90 || !Number.isFinite(longitude) || longitude < -180 || longitude > 180 || !Number.isFinite(accuracy) || accuracy < 0 || !Number.isFinite(position.timestamp)) {
6745
+ throw new Error("Your device returned an invalid location.");
6746
+ }
6747
+ return {
6748
+ requestId,
6749
+ optionId: "approve",
6750
+ text: JSON.stringify({
6751
+ status: "shared",
6752
+ location: {
6753
+ source: "device",
6754
+ latitude,
6755
+ longitude,
6756
+ accuracyMeters: accuracy,
6757
+ capturedAt: new Date(position.timestamp).toISOString(),
6758
+ consentedAt: (/* @__PURE__ */ new Date()).toISOString(),
6759
+ scope: "conversation"
6760
+ }
6761
+ })
6762
+ };
6763
+ }
6764
+ function getPreciseLocation(geolocation) {
6765
+ return new Promise(
6766
+ (resolve, reject) => geolocation.getCurrentPosition(
6767
+ resolve,
6768
+ (error) => reject(
6769
+ new Error(
6770
+ error.code === 1 ? "Location access is blocked. Allow it in your browser, or continue without sharing." : "Your location couldn\u2019t be found. Try again or continue without sharing."
6771
+ )
6772
+ ),
6773
+ { enableHighAccuracy: true, maximumAge: 0, timeout: 1e4 }
6774
+ )
6775
+ );
6776
+ }
6777
+
6778
+ // src/react/components/LocationConsent/LocationConsent.tsx
6155
6779
  var import_jsx_runtime12 = require("react/jsx-runtime");
6780
+ function LocationConsent({
6781
+ request,
6782
+ onRespond
6783
+ }) {
6784
+ const [preference, setPreference] = (0, import_react15.useState)("unset");
6785
+ const [locating, setLocating] = (0, import_react15.useState)(false);
6786
+ const [error, setError] = (0, import_react15.useState)(null);
6787
+ const respond = (0, import_react15.useRef)(onRespond);
6788
+ const answered = (0, import_react15.useRef)(null);
6789
+ const requestId = request?.requestId;
6790
+ (0, import_react15.useEffect)(() => {
6791
+ respond.current = onRespond;
6792
+ }, [onRespond]);
6793
+ (0, import_react15.useEffect)(() => {
6794
+ if (!requestId || preference === "unset" || answered.current === requestId || !respond.current)
6795
+ return;
6796
+ if (preference === "off") {
6797
+ setLocating(false);
6798
+ answered.current = requestId;
6799
+ respond.current({
6800
+ requestId,
6801
+ optionId: "approve",
6802
+ text: JSON.stringify({ status: "declined" })
6803
+ });
6804
+ return;
6805
+ }
6806
+ let cancelled = false;
6807
+ const pendingId = requestId;
6808
+ setLocating(true);
6809
+ setError(null);
6810
+ async function locate() {
6811
+ try {
6812
+ if (!Reflect.has(navigator, "geolocation"))
6813
+ throw new Error("Location sharing isn\u2019t available in this browser.");
6814
+ const position = await getPreciseLocation(navigator.geolocation);
6815
+ if (cancelled) return;
6816
+ const response = preciseLocationResponse(pendingId, position);
6817
+ answered.current = pendingId;
6818
+ respond.current?.(response);
6819
+ } catch (failure) {
6820
+ if (cancelled) return;
6821
+ setPreference("unset");
6822
+ setError(
6823
+ failure instanceof Error ? failure.message : "Location sharing failed. Try again or continue without sharing."
6824
+ );
6825
+ } finally {
6826
+ if (!cancelled) setLocating(false);
6827
+ }
6828
+ }
6829
+ void locate();
6830
+ return () => {
6831
+ cancelled = true;
6832
+ };
6833
+ }, [requestId, preference]);
6834
+ const isLocating = Boolean(requestId) && preference === "on" && locating;
6835
+ if (!request && preference === "unset") return null;
6836
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: "location-consent", "aria-label": "Location sharing", children: [
6837
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "location-consent__copy", children: [
6838
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: isLocating ? "Getting your location\u2026" : request ? "Get better results" : "Precise location" }),
6839
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: isLocating ? "Allow location access in your browser." : request ? "Share your precise location" : preference === "on" ? "On for location-aware answers" : "Off for this chat" })
6840
+ ] }),
6841
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "location-consent__actions", children: [
6842
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6843
+ "button",
6844
+ {
6845
+ type: "button",
6846
+ role: "switch",
6847
+ className: "location-consent__toggle",
6848
+ "aria-label": "Share precise location",
6849
+ "aria-checked": preference === "on",
6850
+ "aria-busy": isLocating,
6851
+ disabled: !onRespond,
6852
+ onClick: () => {
6853
+ setError(null);
6854
+ setPreference(preference === "on" ? "off" : "on");
6855
+ },
6856
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", {})
6857
+ }
6858
+ ),
6859
+ request && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6860
+ "button",
6861
+ {
6862
+ type: "button",
6863
+ className: "location-consent__decline",
6864
+ disabled: !onRespond,
6865
+ onClick: () => {
6866
+ setError(null);
6867
+ setPreference("off");
6868
+ },
6869
+ children: "No thanks"
6870
+ }
6871
+ )
6872
+ ] }),
6873
+ error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { role: "alert", className: "location-consent__error", children: error })
6874
+ ] });
6875
+ }
6876
+
6877
+ // src/react/components/CollectionResultCard/CollectionResultCard.tsx
6878
+ var import_jsx_runtime13 = require("react/jsx-runtime");
6156
6879
  function CollectionResultCard({
6157
6880
  result
6158
6881
  }) {
6159
6882
  const empty = result.items.length === 0;
6160
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
6883
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
6161
6884
  "section",
6162
6885
  {
6163
6886
  className: `collection-result-card tool-result-card tool-result-card--${result.status}`,
6164
6887
  "aria-label": result.title,
6165
6888
  role: result.status === "completed" ? "status" : "alert",
6166
6889
  children: [
6167
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "tool-result-card__heading", children: [
6168
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
6169
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: result.title })
6890
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "tool-result-card__heading", children: [
6891
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
6892
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
6170
6893
  ] }),
6171
- empty ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "collection-result-card__empty", children: "No matching record for the email you shared." }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className: "collection-result-card__list", children: result.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("li", { children: [
6172
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "collection-result-card__item-title", children: item.title }),
6173
- item.description ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { children: item.description }) : null,
6174
- item.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dl", { children: item.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
6175
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dt", { children: detail.label }),
6176
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dd", { children: detail.value })
6894
+ empty ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "collection-result-card__empty", children: "No matching record for the email you shared." }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("ul", { className: "collection-result-card__list", children: result.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("li", { children: [
6895
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "collection-result-card__item-title", children: item.title }),
6896
+ item.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: item.description }) : null,
6897
+ item.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: item.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
6898
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
6899
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
6177
6900
  ] }, `${detail.label}:${detail.value}`)) }) : null,
6178
- item.href ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: item.href, target: "_blank", rel: "noreferrer", children: "Open record" }) : null
6901
+ item.href ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("a", { href: item.href, target: "_blank", rel: "noreferrer", children: "Open record" }) : null
6179
6902
  ] }, item.title)) })
6180
6903
  ]
6181
6904
  }
@@ -6183,23 +6906,23 @@ function CollectionResultCard({
6183
6906
  }
6184
6907
 
6185
6908
  // src/react/components/EntityResultCard/EntityResultCard.tsx
6186
- var import_jsx_runtime13 = require("react/jsx-runtime");
6909
+ var import_jsx_runtime14 = require("react/jsx-runtime");
6187
6910
  function EntityResultCard({
6188
6911
  result
6189
6912
  }) {
6190
6913
  const compact = !result.description && !result.details?.length && !result.links?.length;
6191
6914
  const collapsible = result.status === "completed" && Boolean(result.details?.length) && !result.links?.length;
6192
- const heading = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "tool-result-card__heading", children: [
6193
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
6194
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
6915
+ const heading = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "tool-result-card__heading", children: [
6916
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
6917
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: result.title })
6195
6918
  ] });
6196
- const content = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
6197
- result.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: result.description }) : null,
6198
- result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
6199
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
6200
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
6919
+ const content = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
6920
+ result.description ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { children: result.description }) : null,
6921
+ result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
6922
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { children: detail.label }),
6923
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { children: detail.value })
6201
6924
  ] }, `${detail.label}:${detail.value}`)) }) : null,
6202
- result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
6925
+ result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
6203
6926
  "a",
6204
6927
  {
6205
6928
  href: link.href,
@@ -6211,12 +6934,12 @@ function EntityResultCard({
6211
6934
  )) }) : null
6212
6935
  ] });
6213
6936
  if (collapsible) {
6214
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("details", { className: "entity-result-card tool-result-card entity-result-card--disclosure", children: [
6215
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("summary", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { role: "status", children: heading }) }),
6937
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("details", { className: "entity-result-card tool-result-card entity-result-card--disclosure", children: [
6938
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("summary", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { role: "status", children: heading }) }),
6216
6939
  content
6217
6940
  ] });
6218
6941
  }
6219
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
6942
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
6220
6943
  "section",
6221
6944
  {
6222
6945
  className: `entity-result-card tool-result-card tool-result-card--${result.status}${compact ? " entity-result-card--compact" : ""}`,
@@ -6231,24 +6954,24 @@ function EntityResultCard({
6231
6954
  }
6232
6955
 
6233
6956
  // src/react/components/SignatureResultCard/SignatureResultCard.tsx
6234
- var import_jsx_runtime14 = require("react/jsx-runtime");
6957
+ var import_jsx_runtime15 = require("react/jsx-runtime");
6235
6958
  function SignatureResultCard({
6236
6959
  result
6237
6960
  }) {
6238
6961
  const primaryLink = result.links?.[0];
6239
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
6962
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
6240
6963
  "section",
6241
6964
  {
6242
6965
  className: `signature-result-card tool-result-card tool-result-card--${result.status}`,
6243
6966
  "aria-label": result.title,
6244
6967
  children: [
6245
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "tool-result-card__heading", children: [
6246
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
6247
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: result.title })
6968
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tool-result-card__heading", children: [
6969
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
6970
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: result.title })
6248
6971
  ] }),
6249
- result.statusLabel ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "signature-result-card__badge", children: result.statusLabel }) : null,
6250
- result.description ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { children: result.description }) : null,
6251
- primaryLink ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
6972
+ result.statusLabel ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "signature-result-card__badge", children: result.statusLabel }) : null,
6973
+ result.description ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: result.description }) : null,
6974
+ primaryLink ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6252
6975
  "a",
6253
6976
  {
6254
6977
  className: "signature-result-card__cta",
@@ -6264,27 +6987,27 @@ function SignatureResultCard({
6264
6987
  }
6265
6988
 
6266
6989
  // src/react/components/ToolResultCard/ToolResultCard.tsx
6267
- var import_jsx_runtime15 = require("react/jsx-runtime");
6990
+ var import_jsx_runtime16 = require("react/jsx-runtime");
6268
6991
  function ToolResultCard({
6269
6992
  result
6270
6993
  }) {
6271
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
6994
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
6272
6995
  "section",
6273
6996
  {
6274
6997
  className: `tool-result-card tool-result-card--${result.status}`,
6275
6998
  "aria-label": result.title,
6276
6999
  role: result.status === "completed" ? "status" : "alert",
6277
7000
  children: [
6278
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tool-result-card__heading", children: [
6279
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
6280
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: result.title })
7001
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "tool-result-card__heading", children: [
7002
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
7003
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: result.title })
6281
7004
  ] }),
6282
- result.description ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: result.description }) : null,
6283
- result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
6284
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: detail.label }),
6285
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: detail.value })
7005
+ result.description ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: result.description }) : null,
7006
+ result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
7007
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { children: detail.label }),
7008
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { children: detail.value })
6286
7009
  ] }, `${detail.label}:${detail.value}`)) }) : null,
6287
- result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7010
+ result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6288
7011
  "a",
6289
7012
  {
6290
7013
  href: link.href,
@@ -6300,14 +7023,14 @@ function ToolResultCard({
6300
7023
  }
6301
7024
 
6302
7025
  // src/react/components/VisitorToolResultView/VisitorToolResultView.tsx
6303
- var import_jsx_runtime16 = require("react/jsx-runtime");
7026
+ var import_jsx_runtime17 = require("react/jsx-runtime");
6304
7027
  function VisitorToolResultView({
6305
7028
  disabled = false,
6306
7029
  onToolInput,
6307
7030
  result
6308
7031
  }) {
6309
7032
  if (result.kind === "input") {
6310
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7033
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6311
7034
  ToolInputCard,
6312
7035
  {
6313
7036
  disabled,
@@ -6317,16 +7040,16 @@ function VisitorToolResultView({
6317
7040
  );
6318
7041
  }
6319
7042
  if (result.kind === "entity") {
6320
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(EntityResultCard, { result });
7043
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(EntityResultCard, { result });
6321
7044
  }
6322
7045
  if (result.kind === "collection") {
6323
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CollectionResultCard, { result });
7046
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CollectionResultCard, { result });
6324
7047
  }
6325
7048
  if (result.kind === "signature") {
6326
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SignatureResultCard, { result });
7049
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SignatureResultCard, { result });
6327
7050
  }
6328
7051
  if (result.kind === "summary") {
6329
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolResultCard, { result });
7052
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ToolResultCard, { result });
6330
7053
  }
6331
7054
  return null;
6332
7055
  }
@@ -6335,9 +7058,9 @@ function isRenderableVisitorToolResult(result) {
6335
7058
  }
6336
7059
 
6337
7060
  // src/react/components/AgentRail/AgentRail.tsx
6338
- var import_jsx_runtime17 = require("react/jsx-runtime");
7061
+ var import_jsx_runtime18 = require("react/jsx-runtime");
6339
7062
  function MinimizeIcon() {
6340
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7063
+ 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)(
6341
7064
  "path",
6342
7065
  {
6343
7066
  d: "M3.5 8h9",
@@ -6348,7 +7071,7 @@ function MinimizeIcon() {
6348
7071
  ) });
6349
7072
  }
6350
7073
  function CloseIcon2() {
6351
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7074
+ 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)(
6352
7075
  "path",
6353
7076
  {
6354
7077
  d: "M4 4l8 8M12 4l-8 8",
@@ -6359,7 +7082,7 @@ function CloseIcon2() {
6359
7082
  ) });
6360
7083
  }
6361
7084
  function NewChatIcon() {
6362
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7085
+ 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)(
6363
7086
  "path",
6364
7087
  {
6365
7088
  d: "M9.5 3.5h3v3M12.25 3.75 8 8M7 4H4.5A1.5 1.5 0 0 0 3 5.5v6A1.5 1.5 0 0 0 4.5 13h6a1.5 1.5 0 0 0 1.5-1.5V9",
@@ -6371,7 +7094,7 @@ function NewChatIcon() {
6371
7094
  ) });
6372
7095
  }
6373
7096
  function ExpandIcon() {
6374
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7097
+ 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)(
6375
7098
  "path",
6376
7099
  {
6377
7100
  d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
@@ -6383,7 +7106,7 @@ function ExpandIcon() {
6383
7106
  ) });
6384
7107
  }
6385
7108
  function RestoreIcon() {
6386
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7109
+ 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)(
6387
7110
  "path",
6388
7111
  {
6389
7112
  d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
@@ -6395,7 +7118,7 @@ function RestoreIcon() {
6395
7118
  ) });
6396
7119
  }
6397
7120
  function ChevronDownIcon() {
6398
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7121
+ 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)(
6399
7122
  "path",
6400
7123
  {
6401
7124
  d: "M4 6.5l4 4 4-4",
@@ -6409,6 +7132,7 @@ function ChevronDownIcon() {
6409
7132
  var DEFAULT_DISCLAIMER_LABEL = "Agent can make mistakes. Check important info.";
6410
7133
  function AgentRail({
6411
7134
  state,
7135
+ handoff,
6412
7136
  theme,
6413
7137
  colorScheme = "auto",
6414
7138
  brandLabel = "",
@@ -6434,43 +7158,51 @@ function AgentRail({
6434
7158
  onInputResponse,
6435
7159
  onToolInput
6436
7160
  }) {
6437
- const railRef = (0, import_react14.useRef)(null);
6438
- const overlayRef = (0, import_react14.useRef)(null);
6439
- const transcriptRef = (0, import_react14.useRef)(null);
6440
- const responseRef = (0, import_react14.useRef)(null);
6441
- const threadRef = (0, import_react14.useRef)(null);
6442
- const lastScrolledVisitorIdRef = (0, import_react14.useRef)(void 0);
6443
- const pinnedToBottomRef = (0, import_react14.useRef)(true);
6444
- const smoothScrollToLatestRef = (0, import_react14.useRef)(false);
6445
- const lockedTranscriptScrollTopRef = (0, import_react14.useRef)(null);
6446
- const [showJumpToLatest, setShowJumpToLatest] = (0, import_react14.useState)(false);
6447
- const [receiptOpen, setReceiptOpen] = (0, import_react14.useState)(false);
7161
+ const railRef = (0, import_react16.useRef)(null);
7162
+ const overlayRef = (0, import_react16.useRef)(null);
7163
+ const transcriptRef = (0, import_react16.useRef)(null);
7164
+ const responseRef = (0, import_react16.useRef)(null);
7165
+ const threadRef = (0, import_react16.useRef)(null);
7166
+ const lastScrolledVisitorIdRef = (0, import_react16.useRef)(void 0);
7167
+ const pinnedToBottomRef = (0, import_react16.useRef)(true);
7168
+ const smoothScrollToLatestRef = (0, import_react16.useRef)(false);
7169
+ const lockedTranscriptScrollTopRef = (0, import_react16.useRef)(null);
7170
+ const [showJumpToLatest, setShowJumpToLatest] = (0, import_react16.useState)(false);
7171
+ const [receiptOpen, setReceiptOpen] = (0, import_react16.useState)(false);
6448
7172
  const resolvedBrandLabel = brandLabel.trim();
6449
7173
  const resolvedBrandLogoUrl = brandLogoUrl?.trim();
6450
7174
  const resolvedDisclaimerLabel = disclaimerLabel === void 0 ? DEFAULT_DISCLAIMER_LABEL : disclaimerLabel;
6451
- const [failedLogoUrl, setFailedLogoUrl] = (0, import_react14.useState)(null);
7175
+ const [failedLogoUrl, setFailedLogoUrl] = (0, import_react16.useState)(null);
6452
7176
  const showBrandLogo = Boolean(resolvedBrandLogoUrl) && failedLogoUrl !== resolvedBrandLogoUrl;
6453
7177
  const resolvedColorScheme = useAgentColorScheme(colorScheme);
6454
7178
  const railStyle = agentThemeStyle(theme, resolvedColorScheme);
7179
+ const handoffActive = Boolean(handoff?.blocksAI);
7180
+ const handoffStatus = handoff?.page?.status;
7181
+ const locationRequest = handoffActive ? void 0 : state.pendingInputs?.find(isLocationConsentRequest);
6455
7182
  const pendingInputRequests = (state.pendingInputs ?? []).filter(
6456
- (request) => shouldRenderVisitorInputCard(request) && (!state.pendingOffer || request.kind === "tool-approval")
7183
+ (request) => !handoffActive && !isLocationConsentRequest(request) && shouldRenderVisitorInputCard(request) && (!state.pendingOffer || request.kind === "tool-approval")
6457
7184
  );
6458
- const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming" || state.phase === "waiting-input" && pendingInputRequests.length > 0;
6459
- const semanticSurfaceDisabled = isBusy && state.phase !== "waiting-input";
7185
+ const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming" || state.phase === "waiting-input" && (pendingInputRequests.length > 0 || Boolean(locationRequest));
7186
+ const semanticSurfaceDisabled = handoffActive || isBusy && state.phase !== "waiting-input";
6460
7187
  const visitorToolResults = (state.toolResults ?? []).filter(
6461
7188
  isRenderableVisitorToolResult
6462
7189
  );
6463
7190
  const activeVisitorToolInput = [...visitorToolResults].reverse().find((result) => result.kind === "input");
6464
7191
  const visibleVisitorToolResults = activeVisitorToolInput ? [activeVisitorToolInput] : visitorToolResults;
6465
- const activityActive = state.toolSteps.some((step) => step.state === "active");
7192
+ const activityActive = state.toolSteps.some(
7193
+ (step) => step.state === "active"
7194
+ );
6466
7195
  const showActivity = state.toolSteps.length > 0 && pendingInputRequests.length === 0 && !state.pendingOffer && (activityActive || isBusy && !state.streamingText);
6467
- const activitySteps = activityActive || !isBusy || state.streamingText ? state.toolSteps : [...state.toolSteps, {
6468
- id: "preparing-answer",
6469
- kind: "tool",
6470
- label: "Preparing your answer",
6471
- detail: "Preparing your answer",
6472
- state: "active"
6473
- }];
7196
+ const activitySteps = activityActive || !isBusy || state.streamingText ? state.toolSteps : [
7197
+ ...state.toolSteps,
7198
+ {
7199
+ id: "preparing-answer",
7200
+ kind: "tool",
7201
+ label: "Preparing your answer",
7202
+ detail: "Preparing your answer",
7203
+ state: "active"
7204
+ }
7205
+ ];
6474
7206
  const hasVisitorMessages2 = state.messages.some(
6475
7207
  (message) => message.role === "visitor"
6476
7208
  );
@@ -6499,7 +7231,7 @@ function AgentRail({
6499
7231
  }
6500
7232
  }
6501
7233
  const lastIsAgent = lastMessage?.role === "agent";
6502
- const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
7234
+ const showMessageActions = !handoffActive && state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
6503
7235
  const streamingMessage = state.streamingText && !lastIsAgent ? {
6504
7236
  createdAt: 0,
6505
7237
  id: "streaming-response",
@@ -6541,7 +7273,7 @@ function AgentRail({
6541
7273
  ...visibleVisitorToolResults
6542
7274
  ].reverse().find((result) => result.kind !== "input")?.id;
6543
7275
  const receiptSteps = answerReceipt && state.toolSteps.length > 0 ? state.toolSteps : void 0;
6544
- (0, import_react14.useEffect)(() => {
7276
+ (0, import_react16.useEffect)(() => {
6545
7277
  if (state.phase !== "complete") {
6546
7278
  setReceiptOpen(false);
6547
7279
  }
@@ -6563,7 +7295,7 @@ function AgentRail({
6563
7295
  onFollowUpSelect?.(label);
6564
7296
  }
6565
7297
  const latestVisitorId = visibleMessages[lastVisitorIndex]?.id;
6566
- (0, import_react14.useEffect)(() => {
7298
+ (0, import_react16.useEffect)(() => {
6567
7299
  const node = transcriptRef.current;
6568
7300
  if (!node) return;
6569
7301
  if (latestVisitorId !== lastScrolledVisitorIdRef.current) {
@@ -6593,7 +7325,7 @@ function AgentRail({
6593
7325
  state.followUps,
6594
7326
  state.journey
6595
7327
  ]);
6596
- (0, import_react14.useEffect)(() => {
7328
+ (0, import_react16.useEffect)(() => {
6597
7329
  const node = transcriptRef.current;
6598
7330
  if (!node) return;
6599
7331
  const handleScroll = () => {
@@ -6607,7 +7339,7 @@ function AgentRail({
6607
7339
  handleScroll();
6608
7340
  return () => node.removeEventListener("scroll", handleScroll);
6609
7341
  }, []);
6610
- (0, import_react14.useEffect)(() => {
7342
+ (0, import_react16.useEffect)(() => {
6611
7343
  if (!receiptOpen) {
6612
7344
  lockedTranscriptScrollTopRef.current = null;
6613
7345
  return;
@@ -6645,7 +7377,7 @@ function AgentRail({
6645
7377
  window.setTimeout(settle, 900);
6646
7378
  node.scrollTo({ top: node.scrollHeight, behavior: "smooth" });
6647
7379
  }
6648
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7380
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6649
7381
  "aside",
6650
7382
  {
6651
7383
  ref: railRef,
@@ -6659,244 +7391,305 @@ function AgentRail({
6659
7391
  autoFocus: mobileFullscreen || expanded,
6660
7392
  role: mobileFullscreen || expanded ? "dialog" : void 0,
6661
7393
  tabIndex: mobileFullscreen || expanded ? -1 : void 0,
6662
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6663
- AgentRailOverlayContext.Provider,
6664
- {
6665
- value: { railRef, overlayRef },
6666
- children: [
6667
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "agent-rail__surface", inert: receiptOpen || void 0, children: [
6668
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "agent-rail__brand-row", children: [
6669
- onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6670
- "button",
6671
- {
6672
- type: "button",
6673
- className: "agent-rail__collapse",
6674
- "aria-label": "Collapse assist",
6675
- onClick: onCollapse,
6676
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MinimizeIcon, {})
6677
- }
6678
- ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6679
- "button",
6680
- {
6681
- type: "button",
6682
- className: "agent-rail__close",
6683
- "aria-label": "Close agent",
6684
- onClick: onClose,
6685
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CloseIcon2, {})
7394
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(AgentRailOverlayContext.Provider, { value: { railRef, overlayRef }, children: [
7395
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__surface", inert: receiptOpen || void 0, children: [
7396
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__brand-row", children: [
7397
+ onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7398
+ "button",
7399
+ {
7400
+ type: "button",
7401
+ className: "agent-rail__collapse",
7402
+ "aria-label": "Collapse assist",
7403
+ onClick: onCollapse,
7404
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MinimizeIcon, {})
7405
+ }
7406
+ ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7407
+ "button",
7408
+ {
7409
+ type: "button",
7410
+ className: "agent-rail__close",
7411
+ "aria-label": "Close agent",
7412
+ onClick: onClose,
7413
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CloseIcon2, {})
7414
+ }
7415
+ ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
7416
+ resolvedBrandLabel || showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "agent-rail__identity", children: [
7417
+ showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7418
+ "img",
7419
+ {
7420
+ className: "agent-rail__brand-logo",
7421
+ src: resolvedBrandLogoUrl,
7422
+ alt: "",
7423
+ onError: () => {
7424
+ setFailedLogoUrl(resolvedBrandLogoUrl ?? null);
6686
7425
  }
6687
- ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
6688
- resolvedBrandLabel || showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "agent-rail__identity", children: [
6689
- showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6690
- "img",
6691
- {
6692
- className: "agent-rail__brand-logo",
6693
- src: resolvedBrandLogoUrl,
6694
- alt: "",
6695
- onError: () => {
6696
- setFailedLogoUrl(resolvedBrandLogoUrl ?? null);
6697
- }
6698
- }
6699
- ) }) : null,
6700
- resolvedBrandLabel ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "agent-rail__brand-label", children: resolvedBrandLabel }) : null
6701
- ] }) : null,
6702
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "agent-rail__actions", children: [
6703
- onReset ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6704
- "button",
6705
- {
6706
- type: "button",
6707
- className: "agent-rail__new-chat",
6708
- "aria-label": "Start a new conversation",
6709
- disabled: !hasVisitorMessages2,
6710
- onClick: handleReset,
6711
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NewChatIcon, {})
6712
- }
6713
- ) : null,
6714
- onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6715
- "button",
7426
+ }
7427
+ ) }) : null,
7428
+ resolvedBrandLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-rail__brand-label", children: resolvedBrandLabel }) : null
7429
+ ] }) : null,
7430
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "agent-rail__actions", children: [
7431
+ onReset ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7432
+ "button",
7433
+ {
7434
+ type: "button",
7435
+ className: "agent-rail__new-chat",
7436
+ "aria-label": "Start a new conversation",
7437
+ disabled: !hasVisitorMessages2 || handoffActive && !handoff?.canReset,
7438
+ onClick: handleReset,
7439
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NewChatIcon, {})
7440
+ }
7441
+ ) : null,
7442
+ onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7443
+ "button",
7444
+ {
7445
+ type: "button",
7446
+ className: "agent-rail__expand",
7447
+ "aria-label": expanded ? "Exit full screen" : "Open full screen",
7448
+ onClick: onExpandToggle,
7449
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ExpandIcon, {})
7450
+ }
7451
+ ) : null
7452
+ ] })
7453
+ ] }) }),
7454
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: threadRef, className: "agent-rail__thread", children: [
7455
+ !hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
7456
+ greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7457
+ MessageBubble,
7458
+ {
7459
+ showProvenance: Boolean(
7460
+ handoff?.page?.enabled || handoffActive
7461
+ ),
7462
+ message: greeting,
7463
+ bookingDisabled: isBusy || handoffActive,
7464
+ brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
7465
+ onBook
7466
+ }
7467
+ ) : null,
7468
+ showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7469
+ FollowUpChips,
7470
+ {
7471
+ suggestions: state.followUps,
7472
+ disabled: isBusy || handoffActive,
7473
+ label: "Start here",
7474
+ onSelect: (suggestion) => handleFollowUpSelect(suggestion.label)
7475
+ }
7476
+ ) }) : null,
7477
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7478
+ AgentActivityBubble,
7479
+ {
7480
+ brandLabel: resolvedBrandLabel,
7481
+ brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
7482
+ failed: state.phase === "error",
7483
+ steps: activitySteps
7484
+ }
7485
+ ) : null,
7486
+ visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7487
+ VisitorToolResultView,
7488
+ {
7489
+ result,
7490
+ disabled: semanticSurfaceDisabled,
7491
+ onToolInput
7492
+ },
7493
+ result.id
7494
+ )),
7495
+ pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7496
+ HumanInputCard,
7497
+ {
7498
+ request,
7499
+ onRespond: onInputResponse
7500
+ },
7501
+ request.requestId
7502
+ ))
7503
+ ] }) : null,
7504
+ transcriptMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
7505
+ "div",
7506
+ {
7507
+ ref: index === lastVisitorIndex + 1 ? responseRef : void 0,
7508
+ className: "agent-rail__turn-block",
7509
+ children: [
7510
+ message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7511
+ VisitorToolResultView,
6716
7512
  {
6717
- type: "button",
6718
- className: "agent-rail__expand",
6719
- "aria-label": expanded ? "Exit full screen" : "Open full screen",
6720
- onClick: onExpandToggle,
6721
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ExpandIcon, {})
6722
- }
6723
- ) : null
6724
- ] })
6725
- ] }) }),
6726
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: threadRef, className: "agent-rail__thread", children: [
6727
- !hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
6728
- greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7513
+ result
7514
+ },
7515
+ result.id
7516
+ )) : null,
7517
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6729
7518
  MessageBubble,
6730
7519
  {
6731
- message: greeting,
6732
- bookingDisabled: isBusy,
7520
+ showProvenance: Boolean(
7521
+ handoff?.page?.enabled || handoffActive
7522
+ ),
7523
+ message,
7524
+ bookingDisabled: isBusy || handoffActive,
6733
7525
  brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
7526
+ offer: index === transcriptMessages.length - 1 ? state.pendingOffer : void 0,
6734
7527
  onBook
6735
7528
  }
6736
- ) : null,
6737
- showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6738
- FollowUpChips,
7529
+ ),
7530
+ index === lastAgentIndex && showMessageActions && message.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7531
+ MessageActions,
6739
7532
  {
6740
- suggestions: state.followUps,
6741
- disabled: isBusy,
6742
- label: "Start here",
6743
- onSelect: (suggestion) => handleFollowUpSelect(suggestion.label)
6744
- }
6745
- ) }) : null,
6746
- showActivity ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6747
- AgentActivityBubble,
6748
- {
6749
- brandLabel: resolvedBrandLabel,
6750
- brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
6751
- failed: state.phase === "error",
6752
- steps: activitySteps
7533
+ answeredAt: message.createdAt,
7534
+ copyText: hideToolCardFences(message.text).trim() || message.text,
7535
+ readAloud,
7536
+ receiptSteps,
7537
+ onOpenReceipt: receiptSteps ? openReceipt : void 0,
7538
+ onRegenerate: onRegenerate ? handleRegenerate : void 0,
7539
+ onFeedback: onFeedback ? (rating) => onFeedback(rating, message) : void 0
6753
7540
  }
6754
7541
  ) : null,
6755
- visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6756
- VisitorToolResultView,
6757
- {
6758
- result,
6759
- disabled: semanticSurfaceDisabled,
6760
- onToolInput
6761
- },
6762
- result.id
6763
- )),
6764
- pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6765
- HumanInputCard,
6766
- {
6767
- request,
6768
- onRespond: onInputResponse
6769
- },
6770
- request.requestId
6771
- ))
6772
- ] }) : null,
6773
- transcriptMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6774
- "div",
6775
- {
6776
- ref: index === lastVisitorIndex + 1 ? responseRef : void 0,
6777
- className: "agent-rail__turn-block",
6778
- children: [
6779
- message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VisitorToolResultView, { result }, result.id)) : null,
6780
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6781
- MessageBubble,
6782
- {
6783
- message,
6784
- bookingDisabled: isBusy,
6785
- brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
6786
- offer: index === transcriptMessages.length - 1 ? state.pendingOffer : void 0,
6787
- onBook
6788
- }
6789
- ),
6790
- index === lastAgentIndex && showMessageActions && message.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6791
- MessageActions,
6792
- {
6793
- answeredAt: message.createdAt,
6794
- copyText: hideToolCardFences(message.text).trim() || message.text,
6795
- readAloud,
6796
- receiptSteps,
6797
- onOpenReceipt: receiptSteps ? openReceipt : void 0,
6798
- onRegenerate: onRegenerate ? handleRegenerate : void 0,
6799
- onFeedback: onFeedback ? (rating) => onFeedback(rating, message) : void 0
6800
- }
6801
- ) : null,
6802
- index === lastVisitorIndex ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
6803
- showActivity ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6804
- AgentActivityBubble,
6805
- {
6806
- brandLabel: resolvedBrandLabel,
6807
- brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
6808
- failed: state.phase === "error",
6809
- steps: activitySteps
6810
- }
6811
- ) : null,
6812
- visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6813
- VisitorToolResultView,
6814
- {
6815
- result,
6816
- disabled: semanticSurfaceDisabled,
6817
- onToolInput
6818
- },
6819
- result.id
6820
- )),
6821
- pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6822
- HumanInputCard,
6823
- {
6824
- request,
6825
- onRespond: onInputResponse
6826
- },
6827
- request.requestId
6828
- ))
6829
- ] }) : null
6830
- ]
6831
- },
6832
- message.role === "agent" && transcriptMessages[index - 1]?.role === "visitor" ? `answer-${transcriptMessages[index - 1]?.id}` : message.id
6833
- )),
6834
- waitingForBooking ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BookingCardLoader, {}) : null,
6835
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
6836
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
6837
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "Something went wrong" }),
6838
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: state.error })
6839
- ] }),
6840
- onRetry ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
6841
- ] }) : null
6842
- ] }) }),
6843
- showDisclaimerLabel ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: disclaimerLink ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6844
- "a",
7542
+ index === lastVisitorIndex ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7543
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7544
+ AgentActivityBubble,
7545
+ {
7546
+ brandLabel: resolvedBrandLabel,
7547
+ brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
7548
+ failed: state.phase === "error",
7549
+ steps: activitySteps
7550
+ }
7551
+ ) : null,
7552
+ visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7553
+ VisitorToolResultView,
7554
+ {
7555
+ result,
7556
+ disabled: semanticSurfaceDisabled,
7557
+ onToolInput
7558
+ },
7559
+ result.id
7560
+ )),
7561
+ pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7562
+ HumanInputCard,
7563
+ {
7564
+ request,
7565
+ onRespond: onInputResponse
7566
+ },
7567
+ request.requestId
7568
+ ))
7569
+ ] }) : null
7570
+ ]
7571
+ },
7572
+ message.role === "agent" && transcriptMessages[index - 1]?.role === "visitor" ? `answer-${transcriptMessages[index - 1]?.id}` : message.id
7573
+ )),
7574
+ waitingForBooking ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(BookingCardLoader, {}) : null,
7575
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
7576
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
7577
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: "Something went wrong" }),
7578
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: state.error })
7579
+ ] }),
7580
+ onRetry ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
7581
+ ] }) : null
7582
+ ] }) }),
7583
+ showDisclaimerLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: disclaimerLink ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7584
+ "a",
7585
+ {
7586
+ href: disclaimerLink,
7587
+ rel: "noopener noreferrer",
7588
+ target: "_blank",
7589
+ children: resolvedDisclaimerLabel
7590
+ }
7591
+ ) : resolvedDisclaimerLabel }) }) : null,
7592
+ handoff && (handoff.page?.enabled || handoffActive) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__handoff", children: [
7593
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", "aria-live": "polite", children: !handoff.page ? "Checking conversation\u2026" : handoffStatus === "human" ? "Connected with support" : handoffStatus === "queued" ? "Waiting for a representative" : handoffStatus === "requesting" ? "Connecting you to support\u2026" : handoffStatus === "resolved" ? "Your conversation with support has ended" : handoffStatus === "failed" ? "We couldn\u2019t connect you to support" : "Need a person?" }),
7594
+ handoffStatus === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7595
+ "button",
7596
+ {
7597
+ type: "button",
7598
+ disabled: handoff.busy || handoff.hasPending || isBusy,
7599
+ onClick: () => void handoff.start(),
7600
+ children: "Talk to a person"
7601
+ }
7602
+ ) : null,
7603
+ handoffStatus === "resolved" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7604
+ "button",
7605
+ {
7606
+ type: "button",
7607
+ disabled: handoff.busy || handoff.hasPending,
7608
+ onClick: () => void handoff.returnToAI(),
7609
+ children: "Return to AI"
7610
+ }
7611
+ ) : null,
7612
+ handoffStatus === "failed" && onReset ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7613
+ "button",
7614
+ {
7615
+ type: "button",
7616
+ disabled: !handoff.canReset,
7617
+ onClick: handleReset,
7618
+ children: "Start a new conversation"
7619
+ }
7620
+ ) : null,
7621
+ handoff.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { role: "alert", children: [
7622
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: handoff.error }),
7623
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7624
+ "button",
6845
7625
  {
6846
- href: disclaimerLink,
6847
- rel: "noopener noreferrer",
6848
- target: "_blank",
6849
- children: resolvedDisclaimerLabel
7626
+ type: "button",
7627
+ disabled: handoff.busy,
7628
+ onClick: () => void handoff.retry(),
7629
+ children: "Retry"
6850
7630
  }
6851
- ) : resolvedDisclaimerLabel }) }) : null,
6852
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
6853
- showJumpToLatest ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6854
- "button",
6855
- {
6856
- type: "button",
6857
- className: "agent-rail__jump-to-latest",
6858
- "aria-label": "Jump to the latest message",
6859
- title: "Jump to the latest message",
6860
- onClick: scrollToLatest,
6861
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChevronDownIcon, {})
6862
- }
6863
- ) : null,
6864
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6865
- Composer,
6866
- {
6867
- variant: expanded || mobileFullscreen ? "dock" : "default",
6868
- disabled: isBusy,
6869
- form: composerForm && lastMessage ? { ...composerForm, id: `${lastMessage.id}:${composerForm.id}` } : null,
6870
- allowFormResume: !state.pendingOffer && !waitingForBooking && !hasPendingConfirmation,
6871
- placeholder: composerPlaceholder,
6872
- onSubmit: handleSubmit
6873
- },
6874
- `${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
6875
- ),
6876
- poweredByLabel ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: poweredByLabel }) }) }) : null
6877
- ] })
6878
- ] }),
6879
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: overlayRef, className: "agent-rail__overlay" }),
6880
- receiptOpen && receiptSteps ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6881
- AnswerReceiptDialog,
7631
+ )
7632
+ ] }) : null
7633
+ ] }) : null,
7634
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
7635
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7636
+ LocationConsent,
6882
7637
  {
6883
- brandLabel: resolvedBrandLabel,
6884
- onClose: () => setReceiptOpen(false),
6885
- steps: receiptSteps
7638
+ request: locationRequest,
7639
+ onRespond: onInputResponse
7640
+ },
7641
+ state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
7642
+ ),
7643
+ showJumpToLatest ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7644
+ "button",
7645
+ {
7646
+ type: "button",
7647
+ className: "agent-rail__jump-to-latest",
7648
+ "aria-label": "Jump to the latest message",
7649
+ title: "Jump to the latest message",
7650
+ onClick: scrollToLatest,
7651
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronDownIcon, {})
6886
7652
  }
6887
- ) : null
6888
- ]
6889
- }
6890
- )
7653
+ ) : null,
7654
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7655
+ Composer,
7656
+ {
7657
+ variant: expanded || mobileFullscreen ? "dock" : "default",
7658
+ disabled: isBusy || Boolean(handoff?.busy || handoff?.hasPending) || handoffActive && !["requesting", "queued", "human"].includes(
7659
+ handoffStatus ?? ""
7660
+ ),
7661
+ form: !handoffActive && composerForm && lastMessage ? {
7662
+ ...composerForm,
7663
+ id: `${lastMessage.id}:${composerForm.id}`
7664
+ } : null,
7665
+ allowFormResume: !handoffActive && !state.pendingOffer && !waitingForBooking && !hasPendingConfirmation,
7666
+ placeholder: handoffActive ? "Message support\u2026" : composerPlaceholder,
7667
+ onSubmit: handleSubmit
7668
+ },
7669
+ `${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
7670
+ ),
7671
+ poweredByLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: poweredByLabel }) }) }) : null
7672
+ ] })
7673
+ ] }),
7674
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: overlayRef, className: "agent-rail__overlay" }),
7675
+ receiptOpen && receiptSteps ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7676
+ AnswerReceiptDialog,
7677
+ {
7678
+ brandLabel: resolvedBrandLabel,
7679
+ onClose: () => setReceiptOpen(false),
7680
+ steps: receiptSteps
7681
+ }
7682
+ ) : null
7683
+ ] })
6891
7684
  }
6892
7685
  );
6893
7686
  }
6894
7687
 
6895
7688
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
6896
- var import_react15 = require("react");
6897
- var import_jsx_runtime18 = require("react/jsx-runtime");
7689
+ var import_react17 = require("react");
7690
+ var import_jsx_runtime19 = require("react/jsx-runtime");
6898
7691
  function ChatSparkIcon() {
6899
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
7692
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
6900
7693
  "svg",
6901
7694
  {
6902
7695
  className: "assist-edge-tab__chat-spark",
@@ -6904,7 +7697,7 @@ function ChatSparkIcon() {
6904
7697
  fill: "none",
6905
7698
  "aria-hidden": "true",
6906
7699
  children: [
6907
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7700
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6908
7701
  "path",
6909
7702
  {
6910
7703
  className: "assist-edge-tab__spark assist-edge-tab__spark--a",
@@ -6912,7 +7705,7 @@ function ChatSparkIcon() {
6912
7705
  fill: "currentColor"
6913
7706
  }
6914
7707
  ),
6915
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7708
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6916
7709
  "path",
6917
7710
  {
6918
7711
  className: "assist-edge-tab__spark assist-edge-tab__spark--b",
@@ -6920,8 +7713,8 @@ function ChatSparkIcon() {
6920
7713
  fill: "currentColor"
6921
7714
  }
6922
7715
  ),
6923
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { className: "assist-edge-tab__bot", children: [
6924
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7716
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("g", { className: "assist-edge-tab__bot", children: [
7717
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6925
7718
  "path",
6926
7719
  {
6927
7720
  d: "M11.15 5.2V3.05",
@@ -6930,8 +7723,8 @@ function ChatSparkIcon() {
6930
7723
  strokeLinecap: "round"
6931
7724
  }
6932
7725
  ),
6933
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "11.15", cy: "2.45", r: "0.85", fill: "currentColor" }),
6934
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7726
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("circle", { cx: "11.15", cy: "2.45", r: "0.85", fill: "currentColor" }),
7727
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6935
7728
  "rect",
6936
7729
  {
6937
7730
  x: "3.55",
@@ -6943,7 +7736,7 @@ function ChatSparkIcon() {
6943
7736
  strokeWidth: "1.9"
6944
7737
  }
6945
7738
  ),
6946
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7739
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6947
7740
  "circle",
6948
7741
  {
6949
7742
  className: "assist-edge-tab__eye",
@@ -6953,7 +7746,7 @@ function ChatSparkIcon() {
6953
7746
  fill: "currentColor"
6954
7747
  }
6955
7748
  ),
6956
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7749
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6957
7750
  "circle",
6958
7751
  {
6959
7752
  className: "assist-edge-tab__eye assist-edge-tab__eye--r",
@@ -6974,10 +7767,10 @@ function TabMarkIcon({
6974
7767
  }) {
6975
7768
  const custom = customIconUrl?.trim();
6976
7769
  const logo = logoUrl?.trim();
6977
- const [customFailed, setCustomFailed] = (0, import_react15.useState)(false);
6978
- const [logoFailed, setLogoFailed] = (0, import_react15.useState)(false);
7770
+ const [customFailed, setCustomFailed] = (0, import_react17.useState)(false);
7771
+ const [logoFailed, setLogoFailed] = (0, import_react17.useState)(false);
6979
7772
  if (custom && !customFailed) {
6980
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7773
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6981
7774
  "img",
6982
7775
  {
6983
7776
  alt: "",
@@ -6989,7 +7782,7 @@ function TabMarkIcon({
6989
7782
  );
6990
7783
  }
6991
7784
  if (logo && !logoFailed) {
6992
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7785
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6993
7786
  "img",
6994
7787
  {
6995
7788
  alt: "",
@@ -7000,10 +7793,10 @@ function TabMarkIcon({
7000
7793
  }
7001
7794
  );
7002
7795
  }
7003
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChatSparkIcon, {});
7796
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChatSparkIcon, {});
7004
7797
  }
7005
7798
  function ChevronLeftIcon() {
7006
- 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)(
7799
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7007
7800
  "path",
7008
7801
  {
7009
7802
  d: "M10 4L6 8l4 4",
@@ -7015,7 +7808,7 @@ function ChevronLeftIcon() {
7015
7808
  ) });
7016
7809
  }
7017
7810
  function ChevronDownIcon2() {
7018
- 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)(
7811
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7019
7812
  "path",
7020
7813
  {
7021
7814
  d: "M4 6l4 4 4-4",
@@ -7027,7 +7820,7 @@ function ChevronDownIcon2() {
7027
7820
  ) });
7028
7821
  }
7029
7822
  function DragDots() {
7030
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("i", {}, index)) });
7823
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("i", {}, index)) });
7031
7824
  }
7032
7825
  var VARIANT_COPY = {
7033
7826
  outline: { label: "Ask anything", aria: "Ask anything" },
@@ -7082,7 +7875,7 @@ function AssistEdgeTab({
7082
7875
  ...!pill && resolvedTextColor ? { "--as-text": resolvedTextColor } : {},
7083
7876
  colorScheme: chromeScheme
7084
7877
  };
7085
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
7878
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
7086
7879
  "button",
7087
7880
  {
7088
7881
  type: "button",
@@ -7094,13 +7887,13 @@ function AssistEdgeTab({
7094
7887
  tabIndex: visible ? 0 : -1,
7095
7888
  onClick: onOpen,
7096
7889
  children: [
7097
- pill ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7098
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7890
+ pill ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
7891
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7099
7892
  "span",
7100
7893
  {
7101
7894
  className: `assist-edge-tab__mark assist-edge-tab__mark--chip${mobile ? " assist-edge-tab__mark--mobile" : ""}`,
7102
7895
  "aria-hidden": "true",
7103
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7896
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7104
7897
  TabMarkIcon,
7105
7898
  {
7106
7899
  customIconUrl,
@@ -7110,12 +7903,12 @@ function AssistEdgeTab({
7110
7903
  )
7111
7904
  }
7112
7905
  ),
7113
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "assist-edge-tab__text", children: [
7114
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7115
- visibleSubLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
7906
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "assist-edge-tab__text", children: [
7907
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7908
+ visibleSubLabel ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
7116
7909
  ] })
7117
- ] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7118
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7910
+ ] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
7911
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7119
7912
  TabMarkIcon,
7120
7913
  {
7121
7914
  customIconUrl,
@@ -7123,16 +7916,16 @@ function AssistEdgeTab({
7123
7916
  },
7124
7917
  markSourceKey
7125
7918
  ) }),
7126
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7127
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronDownIcon2, {})
7919
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7920
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChevronDownIcon2, {})
7128
7921
  ] }) : null,
7129
- !pill && variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7130
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronLeftIcon, {}),
7131
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7132
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DragDots, {})
7922
+ !pill && variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
7923
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChevronLeftIcon, {}),
7924
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7925
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DragDots, {})
7133
7926
  ] }) : null,
7134
- !pill && variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
7135
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7927
+ !pill && variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
7928
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7136
7929
  TabMarkIcon,
7137
7930
  {
7138
7931
  customIconUrl,
@@ -7140,8 +7933,8 @@ function AssistEdgeTab({
7140
7933
  },
7141
7934
  markSourceKey
7142
7935
  ) }),
7143
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7144
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronLeftIcon, {})
7936
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
7937
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChevronLeftIcon, {})
7145
7938
  ] }) : null
7146
7939
  ]
7147
7940
  }
@@ -7163,8 +7956,8 @@ function findPrecedingVisitorText(messages, agentMessageId) {
7163
7956
  }
7164
7957
  return void 0;
7165
7958
  }
7166
- function normalizeAgentFeedbackAnswerText(text2) {
7167
- const normalized = text2.replace(/\s+/g, " ").trim();
7959
+ function normalizeAgentFeedbackAnswerText(text3) {
7960
+ const normalized = text3.replace(/\s+/g, " ").trim();
7168
7961
  if (!normalized) return void 0;
7169
7962
  return normalized.length > 4e3 ? `${normalized.slice(0, 3997)}...` : normalized;
7170
7963
  }
@@ -7205,7 +7998,7 @@ function sendAgentAnswerFeedback(eventUrl, event) {
7205
7998
  }
7206
7999
 
7207
8000
  // src/react/components/AgentWidget/AgentWidget.tsx
7208
- var import_jsx_runtime19 = require("react/jsx-runtime");
8001
+ var import_jsx_runtime20 = require("react/jsx-runtime");
7209
8002
  function AgentWidget({
7210
8003
  indexId,
7211
8004
  customerId,
@@ -7224,9 +8017,9 @@ function AgentWidget({
7224
8017
  }) {
7225
8018
  const isMobile = useIsMobile();
7226
8019
  const placement = normalizeAgentPlacement(placementInput);
7227
- const railSlotRef = (0, import_react16.useRef)(null);
7228
- const [railCollapsed, setRailCollapsed] = (0, import_react16.useState)(defaultCollapsed);
7229
- const [railExpanded, setRailExpanded] = (0, import_react16.useState)(false);
8020
+ const railSlotRef = (0, import_react18.useRef)(null);
8021
+ const [railCollapsed, setRailCollapsed] = (0, import_react18.useState)(defaultCollapsed);
8022
+ const [railExpanded, setRailExpanded] = (0, import_react18.useState)(false);
7230
8023
  const pageShiftActive = shouldApplyPageShift({
7231
8024
  pageShift,
7232
8025
  isMobile,
@@ -7279,7 +8072,7 @@ function AgentWidget({
7279
8072
  } : {},
7280
8073
  ...branding?.colors?.border ? { border: branding.colors.border } : {}
7281
8074
  };
7282
- (0, import_react16.useEffect)(() => {
8075
+ (0, import_react18.useEffect)(() => {
7283
8076
  if (!registerPanelController) return;
7284
8077
  registerAgentPanelController(customerId, {
7285
8078
  open: () => setRailCollapsed(false),
@@ -7314,7 +8107,7 @@ function AgentWidget({
7314
8107
  })
7315
8108
  );
7316
8109
  }
7317
- (0, import_react16.useEffect)(() => {
8110
+ (0, import_react18.useEffect)(() => {
7318
8111
  if (railCollapsed) return;
7319
8112
  const handleKeyDown = (event) => {
7320
8113
  if (event.key === "Tab" && (isMobile || railExpanded)) {
@@ -7348,19 +8141,19 @@ function AgentWidget({
7348
8141
  window.addEventListener("keydown", handleKeyDown);
7349
8142
  return () => window.removeEventListener("keydown", handleKeyDown);
7350
8143
  }, [isMobile, railCollapsed, railExpanded]);
7351
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "webless-agent-root", children: [
7352
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8144
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "webless-agent-root", children: [
8145
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7353
8146
  "div",
7354
8147
  {
7355
8148
  className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
7356
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8149
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7357
8150
  "div",
7358
8151
  {
7359
8152
  ref: railSlotRef,
7360
8153
  className: "webless-agent-root__rail-slot",
7361
8154
  inert: railCollapsed || void 0,
7362
8155
  "aria-hidden": railCollapsed,
7363
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8156
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7364
8157
  AgentRail,
7365
8158
  {
7366
8159
  theme,
@@ -7397,7 +8190,7 @@ function AgentWidget({
7397
8190
  )
7398
8191
  }
7399
8192
  ),
7400
- railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8193
+ railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7401
8194
  AssistEdgeTab,
7402
8195
  {
7403
8196
  variant: placement.variant,
@@ -7424,10 +8217,10 @@ function AgentWidget({
7424
8217
  }
7425
8218
 
7426
8219
  // src/react/components/AgentTranscript/AgentTranscript.tsx
7427
- var import_react17 = require("react");
8220
+ var import_react19 = require("react");
7428
8221
 
7429
8222
  // src/react/components/AgentTranscript/TranscriptActivity.tsx
7430
- var import_jsx_runtime20 = require("react/jsx-runtime");
8223
+ var import_jsx_runtime21 = require("react/jsx-runtime");
7431
8224
  var statusLabels = {
7432
8225
  started: "No result recorded",
7433
8226
  completed: "",
@@ -7437,33 +8230,33 @@ var statusLabels = {
7437
8230
  function RecordedResult({
7438
8231
  result
7439
8232
  }) {
7440
- if (result.kind === "search") return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SearchReferences, { results: [result] });
8233
+ if (result.kind === "search") return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SearchReferences, { results: [result] });
7441
8234
  if (result.kind === "booking") {
7442
8235
  const card = result.card;
7443
8236
  if (card.type === "booking_offer")
7444
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(BookingCard, { readOnly: true, offer: card });
8237
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(BookingCard, { readOnly: true, offer: card });
7445
8238
  if (card.type === "booking_confirmed")
7446
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { children: [
8239
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("p", { children: [
7447
8240
  "Booking confirmed",
7448
8241
  card.startTime ? ` \xB7 ${card.startTime}` : ""
7449
8242
  ] });
7450
- if (card.type === "booking_canceled") return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: "Booking canceled" });
7451
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: "Information requested" });
8243
+ if (card.type === "booking_canceled") return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "Booking canceled" });
8244
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "Information requested" });
7452
8245
  }
7453
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(VisitorToolResultView, { disabled: true, result });
8246
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(VisitorToolResultView, { disabled: true, result });
7454
8247
  }
7455
8248
  function TranscriptActivity({
7456
8249
  activity
7457
8250
  }) {
7458
8251
  const result = activity.result?.kind === "hidden" ? void 0 : activity.result;
7459
- const heading = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
7460
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: activity.category === "specialist" ? `Specialist \xB7 ${activity.label}` : activity.label }),
7461
- activity.status !== "completed" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "agent-transcript__activity-status", children: statusLabels[activity.status] }) : null
8252
+ const heading = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
8253
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: activity.category === "specialist" ? `Specialist \xB7 ${activity.label}` : activity.label }),
8254
+ activity.status !== "completed" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "agent-transcript__activity-status", children: statusLabels[activity.status] }) : null
7462
8255
  ] });
7463
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { className: "agent-transcript__activity", "data-status": activity.status, children: result ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("details", { children: [
7464
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("summary", { className: "agent-transcript__activity-heading", children: heading }),
7465
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "agent-transcript__activity-result", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(RecordedResult, { result }) })
7466
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "agent-transcript__activity-heading", children: heading }) });
8256
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { className: "agent-transcript__activity", "data-status": activity.status, children: result ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { children: [
8257
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("summary", { className: "agent-transcript__activity-heading", children: heading }),
8258
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "agent-transcript__activity-result", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RecordedResult, { result }) })
8259
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "agent-transcript__activity-heading", children: heading }) });
7467
8260
  }
7468
8261
 
7469
8262
  // src/react/components/AgentTranscript/group-activities.ts
@@ -7492,16 +8285,16 @@ function groupTranscriptActivities(activities) {
7492
8285
  label: activity.createdAt < previous.startedAt ? activity.label : previous.label
7493
8286
  });
7494
8287
  }
7495
- return [...calls.values()].map(({ latest, id, startedAt, label }) => ({
8288
+ return [...calls.values()].map(({ latest, id: id2, startedAt, label }) => ({
7496
8289
  ...latest,
7497
- id,
8290
+ id: id2,
7498
8291
  label,
7499
8292
  createdAt: startedAt
7500
8293
  }));
7501
8294
  }
7502
8295
 
7503
8296
  // src/react/components/AgentTranscript/AgentTranscript.tsx
7504
- var import_jsx_runtime21 = require("react/jsx-runtime");
8297
+ var import_jsx_runtime22 = require("react/jsx-runtime");
7505
8298
  var timestampFormat = new Intl.DateTimeFormat("en-US", {
7506
8299
  month: "short",
7507
8300
  day: "numeric",
@@ -7532,7 +8325,7 @@ function AgentTranscript({
7532
8325
  ...activity
7533
8326
  }))
7534
8327
  ].sort((left, right) => left.createdAt - right.createdAt);
7535
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8328
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7536
8329
  "ol",
7537
8330
  {
7538
8331
  className: "webless-agent-root agent-transcript not-typeset",
@@ -7545,15 +8338,15 @@ function AgentTranscript({
7545
8338
  const previous = entries[index - 1];
7546
8339
  const validTimestamp = Number.isFinite(date.getTime());
7547
8340
  const showTimestamp = validTimestamp && (previous ? entry.createdAt - previous.createdAt >= 5 * 60 * 1e3 || date.toISOString().slice(0, 10) !== new Date(previous.createdAt).toJSON()?.slice(0, 10) : showInitialTimestamp);
7548
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react17.Fragment, { children: [
7549
- showTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { className: "agent-transcript__time-marker", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("time", { dateTime: date.toISOString(), children: formatTimestamp(entry.createdAt) }) }) : null,
7550
- entry.kind === "activity" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TranscriptActivity, { activity: entry }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
8341
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react19.Fragment, { children: [
8342
+ showTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { className: "agent-transcript__time-marker", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("time", { dateTime: date.toISOString(), children: formatTimestamp(entry.createdAt) }) }) : null,
8343
+ entry.kind === "activity" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TranscriptActivity, { activity: entry }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7551
8344
  "li",
7552
8345
  {
7553
8346
  className: `agent-transcript__message agent-transcript__message--${entry.role}`,
7554
8347
  children: [
7555
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "agent-transcript__meta", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: entry.role === "visitor" ? visitorLabel : agentLabel }) }),
7556
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8348
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "agent-transcript__meta", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: entry.role === "visitor" ? visitorLabel : agentLabel }) }),
8349
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7557
8350
  MessageBubble,
7558
8351
  {
7559
8352
  message: entry.role === "agent" ? { ...entry, streaming: false } : entry,