@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/README.md +11 -0
- package/dist/{chunk-74CSWSC5.js → chunk-EVWZF34F.js} +1361 -568
- package/dist/chunk-EVWZF34F.js.map +1 -0
- package/dist/embed.cjs +1394 -601
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.css +151 -0
- package/dist/embed.css.map +1 -1
- package/dist/embed.d.cts +3 -2
- package/dist/embed.d.ts +3 -2
- package/dist/embed.js +1 -1
- package/dist/index.cjs +303 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +297 -15
- package/dist/index.js.map +1 -1
- package/dist/{panel-controller-rxR75tRa.d.cts → panel-controller-CYoivbYB.d.cts} +173 -1
- package/dist/{panel-controller-rxR75tRa.d.ts → panel-controller-CYoivbYB.d.ts} +173 -1
- package/dist/presentation.cjs +3 -0
- package/dist/presentation.cjs.map +1 -1
- package/dist/presentation.d.cts +2 -1
- package/dist/presentation.d.ts +2 -1
- package/dist/presentation.js +3 -0
- package/dist/presentation.js.map +1 -1
- package/dist/react.cjs +1409 -616
- package/dist/react.cjs.map +1 -1
- package/dist/react.css +151 -0
- package/dist/react.css.map +1 -1
- package/dist/react.d.cts +126 -4
- package/dist/react.d.ts +126 -4
- package/dist/react.js +1 -1
- package/dist/{types-sLEIYDqm.d.cts → types-4lTJW5mp.d.cts} +135 -1
- package/dist/{types-sLEIYDqm.d.ts → types-4lTJW5mp.d.ts} +135 -1
- package/package.json +3 -2
- package/scripts/sync-handoff-contract.mjs +18 -0
- package/dist/chunk-74CSWSC5.js.map +0 -1
|
@@ -138,16 +138,16 @@ function parseStep(value) {
|
|
|
138
138
|
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
139
139
|
return null;
|
|
140
140
|
}
|
|
141
|
-
const
|
|
141
|
+
const id2 = boundedString(value.id, 80);
|
|
142
142
|
const label = boundedString(value.label, 160);
|
|
143
143
|
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
144
|
-
if (!
|
|
144
|
+
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(
|
|
145
145
|
(path) => typeof path !== "string" || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || path.length > 160
|
|
146
146
|
)) {
|
|
147
147
|
return null;
|
|
148
148
|
}
|
|
149
149
|
return {
|
|
150
|
-
id,
|
|
150
|
+
id: id2,
|
|
151
151
|
label,
|
|
152
152
|
fieldPaths: value.fieldPaths,
|
|
153
153
|
...description ? { description } : {}
|
|
@@ -184,14 +184,14 @@ function parseAgentToolUiSurface(value) {
|
|
|
184
184
|
])) {
|
|
185
185
|
return null;
|
|
186
186
|
}
|
|
187
|
-
const
|
|
187
|
+
const id2 = boundedString(value.id, 200);
|
|
188
188
|
const title = boundedString(value.title, 200);
|
|
189
189
|
const toolSlug = boundedString(value.toolSlug, 200);
|
|
190
190
|
const description = value.description === void 0 ? void 0 : boundedString(value.description, 800);
|
|
191
191
|
const operationId = value.operationId === void 0 ? void 0 : boundedString(value.operationId, 200);
|
|
192
192
|
const requestId = value.requestId === void 0 ? void 0 : boundedString(value.requestId, 200);
|
|
193
193
|
const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
|
|
194
|
-
if (!
|
|
194
|
+
if (!id2 || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
|
|
195
195
|
return null;
|
|
196
196
|
}
|
|
197
197
|
const fields = value.fields.map(parseField);
|
|
@@ -211,7 +211,7 @@ function parseAgentToolUiSurface(value) {
|
|
|
211
211
|
}
|
|
212
212
|
return {
|
|
213
213
|
schemaVersion: AGENT_TOOL_UI_SCHEMA_VERSION,
|
|
214
|
-
id,
|
|
214
|
+
id: id2,
|
|
215
215
|
title,
|
|
216
216
|
toolSlug,
|
|
217
217
|
fields,
|
|
@@ -391,14 +391,14 @@ function parseAgentSearchDiscoveryOutput(value) {
|
|
|
391
391
|
var COMPOSER_FORM_SKIP_DISMISSAL = "I'd like to keep chatting without sharing the requested details for now. Please don't ask for them again unless I choose to proceed with something that needs them.";
|
|
392
392
|
function visitorMessageDisplayText(message) {
|
|
393
393
|
if (message.role !== "visitor") return message.text;
|
|
394
|
-
const
|
|
395
|
-
if (!
|
|
396
|
-
if (
|
|
397
|
-
const afterDismissal =
|
|
394
|
+
const text3 = message.text.trim();
|
|
395
|
+
if (!text3) return message.text;
|
|
396
|
+
if (text3.startsWith(COMPOSER_FORM_SKIP_DISMISSAL)) {
|
|
397
|
+
const afterDismissal = text3.slice(COMPOSER_FORM_SKIP_DISMISSAL.length).trim().replace(/^\n+/, "").trim();
|
|
398
398
|
if (afterDismissal) return afterDismissal;
|
|
399
399
|
}
|
|
400
400
|
const runtime = message.runtimeText?.trim();
|
|
401
|
-
if (runtime &&
|
|
401
|
+
if (runtime && text3 === runtime && runtime.includes(COMPOSER_FORM_SKIP_DISMISSAL)) {
|
|
402
402
|
const afterDismissal = runtime.slice(
|
|
403
403
|
runtime.indexOf(COMPOSER_FORM_SKIP_DISMISSAL) + COMPOSER_FORM_SKIP_DISMISSAL.length
|
|
404
404
|
).trim().replace(/^\n+/, "").trim();
|
|
@@ -472,13 +472,13 @@ function parseVisitorFormFields(value) {
|
|
|
472
472
|
const seen = /* @__PURE__ */ new Set();
|
|
473
473
|
for (const item of value) {
|
|
474
474
|
const record2 = asRecord(item);
|
|
475
|
-
const
|
|
475
|
+
const id2 = asString(record2?.id).toLowerCase().replace(/[^a-z0-9_-]/g, "");
|
|
476
476
|
const kind = asString(record2?.kind);
|
|
477
|
-
if (!record2 || !
|
|
478
|
-
seen.add(
|
|
479
|
-
const label = asString(record2.label) ||
|
|
477
|
+
if (!record2 || !id2 || seen.has(id2) || !isFieldKind2(kind)) continue;
|
|
478
|
+
seen.add(id2);
|
|
479
|
+
const label = asString(record2.label) || id2;
|
|
480
480
|
fields.push({
|
|
481
|
-
id,
|
|
481
|
+
id: id2,
|
|
482
482
|
kind,
|
|
483
483
|
label,
|
|
484
484
|
placeholder: asString(record2.placeholder) || label,
|
|
@@ -514,52 +514,52 @@ function formatComposerFormMessage(form, values) {
|
|
|
514
514
|
return value ? `${field.label}: ${value}` : "";
|
|
515
515
|
}).filter(Boolean).join("\n");
|
|
516
516
|
}
|
|
517
|
-
function looksLikeFieldCollection(
|
|
517
|
+
function looksLikeFieldCollection(text3) {
|
|
518
518
|
return /\b(please|need|send|share|enter|provide|add|collect|what|which|use)\b/i.test(
|
|
519
|
-
|
|
520
|
-
) || /:\s*$/m.test(
|
|
519
|
+
text3
|
|
520
|
+
) || /:\s*$/m.test(text3) || /^[-*•]\s+/m.test(text3);
|
|
521
521
|
}
|
|
522
|
-
function looksLikeBookingCopy(
|
|
522
|
+
function looksLikeBookingCopy(text3) {
|
|
523
523
|
return /book(ing)? (card|a demo|this time)|pick a (date|time)|available (times|slots)|calendly/i.test(
|
|
524
|
-
|
|
524
|
+
text3
|
|
525
525
|
);
|
|
526
526
|
}
|
|
527
|
-
function echoedLabeledFieldIds(
|
|
527
|
+
function echoedLabeledFieldIds(text3) {
|
|
528
528
|
const ids = /* @__PURE__ */ new Set();
|
|
529
|
-
if (/\bname\s*:\s+\S+/i.test(
|
|
530
|
-
if (/\be-?mail\s*:\s+\S+/i.test(
|
|
531
|
-
if (/\bphone\s*:\s+\S+/i.test(
|
|
532
|
-
if (/\bcompany\s*:\s+\S+/i.test(
|
|
529
|
+
if (/\bname\s*:\s+\S+/i.test(text3)) ids.add("name");
|
|
530
|
+
if (/\be-?mail\s*:\s+\S+/i.test(text3)) ids.add("email");
|
|
531
|
+
if (/\bphone\s*:\s+\S+/i.test(text3)) ids.add("phone");
|
|
532
|
+
if (/\bcompany\s*:\s+\S+/i.test(text3)) ids.add("company");
|
|
533
533
|
return ids;
|
|
534
534
|
}
|
|
535
|
-
function matchLibraryFields(
|
|
535
|
+
function matchLibraryFields(text3) {
|
|
536
536
|
return FIELD_LIBRARY.flatMap((field) => {
|
|
537
|
-
if (field.exclude?.test(
|
|
538
|
-
const leftover =
|
|
537
|
+
if (field.exclude?.test(text3)) {
|
|
538
|
+
const leftover = text3.replace(field.exclude, " ");
|
|
539
539
|
if (!field.patterns.some((pattern) => pattern.test(leftover))) return [];
|
|
540
|
-
} else if (!field.patterns.some((pattern) => pattern.test(
|
|
540
|
+
} else if (!field.patterns.some((pattern) => pattern.test(text3))) {
|
|
541
541
|
return [];
|
|
542
542
|
}
|
|
543
543
|
const { patterns: _patterns, exclude: _exclude, ...next } = field;
|
|
544
544
|
return [next];
|
|
545
545
|
}).slice(0, MAX_FORM_FIELDS);
|
|
546
546
|
}
|
|
547
|
-
function looksLikeCompletedActionRecap(
|
|
548
|
-
const confirmingCreate = /\bshould i create this\b/i.test(
|
|
549
|
-
const echoingFilledFields = /\b(?:name|email|phone|company)\s*:\s+\S+/i.test(
|
|
547
|
+
function looksLikeCompletedActionRecap(text3) {
|
|
548
|
+
const confirmingCreate = /\bshould i create this\b/i.test(text3);
|
|
549
|
+
const echoingFilledFields = /\b(?:name|email|phone|company)\s*:\s+\S+/i.test(text3) && /[^\s@]+@[^\s@]+\.[^\s@]+/i.test(text3);
|
|
550
550
|
if (echoingFilledFields) {
|
|
551
|
-
if (looksLikeFieldCollection(
|
|
552
|
-
const echoed = echoedLabeledFieldIds(
|
|
553
|
-
if (matchLibraryFields(
|
|
551
|
+
if (looksLikeFieldCollection(text3)) {
|
|
552
|
+
const echoed = echoedLabeledFieldIds(text3);
|
|
553
|
+
if (matchLibraryFields(text3).some((field) => !echoed.has(field.id))) {
|
|
554
554
|
return false;
|
|
555
555
|
}
|
|
556
556
|
}
|
|
557
557
|
return true;
|
|
558
558
|
}
|
|
559
|
-
return confirmingCreate && !looksLikeFieldCollection(
|
|
559
|
+
return confirmingCreate && !looksLikeFieldCollection(text3);
|
|
560
560
|
}
|
|
561
|
-
function inferComposerForm(
|
|
562
|
-
const cleaned =
|
|
561
|
+
function inferComposerForm(text3) {
|
|
562
|
+
const cleaned = text3.trim();
|
|
563
563
|
if (!cleaned || looksLikeBookingCopy(cleaned) || looksLikeCompletedActionRecap(cleaned) || !looksLikeFieldCollection(cleaned)) {
|
|
564
564
|
return null;
|
|
565
565
|
}
|
|
@@ -574,8 +574,8 @@ function resolveComposerForm(input) {
|
|
|
574
574
|
if (input.enabled === false || input.hasBookingOffer || input.hasPendingConfirmation) {
|
|
575
575
|
return null;
|
|
576
576
|
}
|
|
577
|
-
const
|
|
578
|
-
if (!
|
|
577
|
+
const text3 = input.agentText.trim();
|
|
578
|
+
if (!text3) return null;
|
|
579
579
|
const card = input.cards?.find((item) => item.type === "visitor_form");
|
|
580
580
|
if (card?.fields && card.fields.length >= MIN_FORM_FIELDS) {
|
|
581
581
|
return {
|
|
@@ -583,7 +583,7 @@ function resolveComposerForm(input) {
|
|
|
583
583
|
fields: card.fields.slice(0, MAX_FORM_FIELDS)
|
|
584
584
|
};
|
|
585
585
|
}
|
|
586
|
-
return inferComposerForm(
|
|
586
|
+
return inferComposerForm(text3);
|
|
587
587
|
}
|
|
588
588
|
|
|
589
589
|
// src/react/lib/tool-card.ts
|
|
@@ -597,9 +597,9 @@ function preferBookingOffer(current, next) {
|
|
|
597
597
|
}
|
|
598
598
|
return next;
|
|
599
599
|
}
|
|
600
|
-
function looksLikeBookingReady(
|
|
600
|
+
function looksLikeBookingReady(text3) {
|
|
601
601
|
return /demo option|options are ready|pick a (date|time)|available (times|slots)|book(ing)? (card|the demo)|\bschedule\b/i.test(
|
|
602
|
-
|
|
602
|
+
text3
|
|
603
603
|
);
|
|
604
604
|
}
|
|
605
605
|
function bookingOfferIdentityKey(offer) {
|
|
@@ -709,29 +709,29 @@ function bookingCardFromActionOutput(output) {
|
|
|
709
709
|
const data = asRecord2(record2?.output) ?? asRecord2(record2?.data) ?? record2;
|
|
710
710
|
return parseToolCard(data);
|
|
711
711
|
}
|
|
712
|
-
function ensureBookingOfferText(
|
|
713
|
-
if (!offer) return
|
|
714
|
-
if (extractToolCards(
|
|
715
|
-
return
|
|
712
|
+
function ensureBookingOfferText(text3, offer) {
|
|
713
|
+
if (!offer) return text3;
|
|
714
|
+
if (extractToolCards(text3).some((card) => card.type === "booking_offer")) {
|
|
715
|
+
return text3;
|
|
716
716
|
}
|
|
717
|
-
const visible = stripToolCards(
|
|
717
|
+
const visible = stripToolCards(text3).trim() || text3.trim();
|
|
718
718
|
return `${visible}
|
|
719
719
|
|
|
720
720
|
${formatBookingOfferFence(offer)}`;
|
|
721
721
|
}
|
|
722
|
-
function hideToolCardFences(
|
|
723
|
-
return
|
|
722
|
+
function hideToolCardFences(text3) {
|
|
723
|
+
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();
|
|
724
724
|
}
|
|
725
725
|
var BOOKING_CARD_FALLBACK = "Pick a date and time that works for you.";
|
|
726
|
-
function looksLikeBookingAvailabilityDump(
|
|
727
|
-
const cleaned =
|
|
726
|
+
function looksLikeBookingAvailabilityDump(text3) {
|
|
727
|
+
const cleaned = text3.trim();
|
|
728
728
|
if (!cleaned) return false;
|
|
729
729
|
const isoCount = (cleaned.match(/\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/g) ?? []).length;
|
|
730
730
|
const utcCount = (cleaned.match(/\bUTC\b/g) ?? []).length;
|
|
731
731
|
return isoCount >= 2 || utcCount >= 2 || /api\.calendly\.com|calendly\.com\//i.test(cleaned) || /webless-tool-card/i.test(cleaned);
|
|
732
732
|
}
|
|
733
|
-
function sanitizeBookingOfferCopy(
|
|
734
|
-
const cleaned = hideToolCardFences(
|
|
733
|
+
function sanitizeBookingOfferCopy(text3) {
|
|
734
|
+
const cleaned = hideToolCardFences(text3);
|
|
735
735
|
if (!cleaned || looksLikeBookingAvailabilityDump(cleaned)) {
|
|
736
736
|
return BOOKING_CARD_FALLBACK;
|
|
737
737
|
}
|
|
@@ -744,9 +744,9 @@ function visitorTimeZone() {
|
|
|
744
744
|
return "UTC";
|
|
745
745
|
}
|
|
746
746
|
}
|
|
747
|
-
function extractToolCards(
|
|
747
|
+
function extractToolCards(text3) {
|
|
748
748
|
const cards = [];
|
|
749
|
-
for (const match of
|
|
749
|
+
for (const match of text3.matchAll(FENCE_PATTERN)) {
|
|
750
750
|
try {
|
|
751
751
|
const card = parseToolCard(JSON.parse(match[1] ?? ""));
|
|
752
752
|
if (card) cards.push(card);
|
|
@@ -755,8 +755,8 @@ function extractToolCards(text2) {
|
|
|
755
755
|
}
|
|
756
756
|
return cards;
|
|
757
757
|
}
|
|
758
|
-
function stripToolCards(
|
|
759
|
-
return
|
|
758
|
+
function stripToolCards(text3) {
|
|
759
|
+
return text3.replace(FENCE_PATTERN, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
760
760
|
}
|
|
761
761
|
function localDateKey(date) {
|
|
762
762
|
if (Number.isNaN(date.getTime())) return "";
|
|
@@ -876,10 +876,10 @@ function safeText(value) {
|
|
|
876
876
|
return value.trim().slice(0, MAX_TEXT_LENGTH);
|
|
877
877
|
}
|
|
878
878
|
function safeHref(value) {
|
|
879
|
-
const
|
|
880
|
-
if (!
|
|
879
|
+
const text3 = safeText(value);
|
|
880
|
+
if (!text3) return "";
|
|
881
881
|
try {
|
|
882
|
-
const url = new URL(
|
|
882
|
+
const url = new URL(text3);
|
|
883
883
|
return url.protocol === "https:" ? url.toString() : "";
|
|
884
884
|
} catch {
|
|
885
885
|
return "";
|
|
@@ -1099,6 +1099,9 @@ function finalizeSummaryPresentation(result, proposed) {
|
|
|
1099
1099
|
};
|
|
1100
1100
|
}
|
|
1101
1101
|
function presentVisitorToolResult(result, registry = []) {
|
|
1102
|
+
if (result.toolName === "request_location") {
|
|
1103
|
+
return { id: result.callId, toolName: result.toolName, status: result.status, kind: "hidden" };
|
|
1104
|
+
}
|
|
1102
1105
|
if (result.status === "completed" && toolResultFailed(result)) {
|
|
1103
1106
|
result = { ...result, status: "failed" };
|
|
1104
1107
|
}
|
|
@@ -1209,17 +1212,372 @@ function legacyBookingEnvelope(output) {
|
|
|
1209
1212
|
} : null;
|
|
1210
1213
|
}
|
|
1211
1214
|
|
|
1215
|
+
// src/react/hooks/useAgentHandoff.ts
|
|
1216
|
+
import { ClientError } from "eve/client";
|
|
1217
|
+
import { useEffect, useRef, useState } from "react";
|
|
1218
|
+
function useAgentHandoff(options) {
|
|
1219
|
+
const [page, setPage] = useState(null);
|
|
1220
|
+
const [busy, setBusy] = useState(false);
|
|
1221
|
+
const [rejected, setRejected] = useState(false);
|
|
1222
|
+
const [error, setError] = useState(null);
|
|
1223
|
+
const callbacks = useRef(options);
|
|
1224
|
+
callbacks.current = options;
|
|
1225
|
+
const pending = useRef(null);
|
|
1226
|
+
const inFlight = useRef(null);
|
|
1227
|
+
const pageRef = useRef(null);
|
|
1228
|
+
const refreshRef = useRef(null);
|
|
1229
|
+
const generation = useRef(0);
|
|
1230
|
+
useEffect(() => {
|
|
1231
|
+
const token = ++generation.current;
|
|
1232
|
+
const controller = new AbortController();
|
|
1233
|
+
let timer;
|
|
1234
|
+
let reading = null;
|
|
1235
|
+
let cursor = 0;
|
|
1236
|
+
pageRef.current = null;
|
|
1237
|
+
pending.current = null;
|
|
1238
|
+
inFlight.current?.abort();
|
|
1239
|
+
inFlight.current = null;
|
|
1240
|
+
setRejected(false);
|
|
1241
|
+
setPage(null);
|
|
1242
|
+
setError(null);
|
|
1243
|
+
setBusy(false);
|
|
1244
|
+
if (!options.enabled || !options.sessionId) return;
|
|
1245
|
+
const active = () => !controller.signal.aborted && generation.current === token;
|
|
1246
|
+
const refresh = () => {
|
|
1247
|
+
reading ??= (async () => {
|
|
1248
|
+
do {
|
|
1249
|
+
const next = await options.client.handoff.read({
|
|
1250
|
+
after: cursor,
|
|
1251
|
+
signal: AbortSignal.any([
|
|
1252
|
+
controller.signal,
|
|
1253
|
+
AbortSignal.timeout(15e3)
|
|
1254
|
+
])
|
|
1255
|
+
});
|
|
1256
|
+
if (!active()) return;
|
|
1257
|
+
callbacks.current.onEvents(next.events);
|
|
1258
|
+
if (next.status !== "ai") callbacks.current.onOwnership();
|
|
1259
|
+
cursor = next.cursor;
|
|
1260
|
+
pageRef.current = next;
|
|
1261
|
+
setPage(next);
|
|
1262
|
+
setRejected(false);
|
|
1263
|
+
if (!pending.current) setError(null);
|
|
1264
|
+
if (!next.hasMore) break;
|
|
1265
|
+
} while (active());
|
|
1266
|
+
})().finally(() => {
|
|
1267
|
+
reading = null;
|
|
1268
|
+
});
|
|
1269
|
+
return reading;
|
|
1270
|
+
};
|
|
1271
|
+
refreshRef.current = refresh;
|
|
1272
|
+
const poll = async () => {
|
|
1273
|
+
try {
|
|
1274
|
+
await refresh();
|
|
1275
|
+
} catch (cause) {
|
|
1276
|
+
if (active()) {
|
|
1277
|
+
const denied = cause instanceof ClientError && cause.status === 403;
|
|
1278
|
+
setRejected(denied);
|
|
1279
|
+
setError(
|
|
1280
|
+
denied ? "This preview has changed. Restart the preview chat to test the current version." : "Reconnecting to your conversation\u2026"
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
} finally {
|
|
1284
|
+
if (active()) timer = setTimeout(() => void poll(), 1500);
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
void poll();
|
|
1288
|
+
return () => {
|
|
1289
|
+
controller.abort();
|
|
1290
|
+
inFlight.current?.abort();
|
|
1291
|
+
clearTimeout(timer);
|
|
1292
|
+
refreshRef.current = null;
|
|
1293
|
+
};
|
|
1294
|
+
}, [options.client, options.enabled, options.sessionId]);
|
|
1295
|
+
async function execute(operation) {
|
|
1296
|
+
if (inFlight.current) return;
|
|
1297
|
+
const controller = new AbortController();
|
|
1298
|
+
inFlight.current = controller;
|
|
1299
|
+
const signal = AbortSignal.any([
|
|
1300
|
+
controller.signal,
|
|
1301
|
+
AbortSignal.timeout(15e3)
|
|
1302
|
+
]);
|
|
1303
|
+
const token = generation.current;
|
|
1304
|
+
pending.current = operation;
|
|
1305
|
+
setBusy(true);
|
|
1306
|
+
setError(null);
|
|
1307
|
+
try {
|
|
1308
|
+
if (operation.type === "start")
|
|
1309
|
+
await options.client.handoff.start(operation.operationId, signal);
|
|
1310
|
+
else if (operation.type === "message") {
|
|
1311
|
+
const { type: _, ...command } = operation;
|
|
1312
|
+
await options.client.handoff.send(command, signal);
|
|
1313
|
+
} else {
|
|
1314
|
+
const { type: _, ...command } = operation;
|
|
1315
|
+
await options.client.handoff.returnToAI(command, signal);
|
|
1316
|
+
}
|
|
1317
|
+
if (token !== generation.current) return;
|
|
1318
|
+
pending.current = null;
|
|
1319
|
+
await refreshRef.current?.();
|
|
1320
|
+
} catch {
|
|
1321
|
+
if (token === generation.current)
|
|
1322
|
+
setError(
|
|
1323
|
+
"Could not confirm delivery. Retry to check the same request."
|
|
1324
|
+
);
|
|
1325
|
+
} finally {
|
|
1326
|
+
if (inFlight.current === controller) inFlight.current = null;
|
|
1327
|
+
if (token === generation.current) setBusy(false);
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
const binding = () => {
|
|
1331
|
+
const current = pageRef.current;
|
|
1332
|
+
if (!current?.handoffId) throw new Error("No active human conversation.");
|
|
1333
|
+
return { handoffId: current.handoffId, epoch: current.epoch };
|
|
1334
|
+
};
|
|
1335
|
+
return {
|
|
1336
|
+
page,
|
|
1337
|
+
busy,
|
|
1338
|
+
error,
|
|
1339
|
+
hasPending: Boolean(pending.current),
|
|
1340
|
+
canReset: !busy && !pending.current && (rejected || page?.status === "ai" || page?.status === "failed" || !options.sessionId),
|
|
1341
|
+
blocksAI: Boolean(options.enabled && options.sessionId && !page) || busy || Boolean(pending.current) || Boolean(page && page.status !== "ai"),
|
|
1342
|
+
start: () => execute(
|
|
1343
|
+
pending.current ?? { type: "start", operationId: crypto.randomUUID() }
|
|
1344
|
+
),
|
|
1345
|
+
send: (message) => {
|
|
1346
|
+
if (pending.current)
|
|
1347
|
+
throw new Error(
|
|
1348
|
+
"Retry the pending request before sending another message."
|
|
1349
|
+
);
|
|
1350
|
+
return execute({
|
|
1351
|
+
type: "message",
|
|
1352
|
+
operationId: crypto.randomUUID(),
|
|
1353
|
+
...binding(),
|
|
1354
|
+
message
|
|
1355
|
+
});
|
|
1356
|
+
},
|
|
1357
|
+
returnToAI: () => execute(
|
|
1358
|
+
pending.current ?? {
|
|
1359
|
+
type: "return",
|
|
1360
|
+
operationId: crypto.randomUUID(),
|
|
1361
|
+
...binding()
|
|
1362
|
+
}
|
|
1363
|
+
),
|
|
1364
|
+
retry: async () => {
|
|
1365
|
+
if (pending.current) return execute(pending.current);
|
|
1366
|
+
try {
|
|
1367
|
+
await refreshRef.current?.();
|
|
1368
|
+
} catch {
|
|
1369
|
+
setError("Reconnecting to your conversation\u2026");
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1212
1375
|
// src/react/hooks/useAgentChat.ts
|
|
1213
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
1376
|
+
import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
1214
1377
|
|
|
1215
1378
|
// src/runtime/client.ts
|
|
1216
1379
|
import {
|
|
1217
1380
|
Client,
|
|
1218
|
-
ClientError as
|
|
1381
|
+
ClientError as ClientError4
|
|
1219
1382
|
} from "eve/client";
|
|
1220
1383
|
|
|
1384
|
+
// src/runtime/handoff.ts
|
|
1385
|
+
import { ClientError as ClientError3 } from "eve/client";
|
|
1386
|
+
|
|
1387
|
+
// src/runtime/generated/handoff-contract.ts
|
|
1388
|
+
import { z } from "zod";
|
|
1389
|
+
var id = z.string().min(1).max(200);
|
|
1390
|
+
var sequence = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
1391
|
+
var text2 = z.string().trim().min(1).max(16e3);
|
|
1392
|
+
var agentRuntimeHandoffVersion = "webless.ai/agent-runtime-handoff/v1";
|
|
1393
|
+
var agentRuntimeHandoffStatusSchema = z.enum([
|
|
1394
|
+
"ai",
|
|
1395
|
+
"requesting",
|
|
1396
|
+
"queued",
|
|
1397
|
+
"human",
|
|
1398
|
+
"resolved",
|
|
1399
|
+
"failed"
|
|
1400
|
+
]);
|
|
1401
|
+
var agentRuntimeHandoffActorSchema = z.strictObject({
|
|
1402
|
+
id,
|
|
1403
|
+
name: z.string().trim().min(1).max(200)
|
|
1404
|
+
});
|
|
1405
|
+
var eventBase = {
|
|
1406
|
+
id,
|
|
1407
|
+
sequence: sequence.refine((value) => value > 0),
|
|
1408
|
+
handoffId: id,
|
|
1409
|
+
epoch: sequence.refine((value) => value > 0),
|
|
1410
|
+
createdAt: z.iso.datetime()
|
|
1411
|
+
};
|
|
1412
|
+
var agentRuntimeHandoffEventSchema = z.discriminatedUnion("type", [
|
|
1413
|
+
z.strictObject({
|
|
1414
|
+
...eventBase,
|
|
1415
|
+
type: z.literal("status"),
|
|
1416
|
+
status: agentRuntimeHandoffStatusSchema,
|
|
1417
|
+
actor: agentRuntimeHandoffActorSchema.nullable()
|
|
1418
|
+
}),
|
|
1419
|
+
z.strictObject({
|
|
1420
|
+
...eventBase,
|
|
1421
|
+
type: z.literal("visitor.message"),
|
|
1422
|
+
message: text2,
|
|
1423
|
+
operationId: id
|
|
1424
|
+
}),
|
|
1425
|
+
z.strictObject({
|
|
1426
|
+
...eventBase,
|
|
1427
|
+
type: z.literal("human.message"),
|
|
1428
|
+
message: text2,
|
|
1429
|
+
actor: agentRuntimeHandoffActorSchema
|
|
1430
|
+
})
|
|
1431
|
+
]);
|
|
1432
|
+
var agentRuntimeHandoffReadRequestSchema = z.strictObject({
|
|
1433
|
+
after: sequence.default(0)
|
|
1434
|
+
});
|
|
1435
|
+
var agentRuntimeHandoffPageSchema = z.strictObject({
|
|
1436
|
+
apiVersion: z.literal(agentRuntimeHandoffVersion),
|
|
1437
|
+
sessionId: id,
|
|
1438
|
+
enabled: z.boolean(),
|
|
1439
|
+
status: agentRuntimeHandoffStatusSchema,
|
|
1440
|
+
handoffId: id.nullable(),
|
|
1441
|
+
epoch: sequence,
|
|
1442
|
+
after: sequence,
|
|
1443
|
+
cursor: sequence,
|
|
1444
|
+
hasMore: z.boolean(),
|
|
1445
|
+
events: z.array(agentRuntimeHandoffEventSchema).max(100)
|
|
1446
|
+
}).superRefine((page, ctx) => {
|
|
1447
|
+
let cursor = page.after;
|
|
1448
|
+
let previousEpoch = 0;
|
|
1449
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
1450
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1451
|
+
const handoffs = /* @__PURE__ */ new Map();
|
|
1452
|
+
const terminalEpochs = /* @__PURE__ */ new Set();
|
|
1453
|
+
let currentStatus;
|
|
1454
|
+
for (const event of page.events) {
|
|
1455
|
+
if (event.epoch < previousEpoch)
|
|
1456
|
+
ctx.addIssue({
|
|
1457
|
+
code: "custom",
|
|
1458
|
+
message: "Handoff epochs cannot decrease."
|
|
1459
|
+
});
|
|
1460
|
+
previousEpoch = event.epoch;
|
|
1461
|
+
if (ids.has(event.id))
|
|
1462
|
+
ctx.addIssue({
|
|
1463
|
+
code: "custom",
|
|
1464
|
+
message: "Duplicate handoff event ID."
|
|
1465
|
+
});
|
|
1466
|
+
ids.add(event.id);
|
|
1467
|
+
const handoffId = handoffs.get(event.epoch);
|
|
1468
|
+
if (handoffId !== void 0 && handoffId !== event.handoffId || event.epoch === page.epoch && event.handoffId !== page.handoffId)
|
|
1469
|
+
ctx.addIssue({
|
|
1470
|
+
code: "custom",
|
|
1471
|
+
message: "Inconsistent handoff epoch identity."
|
|
1472
|
+
});
|
|
1473
|
+
handoffs.set(event.epoch, event.handoffId);
|
|
1474
|
+
if (terminalEpochs.has(event.epoch) && (event.type !== "status" || event.status !== "ai"))
|
|
1475
|
+
ctx.addIssue({
|
|
1476
|
+
code: "custom",
|
|
1477
|
+
message: "Handoff event follows resolution."
|
|
1478
|
+
});
|
|
1479
|
+
if (event.type === "status") {
|
|
1480
|
+
if (event.status === "human" && event.actor === null)
|
|
1481
|
+
ctx.addIssue({
|
|
1482
|
+
code: "custom",
|
|
1483
|
+
message: "Human ownership requires a representative."
|
|
1484
|
+
});
|
|
1485
|
+
const previous = statuses.get(event.epoch);
|
|
1486
|
+
const transitions = {
|
|
1487
|
+
ai: [],
|
|
1488
|
+
requesting: ["queued", "resolved", "failed"],
|
|
1489
|
+
queued: ["human", "resolved", "failed"],
|
|
1490
|
+
human: ["resolved", "failed"],
|
|
1491
|
+
resolved: ["ai"],
|
|
1492
|
+
failed: []
|
|
1493
|
+
};
|
|
1494
|
+
if (previous !== void 0 && !transitions[previous].includes(event.status))
|
|
1495
|
+
ctx.addIssue({
|
|
1496
|
+
code: "custom",
|
|
1497
|
+
message: "Invalid handoff ownership transition."
|
|
1498
|
+
});
|
|
1499
|
+
statuses.set(event.epoch, event.status);
|
|
1500
|
+
if (["resolved", "failed", "ai"].includes(event.status))
|
|
1501
|
+
terminalEpochs.add(event.epoch);
|
|
1502
|
+
if (event.epoch === page.epoch) currentStatus = event.status;
|
|
1503
|
+
}
|
|
1504
|
+
if (event.sequence !== cursor + 1) {
|
|
1505
|
+
ctx.addIssue({
|
|
1506
|
+
code: "custom",
|
|
1507
|
+
message: "Handoff event gap or replay."
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
cursor = event.sequence;
|
|
1511
|
+
if (event.epoch > page.epoch) {
|
|
1512
|
+
ctx.addIssue({
|
|
1513
|
+
code: "custom",
|
|
1514
|
+
message: "Event exceeds current epoch."
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
if (!page.hasMore && currentStatus !== void 0 && currentStatus !== page.status)
|
|
1519
|
+
ctx.addIssue({
|
|
1520
|
+
code: "custom",
|
|
1521
|
+
message: "Handoff ownership contradicts its final status event."
|
|
1522
|
+
});
|
|
1523
|
+
if (page.cursor !== cursor || page.hasMore && page.events.length === 0) {
|
|
1524
|
+
ctx.addIssue({ code: "custom", message: "Invalid handoff page cursor." });
|
|
1525
|
+
}
|
|
1526
|
+
if (page.epoch === 0 !== (page.handoffId === null)) {
|
|
1527
|
+
ctx.addIssue({ code: "custom", message: "Invalid handoff identity." });
|
|
1528
|
+
}
|
|
1529
|
+
if (page.handoffId === null && page.status !== "ai") {
|
|
1530
|
+
ctx.addIssue({
|
|
1531
|
+
code: "custom",
|
|
1532
|
+
message: "Handoff identity is required."
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
});
|
|
1536
|
+
var agentRuntimeHandoffStartSchema = z.strictObject({
|
|
1537
|
+
operationId: id
|
|
1538
|
+
});
|
|
1539
|
+
var agentRuntimeHandoffCommandSchema = z.strictObject({
|
|
1540
|
+
operationId: id,
|
|
1541
|
+
handoffId: id,
|
|
1542
|
+
epoch: sequence.refine((value) => value > 0)
|
|
1543
|
+
});
|
|
1544
|
+
var agentRuntimeHandoffMessageSchema = agentRuntimeHandoffCommandSchema.extend({ message: text2 });
|
|
1545
|
+
var agentRuntimeHandoffBindingSchema = z.strictObject({
|
|
1546
|
+
tenantId: id,
|
|
1547
|
+
indexId: id,
|
|
1548
|
+
visitorSubject: id,
|
|
1549
|
+
sessionId: id,
|
|
1550
|
+
handoffId: id,
|
|
1551
|
+
epoch: sequence.refine((value) => value > 0)
|
|
1552
|
+
});
|
|
1553
|
+
var providerEventBase = {
|
|
1554
|
+
apiVersion: z.literal(agentRuntimeHandoffVersion),
|
|
1555
|
+
binding: agentRuntimeHandoffBindingSchema,
|
|
1556
|
+
eventId: id,
|
|
1557
|
+
sequence: sequence.refine((value) => value > 0)
|
|
1558
|
+
};
|
|
1559
|
+
var agentRuntimeHandoffProviderEventSchema = z.discriminatedUnion(
|
|
1560
|
+
"type",
|
|
1561
|
+
[
|
|
1562
|
+
z.strictObject({ ...providerEventBase, type: z.literal("queued") }),
|
|
1563
|
+
z.strictObject({
|
|
1564
|
+
...providerEventBase,
|
|
1565
|
+
type: z.literal("assigned"),
|
|
1566
|
+
actor: agentRuntimeHandoffActorSchema
|
|
1567
|
+
}),
|
|
1568
|
+
z.strictObject({
|
|
1569
|
+
...providerEventBase,
|
|
1570
|
+
type: z.literal("human.message"),
|
|
1571
|
+
actor: agentRuntimeHandoffActorSchema,
|
|
1572
|
+
message: text2
|
|
1573
|
+
}),
|
|
1574
|
+
z.strictObject({ ...providerEventBase, type: z.literal("resolved") }),
|
|
1575
|
+
z.strictObject({ ...providerEventBase, type: z.literal("failed") })
|
|
1576
|
+
]
|
|
1577
|
+
);
|
|
1578
|
+
|
|
1221
1579
|
// src/runtime/capability.ts
|
|
1222
|
-
import { ClientError } from "eve/client";
|
|
1580
|
+
import { ClientError as ClientError2 } from "eve/client";
|
|
1223
1581
|
var MAX_REFRESH_SKEW_MS = 3e4;
|
|
1224
1582
|
var LOCAL_LOOPBACK_ORIGINS = [
|
|
1225
1583
|
"http://127.0.0.1:3010",
|
|
@@ -1287,18 +1645,26 @@ function createAgentRuntimeCapability(options) {
|
|
|
1287
1645
|
);
|
|
1288
1646
|
}
|
|
1289
1647
|
}
|
|
1290
|
-
const bootstrapBody =
|
|
1648
|
+
const bootstrapBody = {
|
|
1291
1649
|
clientSessionId: options.visitorSessionId,
|
|
1292
1650
|
indexId: options.indexId,
|
|
1293
1651
|
...previewBuildId ? { previewBuildId } : {},
|
|
1294
1652
|
...previewGrant ? { previewGrant } : {},
|
|
1295
1653
|
version: options.version
|
|
1296
|
-
}
|
|
1297
|
-
const postBootstrap = (origin) =>
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1654
|
+
};
|
|
1655
|
+
const postBootstrap = async (origin) => {
|
|
1656
|
+
const send = (advertiseLocation) => fetchImplementation(`${origin}/webless/v1/bootstrap`, {
|
|
1657
|
+
body: JSON.stringify({ ...bootstrapBody, ...advertiseLocation ? { locationConsent: "v1" } : {} }),
|
|
1658
|
+
headers: { "content-type": "application/json" },
|
|
1659
|
+
method: "POST"
|
|
1660
|
+
});
|
|
1661
|
+
const response2 = await send(Boolean(options.locationConsent));
|
|
1662
|
+
if (options.locationConsent && response2.status === 400) {
|
|
1663
|
+
const error = await response2.clone().json().catch(() => null);
|
|
1664
|
+
if (isRecord3(error) && error.code === "invalid_request") return send(false);
|
|
1665
|
+
}
|
|
1666
|
+
return response2;
|
|
1667
|
+
};
|
|
1302
1668
|
let response;
|
|
1303
1669
|
let lastError;
|
|
1304
1670
|
for (const origin of localBootstrapOrigins(options.runtimeOrigin)) {
|
|
@@ -1356,7 +1722,7 @@ async function withCapabilityRefresh(capability, request) {
|
|
|
1356
1722
|
try {
|
|
1357
1723
|
return await request();
|
|
1358
1724
|
} catch (error) {
|
|
1359
|
-
if (!(error instanceof
|
|
1725
|
+
if (!(error instanceof ClientError2) || error.status !== 401) {
|
|
1360
1726
|
throw error;
|
|
1361
1727
|
}
|
|
1362
1728
|
capability.invalidate();
|
|
@@ -1364,6 +1730,75 @@ async function withCapabilityRefresh(capability, request) {
|
|
|
1364
1730
|
}
|
|
1365
1731
|
}
|
|
1366
1732
|
|
|
1733
|
+
// src/runtime/handoff.ts
|
|
1734
|
+
function createHandoffClient(options) {
|
|
1735
|
+
const target = () => {
|
|
1736
|
+
const sessionId = options.getSessionId();
|
|
1737
|
+
if (!sessionId)
|
|
1738
|
+
throw new Error(
|
|
1739
|
+
"Start a conversation before requesting a representative."
|
|
1740
|
+
);
|
|
1741
|
+
return {
|
|
1742
|
+
sessionId,
|
|
1743
|
+
path: `/webless/v1/session/${encodeURIComponent(sessionId)}/handoff`
|
|
1744
|
+
};
|
|
1745
|
+
};
|
|
1746
|
+
const request = (path, init) => withCapabilityRefresh(options.capability, async () => {
|
|
1747
|
+
const response = await options.getClient().fetch(path, {
|
|
1748
|
+
...init,
|
|
1749
|
+
cache: "no-store",
|
|
1750
|
+
redirect: "error"
|
|
1751
|
+
});
|
|
1752
|
+
if (!response.ok) {
|
|
1753
|
+
throw new ClientError3(
|
|
1754
|
+
response.status,
|
|
1755
|
+
await response.text(),
|
|
1756
|
+
response.headers
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
return response;
|
|
1760
|
+
});
|
|
1761
|
+
const command = async (suffix, body, signal) => {
|
|
1762
|
+
const { path } = target();
|
|
1763
|
+
await request(path + suffix, {
|
|
1764
|
+
method: "POST",
|
|
1765
|
+
headers: { "content-type": "application/json" },
|
|
1766
|
+
body: JSON.stringify(body),
|
|
1767
|
+
signal
|
|
1768
|
+
});
|
|
1769
|
+
};
|
|
1770
|
+
return {
|
|
1771
|
+
async read(input = {}) {
|
|
1772
|
+
const { after } = agentRuntimeHandoffReadRequestSchema.parse({
|
|
1773
|
+
after: input.after
|
|
1774
|
+
});
|
|
1775
|
+
const { sessionId, path } = target();
|
|
1776
|
+
const response = await request(`${path}?after=${after}`, {
|
|
1777
|
+
signal: input.signal
|
|
1778
|
+
});
|
|
1779
|
+
const value = await response.json();
|
|
1780
|
+
const page = agentRuntimeHandoffPageSchema.parse(value);
|
|
1781
|
+
if (page.sessionId !== sessionId || page.after !== after) {
|
|
1782
|
+
throw new Error(
|
|
1783
|
+
"The handoff response does not belong to this conversation or cursor."
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
return page;
|
|
1787
|
+
},
|
|
1788
|
+
start: (operationId, signal) => command(
|
|
1789
|
+
"",
|
|
1790
|
+
agentRuntimeHandoffStartSchema.parse({ operationId }),
|
|
1791
|
+
signal
|
|
1792
|
+
),
|
|
1793
|
+
send: (input, signal) => command(
|
|
1794
|
+
"/messages",
|
|
1795
|
+
agentRuntimeHandoffMessageSchema.parse(input),
|
|
1796
|
+
signal
|
|
1797
|
+
),
|
|
1798
|
+
returnToAI: (input, signal) => command("/return", agentRuntimeHandoffCommandSchema.parse(input), signal)
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1367
1802
|
// src/runtime/config.ts
|
|
1368
1803
|
var DEFAULT_RUNTIME_ORIGIN = "https://runtime.staging.webless.ai";
|
|
1369
1804
|
var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
|
|
@@ -1833,6 +2268,7 @@ function specialistNameFromInput(input) {
|
|
|
1833
2268
|
return match?.[1]?.trim() || void 0;
|
|
1834
2269
|
}
|
|
1835
2270
|
function requestedWorkItem(action) {
|
|
2271
|
+
if (action.kind === "tool-call" && action.toolName === "request_location") return null;
|
|
1836
2272
|
if (action.kind === "tool-call" && action.toolName === "search_discovery") {
|
|
1837
2273
|
return {
|
|
1838
2274
|
id: action.callId,
|
|
@@ -1938,13 +2374,14 @@ function applyWorkEvent(event, handlers, workItems) {
|
|
|
1938
2374
|
);
|
|
1939
2375
|
}
|
|
1940
2376
|
var AgentSession = class {
|
|
1941
|
-
constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, previewBuildId, getUnpublishedPreviewGrant) {
|
|
2377
|
+
constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, previewBuildId, getUnpublishedPreviewGrant, locationConsent) {
|
|
1942
2378
|
this.indexId = indexId;
|
|
1943
2379
|
this.version = version;
|
|
1944
2380
|
this.runtimeOrigin = runtimeOrigin;
|
|
1945
2381
|
this.visitorSessionId = visitorSessionId;
|
|
1946
2382
|
this.storeOptions = storeOptions;
|
|
1947
2383
|
this.capability = createAgentRuntimeCapability({
|
|
2384
|
+
locationConsent,
|
|
1948
2385
|
getUnpublishedPreviewGrant,
|
|
1949
2386
|
indexId,
|
|
1950
2387
|
previewBuildId,
|
|
@@ -1952,6 +2389,11 @@ var AgentSession = class {
|
|
|
1952
2389
|
version,
|
|
1953
2390
|
visitorSessionId
|
|
1954
2391
|
});
|
|
2392
|
+
this.handoff = createHandoffClient({
|
|
2393
|
+
getClient: () => this.ensureClient(),
|
|
2394
|
+
getSessionId: () => this.getActiveSessionId(),
|
|
2395
|
+
capability: this.capability
|
|
2396
|
+
});
|
|
1955
2397
|
}
|
|
1956
2398
|
indexId;
|
|
1957
2399
|
version;
|
|
@@ -1964,6 +2406,7 @@ var AgentSession = class {
|
|
|
1964
2406
|
activeResponse;
|
|
1965
2407
|
childStreams;
|
|
1966
2408
|
capability;
|
|
2409
|
+
handoff;
|
|
1967
2410
|
getActiveSessionId() {
|
|
1968
2411
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
1969
2412
|
}
|
|
@@ -2074,7 +2517,7 @@ var AgentSession = class {
|
|
|
2074
2517
|
() => activeSession.send(message, { signal })
|
|
2075
2518
|
);
|
|
2076
2519
|
} catch (error) {
|
|
2077
|
-
if (error instanceof
|
|
2520
|
+
if (error instanceof ClientError4 && error.status === 409 && error.code === "session_not_active") {
|
|
2078
2521
|
clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
2079
2522
|
this.session = void 0;
|
|
2080
2523
|
session = void 0;
|
|
@@ -2248,10 +2691,10 @@ var AgentSession = class {
|
|
|
2248
2691
|
}
|
|
2249
2692
|
this.session = session;
|
|
2250
2693
|
const inputResponses = responses.map(
|
|
2251
|
-
({ requestId, optionId, text:
|
|
2694
|
+
({ requestId, optionId, text: text3 }) => ({
|
|
2252
2695
|
requestId,
|
|
2253
2696
|
...optionId ? { optionId } : {},
|
|
2254
|
-
...
|
|
2697
|
+
...text3 ? { text: text3 } : {}
|
|
2255
2698
|
})
|
|
2256
2699
|
);
|
|
2257
2700
|
const response = await withCapabilityRefresh(
|
|
@@ -2336,10 +2779,12 @@ function createAgentClient(options) {
|
|
|
2336
2779
|
visitorSessionId,
|
|
2337
2780
|
storeOptions,
|
|
2338
2781
|
options.previewBuildId,
|
|
2339
|
-
options.getUnpublishedPreviewGrant
|
|
2782
|
+
options.getUnpublishedPreviewGrant,
|
|
2783
|
+
options.locationConsent
|
|
2340
2784
|
);
|
|
2341
2785
|
return {
|
|
2342
2786
|
indexId,
|
|
2787
|
+
handoff: session.handoff,
|
|
2343
2788
|
version,
|
|
2344
2789
|
runtimeOrigin,
|
|
2345
2790
|
visitorSessionId,
|
|
@@ -2371,7 +2816,7 @@ function createAgentClient(options) {
|
|
|
2371
2816
|
}
|
|
2372
2817
|
|
|
2373
2818
|
// src/runtime/errors.ts
|
|
2374
|
-
import { ClientError as
|
|
2819
|
+
import { ClientError as ClientError5 } from "eve/client";
|
|
2375
2820
|
var TRANSIENT_AGENT_ERROR_MESSAGE = "The agent run stopped before the action finished. Please try again.";
|
|
2376
2821
|
var PREVIEW_AUTHORIZATION_ERROR_MESSAGE = "This preview could not be authorized. Open the latest preview from Webless.";
|
|
2377
2822
|
function isTransientRuntimeMessage(message) {
|
|
@@ -2383,7 +2828,7 @@ function isPreviewAuthorizationMessage(message) {
|
|
|
2383
2828
|
return normalized.includes("unpublished preview authorization") || normalized.includes("unpublished preview grant") || normalized.includes("agent studio preview grant") || normalized.includes("preview authorization");
|
|
2384
2829
|
}
|
|
2385
2830
|
function formatAgentError(error) {
|
|
2386
|
-
if (error instanceof
|
|
2831
|
+
if (error instanceof ClientError5) {
|
|
2387
2832
|
if (error.status === 401 && error.code === "index_required") {
|
|
2388
2833
|
return "Missing indexId \u2014 pass a published index id to createAgentClient().";
|
|
2389
2834
|
}
|
|
@@ -2421,9 +2866,21 @@ function conversationKey(storageKeyPrefix, visitorSessionId) {
|
|
|
2421
2866
|
function parseMessage(value) {
|
|
2422
2867
|
if (typeof value !== "object" || value === null) return null;
|
|
2423
2868
|
const record2 = value;
|
|
2424
|
-
if (typeof record2.id !== "string" || record2.role !== "agent" && record2.role !== "visitor" || typeof record2.text !== "string" || typeof record2.createdAt !== "number" || !Number.isFinite(record2.createdAt)) {
|
|
2869
|
+
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)) {
|
|
2425
2870
|
return null;
|
|
2426
2871
|
}
|
|
2872
|
+
if (record2.role === "human") {
|
|
2873
|
+
const person = record2.representative;
|
|
2874
|
+
if (typeof person !== "object" || person === null || !("id" in person) || !("name" in person) || typeof person.id !== "string" || typeof person.name !== "string")
|
|
2875
|
+
return null;
|
|
2876
|
+
return {
|
|
2877
|
+
id: record2.id,
|
|
2878
|
+
role: "human",
|
|
2879
|
+
text: record2.text,
|
|
2880
|
+
createdAt: record2.createdAt,
|
|
2881
|
+
representative: { id: person.id, name: person.name }
|
|
2882
|
+
};
|
|
2883
|
+
}
|
|
2427
2884
|
if (record2.role === "visitor") {
|
|
2428
2885
|
return {
|
|
2429
2886
|
id: record2.id,
|
|
@@ -2737,15 +3194,15 @@ function appendChatCollectiblePrompts(messages, requests) {
|
|
|
2737
3194
|
}
|
|
2738
3195
|
return next;
|
|
2739
3196
|
}
|
|
2740
|
-
function chatInputResponseForText(requests,
|
|
2741
|
-
const trimmed =
|
|
3197
|
+
function chatInputResponseForText(requests, text3) {
|
|
3198
|
+
const trimmed = text3.trim();
|
|
2742
3199
|
if (!trimmed) return null;
|
|
2743
3200
|
const pending = requests.find(isChatCollectibleInputRequest);
|
|
2744
3201
|
if (!pending) return null;
|
|
2745
3202
|
return { requestId: pending.requestId, text: trimmed };
|
|
2746
3203
|
}
|
|
2747
|
-
function normalizeAssistantDedupeKey(
|
|
2748
|
-
return
|
|
3204
|
+
function normalizeAssistantDedupeKey(text3) {
|
|
3205
|
+
return text3.trim().replace(/\s+/g, " ").toLowerCase();
|
|
2749
3206
|
}
|
|
2750
3207
|
function isNearDuplicateAssistantText(left, right) {
|
|
2751
3208
|
const a = normalizeAssistantDedupeKey(left);
|
|
@@ -2858,6 +3315,7 @@ function isJsonRecord(value) {
|
|
|
2858
3315
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2859
3316
|
}
|
|
2860
3317
|
function useAgentChat({
|
|
3318
|
+
handoffEnabled = false,
|
|
2861
3319
|
customerId,
|
|
2862
3320
|
getUnpublishedPreviewGrant,
|
|
2863
3321
|
indexId,
|
|
@@ -2873,9 +3331,9 @@ function useAgentChat({
|
|
|
2873
3331
|
() => createInitialState(greeting?.trim() || DEFAULT_GREETING),
|
|
2874
3332
|
[greeting]
|
|
2875
3333
|
);
|
|
2876
|
-
const previewGrantProviderRef =
|
|
3334
|
+
const previewGrantProviderRef = useRef2(getUnpublishedPreviewGrant);
|
|
2877
3335
|
previewGrantProviderRef.current = getUnpublishedPreviewGrant;
|
|
2878
|
-
const toolResultRegistryRef =
|
|
3336
|
+
const toolResultRegistryRef = useRef2(toolResultRegistry);
|
|
2879
3337
|
toolResultRegistryRef.current = toolResultRegistry;
|
|
2880
3338
|
const resolveUnpublishedPreviewGrant = () => {
|
|
2881
3339
|
const provider = previewGrantProviderRef.current;
|
|
@@ -2903,18 +3361,19 @@ function useAgentChat({
|
|
|
2903
3361
|
}),
|
|
2904
3362
|
[resolvedStorageKeyPrefix, visitorSessionId]
|
|
2905
3363
|
);
|
|
2906
|
-
const [state, setState] =
|
|
3364
|
+
const [state, setState] = useState2(
|
|
2907
3365
|
() => stateFromConversation(
|
|
2908
3366
|
loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
|
|
2909
3367
|
initialState
|
|
2910
3368
|
)
|
|
2911
3369
|
);
|
|
2912
|
-
const pendingBookingRef =
|
|
3370
|
+
const pendingBookingRef = useRef2(
|
|
2913
3371
|
loadPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId)
|
|
2914
3372
|
);
|
|
2915
|
-
const runRef =
|
|
2916
|
-
const clientRef =
|
|
3373
|
+
const runRef = useRef2(null);
|
|
3374
|
+
const clientRef = useRef2(
|
|
2917
3375
|
createAgentClient({
|
|
3376
|
+
locationConsent: true,
|
|
2918
3377
|
customerId,
|
|
2919
3378
|
getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
|
|
2920
3379
|
indexId,
|
|
@@ -2926,8 +3385,8 @@ function useAgentChat({
|
|
|
2926
3385
|
})
|
|
2927
3386
|
);
|
|
2928
3387
|
const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${previewBuildId ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
|
|
2929
|
-
const identityRef =
|
|
2930
|
-
|
|
3388
|
+
const identityRef = useRef2(identityKey);
|
|
3389
|
+
useEffect2(() => {
|
|
2931
3390
|
if (identityRef.current === identityKey) {
|
|
2932
3391
|
return;
|
|
2933
3392
|
}
|
|
@@ -2935,6 +3394,7 @@ function useAgentChat({
|
|
|
2935
3394
|
runRef.current?.abort();
|
|
2936
3395
|
runRef.current = null;
|
|
2937
3396
|
clientRef.current = createAgentClient({
|
|
3397
|
+
locationConsent: true,
|
|
2938
3398
|
customerId,
|
|
2939
3399
|
getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
|
|
2940
3400
|
indexId,
|
|
@@ -2965,7 +3425,7 @@ function useAgentChat({
|
|
|
2965
3425
|
version,
|
|
2966
3426
|
visitorId
|
|
2967
3427
|
]);
|
|
2968
|
-
|
|
3428
|
+
useEffect2(() => {
|
|
2969
3429
|
if (!hasVisitorMessages(state.messages)) return;
|
|
2970
3430
|
savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
|
|
2971
3431
|
messages: state.messages,
|
|
@@ -2985,16 +3445,77 @@ function useAgentChat({
|
|
|
2985
3445
|
state.toolResults,
|
|
2986
3446
|
visitorId
|
|
2987
3447
|
]);
|
|
3448
|
+
const handoff = useAgentHandoff({
|
|
3449
|
+
enabled: handoffEnabled,
|
|
3450
|
+
client: clientRef.current,
|
|
3451
|
+
sessionId: clientRef.current.getActiveSessionId(),
|
|
3452
|
+
onOwnership: () => {
|
|
3453
|
+
runRef.current?.abort();
|
|
3454
|
+
runRef.current = null;
|
|
3455
|
+
setState(
|
|
3456
|
+
(prev) => prev.phase === "complete" && !prev.streamingText && !prev.pendingInputs?.length && !prev.toolSteps.length ? prev : {
|
|
3457
|
+
...prev,
|
|
3458
|
+
phase: "complete",
|
|
3459
|
+
streamingText: "",
|
|
3460
|
+
pendingInputs: [],
|
|
3461
|
+
toolSteps: [],
|
|
3462
|
+
toolResults: [],
|
|
3463
|
+
pendingOffer: null,
|
|
3464
|
+
error: null
|
|
3465
|
+
}
|
|
3466
|
+
);
|
|
3467
|
+
},
|
|
3468
|
+
onEvents: (events) => {
|
|
3469
|
+
setState((prev) => {
|
|
3470
|
+
const seen = new Set(prev.messages.map((message) => message.id));
|
|
3471
|
+
const messages = [];
|
|
3472
|
+
for (const event of events) {
|
|
3473
|
+
if (event.type === "status" || seen.has(`handoff-${event.id}`))
|
|
3474
|
+
continue;
|
|
3475
|
+
messages.push(
|
|
3476
|
+
event.type === "human.message" ? {
|
|
3477
|
+
id: `handoff-${event.id}`,
|
|
3478
|
+
role: "human",
|
|
3479
|
+
text: event.message,
|
|
3480
|
+
createdAt: Date.parse(event.createdAt),
|
|
3481
|
+
representative: event.actor
|
|
3482
|
+
} : {
|
|
3483
|
+
id: `handoff-${event.id}`,
|
|
3484
|
+
role: "visitor",
|
|
3485
|
+
text: event.message,
|
|
3486
|
+
createdAt: Date.parse(event.createdAt)
|
|
3487
|
+
}
|
|
3488
|
+
);
|
|
3489
|
+
}
|
|
3490
|
+
return messages.length ? {
|
|
3491
|
+
...prev,
|
|
3492
|
+
messages: [...prev.messages, ...messages].sort(
|
|
3493
|
+
(a, b) => a.createdAt - b.createdAt
|
|
3494
|
+
)
|
|
3495
|
+
} : prev;
|
|
3496
|
+
});
|
|
3497
|
+
}
|
|
3498
|
+
});
|
|
3499
|
+
const handoffBlocksAI = useRef2(handoff.blocksAI);
|
|
3500
|
+
handoffBlocksAI.current = handoff.blocksAI;
|
|
2988
3501
|
const reset = useCallback(() => {
|
|
3502
|
+
if (handoff.blocksAI && !handoff.canReset) return;
|
|
2989
3503
|
runRef.current?.abort();
|
|
2990
3504
|
runRef.current = null;
|
|
2991
3505
|
clientRef.current.reset();
|
|
2992
3506
|
pendingBookingRef.current = null;
|
|
2993
3507
|
clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
|
|
2994
3508
|
setState(initialState);
|
|
2995
|
-
}, [
|
|
3509
|
+
}, [
|
|
3510
|
+
handoff.blocksAI,
|
|
3511
|
+
handoff.canReset,
|
|
3512
|
+
initialState,
|
|
3513
|
+
resolvedStorageKeyPrefix,
|
|
3514
|
+
visitorId
|
|
3515
|
+
]);
|
|
2996
3516
|
const runTurn = useCallback(
|
|
2997
3517
|
async (input) => {
|
|
3518
|
+
if (handoffBlocksAI.current) return null;
|
|
2998
3519
|
const {
|
|
2999
3520
|
controller,
|
|
3000
3521
|
initialText = "",
|
|
@@ -3118,6 +3639,7 @@ function useAgentChat({
|
|
|
3118
3639
|
signal
|
|
3119
3640
|
});
|
|
3120
3641
|
if (resume && finalText === null) {
|
|
3642
|
+
if (!isActiveRun() || handoffBlocksAI.current) return null;
|
|
3121
3643
|
finalText = await clientRef.current.sendTurn(visitorText, {
|
|
3122
3644
|
handlers,
|
|
3123
3645
|
signal
|
|
@@ -3150,8 +3672,12 @@ function useAgentChat({
|
|
|
3150
3672
|
messages: appendAgentTurnMessage(
|
|
3151
3673
|
prev.messages,
|
|
3152
3674
|
displayText,
|
|
3153
|
-
(prev.toolResults ?? []).filter(
|
|
3154
|
-
|
|
3675
|
+
(prev.toolResults ?? []).filter(
|
|
3676
|
+
(result) => result.kind === "search"
|
|
3677
|
+
),
|
|
3678
|
+
(prev.toolResults ?? []).filter(
|
|
3679
|
+
(result) => result.kind !== "search" && result.kind !== "input"
|
|
3680
|
+
)
|
|
3155
3681
|
),
|
|
3156
3682
|
toolResults: (prev.toolResults ?? []).filter(
|
|
3157
3683
|
(result) => result.kind === "input"
|
|
@@ -3219,6 +3745,15 @@ function useAgentChat({
|
|
|
3219
3745
|
const outgoing = options?.runtimeText ?? visitorText;
|
|
3220
3746
|
if (!outgoing.trim()) return null;
|
|
3221
3747
|
const declinedComposerFormId = options?.declinedComposerFormId?.trim();
|
|
3748
|
+
if (handoff.blocksAI) {
|
|
3749
|
+
if (!["requesting", "queued", "human"].includes(
|
|
3750
|
+
handoff.page?.status ?? ""
|
|
3751
|
+
) || handoff.busy)
|
|
3752
|
+
return null;
|
|
3753
|
+
if (!trimmed) return null;
|
|
3754
|
+
await handoff.send(trimmed);
|
|
3755
|
+
return null;
|
|
3756
|
+
}
|
|
3222
3757
|
const chatResponse = chatInputResponseForText(
|
|
3223
3758
|
state.pendingInputs ?? [],
|
|
3224
3759
|
outgoing.trim()
|
|
@@ -3320,9 +3855,10 @@ ${outgoing}` : outgoing;
|
|
|
3320
3855
|
visitorText: runtimeText
|
|
3321
3856
|
});
|
|
3322
3857
|
},
|
|
3323
|
-
[runTurn, state.pendingInputs]
|
|
3858
|
+
[handoff, runTurn, state.pendingInputs]
|
|
3324
3859
|
);
|
|
3325
3860
|
const retry = useCallback(async () => {
|
|
3861
|
+
if (handoffBlocksAI.current) return;
|
|
3326
3862
|
const visitorMessage = [...state.messages].reverse().find((message) => message.role === "visitor");
|
|
3327
3863
|
if (!visitorMessage) return;
|
|
3328
3864
|
if (runRef.current) {
|
|
@@ -3356,6 +3892,7 @@ ${outgoing}` : outgoing;
|
|
|
3356
3892
|
});
|
|
3357
3893
|
}, [runTurn, state.messages]);
|
|
3358
3894
|
const regenerate = useCallback(async () => {
|
|
3895
|
+
if (handoffBlocksAI.current) return null;
|
|
3359
3896
|
let lastVisitorIndex = -1;
|
|
3360
3897
|
for (let index = state.messages.length - 1; index >= 0; index -= 1) {
|
|
3361
3898
|
if (state.messages[index]?.role === "visitor") {
|
|
@@ -3413,7 +3950,7 @@ ${outgoing}` : outgoing;
|
|
|
3413
3950
|
);
|
|
3414
3951
|
const respondToInput = useCallback(
|
|
3415
3952
|
async (response) => {
|
|
3416
|
-
if (runRef.current) return;
|
|
3953
|
+
if (handoffBlocksAI.current || runRef.current) return;
|
|
3417
3954
|
const pending = state.pendingInputs?.find(
|
|
3418
3955
|
(request) => request.requestId === response.requestId
|
|
3419
3956
|
);
|
|
@@ -3441,7 +3978,8 @@ ${outgoing}` : outgoing;
|
|
|
3441
3978
|
},
|
|
3442
3979
|
[respondToToolInput, runTurn, state.pendingInputs]
|
|
3443
3980
|
);
|
|
3444
|
-
|
|
3981
|
+
useEffect2(() => {
|
|
3982
|
+
if (handoff.blocksAI) return;
|
|
3445
3983
|
const conversation = loadPersistedAgentConversation(
|
|
3446
3984
|
resolvedStorageKeyPrefix,
|
|
3447
3985
|
visitorId
|
|
@@ -3463,14 +4001,21 @@ ${outgoing}` : outgoing;
|
|
|
3463
4001
|
}
|
|
3464
4002
|
controller.abort();
|
|
3465
4003
|
};
|
|
3466
|
-
}, [
|
|
3467
|
-
|
|
4004
|
+
}, [
|
|
4005
|
+
handoff.blocksAI,
|
|
4006
|
+
identityKey,
|
|
4007
|
+
resolvedStorageKeyPrefix,
|
|
4008
|
+
runTurn,
|
|
4009
|
+
visitorId
|
|
4010
|
+
]);
|
|
4011
|
+
useEffect2(() => {
|
|
3468
4012
|
return () => {
|
|
3469
4013
|
runRef.current?.abort();
|
|
3470
4014
|
runRef.current = null;
|
|
3471
4015
|
};
|
|
3472
4016
|
}, []);
|
|
3473
4017
|
return {
|
|
4018
|
+
handoff,
|
|
3474
4019
|
state,
|
|
3475
4020
|
reset,
|
|
3476
4021
|
retry,
|
|
@@ -3581,12 +4126,12 @@ var defaultDarkAgentRailTheme = {
|
|
|
3581
4126
|
};
|
|
3582
4127
|
|
|
3583
4128
|
// src/react/components/MessageActions/MessageActions.tsx
|
|
3584
|
-
import { useEffect as
|
|
4129
|
+
import { useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as useState3 } from "react";
|
|
3585
4130
|
import { createPortal } from "react-dom";
|
|
3586
4131
|
|
|
3587
4132
|
// src/react/lib/speech.ts
|
|
3588
|
-
function toSpeechText(
|
|
3589
|
-
let out = hideToolCardFences(
|
|
4133
|
+
function toSpeechText(text3) {
|
|
4134
|
+
let out = hideToolCardFences(text3);
|
|
3590
4135
|
out = out.replace(/```[\s\S]*?```/g, " ");
|
|
3591
4136
|
out = out.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
|
|
3592
4137
|
out = out.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1");
|
|
@@ -3931,12 +4476,12 @@ function StopIcon() {
|
|
|
3931
4476
|
}
|
|
3932
4477
|
) });
|
|
3933
4478
|
}
|
|
3934
|
-
async function writeToClipboard(
|
|
4479
|
+
async function writeToClipboard(text3) {
|
|
3935
4480
|
try {
|
|
3936
|
-
await navigator.clipboard.writeText(
|
|
4481
|
+
await navigator.clipboard.writeText(text3);
|
|
3937
4482
|
} catch {
|
|
3938
4483
|
const textarea = document.createElement("textarea");
|
|
3939
|
-
textarea.value =
|
|
4484
|
+
textarea.value = text3;
|
|
3940
4485
|
textarea.style.position = "fixed";
|
|
3941
4486
|
textarea.style.opacity = "0";
|
|
3942
4487
|
document.body.appendChild(textarea);
|
|
@@ -3987,16 +4532,16 @@ function MessageActions({
|
|
|
3987
4532
|
speechText
|
|
3988
4533
|
}) {
|
|
3989
4534
|
const menuPortalRoot = useAgentRailMenuPortalRoot();
|
|
3990
|
-
const [copied, setCopied] =
|
|
3991
|
-
const [rating, setRating] =
|
|
3992
|
-
const [menuOpen, setMenuOpen] =
|
|
3993
|
-
const [menuPosition, setMenuPosition] =
|
|
3994
|
-
const [speaking, setSpeaking] =
|
|
3995
|
-
const [speechSupported, setSpeechSupported] =
|
|
3996
|
-
const copyTimerRef =
|
|
3997
|
-
const menuRef =
|
|
3998
|
-
const portaledMenuRef =
|
|
3999
|
-
const moreButtonRef =
|
|
4535
|
+
const [copied, setCopied] = useState3(false);
|
|
4536
|
+
const [rating, setRating] = useState3(null);
|
|
4537
|
+
const [menuOpen, setMenuOpen] = useState3(false);
|
|
4538
|
+
const [menuPosition, setMenuPosition] = useState3(null);
|
|
4539
|
+
const [speaking, setSpeaking] = useState3(false);
|
|
4540
|
+
const [speechSupported, setSpeechSupported] = useState3(null);
|
|
4541
|
+
const copyTimerRef = useRef3(null);
|
|
4542
|
+
const menuRef = useRef3(null);
|
|
4543
|
+
const portaledMenuRef = useRef3(null);
|
|
4544
|
+
const moreButtonRef = useRef3(null);
|
|
4000
4545
|
const answeredLabel = formatAnsweredAt(answeredAt ?? 0);
|
|
4001
4546
|
const resolvedSpeechText = speechText ?? toSpeechText(copyText);
|
|
4002
4547
|
const canOpenReceipt = Boolean(receiptSteps) && Boolean(onOpenReceipt);
|
|
@@ -4023,7 +4568,7 @@ function MessageActions({
|
|
|
4023
4568
|
})
|
|
4024
4569
|
);
|
|
4025
4570
|
}, [menuOpen, menuPortalRoot]);
|
|
4026
|
-
|
|
4571
|
+
useEffect3(() => {
|
|
4027
4572
|
const unsubscribe = subscribeSpeechInterrupts(() => setSpeaking(false));
|
|
4028
4573
|
return () => {
|
|
4029
4574
|
unsubscribe();
|
|
@@ -4033,7 +4578,7 @@ function MessageActions({
|
|
|
4033
4578
|
stopSpeech();
|
|
4034
4579
|
};
|
|
4035
4580
|
}, []);
|
|
4036
|
-
|
|
4581
|
+
useEffect3(() => {
|
|
4037
4582
|
if (!menuOpen) return;
|
|
4038
4583
|
const handlePointerDown = (event) => {
|
|
4039
4584
|
const target = event.target;
|
|
@@ -4202,7 +4747,7 @@ function MessageActions({
|
|
|
4202
4747
|
}
|
|
4203
4748
|
|
|
4204
4749
|
// src/react/components/AgentRail/AgentRail.tsx
|
|
4205
|
-
import { useEffect as
|
|
4750
|
+
import { useEffect as useEffect8, useRef as useRef8, useState as useState11 } from "react";
|
|
4206
4751
|
|
|
4207
4752
|
// src/react/lib/agent-theme.ts
|
|
4208
4753
|
function agentThemeStyle(theme, resolvedColorScheme) {
|
|
@@ -4277,7 +4822,7 @@ function resolveAgentColorScheme(colorScheme = "auto", prefersDarkMode) {
|
|
|
4277
4822
|
}
|
|
4278
4823
|
|
|
4279
4824
|
// src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
|
|
4280
|
-
import { useState as
|
|
4825
|
+
import { useState as useState4 } from "react";
|
|
4281
4826
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
4282
4827
|
function joinLabels(labels) {
|
|
4283
4828
|
if (labels.length <= 1) return labels[0] ?? "";
|
|
@@ -4396,7 +4941,7 @@ function AgentActivityBubble({
|
|
|
4396
4941
|
const statusText = workSummary(steps, failed, brandLabel);
|
|
4397
4942
|
const softReview = statusText === AGENT_SOFT_REVIEW_STATUS;
|
|
4398
4943
|
const receiptId = steps.map((step) => step.id).join(":");
|
|
4399
|
-
const [expandedReceiptId, setExpandedReceiptId] =
|
|
4944
|
+
const [expandedReceiptId, setExpandedReceiptId] = useState4(
|
|
4400
4945
|
null
|
|
4401
4946
|
);
|
|
4402
4947
|
const detailsOpen = !active && expandedReceiptId === receiptId;
|
|
@@ -4447,7 +4992,7 @@ function AgentActivityBubble({
|
|
|
4447
4992
|
}
|
|
4448
4993
|
|
|
4449
4994
|
// src/react/components/AnswerReceiptDialog/AnswerReceiptDialog.tsx
|
|
4450
|
-
import { useEffect as
|
|
4995
|
+
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
4451
4996
|
import { createPortal as createPortal2 } from "react-dom";
|
|
4452
4997
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4453
4998
|
var FOCUSABLE_SELECTOR = 'button:not(:disabled), a[href], textarea:not(:disabled), input:not(:disabled), [tabindex]:not([tabindex="-1"])';
|
|
@@ -4469,10 +5014,10 @@ function AnswerReceiptDialog({
|
|
|
4469
5014
|
}) {
|
|
4470
5015
|
const portalRoots = useAgentRailPortalRoots();
|
|
4471
5016
|
const overlayRoot = portalRoots?.overlayRef ?? null;
|
|
4472
|
-
const cardRef =
|
|
4473
|
-
const closeButtonRef =
|
|
4474
|
-
const previouslyFocusedRef =
|
|
4475
|
-
|
|
5017
|
+
const cardRef = useRef4(null);
|
|
5018
|
+
const closeButtonRef = useRef4(null);
|
|
5019
|
+
const previouslyFocusedRef = useRef4(null);
|
|
5020
|
+
useEffect4(() => {
|
|
4476
5021
|
previouslyFocusedRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
4477
5022
|
closeButtonRef.current?.focus({ preventScroll: true });
|
|
4478
5023
|
const handleKeyDown = (event) => {
|
|
@@ -4558,10 +5103,10 @@ function AnswerReceiptDialog({
|
|
|
4558
5103
|
|
|
4559
5104
|
// src/react/components/Composer/Composer.tsx
|
|
4560
5105
|
import {
|
|
4561
|
-
useEffect as
|
|
5106
|
+
useEffect as useEffect5,
|
|
4562
5107
|
useId,
|
|
4563
|
-
useRef as
|
|
4564
|
-
useState as
|
|
5108
|
+
useRef as useRef5,
|
|
5109
|
+
useState as useState5
|
|
4565
5110
|
} from "react";
|
|
4566
5111
|
import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
4567
5112
|
var FORM_SUBMITTED_MESSAGE = "Shared my details";
|
|
@@ -4624,17 +5169,17 @@ function Composer({
|
|
|
4624
5169
|
allowFormResume = true,
|
|
4625
5170
|
onSubmit
|
|
4626
5171
|
}) {
|
|
4627
|
-
const [value, setValue] =
|
|
4628
|
-
const [draft, setDraft] =
|
|
4629
|
-
const inputRef =
|
|
4630
|
-
const firstFieldRef =
|
|
4631
|
-
const formRef =
|
|
5172
|
+
const [value, setValue] = useState5("");
|
|
5173
|
+
const [draft, setDraft] = useState5(() => createDraft(form));
|
|
5174
|
+
const inputRef = useRef5(null);
|
|
5175
|
+
const firstFieldRef = useRef5(null);
|
|
5176
|
+
const formRef = useRef5(null);
|
|
4632
5177
|
const formId = useId();
|
|
4633
5178
|
if (form && form.id !== draft.form?.id) setDraft(createDraft(form));
|
|
4634
5179
|
const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
|
|
4635
5180
|
const activeForm = !disabled && draft.expanded ? savedForm : null;
|
|
4636
5181
|
const canSend = !disabled && Boolean(value.trim() || activeForm);
|
|
4637
|
-
|
|
5182
|
+
useEffect5(() => {
|
|
4638
5183
|
if (activeForm) firstFieldRef.current?.focus();
|
|
4639
5184
|
else if ((savedForm || draft.submitted) && !disabled)
|
|
4640
5185
|
inputRef.current?.focus();
|
|
@@ -4895,7 +5440,7 @@ function FollowUpChips({
|
|
|
4895
5440
|
}
|
|
4896
5441
|
|
|
4897
5442
|
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
4898
|
-
import { useState as
|
|
5443
|
+
import { useState as useState7 } from "react";
|
|
4899
5444
|
|
|
4900
5445
|
// src/react/components/SearchReferences/SearchReferences.tsx
|
|
4901
5446
|
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
@@ -4987,11 +5532,11 @@ function SearchReferences({
|
|
|
4987
5532
|
|
|
4988
5533
|
// src/react/components/BookingCard/BookingCard.tsx
|
|
4989
5534
|
import {
|
|
4990
|
-
useEffect as
|
|
5535
|
+
useEffect as useEffect6,
|
|
4991
5536
|
useId as useId2,
|
|
4992
5537
|
useMemo as useMemo2,
|
|
4993
|
-
useRef as
|
|
4994
|
-
useState as
|
|
5538
|
+
useRef as useRef6,
|
|
5539
|
+
useState as useState6
|
|
4995
5540
|
} from "react";
|
|
4996
5541
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4997
5542
|
var BOOKING_STEPS = [
|
|
@@ -5049,16 +5594,16 @@ function InteractiveBookingCard({
|
|
|
5049
5594
|
}) {
|
|
5050
5595
|
const fieldId = useId2();
|
|
5051
5596
|
const defaultType = offer.eventTypes[0]?.uri ?? offer.slots[0]?.eventTypeUri ?? "";
|
|
5052
|
-
const [step, setStep] =
|
|
5053
|
-
const [eventTypeUri, setEventTypeUri] =
|
|
5054
|
-
const [selectedDate, setSelectedDate] =
|
|
5055
|
-
const [startTime, setStartTime] =
|
|
5056
|
-
const [name, setName] =
|
|
5057
|
-
const [email, setEmail] =
|
|
5058
|
-
const activeStepRef =
|
|
5059
|
-
const previousStepRef =
|
|
5597
|
+
const [step, setStep] = useState6("date");
|
|
5598
|
+
const [eventTypeUri, setEventTypeUri] = useState6(defaultType);
|
|
5599
|
+
const [selectedDate, setSelectedDate] = useState6("");
|
|
5600
|
+
const [startTime, setStartTime] = useState6("");
|
|
5601
|
+
const [name, setName] = useState6("");
|
|
5602
|
+
const [email, setEmail] = useState6("");
|
|
5603
|
+
const activeStepRef = useRef6(null);
|
|
5604
|
+
const previousStepRef = useRef6(step);
|
|
5060
5605
|
const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
|
|
5061
|
-
|
|
5606
|
+
useEffect6(() => {
|
|
5062
5607
|
if (previousStepRef.current === step) return;
|
|
5063
5608
|
previousStepRef.current = step;
|
|
5064
5609
|
activeStepRef.current?.scrollIntoView({ block: "nearest" });
|
|
@@ -5075,7 +5620,7 @@ function InteractiveBookingCard({
|
|
|
5075
5620
|
}
|
|
5076
5621
|
return next;
|
|
5077
5622
|
}, [slots]);
|
|
5078
|
-
const [visibleMonth, setVisibleMonth] =
|
|
5623
|
+
const [visibleMonth, setVisibleMonth] = useState6(
|
|
5079
5624
|
() => firstAvailableBookingMonth(slots)
|
|
5080
5625
|
);
|
|
5081
5626
|
function selectEventType(nextType) {
|
|
@@ -5383,8 +5928,8 @@ function resolveMessageUrl(safeUrl, baseUrl) {
|
|
|
5383
5928
|
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
5384
5929
|
import "streamdown/styles.css";
|
|
5385
5930
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
5386
|
-
function normalizeDedupeText(
|
|
5387
|
-
return
|
|
5931
|
+
function normalizeDedupeText(text3) {
|
|
5932
|
+
return text3.trim().replace(/\s+/g, " ").toLowerCase();
|
|
5388
5933
|
}
|
|
5389
5934
|
function paragraphsAreNearDuplicates(first, second) {
|
|
5390
5935
|
const left = normalizeDedupeText(first);
|
|
@@ -5400,8 +5945,8 @@ function paragraphsShareOpening(first, second) {
|
|
|
5400
5945
|
if (!opening || opening.length < 20) return false;
|
|
5401
5946
|
return second.trim().startsWith(opening);
|
|
5402
5947
|
}
|
|
5403
|
-
function collapseRepeatedText(
|
|
5404
|
-
const trimmed =
|
|
5948
|
+
function collapseRepeatedText(text3) {
|
|
5949
|
+
const trimmed = text3.trim();
|
|
5405
5950
|
if (trimmed.length < 40) return trimmed;
|
|
5406
5951
|
const paragraphs = trimmed.split(/\n{2,}/u).map((part) => part.trim()).filter(Boolean);
|
|
5407
5952
|
if (paragraphs.length === 2 && (paragraphsAreNearDuplicates(paragraphs[0], paragraphs[1]) || paragraphsShareOpening(paragraphs[0], paragraphs[1]))) {
|
|
@@ -5422,13 +5967,14 @@ function MessageBubble({
|
|
|
5422
5967
|
message,
|
|
5423
5968
|
brandLogoUrl,
|
|
5424
5969
|
bookingDisabled = false,
|
|
5970
|
+
showProvenance = false,
|
|
5425
5971
|
bookingReadOnly = false,
|
|
5426
5972
|
linkBaseUrl,
|
|
5427
5973
|
offer,
|
|
5428
5974
|
onBook
|
|
5429
5975
|
}) {
|
|
5430
5976
|
const resolvedLogoUrl = brandLogoUrl?.trim();
|
|
5431
|
-
const [failedLogoUrl, setFailedLogoUrl] =
|
|
5977
|
+
const [failedLogoUrl, setFailedLogoUrl] = useState7(null);
|
|
5432
5978
|
const showBrandLogo = Boolean(resolvedLogoUrl) && failedLogoUrl !== resolvedLogoUrl;
|
|
5433
5979
|
const cards = message.role === "agent" ? extractToolCards(message.text) : [];
|
|
5434
5980
|
const extractedOffers = cards.filter(
|
|
@@ -5443,7 +5989,34 @@ function MessageBubble({
|
|
|
5443
5989
|
if (message.role === "visitor") {
|
|
5444
5990
|
const visitorText = visitorMessageDisplayText(message).trim();
|
|
5445
5991
|
if (!visitorText) return null;
|
|
5446
|
-
return /* @__PURE__ */
|
|
5992
|
+
return /* @__PURE__ */ jsxs8(
|
|
5993
|
+
"article",
|
|
5994
|
+
{
|
|
5995
|
+
className: "message-bubble message-bubble--visitor",
|
|
5996
|
+
"aria-label": "Message from visitor",
|
|
5997
|
+
children: [
|
|
5998
|
+
showProvenance ? /* @__PURE__ */ jsx8("span", { className: "message-bubble__speaker", children: "You \xB7 Visitor" }) : null,
|
|
5999
|
+
/* @__PURE__ */ jsx8("p", { className: "message-bubble__text", children: visitorText })
|
|
6000
|
+
]
|
|
6001
|
+
}
|
|
6002
|
+
);
|
|
6003
|
+
}
|
|
6004
|
+
if (message.role === "human") {
|
|
6005
|
+
return /* @__PURE__ */ jsxs8(
|
|
6006
|
+
"article",
|
|
6007
|
+
{
|
|
6008
|
+
className: "message-bubble message-bubble--human",
|
|
6009
|
+
"aria-label": `Message from ${message.representative.name}`,
|
|
6010
|
+
children: [
|
|
6011
|
+
/* @__PURE__ */ jsxs8("strong", { className: "message-bubble__representative", children: [
|
|
6012
|
+
message.representative.name,
|
|
6013
|
+
" ",
|
|
6014
|
+
/* @__PURE__ */ jsx8("span", { children: "Human representative" })
|
|
6015
|
+
] }),
|
|
6016
|
+
/* @__PURE__ */ jsx8("p", { className: "message-bubble__text", children: message.text })
|
|
6017
|
+
]
|
|
6018
|
+
}
|
|
6019
|
+
);
|
|
5447
6020
|
}
|
|
5448
6021
|
const citations = message.citations ?? [];
|
|
5449
6022
|
const agentText = /* @__PURE__ */ jsxs8("div", { className: "message-bubble__text", children: [
|
|
@@ -5480,35 +6053,43 @@ function MessageBubble({
|
|
|
5480
6053
|
] });
|
|
5481
6054
|
if (!displayText && !message.searchResults?.length && offers.length === 0)
|
|
5482
6055
|
return null;
|
|
5483
|
-
return /* @__PURE__ */ jsxs8(
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
6056
|
+
return /* @__PURE__ */ jsxs8(
|
|
6057
|
+
"article",
|
|
6058
|
+
{
|
|
6059
|
+
className: "message-bubble message-bubble--agent",
|
|
6060
|
+
"aria-label": "Message from AI assistant",
|
|
6061
|
+
children: [
|
|
6062
|
+
showProvenance ? /* @__PURE__ */ jsx8("span", { className: "message-bubble__speaker", children: "AI assistant" }) : null,
|
|
6063
|
+
displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ jsxs8("div", { className: "message-bubble__agent-row", children: [
|
|
6064
|
+
/* @__PURE__ */ jsx8("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsx8(
|
|
6065
|
+
"img",
|
|
6066
|
+
{
|
|
6067
|
+
src: resolvedLogoUrl,
|
|
6068
|
+
alt: "",
|
|
6069
|
+
onError: () => {
|
|
6070
|
+
setFailedLogoUrl(resolvedLogoUrl ?? null);
|
|
6071
|
+
}
|
|
6072
|
+
}
|
|
6073
|
+
) }),
|
|
6074
|
+
agentText
|
|
6075
|
+
] }) : agentText : null,
|
|
6076
|
+
offers.map((nextOffer, index) => /* @__PURE__ */ jsx8(
|
|
6077
|
+
BookingCard,
|
|
6078
|
+
{
|
|
6079
|
+
disabled: bookingDisabled,
|
|
6080
|
+
readOnly: bookingReadOnly,
|
|
6081
|
+
offer: nextOffer,
|
|
6082
|
+
onBook
|
|
6083
|
+
},
|
|
6084
|
+
`${bookingOfferIdentityKey(nextOffer)}-${index}`
|
|
6085
|
+
))
|
|
6086
|
+
]
|
|
6087
|
+
}
|
|
6088
|
+
);
|
|
5508
6089
|
}
|
|
5509
6090
|
|
|
5510
6091
|
// src/react/components/HumanInputCard/HumanInputCard.tsx
|
|
5511
|
-
import { useState as
|
|
6092
|
+
import { useState as useState9 } from "react";
|
|
5512
6093
|
|
|
5513
6094
|
// src/react/components/ConfirmationCard/ConfirmationCard.tsx
|
|
5514
6095
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
@@ -5550,7 +6131,7 @@ function ConfirmationCard({
|
|
|
5550
6131
|
}
|
|
5551
6132
|
|
|
5552
6133
|
// src/react/components/ToolInputCard/ToolInputCard.tsx
|
|
5553
|
-
import { useState as
|
|
6134
|
+
import { useState as useState8 } from "react";
|
|
5554
6135
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5555
6136
|
function isRecord5(value) {
|
|
5556
6137
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -5673,13 +6254,13 @@ function valuesMatch(left, right) {
|
|
|
5673
6254
|
}
|
|
5674
6255
|
function FieldDescription({
|
|
5675
6256
|
field,
|
|
5676
|
-
id
|
|
6257
|
+
id: id2
|
|
5677
6258
|
}) {
|
|
5678
|
-
return field.description ? /* @__PURE__ */ jsx10("span", { id, className: "tool-input-card__description", children: field.description }) : null;
|
|
6259
|
+
return field.description ? /* @__PURE__ */ jsx10("span", { id: id2, className: "tool-input-card__description", children: field.description }) : null;
|
|
5679
6260
|
}
|
|
5680
6261
|
function ChoiceField({
|
|
5681
6262
|
field,
|
|
5682
|
-
id,
|
|
6263
|
+
id: id2,
|
|
5683
6264
|
value,
|
|
5684
6265
|
disabled,
|
|
5685
6266
|
describedBy,
|
|
@@ -5697,7 +6278,7 @@ function ChoiceField({
|
|
|
5697
6278
|
return /* @__PURE__ */ jsxs10(
|
|
5698
6279
|
"select",
|
|
5699
6280
|
{
|
|
5700
|
-
id,
|
|
6281
|
+
id: id2,
|
|
5701
6282
|
value: selectedIndex >= 0 ? String(selectedIndex) : "",
|
|
5702
6283
|
disabled,
|
|
5703
6284
|
required: field.required,
|
|
@@ -5720,7 +6301,7 @@ function ChoiceField({
|
|
|
5720
6301
|
{
|
|
5721
6302
|
className: "tool-input-card__choices",
|
|
5722
6303
|
role: multiple ? "group" : "radiogroup",
|
|
5723
|
-
"aria-labelledby": `${
|
|
6304
|
+
"aria-labelledby": `${id2}-label`,
|
|
5724
6305
|
"aria-describedby": describedBy,
|
|
5725
6306
|
"aria-invalid": Boolean(error),
|
|
5726
6307
|
"aria-required": field.required,
|
|
@@ -5731,7 +6312,7 @@ function ChoiceField({
|
|
|
5731
6312
|
"input",
|
|
5732
6313
|
{
|
|
5733
6314
|
type: multiple ? "checkbox" : "radio",
|
|
5734
|
-
name:
|
|
6315
|
+
name: id2,
|
|
5735
6316
|
value: String(index),
|
|
5736
6317
|
checked,
|
|
5737
6318
|
disabled,
|
|
@@ -5759,22 +6340,22 @@ function ToolField({
|
|
|
5759
6340
|
disabled,
|
|
5760
6341
|
error,
|
|
5761
6342
|
field,
|
|
5762
|
-
id,
|
|
6343
|
+
id: id2,
|
|
5763
6344
|
value,
|
|
5764
6345
|
onBlur,
|
|
5765
6346
|
onChange
|
|
5766
6347
|
}) {
|
|
5767
6348
|
const describedBy = [
|
|
5768
|
-
field.description ? `${
|
|
5769
|
-
error ? `${
|
|
6349
|
+
field.description ? `${id2}-description` : "",
|
|
6350
|
+
error ? `${id2}-error` : ""
|
|
5770
6351
|
].filter(Boolean).join(" ");
|
|
5771
6352
|
if (field.kind === "checkbox" || field.kind === "confirmation") {
|
|
5772
6353
|
return /* @__PURE__ */ jsxs10("div", { className: "tool-input-card__field", children: [
|
|
5773
|
-
/* @__PURE__ */ jsxs10("label", { className: "tool-input-card__check", htmlFor:
|
|
6354
|
+
/* @__PURE__ */ jsxs10("label", { className: "tool-input-card__check", htmlFor: id2, children: [
|
|
5774
6355
|
/* @__PURE__ */ jsx10(
|
|
5775
6356
|
"input",
|
|
5776
6357
|
{
|
|
5777
|
-
id,
|
|
6358
|
+
id: id2,
|
|
5778
6359
|
type: "checkbox",
|
|
5779
6360
|
checked: value === true,
|
|
5780
6361
|
disabled,
|
|
@@ -5786,18 +6367,18 @@ function ToolField({
|
|
|
5786
6367
|
),
|
|
5787
6368
|
/* @__PURE__ */ jsxs10("span", { children: [
|
|
5788
6369
|
/* @__PURE__ */ jsx10("strong", { children: field.label }),
|
|
5789
|
-
field.description ? /* @__PURE__ */ jsx10("span", { id: `${
|
|
6370
|
+
field.description ? /* @__PURE__ */ jsx10("span", { id: `${id2}-description`, children: field.description }) : null
|
|
5790
6371
|
] })
|
|
5791
6372
|
] }),
|
|
5792
|
-
error ? /* @__PURE__ */ jsx10("span", { id: `${
|
|
6373
|
+
error ? /* @__PURE__ */ jsx10("span", { id: `${id2}-error`, className: "tool-input-card__error", children: error }) : null
|
|
5793
6374
|
] });
|
|
5794
6375
|
}
|
|
5795
|
-
const label = /* @__PURE__ */ jsxs10("label", { id: `${
|
|
6376
|
+
const label = /* @__PURE__ */ jsxs10("label", { id: `${id2}-label`, htmlFor: id2, children: [
|
|
5796
6377
|
field.label,
|
|
5797
6378
|
field.required ? /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: " *" }) : null
|
|
5798
6379
|
] });
|
|
5799
6380
|
const common = {
|
|
5800
|
-
id,
|
|
6381
|
+
id: id2,
|
|
5801
6382
|
disabled,
|
|
5802
6383
|
required: field.required,
|
|
5803
6384
|
"aria-describedby": describedBy || void 0,
|
|
@@ -5810,7 +6391,7 @@ function ToolField({
|
|
|
5810
6391
|
ChoiceField,
|
|
5811
6392
|
{
|
|
5812
6393
|
field,
|
|
5813
|
-
id,
|
|
6394
|
+
id: id2,
|
|
5814
6395
|
value,
|
|
5815
6396
|
disabled,
|
|
5816
6397
|
describedBy: describedBy || void 0,
|
|
@@ -5847,7 +6428,7 @@ function ToolField({
|
|
|
5847
6428
|
onChange: (event) => onChange(Number(event.target.value))
|
|
5848
6429
|
}
|
|
5849
6430
|
),
|
|
5850
|
-
/* @__PURE__ */ jsx10("output", { htmlFor:
|
|
6431
|
+
/* @__PURE__ */ jsx10("output", { htmlFor: id2, children: numericValue })
|
|
5851
6432
|
] });
|
|
5852
6433
|
} else {
|
|
5853
6434
|
const type = field.kind === "date-time" ? "datetime-local" : field.kind === "calendar" ? "date" : field.kind;
|
|
@@ -5871,9 +6452,9 @@ function ToolField({
|
|
|
5871
6452
|
}
|
|
5872
6453
|
return /* @__PURE__ */ jsxs10("div", { className: "tool-input-card__field", children: [
|
|
5873
6454
|
label,
|
|
5874
|
-
/* @__PURE__ */ jsx10(FieldDescription, { field, id: `${
|
|
6455
|
+
/* @__PURE__ */ jsx10(FieldDescription, { field, id: `${id2}-description` }),
|
|
5875
6456
|
control,
|
|
5876
|
-
error ? /* @__PURE__ */ jsx10("span", { id: `${
|
|
6457
|
+
error ? /* @__PURE__ */ jsx10("span", { id: `${id2}-error`, className: "tool-input-card__error", children: error }) : null
|
|
5877
6458
|
] });
|
|
5878
6459
|
}
|
|
5879
6460
|
function ToolInputCard({
|
|
@@ -5881,11 +6462,11 @@ function ToolInputCard({
|
|
|
5881
6462
|
surface,
|
|
5882
6463
|
onSubmit
|
|
5883
6464
|
}) {
|
|
5884
|
-
const [values, setValues] =
|
|
6465
|
+
const [values, setValues] = useState8(
|
|
5885
6466
|
() => initialValues(surface)
|
|
5886
6467
|
);
|
|
5887
|
-
const [touched, setTouched] =
|
|
5888
|
-
const [submitted, setSubmitted] =
|
|
6468
|
+
const [touched, setTouched] = useState8(() => /* @__PURE__ */ new Set());
|
|
6469
|
+
const [submitted, setSubmitted] = useState8(false);
|
|
5889
6470
|
const errors = Object.fromEntries(
|
|
5890
6471
|
surface.fields.map((field) => [
|
|
5891
6472
|
field.path,
|
|
@@ -5978,7 +6559,7 @@ function HumanInputCard({
|
|
|
5978
6559
|
request,
|
|
5979
6560
|
onRespond
|
|
5980
6561
|
}) {
|
|
5981
|
-
const [
|
|
6562
|
+
const [text3, setText] = useState9("");
|
|
5982
6563
|
const options = request.options ?? [];
|
|
5983
6564
|
const showText = request.display === "text" || request.allowFreeform && options.length === 0;
|
|
5984
6565
|
if (request.ui) {
|
|
@@ -6003,7 +6584,7 @@ function HumanInputCard({
|
|
|
6003
6584
|
}
|
|
6004
6585
|
function submitText(event) {
|
|
6005
6586
|
event.preventDefault();
|
|
6006
|
-
const value =
|
|
6587
|
+
const value = text3.trim();
|
|
6007
6588
|
if (!value || disabled) return;
|
|
6008
6589
|
onRespond?.({ requestId: request.requestId, text: value });
|
|
6009
6590
|
}
|
|
@@ -6021,12 +6602,12 @@ function HumanInputCard({
|
|
|
6021
6602
|
"input",
|
|
6022
6603
|
{
|
|
6023
6604
|
id: `human-input-text-${request.requestId}`,
|
|
6024
|
-
value:
|
|
6605
|
+
value: text3,
|
|
6025
6606
|
disabled,
|
|
6026
6607
|
onChange: (event) => setText(event.target.value)
|
|
6027
6608
|
}
|
|
6028
6609
|
),
|
|
6029
|
-
/* @__PURE__ */ jsx11("button", { type: "submit", disabled: disabled || !
|
|
6610
|
+
/* @__PURE__ */ jsx11("button", { type: "submit", disabled: disabled || !text3.trim(), children: "Send" })
|
|
6030
6611
|
] })
|
|
6031
6612
|
] }) : null,
|
|
6032
6613
|
!showText && options.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "human-input-card__unavailable", role: "status", children: "This request can\u2019t be answered here." }) : null
|
|
@@ -6035,31 +6616,173 @@ function HumanInputCard({
|
|
|
6035
6616
|
);
|
|
6036
6617
|
}
|
|
6037
6618
|
|
|
6038
|
-
// src/react/components/
|
|
6619
|
+
// src/react/components/LocationConsent/LocationConsent.tsx
|
|
6620
|
+
import { useEffect as useEffect7, useRef as useRef7, useState as useState10 } from "react";
|
|
6621
|
+
|
|
6622
|
+
// src/runtime/location-consent.ts
|
|
6623
|
+
function isLocationConsentRequest(request) {
|
|
6624
|
+
return request.kind === "tool-approval" && request.action.toolName === "request_location";
|
|
6625
|
+
}
|
|
6626
|
+
function preciseLocationResponse(requestId, position) {
|
|
6627
|
+
const { latitude, longitude, accuracy } = position.coords;
|
|
6628
|
+
if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90 || !Number.isFinite(longitude) || longitude < -180 || longitude > 180 || !Number.isFinite(accuracy) || accuracy < 0 || !Number.isFinite(position.timestamp)) {
|
|
6629
|
+
throw new Error("Your device returned an invalid location.");
|
|
6630
|
+
}
|
|
6631
|
+
return {
|
|
6632
|
+
requestId,
|
|
6633
|
+
optionId: "approve",
|
|
6634
|
+
text: JSON.stringify({
|
|
6635
|
+
status: "shared",
|
|
6636
|
+
location: {
|
|
6637
|
+
source: "device",
|
|
6638
|
+
latitude,
|
|
6639
|
+
longitude,
|
|
6640
|
+
accuracyMeters: accuracy,
|
|
6641
|
+
capturedAt: new Date(position.timestamp).toISOString(),
|
|
6642
|
+
consentedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6643
|
+
scope: "conversation"
|
|
6644
|
+
}
|
|
6645
|
+
})
|
|
6646
|
+
};
|
|
6647
|
+
}
|
|
6648
|
+
function getPreciseLocation(geolocation) {
|
|
6649
|
+
return new Promise(
|
|
6650
|
+
(resolve, reject) => geolocation.getCurrentPosition(
|
|
6651
|
+
resolve,
|
|
6652
|
+
(error) => reject(
|
|
6653
|
+
new Error(
|
|
6654
|
+
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."
|
|
6655
|
+
)
|
|
6656
|
+
),
|
|
6657
|
+
{ enableHighAccuracy: true, maximumAge: 0, timeout: 1e4 }
|
|
6658
|
+
)
|
|
6659
|
+
);
|
|
6660
|
+
}
|
|
6661
|
+
|
|
6662
|
+
// src/react/components/LocationConsent/LocationConsent.tsx
|
|
6039
6663
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
6664
|
+
function LocationConsent({
|
|
6665
|
+
request,
|
|
6666
|
+
onRespond
|
|
6667
|
+
}) {
|
|
6668
|
+
const [preference, setPreference] = useState10("unset");
|
|
6669
|
+
const [locating, setLocating] = useState10(false);
|
|
6670
|
+
const [error, setError] = useState10(null);
|
|
6671
|
+
const respond = useRef7(onRespond);
|
|
6672
|
+
const answered = useRef7(null);
|
|
6673
|
+
const requestId = request?.requestId;
|
|
6674
|
+
useEffect7(() => {
|
|
6675
|
+
respond.current = onRespond;
|
|
6676
|
+
}, [onRespond]);
|
|
6677
|
+
useEffect7(() => {
|
|
6678
|
+
if (!requestId || preference === "unset" || answered.current === requestId || !respond.current)
|
|
6679
|
+
return;
|
|
6680
|
+
if (preference === "off") {
|
|
6681
|
+
setLocating(false);
|
|
6682
|
+
answered.current = requestId;
|
|
6683
|
+
respond.current({
|
|
6684
|
+
requestId,
|
|
6685
|
+
optionId: "approve",
|
|
6686
|
+
text: JSON.stringify({ status: "declined" })
|
|
6687
|
+
});
|
|
6688
|
+
return;
|
|
6689
|
+
}
|
|
6690
|
+
let cancelled = false;
|
|
6691
|
+
const pendingId = requestId;
|
|
6692
|
+
setLocating(true);
|
|
6693
|
+
setError(null);
|
|
6694
|
+
async function locate() {
|
|
6695
|
+
try {
|
|
6696
|
+
if (!Reflect.has(navigator, "geolocation"))
|
|
6697
|
+
throw new Error("Location sharing isn\u2019t available in this browser.");
|
|
6698
|
+
const position = await getPreciseLocation(navigator.geolocation);
|
|
6699
|
+
if (cancelled) return;
|
|
6700
|
+
const response = preciseLocationResponse(pendingId, position);
|
|
6701
|
+
answered.current = pendingId;
|
|
6702
|
+
respond.current?.(response);
|
|
6703
|
+
} catch (failure) {
|
|
6704
|
+
if (cancelled) return;
|
|
6705
|
+
setPreference("unset");
|
|
6706
|
+
setError(
|
|
6707
|
+
failure instanceof Error ? failure.message : "Location sharing failed. Try again or continue without sharing."
|
|
6708
|
+
);
|
|
6709
|
+
} finally {
|
|
6710
|
+
if (!cancelled) setLocating(false);
|
|
6711
|
+
}
|
|
6712
|
+
}
|
|
6713
|
+
void locate();
|
|
6714
|
+
return () => {
|
|
6715
|
+
cancelled = true;
|
|
6716
|
+
};
|
|
6717
|
+
}, [requestId, preference]);
|
|
6718
|
+
const isLocating = Boolean(requestId) && preference === "on" && locating;
|
|
6719
|
+
if (!request && preference === "unset") return null;
|
|
6720
|
+
return /* @__PURE__ */ jsxs12("section", { className: "location-consent", "aria-label": "Location sharing", children: [
|
|
6721
|
+
/* @__PURE__ */ jsxs12("div", { className: "location-consent__copy", children: [
|
|
6722
|
+
/* @__PURE__ */ jsx12("strong", { children: isLocating ? "Getting your location\u2026" : request ? "Get better results" : "Precise location" }),
|
|
6723
|
+
/* @__PURE__ */ jsx12("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" })
|
|
6724
|
+
] }),
|
|
6725
|
+
/* @__PURE__ */ jsxs12("div", { className: "location-consent__actions", children: [
|
|
6726
|
+
/* @__PURE__ */ jsx12(
|
|
6727
|
+
"button",
|
|
6728
|
+
{
|
|
6729
|
+
type: "button",
|
|
6730
|
+
role: "switch",
|
|
6731
|
+
className: "location-consent__toggle",
|
|
6732
|
+
"aria-label": "Share precise location",
|
|
6733
|
+
"aria-checked": preference === "on",
|
|
6734
|
+
"aria-busy": isLocating,
|
|
6735
|
+
disabled: !onRespond,
|
|
6736
|
+
onClick: () => {
|
|
6737
|
+
setError(null);
|
|
6738
|
+
setPreference(preference === "on" ? "off" : "on");
|
|
6739
|
+
},
|
|
6740
|
+
children: /* @__PURE__ */ jsx12("span", {})
|
|
6741
|
+
}
|
|
6742
|
+
),
|
|
6743
|
+
request && /* @__PURE__ */ jsx12(
|
|
6744
|
+
"button",
|
|
6745
|
+
{
|
|
6746
|
+
type: "button",
|
|
6747
|
+
className: "location-consent__decline",
|
|
6748
|
+
disabled: !onRespond,
|
|
6749
|
+
onClick: () => {
|
|
6750
|
+
setError(null);
|
|
6751
|
+
setPreference("off");
|
|
6752
|
+
},
|
|
6753
|
+
children: "No thanks"
|
|
6754
|
+
}
|
|
6755
|
+
)
|
|
6756
|
+
] }),
|
|
6757
|
+
error && /* @__PURE__ */ jsx12("p", { role: "alert", className: "location-consent__error", children: error })
|
|
6758
|
+
] });
|
|
6759
|
+
}
|
|
6760
|
+
|
|
6761
|
+
// src/react/components/CollectionResultCard/CollectionResultCard.tsx
|
|
6762
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6040
6763
|
function CollectionResultCard({
|
|
6041
6764
|
result
|
|
6042
6765
|
}) {
|
|
6043
6766
|
const empty = result.items.length === 0;
|
|
6044
|
-
return /* @__PURE__ */
|
|
6767
|
+
return /* @__PURE__ */ jsxs13(
|
|
6045
6768
|
"section",
|
|
6046
6769
|
{
|
|
6047
6770
|
className: `collection-result-card tool-result-card tool-result-card--${result.status}`,
|
|
6048
6771
|
"aria-label": result.title,
|
|
6049
6772
|
role: result.status === "completed" ? "status" : "alert",
|
|
6050
6773
|
children: [
|
|
6051
|
-
/* @__PURE__ */
|
|
6052
|
-
/* @__PURE__ */
|
|
6053
|
-
/* @__PURE__ */
|
|
6774
|
+
/* @__PURE__ */ jsxs13("div", { className: "tool-result-card__heading", children: [
|
|
6775
|
+
/* @__PURE__ */ jsx13("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6776
|
+
/* @__PURE__ */ jsx13("strong", { children: result.title })
|
|
6054
6777
|
] }),
|
|
6055
|
-
empty ? /* @__PURE__ */
|
|
6056
|
-
/* @__PURE__ */
|
|
6057
|
-
item.description ? /* @__PURE__ */
|
|
6058
|
-
item.details?.length ? /* @__PURE__ */
|
|
6059
|
-
/* @__PURE__ */
|
|
6060
|
-
/* @__PURE__ */
|
|
6778
|
+
empty ? /* @__PURE__ */ jsx13("p", { className: "collection-result-card__empty", children: "No matching record for the email you shared." }) : /* @__PURE__ */ jsx13("ul", { className: "collection-result-card__list", children: result.items.map((item) => /* @__PURE__ */ jsxs13("li", { children: [
|
|
6779
|
+
/* @__PURE__ */ jsx13("div", { className: "collection-result-card__item-title", children: item.title }),
|
|
6780
|
+
item.description ? /* @__PURE__ */ jsx13("p", { children: item.description }) : null,
|
|
6781
|
+
item.details?.length ? /* @__PURE__ */ jsx13("dl", { children: item.details.map((detail) => /* @__PURE__ */ jsxs13("div", { children: [
|
|
6782
|
+
/* @__PURE__ */ jsx13("dt", { children: detail.label }),
|
|
6783
|
+
/* @__PURE__ */ jsx13("dd", { children: detail.value })
|
|
6061
6784
|
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6062
|
-
item.href ? /* @__PURE__ */
|
|
6785
|
+
item.href ? /* @__PURE__ */ jsx13("a", { href: item.href, target: "_blank", rel: "noreferrer", children: "Open record" }) : null
|
|
6063
6786
|
] }, item.title)) })
|
|
6064
6787
|
]
|
|
6065
6788
|
}
|
|
@@ -6067,23 +6790,23 @@ function CollectionResultCard({
|
|
|
6067
6790
|
}
|
|
6068
6791
|
|
|
6069
6792
|
// src/react/components/EntityResultCard/EntityResultCard.tsx
|
|
6070
|
-
import { Fragment as Fragment3, jsx as
|
|
6793
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
6071
6794
|
function EntityResultCard({
|
|
6072
6795
|
result
|
|
6073
6796
|
}) {
|
|
6074
6797
|
const compact = !result.description && !result.details?.length && !result.links?.length;
|
|
6075
6798
|
const collapsible = result.status === "completed" && Boolean(result.details?.length) && !result.links?.length;
|
|
6076
|
-
const heading = /* @__PURE__ */
|
|
6077
|
-
/* @__PURE__ */
|
|
6078
|
-
/* @__PURE__ */
|
|
6799
|
+
const heading = /* @__PURE__ */ jsxs14("span", { className: "tool-result-card__heading", children: [
|
|
6800
|
+
/* @__PURE__ */ jsx14("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6801
|
+
/* @__PURE__ */ jsx14("strong", { children: result.title })
|
|
6079
6802
|
] });
|
|
6080
|
-
const content = /* @__PURE__ */
|
|
6081
|
-
result.description ? /* @__PURE__ */
|
|
6082
|
-
result.details?.length ? /* @__PURE__ */
|
|
6083
|
-
/* @__PURE__ */
|
|
6084
|
-
/* @__PURE__ */
|
|
6803
|
+
const content = /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
6804
|
+
result.description ? /* @__PURE__ */ jsx14("p", { children: result.description }) : null,
|
|
6805
|
+
result.details?.length ? /* @__PURE__ */ jsx14("dl", { children: result.details.map((detail) => /* @__PURE__ */ jsxs14("div", { children: [
|
|
6806
|
+
/* @__PURE__ */ jsx14("dt", { children: detail.label }),
|
|
6807
|
+
/* @__PURE__ */ jsx14("dd", { children: detail.value })
|
|
6085
6808
|
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6086
|
-
result.links?.length ? /* @__PURE__ */
|
|
6809
|
+
result.links?.length ? /* @__PURE__ */ jsx14("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ jsx14(
|
|
6087
6810
|
"a",
|
|
6088
6811
|
{
|
|
6089
6812
|
href: link.href,
|
|
@@ -6095,12 +6818,12 @@ function EntityResultCard({
|
|
|
6095
6818
|
)) }) : null
|
|
6096
6819
|
] });
|
|
6097
6820
|
if (collapsible) {
|
|
6098
|
-
return /* @__PURE__ */
|
|
6099
|
-
/* @__PURE__ */
|
|
6821
|
+
return /* @__PURE__ */ jsxs14("details", { className: "entity-result-card tool-result-card entity-result-card--disclosure", children: [
|
|
6822
|
+
/* @__PURE__ */ jsx14("summary", { children: /* @__PURE__ */ jsx14("span", { role: "status", children: heading }) }),
|
|
6100
6823
|
content
|
|
6101
6824
|
] });
|
|
6102
6825
|
}
|
|
6103
|
-
return /* @__PURE__ */
|
|
6826
|
+
return /* @__PURE__ */ jsxs14(
|
|
6104
6827
|
"section",
|
|
6105
6828
|
{
|
|
6106
6829
|
className: `entity-result-card tool-result-card tool-result-card--${result.status}${compact ? " entity-result-card--compact" : ""}`,
|
|
@@ -6115,24 +6838,24 @@ function EntityResultCard({
|
|
|
6115
6838
|
}
|
|
6116
6839
|
|
|
6117
6840
|
// src/react/components/SignatureResultCard/SignatureResultCard.tsx
|
|
6118
|
-
import { jsx as
|
|
6841
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6119
6842
|
function SignatureResultCard({
|
|
6120
6843
|
result
|
|
6121
6844
|
}) {
|
|
6122
6845
|
const primaryLink = result.links?.[0];
|
|
6123
|
-
return /* @__PURE__ */
|
|
6846
|
+
return /* @__PURE__ */ jsxs15(
|
|
6124
6847
|
"section",
|
|
6125
6848
|
{
|
|
6126
6849
|
className: `signature-result-card tool-result-card tool-result-card--${result.status}`,
|
|
6127
6850
|
"aria-label": result.title,
|
|
6128
6851
|
children: [
|
|
6129
|
-
/* @__PURE__ */
|
|
6130
|
-
/* @__PURE__ */
|
|
6131
|
-
/* @__PURE__ */
|
|
6852
|
+
/* @__PURE__ */ jsxs15("div", { className: "tool-result-card__heading", children: [
|
|
6853
|
+
/* @__PURE__ */ jsx15("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6854
|
+
/* @__PURE__ */ jsx15("strong", { children: result.title })
|
|
6132
6855
|
] }),
|
|
6133
|
-
result.statusLabel ? /* @__PURE__ */
|
|
6134
|
-
result.description ? /* @__PURE__ */
|
|
6135
|
-
primaryLink ? /* @__PURE__ */
|
|
6856
|
+
result.statusLabel ? /* @__PURE__ */ jsx15("span", { className: "signature-result-card__badge", children: result.statusLabel }) : null,
|
|
6857
|
+
result.description ? /* @__PURE__ */ jsx15("p", { children: result.description }) : null,
|
|
6858
|
+
primaryLink ? /* @__PURE__ */ jsx15(
|
|
6136
6859
|
"a",
|
|
6137
6860
|
{
|
|
6138
6861
|
className: "signature-result-card__cta",
|
|
@@ -6148,27 +6871,27 @@ function SignatureResultCard({
|
|
|
6148
6871
|
}
|
|
6149
6872
|
|
|
6150
6873
|
// src/react/components/ToolResultCard/ToolResultCard.tsx
|
|
6151
|
-
import { jsx as
|
|
6874
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
6152
6875
|
function ToolResultCard({
|
|
6153
6876
|
result
|
|
6154
6877
|
}) {
|
|
6155
|
-
return /* @__PURE__ */
|
|
6878
|
+
return /* @__PURE__ */ jsxs16(
|
|
6156
6879
|
"section",
|
|
6157
6880
|
{
|
|
6158
6881
|
className: `tool-result-card tool-result-card--${result.status}`,
|
|
6159
6882
|
"aria-label": result.title,
|
|
6160
6883
|
role: result.status === "completed" ? "status" : "alert",
|
|
6161
6884
|
children: [
|
|
6162
|
-
/* @__PURE__ */
|
|
6163
|
-
/* @__PURE__ */
|
|
6164
|
-
/* @__PURE__ */
|
|
6885
|
+
/* @__PURE__ */ jsxs16("div", { className: "tool-result-card__heading", children: [
|
|
6886
|
+
/* @__PURE__ */ jsx16("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6887
|
+
/* @__PURE__ */ jsx16("strong", { children: result.title })
|
|
6165
6888
|
] }),
|
|
6166
|
-
result.description ? /* @__PURE__ */
|
|
6167
|
-
result.details?.length ? /* @__PURE__ */
|
|
6168
|
-
/* @__PURE__ */
|
|
6169
|
-
/* @__PURE__ */
|
|
6889
|
+
result.description ? /* @__PURE__ */ jsx16("p", { children: result.description }) : null,
|
|
6890
|
+
result.details?.length ? /* @__PURE__ */ jsx16("dl", { children: result.details.map((detail) => /* @__PURE__ */ jsxs16("div", { children: [
|
|
6891
|
+
/* @__PURE__ */ jsx16("dt", { children: detail.label }),
|
|
6892
|
+
/* @__PURE__ */ jsx16("dd", { children: detail.value })
|
|
6170
6893
|
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6171
|
-
result.links?.length ? /* @__PURE__ */
|
|
6894
|
+
result.links?.length ? /* @__PURE__ */ jsx16("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ jsx16(
|
|
6172
6895
|
"a",
|
|
6173
6896
|
{
|
|
6174
6897
|
href: link.href,
|
|
@@ -6184,14 +6907,14 @@ function ToolResultCard({
|
|
|
6184
6907
|
}
|
|
6185
6908
|
|
|
6186
6909
|
// src/react/components/VisitorToolResultView/VisitorToolResultView.tsx
|
|
6187
|
-
import { jsx as
|
|
6910
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
6188
6911
|
function VisitorToolResultView({
|
|
6189
6912
|
disabled = false,
|
|
6190
6913
|
onToolInput,
|
|
6191
6914
|
result
|
|
6192
6915
|
}) {
|
|
6193
6916
|
if (result.kind === "input") {
|
|
6194
|
-
return /* @__PURE__ */
|
|
6917
|
+
return /* @__PURE__ */ jsx17(
|
|
6195
6918
|
ToolInputCard,
|
|
6196
6919
|
{
|
|
6197
6920
|
disabled,
|
|
@@ -6201,16 +6924,16 @@ function VisitorToolResultView({
|
|
|
6201
6924
|
);
|
|
6202
6925
|
}
|
|
6203
6926
|
if (result.kind === "entity") {
|
|
6204
|
-
return /* @__PURE__ */
|
|
6927
|
+
return /* @__PURE__ */ jsx17(EntityResultCard, { result });
|
|
6205
6928
|
}
|
|
6206
6929
|
if (result.kind === "collection") {
|
|
6207
|
-
return /* @__PURE__ */
|
|
6930
|
+
return /* @__PURE__ */ jsx17(CollectionResultCard, { result });
|
|
6208
6931
|
}
|
|
6209
6932
|
if (result.kind === "signature") {
|
|
6210
|
-
return /* @__PURE__ */
|
|
6933
|
+
return /* @__PURE__ */ jsx17(SignatureResultCard, { result });
|
|
6211
6934
|
}
|
|
6212
6935
|
if (result.kind === "summary") {
|
|
6213
|
-
return /* @__PURE__ */
|
|
6936
|
+
return /* @__PURE__ */ jsx17(ToolResultCard, { result });
|
|
6214
6937
|
}
|
|
6215
6938
|
return null;
|
|
6216
6939
|
}
|
|
@@ -6219,9 +6942,9 @@ function isRenderableVisitorToolResult(result) {
|
|
|
6219
6942
|
}
|
|
6220
6943
|
|
|
6221
6944
|
// src/react/components/AgentRail/AgentRail.tsx
|
|
6222
|
-
import { Fragment as Fragment4, jsx as
|
|
6945
|
+
import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
6223
6946
|
function MinimizeIcon() {
|
|
6224
|
-
return /* @__PURE__ */
|
|
6947
|
+
return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
|
|
6225
6948
|
"path",
|
|
6226
6949
|
{
|
|
6227
6950
|
d: "M3.5 8h9",
|
|
@@ -6232,7 +6955,7 @@ function MinimizeIcon() {
|
|
|
6232
6955
|
) });
|
|
6233
6956
|
}
|
|
6234
6957
|
function CloseIcon2() {
|
|
6235
|
-
return /* @__PURE__ */
|
|
6958
|
+
return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
|
|
6236
6959
|
"path",
|
|
6237
6960
|
{
|
|
6238
6961
|
d: "M4 4l8 8M12 4l-8 8",
|
|
@@ -6243,7 +6966,7 @@ function CloseIcon2() {
|
|
|
6243
6966
|
) });
|
|
6244
6967
|
}
|
|
6245
6968
|
function NewChatIcon() {
|
|
6246
|
-
return /* @__PURE__ */
|
|
6969
|
+
return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
|
|
6247
6970
|
"path",
|
|
6248
6971
|
{
|
|
6249
6972
|
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",
|
|
@@ -6255,7 +6978,7 @@ function NewChatIcon() {
|
|
|
6255
6978
|
) });
|
|
6256
6979
|
}
|
|
6257
6980
|
function ExpandIcon() {
|
|
6258
|
-
return /* @__PURE__ */
|
|
6981
|
+
return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
|
|
6259
6982
|
"path",
|
|
6260
6983
|
{
|
|
6261
6984
|
d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
|
|
@@ -6267,7 +6990,7 @@ function ExpandIcon() {
|
|
|
6267
6990
|
) });
|
|
6268
6991
|
}
|
|
6269
6992
|
function RestoreIcon() {
|
|
6270
|
-
return /* @__PURE__ */
|
|
6993
|
+
return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
|
|
6271
6994
|
"path",
|
|
6272
6995
|
{
|
|
6273
6996
|
d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
|
|
@@ -6279,7 +7002,7 @@ function RestoreIcon() {
|
|
|
6279
7002
|
) });
|
|
6280
7003
|
}
|
|
6281
7004
|
function ChevronDownIcon() {
|
|
6282
|
-
return /* @__PURE__ */
|
|
7005
|
+
return /* @__PURE__ */ jsx18("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
|
|
6283
7006
|
"path",
|
|
6284
7007
|
{
|
|
6285
7008
|
d: "M4 6.5l4 4 4-4",
|
|
@@ -6293,6 +7016,7 @@ function ChevronDownIcon() {
|
|
|
6293
7016
|
var DEFAULT_DISCLAIMER_LABEL = "Agent can make mistakes. Check important info.";
|
|
6294
7017
|
function AgentRail({
|
|
6295
7018
|
state,
|
|
7019
|
+
handoff,
|
|
6296
7020
|
theme,
|
|
6297
7021
|
colorScheme = "auto",
|
|
6298
7022
|
brandLabel = "",
|
|
@@ -6318,43 +7042,51 @@ function AgentRail({
|
|
|
6318
7042
|
onInputResponse,
|
|
6319
7043
|
onToolInput
|
|
6320
7044
|
}) {
|
|
6321
|
-
const railRef =
|
|
6322
|
-
const overlayRef =
|
|
6323
|
-
const transcriptRef =
|
|
6324
|
-
const responseRef =
|
|
6325
|
-
const threadRef =
|
|
6326
|
-
const lastScrolledVisitorIdRef =
|
|
6327
|
-
const pinnedToBottomRef =
|
|
6328
|
-
const smoothScrollToLatestRef =
|
|
6329
|
-
const lockedTranscriptScrollTopRef =
|
|
6330
|
-
const [showJumpToLatest, setShowJumpToLatest] =
|
|
6331
|
-
const [receiptOpen, setReceiptOpen] =
|
|
7045
|
+
const railRef = useRef8(null);
|
|
7046
|
+
const overlayRef = useRef8(null);
|
|
7047
|
+
const transcriptRef = useRef8(null);
|
|
7048
|
+
const responseRef = useRef8(null);
|
|
7049
|
+
const threadRef = useRef8(null);
|
|
7050
|
+
const lastScrolledVisitorIdRef = useRef8(void 0);
|
|
7051
|
+
const pinnedToBottomRef = useRef8(true);
|
|
7052
|
+
const smoothScrollToLatestRef = useRef8(false);
|
|
7053
|
+
const lockedTranscriptScrollTopRef = useRef8(null);
|
|
7054
|
+
const [showJumpToLatest, setShowJumpToLatest] = useState11(false);
|
|
7055
|
+
const [receiptOpen, setReceiptOpen] = useState11(false);
|
|
6332
7056
|
const resolvedBrandLabel = brandLabel.trim();
|
|
6333
7057
|
const resolvedBrandLogoUrl = brandLogoUrl?.trim();
|
|
6334
7058
|
const resolvedDisclaimerLabel = disclaimerLabel === void 0 ? DEFAULT_DISCLAIMER_LABEL : disclaimerLabel;
|
|
6335
|
-
const [failedLogoUrl, setFailedLogoUrl] =
|
|
7059
|
+
const [failedLogoUrl, setFailedLogoUrl] = useState11(null);
|
|
6336
7060
|
const showBrandLogo = Boolean(resolvedBrandLogoUrl) && failedLogoUrl !== resolvedBrandLogoUrl;
|
|
6337
7061
|
const resolvedColorScheme = useAgentColorScheme(colorScheme);
|
|
6338
7062
|
const railStyle = agentThemeStyle(theme, resolvedColorScheme);
|
|
7063
|
+
const handoffActive = Boolean(handoff?.blocksAI);
|
|
7064
|
+
const handoffStatus = handoff?.page?.status;
|
|
7065
|
+
const locationRequest = handoffActive ? void 0 : state.pendingInputs?.find(isLocationConsentRequest);
|
|
6339
7066
|
const pendingInputRequests = (state.pendingInputs ?? []).filter(
|
|
6340
|
-
(request) => shouldRenderVisitorInputCard(request) && (!state.pendingOffer || request.kind === "tool-approval")
|
|
7067
|
+
(request) => !handoffActive && !isLocationConsentRequest(request) && shouldRenderVisitorInputCard(request) && (!state.pendingOffer || request.kind === "tool-approval")
|
|
6341
7068
|
);
|
|
6342
|
-
const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming" || state.phase === "waiting-input" && pendingInputRequests.length > 0;
|
|
6343
|
-
const semanticSurfaceDisabled = isBusy && state.phase !== "waiting-input";
|
|
7069
|
+
const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming" || state.phase === "waiting-input" && (pendingInputRequests.length > 0 || Boolean(locationRequest));
|
|
7070
|
+
const semanticSurfaceDisabled = handoffActive || isBusy && state.phase !== "waiting-input";
|
|
6344
7071
|
const visitorToolResults = (state.toolResults ?? []).filter(
|
|
6345
7072
|
isRenderableVisitorToolResult
|
|
6346
7073
|
);
|
|
6347
7074
|
const activeVisitorToolInput = [...visitorToolResults].reverse().find((result) => result.kind === "input");
|
|
6348
7075
|
const visibleVisitorToolResults = activeVisitorToolInput ? [activeVisitorToolInput] : visitorToolResults;
|
|
6349
|
-
const activityActive = state.toolSteps.some(
|
|
7076
|
+
const activityActive = state.toolSteps.some(
|
|
7077
|
+
(step) => step.state === "active"
|
|
7078
|
+
);
|
|
6350
7079
|
const showActivity = state.toolSteps.length > 0 && pendingInputRequests.length === 0 && !state.pendingOffer && (activityActive || isBusy && !state.streamingText);
|
|
6351
|
-
const activitySteps = activityActive || !isBusy || state.streamingText ? state.toolSteps : [
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
7080
|
+
const activitySteps = activityActive || !isBusy || state.streamingText ? state.toolSteps : [
|
|
7081
|
+
...state.toolSteps,
|
|
7082
|
+
{
|
|
7083
|
+
id: "preparing-answer",
|
|
7084
|
+
kind: "tool",
|
|
7085
|
+
label: "Preparing your answer",
|
|
7086
|
+
detail: "Preparing your answer",
|
|
7087
|
+
state: "active"
|
|
7088
|
+
}
|
|
7089
|
+
];
|
|
6358
7090
|
const hasVisitorMessages2 = state.messages.some(
|
|
6359
7091
|
(message) => message.role === "visitor"
|
|
6360
7092
|
);
|
|
@@ -6383,7 +7115,7 @@ function AgentRail({
|
|
|
6383
7115
|
}
|
|
6384
7116
|
}
|
|
6385
7117
|
const lastIsAgent = lastMessage?.role === "agent";
|
|
6386
|
-
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
7118
|
+
const showMessageActions = !handoffActive && state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
6387
7119
|
const streamingMessage = state.streamingText && !lastIsAgent ? {
|
|
6388
7120
|
createdAt: 0,
|
|
6389
7121
|
id: "streaming-response",
|
|
@@ -6425,7 +7157,7 @@ function AgentRail({
|
|
|
6425
7157
|
...visibleVisitorToolResults
|
|
6426
7158
|
].reverse().find((result) => result.kind !== "input")?.id;
|
|
6427
7159
|
const receiptSteps = answerReceipt && state.toolSteps.length > 0 ? state.toolSteps : void 0;
|
|
6428
|
-
|
|
7160
|
+
useEffect8(() => {
|
|
6429
7161
|
if (state.phase !== "complete") {
|
|
6430
7162
|
setReceiptOpen(false);
|
|
6431
7163
|
}
|
|
@@ -6447,7 +7179,7 @@ function AgentRail({
|
|
|
6447
7179
|
onFollowUpSelect?.(label);
|
|
6448
7180
|
}
|
|
6449
7181
|
const latestVisitorId = visibleMessages[lastVisitorIndex]?.id;
|
|
6450
|
-
|
|
7182
|
+
useEffect8(() => {
|
|
6451
7183
|
const node = transcriptRef.current;
|
|
6452
7184
|
if (!node) return;
|
|
6453
7185
|
if (latestVisitorId !== lastScrolledVisitorIdRef.current) {
|
|
@@ -6477,7 +7209,7 @@ function AgentRail({
|
|
|
6477
7209
|
state.followUps,
|
|
6478
7210
|
state.journey
|
|
6479
7211
|
]);
|
|
6480
|
-
|
|
7212
|
+
useEffect8(() => {
|
|
6481
7213
|
const node = transcriptRef.current;
|
|
6482
7214
|
if (!node) return;
|
|
6483
7215
|
const handleScroll = () => {
|
|
@@ -6491,7 +7223,7 @@ function AgentRail({
|
|
|
6491
7223
|
handleScroll();
|
|
6492
7224
|
return () => node.removeEventListener("scroll", handleScroll);
|
|
6493
7225
|
}, []);
|
|
6494
|
-
|
|
7226
|
+
useEffect8(() => {
|
|
6495
7227
|
if (!receiptOpen) {
|
|
6496
7228
|
lockedTranscriptScrollTopRef.current = null;
|
|
6497
7229
|
return;
|
|
@@ -6529,7 +7261,7 @@ function AgentRail({
|
|
|
6529
7261
|
window.setTimeout(settle, 900);
|
|
6530
7262
|
node.scrollTo({ top: node.scrollHeight, behavior: "smooth" });
|
|
6531
7263
|
}
|
|
6532
|
-
return /* @__PURE__ */
|
|
7264
|
+
return /* @__PURE__ */ jsx18(
|
|
6533
7265
|
"aside",
|
|
6534
7266
|
{
|
|
6535
7267
|
ref: railRef,
|
|
@@ -6543,244 +7275,305 @@ function AgentRail({
|
|
|
6543
7275
|
autoFocus: mobileFullscreen || expanded,
|
|
6544
7276
|
role: mobileFullscreen || expanded ? "dialog" : void 0,
|
|
6545
7277
|
tabIndex: mobileFullscreen || expanded ? -1 : void 0,
|
|
6546
|
-
children: /* @__PURE__ */
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
7278
|
+
children: /* @__PURE__ */ jsxs17(AgentRailOverlayContext.Provider, { value: { railRef, overlayRef }, children: [
|
|
7279
|
+
/* @__PURE__ */ jsxs17("div", { className: "agent-rail__surface", inert: receiptOpen || void 0, children: [
|
|
7280
|
+
/* @__PURE__ */ jsx18("header", { className: "agent-rail__header", children: /* @__PURE__ */ jsxs17("div", { className: "agent-rail__brand-row", children: [
|
|
7281
|
+
onCollapse ? /* @__PURE__ */ jsx18(
|
|
7282
|
+
"button",
|
|
7283
|
+
{
|
|
7284
|
+
type: "button",
|
|
7285
|
+
className: "agent-rail__collapse",
|
|
7286
|
+
"aria-label": "Collapse assist",
|
|
7287
|
+
onClick: onCollapse,
|
|
7288
|
+
children: /* @__PURE__ */ jsx18(MinimizeIcon, {})
|
|
7289
|
+
}
|
|
7290
|
+
) : onClose ? /* @__PURE__ */ jsx18(
|
|
7291
|
+
"button",
|
|
7292
|
+
{
|
|
7293
|
+
type: "button",
|
|
7294
|
+
className: "agent-rail__close",
|
|
7295
|
+
"aria-label": "Close agent",
|
|
7296
|
+
onClick: onClose,
|
|
7297
|
+
children: /* @__PURE__ */ jsx18(CloseIcon2, {})
|
|
7298
|
+
}
|
|
7299
|
+
) : /* @__PURE__ */ jsx18("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
|
|
7300
|
+
resolvedBrandLabel || showBrandLogo ? /* @__PURE__ */ jsxs17("span", { className: "agent-rail__identity", children: [
|
|
7301
|
+
showBrandLogo ? /* @__PURE__ */ jsx18("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx18(
|
|
7302
|
+
"img",
|
|
7303
|
+
{
|
|
7304
|
+
className: "agent-rail__brand-logo",
|
|
7305
|
+
src: resolvedBrandLogoUrl,
|
|
7306
|
+
alt: "",
|
|
7307
|
+
onError: () => {
|
|
7308
|
+
setFailedLogoUrl(resolvedBrandLogoUrl ?? null);
|
|
6570
7309
|
}
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
7310
|
+
}
|
|
7311
|
+
) }) : null,
|
|
7312
|
+
resolvedBrandLabel ? /* @__PURE__ */ jsx18("span", { className: "agent-rail__brand-label", children: resolvedBrandLabel }) : null
|
|
7313
|
+
] }) : null,
|
|
7314
|
+
/* @__PURE__ */ jsxs17("span", { className: "agent-rail__actions", children: [
|
|
7315
|
+
onReset ? /* @__PURE__ */ jsx18(
|
|
7316
|
+
"button",
|
|
7317
|
+
{
|
|
7318
|
+
type: "button",
|
|
7319
|
+
className: "agent-rail__new-chat",
|
|
7320
|
+
"aria-label": "Start a new conversation",
|
|
7321
|
+
disabled: !hasVisitorMessages2 || handoffActive && !handoff?.canReset,
|
|
7322
|
+
onClick: handleReset,
|
|
7323
|
+
children: /* @__PURE__ */ jsx18(NewChatIcon, {})
|
|
7324
|
+
}
|
|
7325
|
+
) : null,
|
|
7326
|
+
onExpandToggle ? /* @__PURE__ */ jsx18(
|
|
7327
|
+
"button",
|
|
7328
|
+
{
|
|
7329
|
+
type: "button",
|
|
7330
|
+
className: "agent-rail__expand",
|
|
7331
|
+
"aria-label": expanded ? "Exit full screen" : "Open full screen",
|
|
7332
|
+
onClick: onExpandToggle,
|
|
7333
|
+
children: expanded ? /* @__PURE__ */ jsx18(RestoreIcon, {}) : /* @__PURE__ */ jsx18(ExpandIcon, {})
|
|
7334
|
+
}
|
|
7335
|
+
) : null
|
|
7336
|
+
] })
|
|
7337
|
+
] }) }),
|
|
7338
|
+
/* @__PURE__ */ jsx18("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ jsxs17("div", { ref: threadRef, className: "agent-rail__thread", children: [
|
|
7339
|
+
!hasVisitorMessages2 ? /* @__PURE__ */ jsxs17("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
7340
|
+
greeting?.role === "agent" ? /* @__PURE__ */ jsx18(
|
|
7341
|
+
MessageBubble,
|
|
7342
|
+
{
|
|
7343
|
+
showProvenance: Boolean(
|
|
7344
|
+
handoff?.page?.enabled || handoffActive
|
|
7345
|
+
),
|
|
7346
|
+
message: greeting,
|
|
7347
|
+
bookingDisabled: isBusy || handoffActive,
|
|
7348
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7349
|
+
onBook
|
|
7350
|
+
}
|
|
7351
|
+
) : null,
|
|
7352
|
+
showIdleFollowUps ? /* @__PURE__ */ jsx18("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ jsx18(
|
|
7353
|
+
FollowUpChips,
|
|
7354
|
+
{
|
|
7355
|
+
suggestions: state.followUps,
|
|
7356
|
+
disabled: isBusy || handoffActive,
|
|
7357
|
+
label: "Start here",
|
|
7358
|
+
onSelect: (suggestion) => handleFollowUpSelect(suggestion.label)
|
|
7359
|
+
}
|
|
7360
|
+
) }) : null,
|
|
7361
|
+
showActivity ? /* @__PURE__ */ jsx18(
|
|
7362
|
+
AgentActivityBubble,
|
|
7363
|
+
{
|
|
7364
|
+
brandLabel: resolvedBrandLabel,
|
|
7365
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7366
|
+
failed: state.phase === "error",
|
|
7367
|
+
steps: activitySteps
|
|
7368
|
+
}
|
|
7369
|
+
) : null,
|
|
7370
|
+
visibleVisitorToolResults.map((result) => /* @__PURE__ */ jsx18(
|
|
7371
|
+
VisitorToolResultView,
|
|
7372
|
+
{
|
|
7373
|
+
result,
|
|
7374
|
+
disabled: semanticSurfaceDisabled,
|
|
7375
|
+
onToolInput
|
|
7376
|
+
},
|
|
7377
|
+
result.id
|
|
7378
|
+
)),
|
|
7379
|
+
pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ jsx18(
|
|
7380
|
+
HumanInputCard,
|
|
7381
|
+
{
|
|
7382
|
+
request,
|
|
7383
|
+
onRespond: onInputResponse
|
|
7384
|
+
},
|
|
7385
|
+
request.requestId
|
|
7386
|
+
))
|
|
7387
|
+
] }) : null,
|
|
7388
|
+
transcriptMessages.map((message, index) => /* @__PURE__ */ jsxs17(
|
|
7389
|
+
"div",
|
|
7390
|
+
{
|
|
7391
|
+
ref: index === lastVisitorIndex + 1 ? responseRef : void 0,
|
|
7392
|
+
className: "agent-rail__turn-block",
|
|
7393
|
+
children: [
|
|
7394
|
+
message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ jsx18(
|
|
7395
|
+
VisitorToolResultView,
|
|
6600
7396
|
{
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
}
|
|
6607
|
-
) : null
|
|
6608
|
-
] })
|
|
6609
|
-
] }) }),
|
|
6610
|
-
/* @__PURE__ */ jsx17("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ jsxs16("div", { ref: threadRef, className: "agent-rail__thread", children: [
|
|
6611
|
-
!hasVisitorMessages2 ? /* @__PURE__ */ jsxs16("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
6612
|
-
greeting?.role === "agent" ? /* @__PURE__ */ jsx17(
|
|
7397
|
+
result
|
|
7398
|
+
},
|
|
7399
|
+
result.id
|
|
7400
|
+
)) : null,
|
|
7401
|
+
/* @__PURE__ */ jsx18(
|
|
6613
7402
|
MessageBubble,
|
|
6614
7403
|
{
|
|
6615
|
-
|
|
6616
|
-
|
|
7404
|
+
showProvenance: Boolean(
|
|
7405
|
+
handoff?.page?.enabled || handoffActive
|
|
7406
|
+
),
|
|
7407
|
+
message,
|
|
7408
|
+
bookingDisabled: isBusy || handoffActive,
|
|
6617
7409
|
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7410
|
+
offer: index === transcriptMessages.length - 1 ? state.pendingOffer : void 0,
|
|
6618
7411
|
onBook
|
|
6619
7412
|
}
|
|
6620
|
-
)
|
|
6621
|
-
|
|
6622
|
-
|
|
7413
|
+
),
|
|
7414
|
+
index === lastAgentIndex && showMessageActions && message.role === "agent" ? /* @__PURE__ */ jsx18(
|
|
7415
|
+
MessageActions,
|
|
6623
7416
|
{
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
AgentActivityBubble,
|
|
6632
|
-
{
|
|
6633
|
-
brandLabel: resolvedBrandLabel,
|
|
6634
|
-
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
6635
|
-
failed: state.phase === "error",
|
|
6636
|
-
steps: activitySteps
|
|
7417
|
+
answeredAt: message.createdAt,
|
|
7418
|
+
copyText: hideToolCardFences(message.text).trim() || message.text,
|
|
7419
|
+
readAloud,
|
|
7420
|
+
receiptSteps,
|
|
7421
|
+
onOpenReceipt: receiptSteps ? openReceipt : void 0,
|
|
7422
|
+
onRegenerate: onRegenerate ? handleRegenerate : void 0,
|
|
7423
|
+
onFeedback: onFeedback ? (rating) => onFeedback(rating, message) : void 0
|
|
6637
7424
|
}
|
|
6638
7425
|
) : null,
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
/* @__PURE__ */ jsx17("p", { children: state.error })
|
|
6723
|
-
] }),
|
|
6724
|
-
onRetry ? /* @__PURE__ */ jsx17("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
|
|
6725
|
-
] }) : null
|
|
6726
|
-
] }) }),
|
|
6727
|
-
showDisclaimerLabel ? /* @__PURE__ */ jsx17("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ jsx17("p", { children: disclaimerLink ? /* @__PURE__ */ jsx17(
|
|
6728
|
-
"a",
|
|
7426
|
+
index === lastVisitorIndex ? /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
7427
|
+
showActivity ? /* @__PURE__ */ jsx18(
|
|
7428
|
+
AgentActivityBubble,
|
|
7429
|
+
{
|
|
7430
|
+
brandLabel: resolvedBrandLabel,
|
|
7431
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7432
|
+
failed: state.phase === "error",
|
|
7433
|
+
steps: activitySteps
|
|
7434
|
+
}
|
|
7435
|
+
) : null,
|
|
7436
|
+
visibleVisitorToolResults.map((result) => /* @__PURE__ */ jsx18(
|
|
7437
|
+
VisitorToolResultView,
|
|
7438
|
+
{
|
|
7439
|
+
result,
|
|
7440
|
+
disabled: semanticSurfaceDisabled,
|
|
7441
|
+
onToolInput
|
|
7442
|
+
},
|
|
7443
|
+
result.id
|
|
7444
|
+
)),
|
|
7445
|
+
pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ jsx18(
|
|
7446
|
+
HumanInputCard,
|
|
7447
|
+
{
|
|
7448
|
+
request,
|
|
7449
|
+
onRespond: onInputResponse
|
|
7450
|
+
},
|
|
7451
|
+
request.requestId
|
|
7452
|
+
))
|
|
7453
|
+
] }) : null
|
|
7454
|
+
]
|
|
7455
|
+
},
|
|
7456
|
+
message.role === "agent" && transcriptMessages[index - 1]?.role === "visitor" ? `answer-${transcriptMessages[index - 1]?.id}` : message.id
|
|
7457
|
+
)),
|
|
7458
|
+
waitingForBooking ? /* @__PURE__ */ jsx18(BookingCardLoader, {}) : null,
|
|
7459
|
+
state.error ? /* @__PURE__ */ jsxs17("section", { className: "agent-rail__error", role: "alert", children: [
|
|
7460
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
7461
|
+
/* @__PURE__ */ jsx18("strong", { children: "Something went wrong" }),
|
|
7462
|
+
/* @__PURE__ */ jsx18("p", { children: state.error })
|
|
7463
|
+
] }),
|
|
7464
|
+
onRetry ? /* @__PURE__ */ jsx18("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
|
|
7465
|
+
] }) : null
|
|
7466
|
+
] }) }),
|
|
7467
|
+
showDisclaimerLabel ? /* @__PURE__ */ jsx18("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ jsx18("p", { children: disclaimerLink ? /* @__PURE__ */ jsx18(
|
|
7468
|
+
"a",
|
|
7469
|
+
{
|
|
7470
|
+
href: disclaimerLink,
|
|
7471
|
+
rel: "noopener noreferrer",
|
|
7472
|
+
target: "_blank",
|
|
7473
|
+
children: resolvedDisclaimerLabel
|
|
7474
|
+
}
|
|
7475
|
+
) : resolvedDisclaimerLabel }) }) : null,
|
|
7476
|
+
handoff && (handoff.page?.enabled || handoffActive) ? /* @__PURE__ */ jsxs17("div", { className: "agent-rail__handoff", children: [
|
|
7477
|
+
/* @__PURE__ */ jsx18("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?" }),
|
|
7478
|
+
handoffStatus === "ai" ? /* @__PURE__ */ jsx18(
|
|
7479
|
+
"button",
|
|
7480
|
+
{
|
|
7481
|
+
type: "button",
|
|
7482
|
+
disabled: handoff.busy || handoff.hasPending || isBusy,
|
|
7483
|
+
onClick: () => void handoff.start(),
|
|
7484
|
+
children: "Talk to a person"
|
|
7485
|
+
}
|
|
7486
|
+
) : null,
|
|
7487
|
+
handoffStatus === "resolved" ? /* @__PURE__ */ jsx18(
|
|
7488
|
+
"button",
|
|
7489
|
+
{
|
|
7490
|
+
type: "button",
|
|
7491
|
+
disabled: handoff.busy || handoff.hasPending,
|
|
7492
|
+
onClick: () => void handoff.returnToAI(),
|
|
7493
|
+
children: "Return to AI"
|
|
7494
|
+
}
|
|
7495
|
+
) : null,
|
|
7496
|
+
handoffStatus === "failed" && onReset ? /* @__PURE__ */ jsx18(
|
|
7497
|
+
"button",
|
|
7498
|
+
{
|
|
7499
|
+
type: "button",
|
|
7500
|
+
disabled: !handoff.canReset,
|
|
7501
|
+
onClick: handleReset,
|
|
7502
|
+
children: "Start a new conversation"
|
|
7503
|
+
}
|
|
7504
|
+
) : null,
|
|
7505
|
+
handoff.error ? /* @__PURE__ */ jsxs17("div", { role: "alert", children: [
|
|
7506
|
+
/* @__PURE__ */ jsx18("span", { children: handoff.error }),
|
|
7507
|
+
/* @__PURE__ */ jsx18(
|
|
7508
|
+
"button",
|
|
6729
7509
|
{
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
children:
|
|
7510
|
+
type: "button",
|
|
7511
|
+
disabled: handoff.busy,
|
|
7512
|
+
onClick: () => void handoff.retry(),
|
|
7513
|
+
children: "Retry"
|
|
6734
7514
|
}
|
|
6735
|
-
)
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
Composer,
|
|
6750
|
-
{
|
|
6751
|
-
variant: expanded || mobileFullscreen ? "dock" : "default",
|
|
6752
|
-
disabled: isBusy,
|
|
6753
|
-
form: composerForm && lastMessage ? { ...composerForm, id: `${lastMessage.id}:${composerForm.id}` } : null,
|
|
6754
|
-
allowFormResume: !state.pendingOffer && !waitingForBooking && !hasPendingConfirmation,
|
|
6755
|
-
placeholder: composerPlaceholder,
|
|
6756
|
-
onSubmit: handleSubmit
|
|
6757
|
-
},
|
|
6758
|
-
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
6759
|
-
),
|
|
6760
|
-
poweredByLabel ? /* @__PURE__ */ jsx17("div", { className: "agent-rail__footer", children: /* @__PURE__ */ jsx17("p", { children: /* @__PURE__ */ jsx17("span", { children: poweredByLabel }) }) }) : null
|
|
6761
|
-
] })
|
|
6762
|
-
] }),
|
|
6763
|
-
/* @__PURE__ */ jsx17("div", { ref: overlayRef, className: "agent-rail__overlay" }),
|
|
6764
|
-
receiptOpen && receiptSteps ? /* @__PURE__ */ jsx17(
|
|
6765
|
-
AnswerReceiptDialog,
|
|
7515
|
+
)
|
|
7516
|
+
] }) : null
|
|
7517
|
+
] }) : null,
|
|
7518
|
+
/* @__PURE__ */ jsxs17("div", { className: "agent-rail__composer-wrap", children: [
|
|
7519
|
+
/* @__PURE__ */ jsx18(
|
|
7520
|
+
LocationConsent,
|
|
7521
|
+
{
|
|
7522
|
+
request: locationRequest,
|
|
7523
|
+
onRespond: onInputResponse
|
|
7524
|
+
},
|
|
7525
|
+
state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
|
|
7526
|
+
),
|
|
7527
|
+
showJumpToLatest ? /* @__PURE__ */ jsx18(
|
|
7528
|
+
"button",
|
|
6766
7529
|
{
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
7530
|
+
type: "button",
|
|
7531
|
+
className: "agent-rail__jump-to-latest",
|
|
7532
|
+
"aria-label": "Jump to the latest message",
|
|
7533
|
+
title: "Jump to the latest message",
|
|
7534
|
+
onClick: scrollToLatest,
|
|
7535
|
+
children: /* @__PURE__ */ jsx18(ChevronDownIcon, {})
|
|
6770
7536
|
}
|
|
6771
|
-
) : null
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
7537
|
+
) : null,
|
|
7538
|
+
/* @__PURE__ */ jsx18(
|
|
7539
|
+
Composer,
|
|
7540
|
+
{
|
|
7541
|
+
variant: expanded || mobileFullscreen ? "dock" : "default",
|
|
7542
|
+
disabled: isBusy || Boolean(handoff?.busy || handoff?.hasPending) || handoffActive && !["requesting", "queued", "human"].includes(
|
|
7543
|
+
handoffStatus ?? ""
|
|
7544
|
+
),
|
|
7545
|
+
form: !handoffActive && composerForm && lastMessage ? {
|
|
7546
|
+
...composerForm,
|
|
7547
|
+
id: `${lastMessage.id}:${composerForm.id}`
|
|
7548
|
+
} : null,
|
|
7549
|
+
allowFormResume: !handoffActive && !state.pendingOffer && !waitingForBooking && !hasPendingConfirmation,
|
|
7550
|
+
placeholder: handoffActive ? "Message support\u2026" : composerPlaceholder,
|
|
7551
|
+
onSubmit: handleSubmit
|
|
7552
|
+
},
|
|
7553
|
+
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
7554
|
+
),
|
|
7555
|
+
poweredByLabel ? /* @__PURE__ */ jsx18("div", { className: "agent-rail__footer", children: /* @__PURE__ */ jsx18("p", { children: /* @__PURE__ */ jsx18("span", { children: poweredByLabel }) }) }) : null
|
|
7556
|
+
] })
|
|
7557
|
+
] }),
|
|
7558
|
+
/* @__PURE__ */ jsx18("div", { ref: overlayRef, className: "agent-rail__overlay" }),
|
|
7559
|
+
receiptOpen && receiptSteps ? /* @__PURE__ */ jsx18(
|
|
7560
|
+
AnswerReceiptDialog,
|
|
7561
|
+
{
|
|
7562
|
+
brandLabel: resolvedBrandLabel,
|
|
7563
|
+
onClose: () => setReceiptOpen(false),
|
|
7564
|
+
steps: receiptSteps
|
|
7565
|
+
}
|
|
7566
|
+
) : null
|
|
7567
|
+
] })
|
|
6775
7568
|
}
|
|
6776
7569
|
);
|
|
6777
7570
|
}
|
|
6778
7571
|
|
|
6779
7572
|
// src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
|
|
6780
|
-
import { useState as
|
|
6781
|
-
import { Fragment as Fragment5, jsx as
|
|
7573
|
+
import { useState as useState12 } from "react";
|
|
7574
|
+
import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
6782
7575
|
function ChatSparkIcon() {
|
|
6783
|
-
return /* @__PURE__ */
|
|
7576
|
+
return /* @__PURE__ */ jsxs18(
|
|
6784
7577
|
"svg",
|
|
6785
7578
|
{
|
|
6786
7579
|
className: "assist-edge-tab__chat-spark",
|
|
@@ -6788,7 +7581,7 @@ function ChatSparkIcon() {
|
|
|
6788
7581
|
fill: "none",
|
|
6789
7582
|
"aria-hidden": "true",
|
|
6790
7583
|
children: [
|
|
6791
|
-
/* @__PURE__ */
|
|
7584
|
+
/* @__PURE__ */ jsx19(
|
|
6792
7585
|
"path",
|
|
6793
7586
|
{
|
|
6794
7587
|
className: "assist-edge-tab__spark assist-edge-tab__spark--a",
|
|
@@ -6796,7 +7589,7 @@ function ChatSparkIcon() {
|
|
|
6796
7589
|
fill: "currentColor"
|
|
6797
7590
|
}
|
|
6798
7591
|
),
|
|
6799
|
-
/* @__PURE__ */
|
|
7592
|
+
/* @__PURE__ */ jsx19(
|
|
6800
7593
|
"path",
|
|
6801
7594
|
{
|
|
6802
7595
|
className: "assist-edge-tab__spark assist-edge-tab__spark--b",
|
|
@@ -6804,8 +7597,8 @@ function ChatSparkIcon() {
|
|
|
6804
7597
|
fill: "currentColor"
|
|
6805
7598
|
}
|
|
6806
7599
|
),
|
|
6807
|
-
/* @__PURE__ */
|
|
6808
|
-
/* @__PURE__ */
|
|
7600
|
+
/* @__PURE__ */ jsxs18("g", { className: "assist-edge-tab__bot", children: [
|
|
7601
|
+
/* @__PURE__ */ jsx19(
|
|
6809
7602
|
"path",
|
|
6810
7603
|
{
|
|
6811
7604
|
d: "M11.15 5.2V3.05",
|
|
@@ -6814,8 +7607,8 @@ function ChatSparkIcon() {
|
|
|
6814
7607
|
strokeLinecap: "round"
|
|
6815
7608
|
}
|
|
6816
7609
|
),
|
|
6817
|
-
/* @__PURE__ */
|
|
6818
|
-
/* @__PURE__ */
|
|
7610
|
+
/* @__PURE__ */ jsx19("circle", { cx: "11.15", cy: "2.45", r: "0.85", fill: "currentColor" }),
|
|
7611
|
+
/* @__PURE__ */ jsx19(
|
|
6819
7612
|
"rect",
|
|
6820
7613
|
{
|
|
6821
7614
|
x: "3.55",
|
|
@@ -6827,7 +7620,7 @@ function ChatSparkIcon() {
|
|
|
6827
7620
|
strokeWidth: "1.9"
|
|
6828
7621
|
}
|
|
6829
7622
|
),
|
|
6830
|
-
/* @__PURE__ */
|
|
7623
|
+
/* @__PURE__ */ jsx19(
|
|
6831
7624
|
"circle",
|
|
6832
7625
|
{
|
|
6833
7626
|
className: "assist-edge-tab__eye",
|
|
@@ -6837,7 +7630,7 @@ function ChatSparkIcon() {
|
|
|
6837
7630
|
fill: "currentColor"
|
|
6838
7631
|
}
|
|
6839
7632
|
),
|
|
6840
|
-
/* @__PURE__ */
|
|
7633
|
+
/* @__PURE__ */ jsx19(
|
|
6841
7634
|
"circle",
|
|
6842
7635
|
{
|
|
6843
7636
|
className: "assist-edge-tab__eye assist-edge-tab__eye--r",
|
|
@@ -6858,10 +7651,10 @@ function TabMarkIcon({
|
|
|
6858
7651
|
}) {
|
|
6859
7652
|
const custom = customIconUrl?.trim();
|
|
6860
7653
|
const logo = logoUrl?.trim();
|
|
6861
|
-
const [customFailed, setCustomFailed] =
|
|
6862
|
-
const [logoFailed, setLogoFailed] =
|
|
7654
|
+
const [customFailed, setCustomFailed] = useState12(false);
|
|
7655
|
+
const [logoFailed, setLogoFailed] = useState12(false);
|
|
6863
7656
|
if (custom && !customFailed) {
|
|
6864
|
-
return /* @__PURE__ */
|
|
7657
|
+
return /* @__PURE__ */ jsx19(
|
|
6865
7658
|
"img",
|
|
6866
7659
|
{
|
|
6867
7660
|
alt: "",
|
|
@@ -6873,7 +7666,7 @@ function TabMarkIcon({
|
|
|
6873
7666
|
);
|
|
6874
7667
|
}
|
|
6875
7668
|
if (logo && !logoFailed) {
|
|
6876
|
-
return /* @__PURE__ */
|
|
7669
|
+
return /* @__PURE__ */ jsx19(
|
|
6877
7670
|
"img",
|
|
6878
7671
|
{
|
|
6879
7672
|
alt: "",
|
|
@@ -6884,10 +7677,10 @@ function TabMarkIcon({
|
|
|
6884
7677
|
}
|
|
6885
7678
|
);
|
|
6886
7679
|
}
|
|
6887
|
-
return /* @__PURE__ */
|
|
7680
|
+
return /* @__PURE__ */ jsx19(ChatSparkIcon, {});
|
|
6888
7681
|
}
|
|
6889
7682
|
function ChevronLeftIcon() {
|
|
6890
|
-
return /* @__PURE__ */
|
|
7683
|
+
return /* @__PURE__ */ jsx19("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx19(
|
|
6891
7684
|
"path",
|
|
6892
7685
|
{
|
|
6893
7686
|
d: "M10 4L6 8l4 4",
|
|
@@ -6899,7 +7692,7 @@ function ChevronLeftIcon() {
|
|
|
6899
7692
|
) });
|
|
6900
7693
|
}
|
|
6901
7694
|
function ChevronDownIcon2() {
|
|
6902
|
-
return /* @__PURE__ */
|
|
7695
|
+
return /* @__PURE__ */ jsx19("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx19(
|
|
6903
7696
|
"path",
|
|
6904
7697
|
{
|
|
6905
7698
|
d: "M4 6l4 4 4-4",
|
|
@@ -6911,7 +7704,7 @@ function ChevronDownIcon2() {
|
|
|
6911
7704
|
) });
|
|
6912
7705
|
}
|
|
6913
7706
|
function DragDots() {
|
|
6914
|
-
return /* @__PURE__ */
|
|
7707
|
+
return /* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ jsx19("i", {}, index)) });
|
|
6915
7708
|
}
|
|
6916
7709
|
var VARIANT_COPY = {
|
|
6917
7710
|
outline: { label: "Ask anything", aria: "Ask anything" },
|
|
@@ -6966,7 +7759,7 @@ function AssistEdgeTab({
|
|
|
6966
7759
|
...!pill && resolvedTextColor ? { "--as-text": resolvedTextColor } : {},
|
|
6967
7760
|
colorScheme: chromeScheme
|
|
6968
7761
|
};
|
|
6969
|
-
return /* @__PURE__ */
|
|
7762
|
+
return /* @__PURE__ */ jsxs18(
|
|
6970
7763
|
"button",
|
|
6971
7764
|
{
|
|
6972
7765
|
type: "button",
|
|
@@ -6978,13 +7771,13 @@ function AssistEdgeTab({
|
|
|
6978
7771
|
tabIndex: visible ? 0 : -1,
|
|
6979
7772
|
onClick: onOpen,
|
|
6980
7773
|
children: [
|
|
6981
|
-
pill ? /* @__PURE__ */
|
|
6982
|
-
/* @__PURE__ */
|
|
7774
|
+
pill ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
|
|
7775
|
+
/* @__PURE__ */ jsx19(
|
|
6983
7776
|
"span",
|
|
6984
7777
|
{
|
|
6985
7778
|
className: `assist-edge-tab__mark assist-edge-tab__mark--chip${mobile ? " assist-edge-tab__mark--mobile" : ""}`,
|
|
6986
7779
|
"aria-hidden": "true",
|
|
6987
|
-
children: /* @__PURE__ */
|
|
7780
|
+
children: /* @__PURE__ */ jsx19(
|
|
6988
7781
|
TabMarkIcon,
|
|
6989
7782
|
{
|
|
6990
7783
|
customIconUrl,
|
|
@@ -6994,12 +7787,12 @@ function AssistEdgeTab({
|
|
|
6994
7787
|
)
|
|
6995
7788
|
}
|
|
6996
7789
|
),
|
|
6997
|
-
/* @__PURE__ */
|
|
6998
|
-
/* @__PURE__ */
|
|
6999
|
-
visibleSubLabel ? /* @__PURE__ */
|
|
7790
|
+
/* @__PURE__ */ jsxs18("span", { className: "assist-edge-tab__text", children: [
|
|
7791
|
+
/* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7792
|
+
visibleSubLabel ? /* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
|
|
7000
7793
|
] })
|
|
7001
|
-
] }) : variant === "outline" ? /* @__PURE__ */
|
|
7002
|
-
/* @__PURE__ */
|
|
7794
|
+
] }) : variant === "outline" ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
|
|
7795
|
+
/* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx19(
|
|
7003
7796
|
TabMarkIcon,
|
|
7004
7797
|
{
|
|
7005
7798
|
customIconUrl,
|
|
@@ -7007,16 +7800,16 @@ function AssistEdgeTab({
|
|
|
7007
7800
|
},
|
|
7008
7801
|
markSourceKey
|
|
7009
7802
|
) }),
|
|
7010
|
-
/* @__PURE__ */
|
|
7011
|
-
/* @__PURE__ */
|
|
7803
|
+
/* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7804
|
+
/* @__PURE__ */ jsx19(ChevronDownIcon2, {})
|
|
7012
7805
|
] }) : null,
|
|
7013
|
-
!pill && variant === "ask" ? /* @__PURE__ */
|
|
7014
|
-
/* @__PURE__ */
|
|
7015
|
-
/* @__PURE__ */
|
|
7016
|
-
/* @__PURE__ */
|
|
7806
|
+
!pill && variant === "ask" ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
|
|
7807
|
+
/* @__PURE__ */ jsx19(ChevronLeftIcon, {}),
|
|
7808
|
+
/* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7809
|
+
/* @__PURE__ */ jsx19(DragDots, {})
|
|
7017
7810
|
] }) : null,
|
|
7018
|
-
!pill && variant === "fill" ? /* @__PURE__ */
|
|
7019
|
-
/* @__PURE__ */
|
|
7811
|
+
!pill && variant === "fill" ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
|
|
7812
|
+
/* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx19(
|
|
7020
7813
|
TabMarkIcon,
|
|
7021
7814
|
{
|
|
7022
7815
|
customIconUrl,
|
|
@@ -7024,8 +7817,8 @@ function AssistEdgeTab({
|
|
|
7024
7817
|
},
|
|
7025
7818
|
markSourceKey
|
|
7026
7819
|
) }),
|
|
7027
|
-
/* @__PURE__ */
|
|
7028
|
-
/* @__PURE__ */
|
|
7820
|
+
/* @__PURE__ */ jsx19("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7821
|
+
/* @__PURE__ */ jsx19(ChevronLeftIcon, {})
|
|
7029
7822
|
] }) : null
|
|
7030
7823
|
]
|
|
7031
7824
|
}
|
|
@@ -7047,8 +7840,8 @@ function findPrecedingVisitorText(messages, agentMessageId) {
|
|
|
7047
7840
|
}
|
|
7048
7841
|
return void 0;
|
|
7049
7842
|
}
|
|
7050
|
-
function normalizeAgentFeedbackAnswerText(
|
|
7051
|
-
const normalized =
|
|
7843
|
+
function normalizeAgentFeedbackAnswerText(text3) {
|
|
7844
|
+
const normalized = text3.replace(/\s+/g, " ").trim();
|
|
7052
7845
|
if (!normalized) return void 0;
|
|
7053
7846
|
return normalized.length > 4e3 ? `${normalized.slice(0, 3997)}...` : normalized;
|
|
7054
7847
|
}
|
|
@@ -7089,10 +7882,10 @@ function sendAgentAnswerFeedback(eventUrl, event) {
|
|
|
7089
7882
|
}
|
|
7090
7883
|
|
|
7091
7884
|
// src/react/components/AgentWidget/AgentWidget.tsx
|
|
7092
|
-
import { useEffect as
|
|
7885
|
+
import { useEffect as useEffect11, useRef as useRef9, useState as useState14 } from "react";
|
|
7093
7886
|
|
|
7094
7887
|
// src/react/page-shift.ts
|
|
7095
|
-
import { useEffect as
|
|
7888
|
+
import { useEffect as useEffect9 } from "react";
|
|
7096
7889
|
var PAGE_SHIFT_CLASS = "webless-agent-page-shift";
|
|
7097
7890
|
var DEFAULT_RAIL_WIDTH_PX = 450;
|
|
7098
7891
|
function shouldApplyPageShift(input) {
|
|
@@ -7144,7 +7937,7 @@ function clearPageMargin() {
|
|
|
7144
7937
|
}
|
|
7145
7938
|
function usePageShift(input) {
|
|
7146
7939
|
const { active, railSlotRef } = input;
|
|
7147
|
-
|
|
7940
|
+
useEffect9(() => {
|
|
7148
7941
|
if (typeof document === "undefined") {
|
|
7149
7942
|
return;
|
|
7150
7943
|
}
|
|
@@ -7172,12 +7965,12 @@ function usePageShift(input) {
|
|
|
7172
7965
|
}
|
|
7173
7966
|
|
|
7174
7967
|
// src/react/hooks/useIsMobile.ts
|
|
7175
|
-
import { useEffect as
|
|
7968
|
+
import { useEffect as useEffect10, useState as useState13 } from "react";
|
|
7176
7969
|
function useIsMobile(breakpoint = 767) {
|
|
7177
|
-
const [isMobile, setIsMobile] =
|
|
7970
|
+
const [isMobile, setIsMobile] = useState13(
|
|
7178
7971
|
() => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
|
|
7179
7972
|
);
|
|
7180
|
-
|
|
7973
|
+
useEffect10(() => {
|
|
7181
7974
|
const media = window.matchMedia(`(max-width: ${breakpoint}px)`);
|
|
7182
7975
|
const onChange = () => setIsMobile(media.matches);
|
|
7183
7976
|
onChange();
|
|
@@ -7188,7 +7981,7 @@ function useIsMobile(breakpoint = 767) {
|
|
|
7188
7981
|
}
|
|
7189
7982
|
|
|
7190
7983
|
// src/react/components/AgentWidget/AgentWidget.tsx
|
|
7191
|
-
import { jsx as
|
|
7984
|
+
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
7192
7985
|
function AgentWidget({
|
|
7193
7986
|
indexId,
|
|
7194
7987
|
customerId,
|
|
@@ -7207,9 +8000,9 @@ function AgentWidget({
|
|
|
7207
8000
|
}) {
|
|
7208
8001
|
const isMobile = useIsMobile();
|
|
7209
8002
|
const placement = normalizeAgentPlacement(placementInput);
|
|
7210
|
-
const railSlotRef =
|
|
7211
|
-
const [railCollapsed, setRailCollapsed] =
|
|
7212
|
-
const [railExpanded, setRailExpanded] =
|
|
8003
|
+
const railSlotRef = useRef9(null);
|
|
8004
|
+
const [railCollapsed, setRailCollapsed] = useState14(defaultCollapsed);
|
|
8005
|
+
const [railExpanded, setRailExpanded] = useState14(false);
|
|
7213
8006
|
const pageShiftActive = shouldApplyPageShift({
|
|
7214
8007
|
pageShift,
|
|
7215
8008
|
isMobile,
|
|
@@ -7262,7 +8055,7 @@ function AgentWidget({
|
|
|
7262
8055
|
} : {},
|
|
7263
8056
|
...branding?.colors?.border ? { border: branding.colors.border } : {}
|
|
7264
8057
|
};
|
|
7265
|
-
|
|
8058
|
+
useEffect11(() => {
|
|
7266
8059
|
if (!registerPanelController) return;
|
|
7267
8060
|
registerAgentPanelController(customerId, {
|
|
7268
8061
|
open: () => setRailCollapsed(false),
|
|
@@ -7297,7 +8090,7 @@ function AgentWidget({
|
|
|
7297
8090
|
})
|
|
7298
8091
|
);
|
|
7299
8092
|
}
|
|
7300
|
-
|
|
8093
|
+
useEffect11(() => {
|
|
7301
8094
|
if (railCollapsed) return;
|
|
7302
8095
|
const handleKeyDown = (event) => {
|
|
7303
8096
|
if (event.key === "Tab" && (isMobile || railExpanded)) {
|
|
@@ -7331,19 +8124,19 @@ function AgentWidget({
|
|
|
7331
8124
|
window.addEventListener("keydown", handleKeyDown);
|
|
7332
8125
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
7333
8126
|
}, [isMobile, railCollapsed, railExpanded]);
|
|
7334
|
-
return /* @__PURE__ */
|
|
7335
|
-
/* @__PURE__ */
|
|
8127
|
+
return /* @__PURE__ */ jsxs19("div", { className: "webless-agent-root", children: [
|
|
8128
|
+
/* @__PURE__ */ jsx20(
|
|
7336
8129
|
"div",
|
|
7337
8130
|
{
|
|
7338
8131
|
className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
|
|
7339
|
-
children: /* @__PURE__ */
|
|
8132
|
+
children: /* @__PURE__ */ jsx20(
|
|
7340
8133
|
"div",
|
|
7341
8134
|
{
|
|
7342
8135
|
ref: railSlotRef,
|
|
7343
8136
|
className: "webless-agent-root__rail-slot",
|
|
7344
8137
|
inert: railCollapsed || void 0,
|
|
7345
8138
|
"aria-hidden": railCollapsed,
|
|
7346
|
-
children: /* @__PURE__ */
|
|
8139
|
+
children: /* @__PURE__ */ jsx20(
|
|
7347
8140
|
AgentRail,
|
|
7348
8141
|
{
|
|
7349
8142
|
theme,
|
|
@@ -7380,7 +8173,7 @@ function AgentWidget({
|
|
|
7380
8173
|
)
|
|
7381
8174
|
}
|
|
7382
8175
|
),
|
|
7383
|
-
railCollapsed ? /* @__PURE__ */
|
|
8176
|
+
railCollapsed ? /* @__PURE__ */ jsx20(
|
|
7384
8177
|
AssistEdgeTab,
|
|
7385
8178
|
{
|
|
7386
8179
|
variant: placement.variant,
|
|
@@ -7441,4 +8234,4 @@ export {
|
|
|
7441
8234
|
sendAgentAnswerFeedback,
|
|
7442
8235
|
AgentWidget
|
|
7443
8236
|
};
|
|
7444
|
-
//# sourceMappingURL=chunk-
|
|
8237
|
+
//# sourceMappingURL=chunk-EVWZF34F.js.map
|