@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
package/dist/embed.cjs
CHANGED
|
@@ -34,7 +34,7 @@ __export(embed_exports, {
|
|
|
34
34
|
module.exports = __toCommonJS(embed_exports);
|
|
35
35
|
|
|
36
36
|
// src/embed/mount.tsx
|
|
37
|
-
var
|
|
37
|
+
var import_client7 = require("react-dom/client");
|
|
38
38
|
|
|
39
39
|
// src/react/panel-controller.ts
|
|
40
40
|
var controllers = /* @__PURE__ */ new Map();
|
|
@@ -64,7 +64,7 @@ function submitAgentPanel(customerId, message, options) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// src/react/components/AgentWidget/AgentWidget.tsx
|
|
67
|
-
var
|
|
67
|
+
var import_react18 = require("react");
|
|
68
68
|
|
|
69
69
|
// src/react/page-shift.ts
|
|
70
70
|
var import_react = require("react");
|
|
@@ -146,8 +146,168 @@ function usePageShift(input) {
|
|
|
146
146
|
}, [active, railSlotRef]);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
// src/react/hooks/
|
|
149
|
+
// src/react/hooks/useAgentHandoff.ts
|
|
150
|
+
var import_client = require("eve/client");
|
|
150
151
|
var import_react2 = require("react");
|
|
152
|
+
function useAgentHandoff(options) {
|
|
153
|
+
const [page, setPage] = (0, import_react2.useState)(null);
|
|
154
|
+
const [busy, setBusy] = (0, import_react2.useState)(false);
|
|
155
|
+
const [rejected, setRejected] = (0, import_react2.useState)(false);
|
|
156
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
157
|
+
const callbacks = (0, import_react2.useRef)(options);
|
|
158
|
+
callbacks.current = options;
|
|
159
|
+
const pending = (0, import_react2.useRef)(null);
|
|
160
|
+
const inFlight = (0, import_react2.useRef)(null);
|
|
161
|
+
const pageRef = (0, import_react2.useRef)(null);
|
|
162
|
+
const refreshRef = (0, import_react2.useRef)(null);
|
|
163
|
+
const generation = (0, import_react2.useRef)(0);
|
|
164
|
+
(0, import_react2.useEffect)(() => {
|
|
165
|
+
const token = ++generation.current;
|
|
166
|
+
const controller = new AbortController();
|
|
167
|
+
let timer;
|
|
168
|
+
let reading = null;
|
|
169
|
+
let cursor = 0;
|
|
170
|
+
pageRef.current = null;
|
|
171
|
+
pending.current = null;
|
|
172
|
+
inFlight.current?.abort();
|
|
173
|
+
inFlight.current = null;
|
|
174
|
+
setRejected(false);
|
|
175
|
+
setPage(null);
|
|
176
|
+
setError(null);
|
|
177
|
+
setBusy(false);
|
|
178
|
+
if (!options.enabled || !options.sessionId) return;
|
|
179
|
+
const active = () => !controller.signal.aborted && generation.current === token;
|
|
180
|
+
const refresh = () => {
|
|
181
|
+
reading ??= (async () => {
|
|
182
|
+
do {
|
|
183
|
+
const next = await options.client.handoff.read({
|
|
184
|
+
after: cursor,
|
|
185
|
+
signal: AbortSignal.any([
|
|
186
|
+
controller.signal,
|
|
187
|
+
AbortSignal.timeout(15e3)
|
|
188
|
+
])
|
|
189
|
+
});
|
|
190
|
+
if (!active()) return;
|
|
191
|
+
callbacks.current.onEvents(next.events);
|
|
192
|
+
if (next.status !== "ai") callbacks.current.onOwnership();
|
|
193
|
+
cursor = next.cursor;
|
|
194
|
+
pageRef.current = next;
|
|
195
|
+
setPage(next);
|
|
196
|
+
setRejected(false);
|
|
197
|
+
if (!pending.current) setError(null);
|
|
198
|
+
if (!next.hasMore) break;
|
|
199
|
+
} while (active());
|
|
200
|
+
})().finally(() => {
|
|
201
|
+
reading = null;
|
|
202
|
+
});
|
|
203
|
+
return reading;
|
|
204
|
+
};
|
|
205
|
+
refreshRef.current = refresh;
|
|
206
|
+
const poll = async () => {
|
|
207
|
+
try {
|
|
208
|
+
await refresh();
|
|
209
|
+
} catch (cause) {
|
|
210
|
+
if (active()) {
|
|
211
|
+
const denied = cause instanceof import_client.ClientError && cause.status === 403;
|
|
212
|
+
setRejected(denied);
|
|
213
|
+
setError(
|
|
214
|
+
denied ? "This preview has changed. Restart the preview chat to test the current version." : "Reconnecting to your conversation\u2026"
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
} finally {
|
|
218
|
+
if (active()) timer = setTimeout(() => void poll(), 1500);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
void poll();
|
|
222
|
+
return () => {
|
|
223
|
+
controller.abort();
|
|
224
|
+
inFlight.current?.abort();
|
|
225
|
+
clearTimeout(timer);
|
|
226
|
+
refreshRef.current = null;
|
|
227
|
+
};
|
|
228
|
+
}, [options.client, options.enabled, options.sessionId]);
|
|
229
|
+
async function execute(operation) {
|
|
230
|
+
if (inFlight.current) return;
|
|
231
|
+
const controller = new AbortController();
|
|
232
|
+
inFlight.current = controller;
|
|
233
|
+
const signal = AbortSignal.any([
|
|
234
|
+
controller.signal,
|
|
235
|
+
AbortSignal.timeout(15e3)
|
|
236
|
+
]);
|
|
237
|
+
const token = generation.current;
|
|
238
|
+
pending.current = operation;
|
|
239
|
+
setBusy(true);
|
|
240
|
+
setError(null);
|
|
241
|
+
try {
|
|
242
|
+
if (operation.type === "start")
|
|
243
|
+
await options.client.handoff.start(operation.operationId, signal);
|
|
244
|
+
else if (operation.type === "message") {
|
|
245
|
+
const { type: _, ...command } = operation;
|
|
246
|
+
await options.client.handoff.send(command, signal);
|
|
247
|
+
} else {
|
|
248
|
+
const { type: _, ...command } = operation;
|
|
249
|
+
await options.client.handoff.returnToAI(command, signal);
|
|
250
|
+
}
|
|
251
|
+
if (token !== generation.current) return;
|
|
252
|
+
pending.current = null;
|
|
253
|
+
await refreshRef.current?.();
|
|
254
|
+
} catch {
|
|
255
|
+
if (token === generation.current)
|
|
256
|
+
setError(
|
|
257
|
+
"Could not confirm delivery. Retry to check the same request."
|
|
258
|
+
);
|
|
259
|
+
} finally {
|
|
260
|
+
if (inFlight.current === controller) inFlight.current = null;
|
|
261
|
+
if (token === generation.current) setBusy(false);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const binding = () => {
|
|
265
|
+
const current = pageRef.current;
|
|
266
|
+
if (!current?.handoffId) throw new Error("No active human conversation.");
|
|
267
|
+
return { handoffId: current.handoffId, epoch: current.epoch };
|
|
268
|
+
};
|
|
269
|
+
return {
|
|
270
|
+
page,
|
|
271
|
+
busy,
|
|
272
|
+
error,
|
|
273
|
+
hasPending: Boolean(pending.current),
|
|
274
|
+
canReset: !busy && !pending.current && (rejected || page?.status === "ai" || page?.status === "failed" || !options.sessionId),
|
|
275
|
+
blocksAI: Boolean(options.enabled && options.sessionId && !page) || busy || Boolean(pending.current) || Boolean(page && page.status !== "ai"),
|
|
276
|
+
start: () => execute(
|
|
277
|
+
pending.current ?? { type: "start", operationId: crypto.randomUUID() }
|
|
278
|
+
),
|
|
279
|
+
send: (message) => {
|
|
280
|
+
if (pending.current)
|
|
281
|
+
throw new Error(
|
|
282
|
+
"Retry the pending request before sending another message."
|
|
283
|
+
);
|
|
284
|
+
return execute({
|
|
285
|
+
type: "message",
|
|
286
|
+
operationId: crypto.randomUUID(),
|
|
287
|
+
...binding(),
|
|
288
|
+
message
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
returnToAI: () => execute(
|
|
292
|
+
pending.current ?? {
|
|
293
|
+
type: "return",
|
|
294
|
+
operationId: crypto.randomUUID(),
|
|
295
|
+
...binding()
|
|
296
|
+
}
|
|
297
|
+
),
|
|
298
|
+
retry: async () => {
|
|
299
|
+
if (pending.current) return execute(pending.current);
|
|
300
|
+
try {
|
|
301
|
+
await refreshRef.current?.();
|
|
302
|
+
} catch {
|
|
303
|
+
setError("Reconnecting to your conversation\u2026");
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// src/react/hooks/useAgentChat.ts
|
|
310
|
+
var import_react3 = require("react");
|
|
151
311
|
|
|
152
312
|
// src/runtime/tool-ui.ts
|
|
153
313
|
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
@@ -289,16 +449,16 @@ function parseStep(value) {
|
|
|
289
449
|
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
290
450
|
return null;
|
|
291
451
|
}
|
|
292
|
-
const
|
|
452
|
+
const id2 = boundedString(value.id, 80);
|
|
293
453
|
const label = boundedString(value.label, 160);
|
|
294
454
|
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
295
|
-
if (!
|
|
455
|
+
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(
|
|
296
456
|
(path) => typeof path !== "string" || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || path.length > 160
|
|
297
457
|
)) {
|
|
298
458
|
return null;
|
|
299
459
|
}
|
|
300
460
|
return {
|
|
301
|
-
id,
|
|
461
|
+
id: id2,
|
|
302
462
|
label,
|
|
303
463
|
fieldPaths: value.fieldPaths,
|
|
304
464
|
...description ? { description } : {}
|
|
@@ -335,14 +495,14 @@ function parseAgentToolUiSurface(value) {
|
|
|
335
495
|
])) {
|
|
336
496
|
return null;
|
|
337
497
|
}
|
|
338
|
-
const
|
|
498
|
+
const id2 = boundedString(value.id, 200);
|
|
339
499
|
const title = boundedString(value.title, 200);
|
|
340
500
|
const toolSlug = boundedString(value.toolSlug, 200);
|
|
341
501
|
const description = value.description === void 0 ? void 0 : boundedString(value.description, 800);
|
|
342
502
|
const operationId = value.operationId === void 0 ? void 0 : boundedString(value.operationId, 200);
|
|
343
503
|
const requestId = value.requestId === void 0 ? void 0 : boundedString(value.requestId, 200);
|
|
344
504
|
const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
|
|
345
|
-
if (!
|
|
505
|
+
if (!id2 || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
|
|
346
506
|
return null;
|
|
347
507
|
}
|
|
348
508
|
const fields = value.fields.map(parseField);
|
|
@@ -362,7 +522,7 @@ function parseAgentToolUiSurface(value) {
|
|
|
362
522
|
}
|
|
363
523
|
return {
|
|
364
524
|
schemaVersion: AGENT_TOOL_UI_SCHEMA_VERSION,
|
|
365
|
-
id,
|
|
525
|
+
id: id2,
|
|
366
526
|
title,
|
|
367
527
|
toolSlug,
|
|
368
528
|
fields,
|
|
@@ -473,10 +633,205 @@ function completeConnectedToolWork(item, result) {
|
|
|
473
633
|
}
|
|
474
634
|
|
|
475
635
|
// src/runtime/client.ts
|
|
476
|
-
var
|
|
636
|
+
var import_client4 = require("eve/client");
|
|
637
|
+
|
|
638
|
+
// src/runtime/handoff.ts
|
|
639
|
+
var import_client3 = require("eve/client");
|
|
640
|
+
|
|
641
|
+
// src/runtime/generated/handoff-contract.ts
|
|
642
|
+
var import_zod = require("zod");
|
|
643
|
+
var id = import_zod.z.string().min(1).max(200);
|
|
644
|
+
var sequence = import_zod.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
645
|
+
var text = import_zod.z.string().trim().min(1).max(16e3);
|
|
646
|
+
var agentRuntimeHandoffVersion = "webless.ai/agent-runtime-handoff/v1";
|
|
647
|
+
var agentRuntimeHandoffStatusSchema = import_zod.z.enum([
|
|
648
|
+
"ai",
|
|
649
|
+
"requesting",
|
|
650
|
+
"queued",
|
|
651
|
+
"human",
|
|
652
|
+
"resolved",
|
|
653
|
+
"failed"
|
|
654
|
+
]);
|
|
655
|
+
var agentRuntimeHandoffActorSchema = import_zod.z.strictObject({
|
|
656
|
+
id,
|
|
657
|
+
name: import_zod.z.string().trim().min(1).max(200)
|
|
658
|
+
});
|
|
659
|
+
var eventBase = {
|
|
660
|
+
id,
|
|
661
|
+
sequence: sequence.refine((value) => value > 0),
|
|
662
|
+
handoffId: id,
|
|
663
|
+
epoch: sequence.refine((value) => value > 0),
|
|
664
|
+
createdAt: import_zod.z.iso.datetime()
|
|
665
|
+
};
|
|
666
|
+
var agentRuntimeHandoffEventSchema = import_zod.z.discriminatedUnion("type", [
|
|
667
|
+
import_zod.z.strictObject({
|
|
668
|
+
...eventBase,
|
|
669
|
+
type: import_zod.z.literal("status"),
|
|
670
|
+
status: agentRuntimeHandoffStatusSchema,
|
|
671
|
+
actor: agentRuntimeHandoffActorSchema.nullable()
|
|
672
|
+
}),
|
|
673
|
+
import_zod.z.strictObject({
|
|
674
|
+
...eventBase,
|
|
675
|
+
type: import_zod.z.literal("visitor.message"),
|
|
676
|
+
message: text,
|
|
677
|
+
operationId: id
|
|
678
|
+
}),
|
|
679
|
+
import_zod.z.strictObject({
|
|
680
|
+
...eventBase,
|
|
681
|
+
type: import_zod.z.literal("human.message"),
|
|
682
|
+
message: text,
|
|
683
|
+
actor: agentRuntimeHandoffActorSchema
|
|
684
|
+
})
|
|
685
|
+
]);
|
|
686
|
+
var agentRuntimeHandoffReadRequestSchema = import_zod.z.strictObject({
|
|
687
|
+
after: sequence.default(0)
|
|
688
|
+
});
|
|
689
|
+
var agentRuntimeHandoffPageSchema = import_zod.z.strictObject({
|
|
690
|
+
apiVersion: import_zod.z.literal(agentRuntimeHandoffVersion),
|
|
691
|
+
sessionId: id,
|
|
692
|
+
enabled: import_zod.z.boolean(),
|
|
693
|
+
status: agentRuntimeHandoffStatusSchema,
|
|
694
|
+
handoffId: id.nullable(),
|
|
695
|
+
epoch: sequence,
|
|
696
|
+
after: sequence,
|
|
697
|
+
cursor: sequence,
|
|
698
|
+
hasMore: import_zod.z.boolean(),
|
|
699
|
+
events: import_zod.z.array(agentRuntimeHandoffEventSchema).max(100)
|
|
700
|
+
}).superRefine((page, ctx) => {
|
|
701
|
+
let cursor = page.after;
|
|
702
|
+
let previousEpoch = 0;
|
|
703
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
704
|
+
const ids = /* @__PURE__ */ new Set();
|
|
705
|
+
const handoffs = /* @__PURE__ */ new Map();
|
|
706
|
+
const terminalEpochs = /* @__PURE__ */ new Set();
|
|
707
|
+
let currentStatus;
|
|
708
|
+
for (const event of page.events) {
|
|
709
|
+
if (event.epoch < previousEpoch)
|
|
710
|
+
ctx.addIssue({
|
|
711
|
+
code: "custom",
|
|
712
|
+
message: "Handoff epochs cannot decrease."
|
|
713
|
+
});
|
|
714
|
+
previousEpoch = event.epoch;
|
|
715
|
+
if (ids.has(event.id))
|
|
716
|
+
ctx.addIssue({
|
|
717
|
+
code: "custom",
|
|
718
|
+
message: "Duplicate handoff event ID."
|
|
719
|
+
});
|
|
720
|
+
ids.add(event.id);
|
|
721
|
+
const handoffId = handoffs.get(event.epoch);
|
|
722
|
+
if (handoffId !== void 0 && handoffId !== event.handoffId || event.epoch === page.epoch && event.handoffId !== page.handoffId)
|
|
723
|
+
ctx.addIssue({
|
|
724
|
+
code: "custom",
|
|
725
|
+
message: "Inconsistent handoff epoch identity."
|
|
726
|
+
});
|
|
727
|
+
handoffs.set(event.epoch, event.handoffId);
|
|
728
|
+
if (terminalEpochs.has(event.epoch) && (event.type !== "status" || event.status !== "ai"))
|
|
729
|
+
ctx.addIssue({
|
|
730
|
+
code: "custom",
|
|
731
|
+
message: "Handoff event follows resolution."
|
|
732
|
+
});
|
|
733
|
+
if (event.type === "status") {
|
|
734
|
+
if (event.status === "human" && event.actor === null)
|
|
735
|
+
ctx.addIssue({
|
|
736
|
+
code: "custom",
|
|
737
|
+
message: "Human ownership requires a representative."
|
|
738
|
+
});
|
|
739
|
+
const previous = statuses.get(event.epoch);
|
|
740
|
+
const transitions = {
|
|
741
|
+
ai: [],
|
|
742
|
+
requesting: ["queued", "resolved", "failed"],
|
|
743
|
+
queued: ["human", "resolved", "failed"],
|
|
744
|
+
human: ["resolved", "failed"],
|
|
745
|
+
resolved: ["ai"],
|
|
746
|
+
failed: []
|
|
747
|
+
};
|
|
748
|
+
if (previous !== void 0 && !transitions[previous].includes(event.status))
|
|
749
|
+
ctx.addIssue({
|
|
750
|
+
code: "custom",
|
|
751
|
+
message: "Invalid handoff ownership transition."
|
|
752
|
+
});
|
|
753
|
+
statuses.set(event.epoch, event.status);
|
|
754
|
+
if (["resolved", "failed", "ai"].includes(event.status))
|
|
755
|
+
terminalEpochs.add(event.epoch);
|
|
756
|
+
if (event.epoch === page.epoch) currentStatus = event.status;
|
|
757
|
+
}
|
|
758
|
+
if (event.sequence !== cursor + 1) {
|
|
759
|
+
ctx.addIssue({
|
|
760
|
+
code: "custom",
|
|
761
|
+
message: "Handoff event gap or replay."
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
cursor = event.sequence;
|
|
765
|
+
if (event.epoch > page.epoch) {
|
|
766
|
+
ctx.addIssue({
|
|
767
|
+
code: "custom",
|
|
768
|
+
message: "Event exceeds current epoch."
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
if (!page.hasMore && currentStatus !== void 0 && currentStatus !== page.status)
|
|
773
|
+
ctx.addIssue({
|
|
774
|
+
code: "custom",
|
|
775
|
+
message: "Handoff ownership contradicts its final status event."
|
|
776
|
+
});
|
|
777
|
+
if (page.cursor !== cursor || page.hasMore && page.events.length === 0) {
|
|
778
|
+
ctx.addIssue({ code: "custom", message: "Invalid handoff page cursor." });
|
|
779
|
+
}
|
|
780
|
+
if (page.epoch === 0 !== (page.handoffId === null)) {
|
|
781
|
+
ctx.addIssue({ code: "custom", message: "Invalid handoff identity." });
|
|
782
|
+
}
|
|
783
|
+
if (page.handoffId === null && page.status !== "ai") {
|
|
784
|
+
ctx.addIssue({
|
|
785
|
+
code: "custom",
|
|
786
|
+
message: "Handoff identity is required."
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
var agentRuntimeHandoffStartSchema = import_zod.z.strictObject({
|
|
791
|
+
operationId: id
|
|
792
|
+
});
|
|
793
|
+
var agentRuntimeHandoffCommandSchema = import_zod.z.strictObject({
|
|
794
|
+
operationId: id,
|
|
795
|
+
handoffId: id,
|
|
796
|
+
epoch: sequence.refine((value) => value > 0)
|
|
797
|
+
});
|
|
798
|
+
var agentRuntimeHandoffMessageSchema = agentRuntimeHandoffCommandSchema.extend({ message: text });
|
|
799
|
+
var agentRuntimeHandoffBindingSchema = import_zod.z.strictObject({
|
|
800
|
+
tenantId: id,
|
|
801
|
+
indexId: id,
|
|
802
|
+
visitorSubject: id,
|
|
803
|
+
sessionId: id,
|
|
804
|
+
handoffId: id,
|
|
805
|
+
epoch: sequence.refine((value) => value > 0)
|
|
806
|
+
});
|
|
807
|
+
var providerEventBase = {
|
|
808
|
+
apiVersion: import_zod.z.literal(agentRuntimeHandoffVersion),
|
|
809
|
+
binding: agentRuntimeHandoffBindingSchema,
|
|
810
|
+
eventId: id,
|
|
811
|
+
sequence: sequence.refine((value) => value > 0)
|
|
812
|
+
};
|
|
813
|
+
var agentRuntimeHandoffProviderEventSchema = import_zod.z.discriminatedUnion(
|
|
814
|
+
"type",
|
|
815
|
+
[
|
|
816
|
+
import_zod.z.strictObject({ ...providerEventBase, type: import_zod.z.literal("queued") }),
|
|
817
|
+
import_zod.z.strictObject({
|
|
818
|
+
...providerEventBase,
|
|
819
|
+
type: import_zod.z.literal("assigned"),
|
|
820
|
+
actor: agentRuntimeHandoffActorSchema
|
|
821
|
+
}),
|
|
822
|
+
import_zod.z.strictObject({
|
|
823
|
+
...providerEventBase,
|
|
824
|
+
type: import_zod.z.literal("human.message"),
|
|
825
|
+
actor: agentRuntimeHandoffActorSchema,
|
|
826
|
+
message: text
|
|
827
|
+
}),
|
|
828
|
+
import_zod.z.strictObject({ ...providerEventBase, type: import_zod.z.literal("resolved") }),
|
|
829
|
+
import_zod.z.strictObject({ ...providerEventBase, type: import_zod.z.literal("failed") })
|
|
830
|
+
]
|
|
831
|
+
);
|
|
477
832
|
|
|
478
833
|
// src/runtime/capability.ts
|
|
479
|
-
var
|
|
834
|
+
var import_client2 = require("eve/client");
|
|
480
835
|
var MAX_REFRESH_SKEW_MS = 3e4;
|
|
481
836
|
var LOCAL_LOOPBACK_ORIGINS = [
|
|
482
837
|
"http://127.0.0.1:3010",
|
|
@@ -544,18 +899,26 @@ function createAgentRuntimeCapability(options) {
|
|
|
544
899
|
);
|
|
545
900
|
}
|
|
546
901
|
}
|
|
547
|
-
const bootstrapBody =
|
|
902
|
+
const bootstrapBody = {
|
|
548
903
|
clientSessionId: options.visitorSessionId,
|
|
549
904
|
indexId: options.indexId,
|
|
550
905
|
...previewBuildId ? { previewBuildId } : {},
|
|
551
906
|
...previewGrant ? { previewGrant } : {},
|
|
552
907
|
version: options.version
|
|
553
|
-
}
|
|
554
|
-
const postBootstrap = (origin) =>
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
908
|
+
};
|
|
909
|
+
const postBootstrap = async (origin) => {
|
|
910
|
+
const send = (advertiseLocation) => fetchImplementation(`${origin}/webless/v1/bootstrap`, {
|
|
911
|
+
body: JSON.stringify({ ...bootstrapBody, ...advertiseLocation ? { locationConsent: "v1" } : {} }),
|
|
912
|
+
headers: { "content-type": "application/json" },
|
|
913
|
+
method: "POST"
|
|
914
|
+
});
|
|
915
|
+
const response2 = await send(Boolean(options.locationConsent));
|
|
916
|
+
if (options.locationConsent && response2.status === 400) {
|
|
917
|
+
const error = await response2.clone().json().catch(() => null);
|
|
918
|
+
if (isRecord3(error) && error.code === "invalid_request") return send(false);
|
|
919
|
+
}
|
|
920
|
+
return response2;
|
|
921
|
+
};
|
|
559
922
|
let response;
|
|
560
923
|
let lastError;
|
|
561
924
|
for (const origin of localBootstrapOrigins(options.runtimeOrigin)) {
|
|
@@ -613,7 +976,7 @@ async function withCapabilityRefresh(capability, request) {
|
|
|
613
976
|
try {
|
|
614
977
|
return await request();
|
|
615
978
|
} catch (error) {
|
|
616
|
-
if (!(error instanceof
|
|
979
|
+
if (!(error instanceof import_client2.ClientError) || error.status !== 401) {
|
|
617
980
|
throw error;
|
|
618
981
|
}
|
|
619
982
|
capability.invalidate();
|
|
@@ -621,6 +984,75 @@ async function withCapabilityRefresh(capability, request) {
|
|
|
621
984
|
}
|
|
622
985
|
}
|
|
623
986
|
|
|
987
|
+
// src/runtime/handoff.ts
|
|
988
|
+
function createHandoffClient(options) {
|
|
989
|
+
const target = () => {
|
|
990
|
+
const sessionId = options.getSessionId();
|
|
991
|
+
if (!sessionId)
|
|
992
|
+
throw new Error(
|
|
993
|
+
"Start a conversation before requesting a representative."
|
|
994
|
+
);
|
|
995
|
+
return {
|
|
996
|
+
sessionId,
|
|
997
|
+
path: `/webless/v1/session/${encodeURIComponent(sessionId)}/handoff`
|
|
998
|
+
};
|
|
999
|
+
};
|
|
1000
|
+
const request = (path, init) => withCapabilityRefresh(options.capability, async () => {
|
|
1001
|
+
const response = await options.getClient().fetch(path, {
|
|
1002
|
+
...init,
|
|
1003
|
+
cache: "no-store",
|
|
1004
|
+
redirect: "error"
|
|
1005
|
+
});
|
|
1006
|
+
if (!response.ok) {
|
|
1007
|
+
throw new import_client3.ClientError(
|
|
1008
|
+
response.status,
|
|
1009
|
+
await response.text(),
|
|
1010
|
+
response.headers
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
return response;
|
|
1014
|
+
});
|
|
1015
|
+
const command = async (suffix, body, signal) => {
|
|
1016
|
+
const { path } = target();
|
|
1017
|
+
await request(path + suffix, {
|
|
1018
|
+
method: "POST",
|
|
1019
|
+
headers: { "content-type": "application/json" },
|
|
1020
|
+
body: JSON.stringify(body),
|
|
1021
|
+
signal
|
|
1022
|
+
});
|
|
1023
|
+
};
|
|
1024
|
+
return {
|
|
1025
|
+
async read(input = {}) {
|
|
1026
|
+
const { after } = agentRuntimeHandoffReadRequestSchema.parse({
|
|
1027
|
+
after: input.after
|
|
1028
|
+
});
|
|
1029
|
+
const { sessionId, path } = target();
|
|
1030
|
+
const response = await request(`${path}?after=${after}`, {
|
|
1031
|
+
signal: input.signal
|
|
1032
|
+
});
|
|
1033
|
+
const value = await response.json();
|
|
1034
|
+
const page = agentRuntimeHandoffPageSchema.parse(value);
|
|
1035
|
+
if (page.sessionId !== sessionId || page.after !== after) {
|
|
1036
|
+
throw new Error(
|
|
1037
|
+
"The handoff response does not belong to this conversation or cursor."
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
return page;
|
|
1041
|
+
},
|
|
1042
|
+
start: (operationId, signal) => command(
|
|
1043
|
+
"",
|
|
1044
|
+
agentRuntimeHandoffStartSchema.parse({ operationId }),
|
|
1045
|
+
signal
|
|
1046
|
+
),
|
|
1047
|
+
send: (input, signal) => command(
|
|
1048
|
+
"/messages",
|
|
1049
|
+
agentRuntimeHandoffMessageSchema.parse(input),
|
|
1050
|
+
signal
|
|
1051
|
+
),
|
|
1052
|
+
returnToAI: (input, signal) => command("/return", agentRuntimeHandoffCommandSchema.parse(input), signal)
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
|
|
624
1056
|
// src/runtime/config.ts
|
|
625
1057
|
var DEFAULT_RUNTIME_ORIGIN = "https://runtime.staging.webless.ai";
|
|
626
1058
|
var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
|
|
@@ -1090,6 +1522,7 @@ function specialistNameFromInput(input) {
|
|
|
1090
1522
|
return match?.[1]?.trim() || void 0;
|
|
1091
1523
|
}
|
|
1092
1524
|
function requestedWorkItem(action) {
|
|
1525
|
+
if (action.kind === "tool-call" && action.toolName === "request_location") return null;
|
|
1093
1526
|
if (action.kind === "tool-call" && action.toolName === "search_discovery") {
|
|
1094
1527
|
return {
|
|
1095
1528
|
id: action.callId,
|
|
@@ -1195,13 +1628,14 @@ function applyWorkEvent(event, handlers, workItems) {
|
|
|
1195
1628
|
);
|
|
1196
1629
|
}
|
|
1197
1630
|
var AgentSession = class {
|
|
1198
|
-
constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, previewBuildId, getUnpublishedPreviewGrant) {
|
|
1631
|
+
constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, previewBuildId, getUnpublishedPreviewGrant, locationConsent) {
|
|
1199
1632
|
this.indexId = indexId;
|
|
1200
1633
|
this.version = version;
|
|
1201
1634
|
this.runtimeOrigin = runtimeOrigin;
|
|
1202
1635
|
this.visitorSessionId = visitorSessionId;
|
|
1203
1636
|
this.storeOptions = storeOptions;
|
|
1204
1637
|
this.capability = createAgentRuntimeCapability({
|
|
1638
|
+
locationConsent,
|
|
1205
1639
|
getUnpublishedPreviewGrant,
|
|
1206
1640
|
indexId,
|
|
1207
1641
|
previewBuildId,
|
|
@@ -1209,6 +1643,11 @@ var AgentSession = class {
|
|
|
1209
1643
|
version,
|
|
1210
1644
|
visitorSessionId
|
|
1211
1645
|
});
|
|
1646
|
+
this.handoff = createHandoffClient({
|
|
1647
|
+
getClient: () => this.ensureClient(),
|
|
1648
|
+
getSessionId: () => this.getActiveSessionId(),
|
|
1649
|
+
capability: this.capability
|
|
1650
|
+
});
|
|
1212
1651
|
}
|
|
1213
1652
|
indexId;
|
|
1214
1653
|
version;
|
|
@@ -1221,6 +1660,7 @@ var AgentSession = class {
|
|
|
1221
1660
|
activeResponse;
|
|
1222
1661
|
childStreams;
|
|
1223
1662
|
capability;
|
|
1663
|
+
handoff;
|
|
1224
1664
|
getActiveSessionId() {
|
|
1225
1665
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
1226
1666
|
}
|
|
@@ -1295,7 +1735,7 @@ var AgentSession = class {
|
|
|
1295
1735
|
}
|
|
1296
1736
|
this.activeResponse = void 0;
|
|
1297
1737
|
this.session = void 0;
|
|
1298
|
-
this.client = new
|
|
1738
|
+
this.client = new import_client4.Client({
|
|
1299
1739
|
auth: { bearer: () => this.capability.getAccessToken() },
|
|
1300
1740
|
host: config.host,
|
|
1301
1741
|
redirect: "error"
|
|
@@ -1331,7 +1771,7 @@ var AgentSession = class {
|
|
|
1331
1771
|
() => activeSession.send(message, { signal })
|
|
1332
1772
|
);
|
|
1333
1773
|
} catch (error) {
|
|
1334
|
-
if (error instanceof
|
|
1774
|
+
if (error instanceof import_client4.ClientError && error.status === 409 && error.code === "session_not_active") {
|
|
1335
1775
|
clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
1336
1776
|
this.session = void 0;
|
|
1337
1777
|
session = void 0;
|
|
@@ -1505,10 +1945,10 @@ var AgentSession = class {
|
|
|
1505
1945
|
}
|
|
1506
1946
|
this.session = session;
|
|
1507
1947
|
const inputResponses = responses.map(
|
|
1508
|
-
({ requestId, optionId, text:
|
|
1948
|
+
({ requestId, optionId, text: text3 }) => ({
|
|
1509
1949
|
requestId,
|
|
1510
1950
|
...optionId ? { optionId } : {},
|
|
1511
|
-
...
|
|
1951
|
+
...text3 ? { text: text3 } : {}
|
|
1512
1952
|
})
|
|
1513
1953
|
);
|
|
1514
1954
|
const response = await withCapabilityRefresh(
|
|
@@ -1593,10 +2033,12 @@ function createAgentClient(options) {
|
|
|
1593
2033
|
visitorSessionId,
|
|
1594
2034
|
storeOptions,
|
|
1595
2035
|
options.previewBuildId,
|
|
1596
|
-
options.getUnpublishedPreviewGrant
|
|
2036
|
+
options.getUnpublishedPreviewGrant,
|
|
2037
|
+
options.locationConsent
|
|
1597
2038
|
);
|
|
1598
2039
|
return {
|
|
1599
2040
|
indexId,
|
|
2041
|
+
handoff: session.handoff,
|
|
1600
2042
|
version,
|
|
1601
2043
|
runtimeOrigin,
|
|
1602
2044
|
visitorSessionId,
|
|
@@ -1628,7 +2070,7 @@ function createAgentClient(options) {
|
|
|
1628
2070
|
}
|
|
1629
2071
|
|
|
1630
2072
|
// src/runtime/errors.ts
|
|
1631
|
-
var
|
|
2073
|
+
var import_client5 = require("eve/client");
|
|
1632
2074
|
var TRANSIENT_AGENT_ERROR_MESSAGE = "The agent run stopped before the action finished. Please try again.";
|
|
1633
2075
|
var PREVIEW_AUTHORIZATION_ERROR_MESSAGE = "This preview could not be authorized. Open the latest preview from Webless.";
|
|
1634
2076
|
function isTransientRuntimeMessage(message) {
|
|
@@ -1640,7 +2082,7 @@ function isPreviewAuthorizationMessage(message) {
|
|
|
1640
2082
|
return normalized.includes("unpublished preview authorization") || normalized.includes("unpublished preview grant") || normalized.includes("agent studio preview grant") || normalized.includes("preview authorization");
|
|
1641
2083
|
}
|
|
1642
2084
|
function formatAgentError(error) {
|
|
1643
|
-
if (error instanceof
|
|
2085
|
+
if (error instanceof import_client5.ClientError) {
|
|
1644
2086
|
if (error.status === 401 && error.code === "index_required") {
|
|
1645
2087
|
return "Missing indexId \u2014 pass a published index id to createAgentClient().";
|
|
1646
2088
|
}
|
|
@@ -1674,14 +2116,14 @@ function formatAgentError(error) {
|
|
|
1674
2116
|
var COMPOSER_FORM_SKIP_DISMISSAL = "I'd like to keep chatting without sharing the requested details for now. Please don't ask for them again unless I choose to proceed with something that needs them.";
|
|
1675
2117
|
function visitorMessageDisplayText(message) {
|
|
1676
2118
|
if (message.role !== "visitor") return message.text;
|
|
1677
|
-
const
|
|
1678
|
-
if (!
|
|
1679
|
-
if (
|
|
1680
|
-
const afterDismissal =
|
|
2119
|
+
const text3 = message.text.trim();
|
|
2120
|
+
if (!text3) return message.text;
|
|
2121
|
+
if (text3.startsWith(COMPOSER_FORM_SKIP_DISMISSAL)) {
|
|
2122
|
+
const afterDismissal = text3.slice(COMPOSER_FORM_SKIP_DISMISSAL.length).trim().replace(/^\n+/, "").trim();
|
|
1681
2123
|
if (afterDismissal) return afterDismissal;
|
|
1682
2124
|
}
|
|
1683
2125
|
const runtime = message.runtimeText?.trim();
|
|
1684
|
-
if (runtime &&
|
|
2126
|
+
if (runtime && text3 === runtime && runtime.includes(COMPOSER_FORM_SKIP_DISMISSAL)) {
|
|
1685
2127
|
const afterDismissal = runtime.slice(
|
|
1686
2128
|
runtime.indexOf(COMPOSER_FORM_SKIP_DISMISSAL) + COMPOSER_FORM_SKIP_DISMISSAL.length
|
|
1687
2129
|
).trim().replace(/^\n+/, "").trim();
|
|
@@ -1755,13 +2197,13 @@ function parseVisitorFormFields(value) {
|
|
|
1755
2197
|
const seen = /* @__PURE__ */ new Set();
|
|
1756
2198
|
for (const item of value) {
|
|
1757
2199
|
const record2 = asRecord(item);
|
|
1758
|
-
const
|
|
2200
|
+
const id2 = asString(record2?.id).toLowerCase().replace(/[^a-z0-9_-]/g, "");
|
|
1759
2201
|
const kind = asString(record2?.kind);
|
|
1760
|
-
if (!record2 || !
|
|
1761
|
-
seen.add(
|
|
1762
|
-
const label = asString(record2.label) ||
|
|
2202
|
+
if (!record2 || !id2 || seen.has(id2) || !isFieldKind2(kind)) continue;
|
|
2203
|
+
seen.add(id2);
|
|
2204
|
+
const label = asString(record2.label) || id2;
|
|
1763
2205
|
fields.push({
|
|
1764
|
-
id,
|
|
2206
|
+
id: id2,
|
|
1765
2207
|
kind,
|
|
1766
2208
|
label,
|
|
1767
2209
|
placeholder: asString(record2.placeholder) || label,
|
|
@@ -1797,52 +2239,52 @@ function formatComposerFormMessage(form, values) {
|
|
|
1797
2239
|
return value ? `${field.label}: ${value}` : "";
|
|
1798
2240
|
}).filter(Boolean).join("\n");
|
|
1799
2241
|
}
|
|
1800
|
-
function looksLikeFieldCollection(
|
|
2242
|
+
function looksLikeFieldCollection(text3) {
|
|
1801
2243
|
return /\b(please|need|send|share|enter|provide|add|collect|what|which|use)\b/i.test(
|
|
1802
|
-
|
|
1803
|
-
) || /:\s*$/m.test(
|
|
2244
|
+
text3
|
|
2245
|
+
) || /:\s*$/m.test(text3) || /^[-*•]\s+/m.test(text3);
|
|
1804
2246
|
}
|
|
1805
|
-
function looksLikeBookingCopy(
|
|
2247
|
+
function looksLikeBookingCopy(text3) {
|
|
1806
2248
|
return /book(ing)? (card|a demo|this time)|pick a (date|time)|available (times|slots)|calendly/i.test(
|
|
1807
|
-
|
|
2249
|
+
text3
|
|
1808
2250
|
);
|
|
1809
2251
|
}
|
|
1810
|
-
function echoedLabeledFieldIds(
|
|
2252
|
+
function echoedLabeledFieldIds(text3) {
|
|
1811
2253
|
const ids = /* @__PURE__ */ new Set();
|
|
1812
|
-
if (/\bname\s*:\s+\S+/i.test(
|
|
1813
|
-
if (/\be-?mail\s*:\s+\S+/i.test(
|
|
1814
|
-
if (/\bphone\s*:\s+\S+/i.test(
|
|
1815
|
-
if (/\bcompany\s*:\s+\S+/i.test(
|
|
2254
|
+
if (/\bname\s*:\s+\S+/i.test(text3)) ids.add("name");
|
|
2255
|
+
if (/\be-?mail\s*:\s+\S+/i.test(text3)) ids.add("email");
|
|
2256
|
+
if (/\bphone\s*:\s+\S+/i.test(text3)) ids.add("phone");
|
|
2257
|
+
if (/\bcompany\s*:\s+\S+/i.test(text3)) ids.add("company");
|
|
1816
2258
|
return ids;
|
|
1817
2259
|
}
|
|
1818
|
-
function matchLibraryFields(
|
|
2260
|
+
function matchLibraryFields(text3) {
|
|
1819
2261
|
return FIELD_LIBRARY.flatMap((field) => {
|
|
1820
|
-
if (field.exclude?.test(
|
|
1821
|
-
const leftover =
|
|
2262
|
+
if (field.exclude?.test(text3)) {
|
|
2263
|
+
const leftover = text3.replace(field.exclude, " ");
|
|
1822
2264
|
if (!field.patterns.some((pattern) => pattern.test(leftover))) return [];
|
|
1823
|
-
} else if (!field.patterns.some((pattern) => pattern.test(
|
|
2265
|
+
} else if (!field.patterns.some((pattern) => pattern.test(text3))) {
|
|
1824
2266
|
return [];
|
|
1825
2267
|
}
|
|
1826
2268
|
const { patterns: _patterns, exclude: _exclude, ...next } = field;
|
|
1827
2269
|
return [next];
|
|
1828
2270
|
}).slice(0, MAX_FORM_FIELDS);
|
|
1829
2271
|
}
|
|
1830
|
-
function looksLikeCompletedActionRecap(
|
|
1831
|
-
const confirmingCreate = /\bshould i create this\b/i.test(
|
|
1832
|
-
const echoingFilledFields = /\b(?:name|email|phone|company)\s*:\s+\S+/i.test(
|
|
2272
|
+
function looksLikeCompletedActionRecap(text3) {
|
|
2273
|
+
const confirmingCreate = /\bshould i create this\b/i.test(text3);
|
|
2274
|
+
const echoingFilledFields = /\b(?:name|email|phone|company)\s*:\s+\S+/i.test(text3) && /[^\s@]+@[^\s@]+\.[^\s@]+/i.test(text3);
|
|
1833
2275
|
if (echoingFilledFields) {
|
|
1834
|
-
if (looksLikeFieldCollection(
|
|
1835
|
-
const echoed = echoedLabeledFieldIds(
|
|
1836
|
-
if (matchLibraryFields(
|
|
2276
|
+
if (looksLikeFieldCollection(text3)) {
|
|
2277
|
+
const echoed = echoedLabeledFieldIds(text3);
|
|
2278
|
+
if (matchLibraryFields(text3).some((field) => !echoed.has(field.id))) {
|
|
1837
2279
|
return false;
|
|
1838
2280
|
}
|
|
1839
2281
|
}
|
|
1840
2282
|
return true;
|
|
1841
2283
|
}
|
|
1842
|
-
return confirmingCreate && !looksLikeFieldCollection(
|
|
2284
|
+
return confirmingCreate && !looksLikeFieldCollection(text3);
|
|
1843
2285
|
}
|
|
1844
|
-
function inferComposerForm(
|
|
1845
|
-
const cleaned =
|
|
2286
|
+
function inferComposerForm(text3) {
|
|
2287
|
+
const cleaned = text3.trim();
|
|
1846
2288
|
if (!cleaned || looksLikeBookingCopy(cleaned) || looksLikeCompletedActionRecap(cleaned) || !looksLikeFieldCollection(cleaned)) {
|
|
1847
2289
|
return null;
|
|
1848
2290
|
}
|
|
@@ -1857,8 +2299,8 @@ function resolveComposerForm(input) {
|
|
|
1857
2299
|
if (input.enabled === false || input.hasBookingOffer || input.hasPendingConfirmation) {
|
|
1858
2300
|
return null;
|
|
1859
2301
|
}
|
|
1860
|
-
const
|
|
1861
|
-
if (!
|
|
2302
|
+
const text3 = input.agentText.trim();
|
|
2303
|
+
if (!text3) return null;
|
|
1862
2304
|
const card = input.cards?.find((item) => item.type === "visitor_form");
|
|
1863
2305
|
if (card?.fields && card.fields.length >= MIN_FORM_FIELDS) {
|
|
1864
2306
|
return {
|
|
@@ -1866,7 +2308,7 @@ function resolveComposerForm(input) {
|
|
|
1866
2308
|
fields: card.fields.slice(0, MAX_FORM_FIELDS)
|
|
1867
2309
|
};
|
|
1868
2310
|
}
|
|
1869
|
-
return inferComposerForm(
|
|
2311
|
+
return inferComposerForm(text3);
|
|
1870
2312
|
}
|
|
1871
2313
|
|
|
1872
2314
|
// src/react/lib/tool-card.ts
|
|
@@ -1880,9 +2322,9 @@ function preferBookingOffer(current, next) {
|
|
|
1880
2322
|
}
|
|
1881
2323
|
return next;
|
|
1882
2324
|
}
|
|
1883
|
-
function looksLikeBookingReady(
|
|
2325
|
+
function looksLikeBookingReady(text3) {
|
|
1884
2326
|
return /demo option|options are ready|pick a (date|time)|available (times|slots)|book(ing)? (card|the demo)|\bschedule\b/i.test(
|
|
1885
|
-
|
|
2327
|
+
text3
|
|
1886
2328
|
);
|
|
1887
2329
|
}
|
|
1888
2330
|
function bookingOfferIdentityKey(offer) {
|
|
@@ -1992,29 +2434,29 @@ function bookingCardFromActionOutput(output) {
|
|
|
1992
2434
|
const data = asRecord2(record2?.output) ?? asRecord2(record2?.data) ?? record2;
|
|
1993
2435
|
return parseToolCard(data);
|
|
1994
2436
|
}
|
|
1995
|
-
function ensureBookingOfferText(
|
|
1996
|
-
if (!offer) return
|
|
1997
|
-
if (extractToolCards(
|
|
1998
|
-
return
|
|
2437
|
+
function ensureBookingOfferText(text3, offer) {
|
|
2438
|
+
if (!offer) return text3;
|
|
2439
|
+
if (extractToolCards(text3).some((card) => card.type === "booking_offer")) {
|
|
2440
|
+
return text3;
|
|
1999
2441
|
}
|
|
2000
|
-
const visible = stripToolCards(
|
|
2442
|
+
const visible = stripToolCards(text3).trim() || text3.trim();
|
|
2001
2443
|
return `${visible}
|
|
2002
2444
|
|
|
2003
2445
|
${formatBookingOfferFence(offer)}`;
|
|
2004
2446
|
}
|
|
2005
|
-
function hideToolCardFences(
|
|
2006
|
-
return
|
|
2447
|
+
function hideToolCardFences(text3) {
|
|
2448
|
+
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();
|
|
2007
2449
|
}
|
|
2008
2450
|
var BOOKING_CARD_FALLBACK = "Pick a date and time that works for you.";
|
|
2009
|
-
function looksLikeBookingAvailabilityDump(
|
|
2010
|
-
const cleaned =
|
|
2451
|
+
function looksLikeBookingAvailabilityDump(text3) {
|
|
2452
|
+
const cleaned = text3.trim();
|
|
2011
2453
|
if (!cleaned) return false;
|
|
2012
2454
|
const isoCount = (cleaned.match(/\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/g) ?? []).length;
|
|
2013
2455
|
const utcCount = (cleaned.match(/\bUTC\b/g) ?? []).length;
|
|
2014
2456
|
return isoCount >= 2 || utcCount >= 2 || /api\.calendly\.com|calendly\.com\//i.test(cleaned) || /webless-tool-card/i.test(cleaned);
|
|
2015
2457
|
}
|
|
2016
|
-
function sanitizeBookingOfferCopy(
|
|
2017
|
-
const cleaned = hideToolCardFences(
|
|
2458
|
+
function sanitizeBookingOfferCopy(text3) {
|
|
2459
|
+
const cleaned = hideToolCardFences(text3);
|
|
2018
2460
|
if (!cleaned || looksLikeBookingAvailabilityDump(cleaned)) {
|
|
2019
2461
|
return BOOKING_CARD_FALLBACK;
|
|
2020
2462
|
}
|
|
@@ -2027,9 +2469,9 @@ function visitorTimeZone() {
|
|
|
2027
2469
|
return "UTC";
|
|
2028
2470
|
}
|
|
2029
2471
|
}
|
|
2030
|
-
function extractToolCards(
|
|
2472
|
+
function extractToolCards(text3) {
|
|
2031
2473
|
const cards = [];
|
|
2032
|
-
for (const match of
|
|
2474
|
+
for (const match of text3.matchAll(FENCE_PATTERN)) {
|
|
2033
2475
|
try {
|
|
2034
2476
|
const card = parseToolCard(JSON.parse(match[1] ?? ""));
|
|
2035
2477
|
if (card) cards.push(card);
|
|
@@ -2038,8 +2480,8 @@ function extractToolCards(text2) {
|
|
|
2038
2480
|
}
|
|
2039
2481
|
return cards;
|
|
2040
2482
|
}
|
|
2041
|
-
function stripToolCards(
|
|
2042
|
-
return
|
|
2483
|
+
function stripToolCards(text3) {
|
|
2484
|
+
return text3.replace(FENCE_PATTERN, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
2043
2485
|
}
|
|
2044
2486
|
function localDateKey(date) {
|
|
2045
2487
|
if (Number.isNaN(date.getTime())) return "";
|
|
@@ -2152,7 +2594,7 @@ function visitorBookingPrefix(booking) {
|
|
|
2152
2594
|
function record(value) {
|
|
2153
2595
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2154
2596
|
}
|
|
2155
|
-
function
|
|
2597
|
+
function text2(value, max = 500) {
|
|
2156
2598
|
return typeof value === "string" && value.trim().length > 0 && value.trim().length <= max;
|
|
2157
2599
|
}
|
|
2158
2600
|
function safeSearchUrl(value) {
|
|
@@ -2173,7 +2615,7 @@ function parseAgentSearchReferences(value) {
|
|
|
2173
2615
|
const source = record(value2);
|
|
2174
2616
|
if (!source || Object.keys(source).some(
|
|
2175
2617
|
(key) => !["id", "title", "url"].includes(key)
|
|
2176
|
-
) || !
|
|
2618
|
+
) || !text2(source.id, Infinity) || !text2(source.title) || source.url !== void 0 && typeof source.url !== "string")
|
|
2177
2619
|
return null;
|
|
2178
2620
|
const url = safeSearchUrl(source.url);
|
|
2179
2621
|
sources.push({
|
|
@@ -2185,7 +2627,7 @@ function parseAgentSearchReferences(value) {
|
|
|
2185
2627
|
let cta;
|
|
2186
2628
|
if (data.cta !== void 0) {
|
|
2187
2629
|
const action = record(data.cta);
|
|
2188
|
-
if (!action || Object.keys(action).some((key) => !["label", "url"].includes(key)) || !
|
|
2630
|
+
if (!action || Object.keys(action).some((key) => !["label", "url"].includes(key)) || !text2(action.label) || action.url !== void 0 && typeof action.url !== "string")
|
|
2189
2631
|
return null;
|
|
2190
2632
|
const url = safeSearchUrl(action.url);
|
|
2191
2633
|
cta = { label: action.label.trim(), ...url ? { url } : {} };
|
|
@@ -2204,7 +2646,7 @@ function parseAgentSearchDiscoveryOutput(value) {
|
|
|
2204
2646
|
const data = record(decoded);
|
|
2205
2647
|
if (!data || Object.keys(data).some(
|
|
2206
2648
|
(key) => !["answer", "sources", "cta", "suggestions"].includes(key)
|
|
2207
|
-
) || !
|
|
2649
|
+
) || !text2(data.answer, 5e4) || !Array.isArray(data.suggestions) || data.suggestions.length > 8 || !data.suggestions.every((item) => text2(item)))
|
|
2208
2650
|
return null;
|
|
2209
2651
|
const references = parseAgentSearchReferences(data);
|
|
2210
2652
|
return references ? {
|
|
@@ -2222,9 +2664,21 @@ function conversationKey(storageKeyPrefix, visitorSessionId) {
|
|
|
2222
2664
|
function parseMessage(value) {
|
|
2223
2665
|
if (typeof value !== "object" || value === null) return null;
|
|
2224
2666
|
const record2 = value;
|
|
2225
|
-
if (typeof record2.id !== "string" || record2.role !== "agent" && record2.role !== "visitor" || typeof record2.text !== "string" || typeof record2.createdAt !== "number" || !Number.isFinite(record2.createdAt)) {
|
|
2667
|
+
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)) {
|
|
2226
2668
|
return null;
|
|
2227
2669
|
}
|
|
2670
|
+
if (record2.role === "human") {
|
|
2671
|
+
const person = record2.representative;
|
|
2672
|
+
if (typeof person !== "object" || person === null || !("id" in person) || !("name" in person) || typeof person.id !== "string" || typeof person.name !== "string")
|
|
2673
|
+
return null;
|
|
2674
|
+
return {
|
|
2675
|
+
id: record2.id,
|
|
2676
|
+
role: "human",
|
|
2677
|
+
text: record2.text,
|
|
2678
|
+
createdAt: record2.createdAt,
|
|
2679
|
+
representative: { id: person.id, name: person.name }
|
|
2680
|
+
};
|
|
2681
|
+
}
|
|
2228
2682
|
if (record2.role === "visitor") {
|
|
2229
2683
|
return {
|
|
2230
2684
|
id: record2.id,
|
|
@@ -2519,10 +2973,10 @@ function safeText(value) {
|
|
|
2519
2973
|
return value.trim().slice(0, MAX_TEXT_LENGTH);
|
|
2520
2974
|
}
|
|
2521
2975
|
function safeHref(value) {
|
|
2522
|
-
const
|
|
2523
|
-
if (!
|
|
2976
|
+
const text3 = safeText(value);
|
|
2977
|
+
if (!text3) return "";
|
|
2524
2978
|
try {
|
|
2525
|
-
const url = new URL(
|
|
2979
|
+
const url = new URL(text3);
|
|
2526
2980
|
return url.protocol === "https:" ? url.toString() : "";
|
|
2527
2981
|
} catch {
|
|
2528
2982
|
return "";
|
|
@@ -2742,6 +3196,9 @@ function finalizeSummaryPresentation(result, proposed) {
|
|
|
2742
3196
|
};
|
|
2743
3197
|
}
|
|
2744
3198
|
function presentVisitorToolResult(result, registry = []) {
|
|
3199
|
+
if (result.toolName === "request_location") {
|
|
3200
|
+
return { id: result.callId, toolName: result.toolName, status: result.status, kind: "hidden" };
|
|
3201
|
+
}
|
|
2745
3202
|
if (result.status === "completed" && toolResultFailed(result)) {
|
|
2746
3203
|
result = { ...result, status: "failed" };
|
|
2747
3204
|
}
|
|
@@ -2882,15 +3339,15 @@ function appendChatCollectiblePrompts(messages, requests) {
|
|
|
2882
3339
|
}
|
|
2883
3340
|
return next;
|
|
2884
3341
|
}
|
|
2885
|
-
function chatInputResponseForText(requests,
|
|
2886
|
-
const trimmed =
|
|
3342
|
+
function chatInputResponseForText(requests, text3) {
|
|
3343
|
+
const trimmed = text3.trim();
|
|
2887
3344
|
if (!trimmed) return null;
|
|
2888
3345
|
const pending = requests.find(isChatCollectibleInputRequest);
|
|
2889
3346
|
if (!pending) return null;
|
|
2890
3347
|
return { requestId: pending.requestId, text: trimmed };
|
|
2891
3348
|
}
|
|
2892
|
-
function normalizeAssistantDedupeKey(
|
|
2893
|
-
return
|
|
3349
|
+
function normalizeAssistantDedupeKey(text3) {
|
|
3350
|
+
return text3.trim().replace(/\s+/g, " ").toLowerCase();
|
|
2894
3351
|
}
|
|
2895
3352
|
function isNearDuplicateAssistantText(left, right) {
|
|
2896
3353
|
const a = normalizeAssistantDedupeKey(left);
|
|
@@ -3003,6 +3460,7 @@ function isJsonRecord(value) {
|
|
|
3003
3460
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3004
3461
|
}
|
|
3005
3462
|
function useAgentChat({
|
|
3463
|
+
handoffEnabled = false,
|
|
3006
3464
|
customerId,
|
|
3007
3465
|
getUnpublishedPreviewGrant,
|
|
3008
3466
|
indexId,
|
|
@@ -3014,13 +3472,13 @@ function useAgentChat({
|
|
|
3014
3472
|
greeting,
|
|
3015
3473
|
toolResultRegistry
|
|
3016
3474
|
}) {
|
|
3017
|
-
const initialState = (0,
|
|
3475
|
+
const initialState = (0, import_react3.useMemo)(
|
|
3018
3476
|
() => createInitialState(greeting?.trim() || DEFAULT_GREETING),
|
|
3019
3477
|
[greeting]
|
|
3020
3478
|
);
|
|
3021
|
-
const previewGrantProviderRef = (0,
|
|
3479
|
+
const previewGrantProviderRef = (0, import_react3.useRef)(getUnpublishedPreviewGrant);
|
|
3022
3480
|
previewGrantProviderRef.current = getUnpublishedPreviewGrant;
|
|
3023
|
-
const toolResultRegistryRef = (0,
|
|
3481
|
+
const toolResultRegistryRef = (0, import_react3.useRef)(toolResultRegistry);
|
|
3024
3482
|
toolResultRegistryRef.current = toolResultRegistry;
|
|
3025
3483
|
const resolveUnpublishedPreviewGrant = () => {
|
|
3026
3484
|
const provider = previewGrantProviderRef.current;
|
|
@@ -3033,7 +3491,7 @@ function useAgentChat({
|
|
|
3033
3491
|
}
|
|
3034
3492
|
return provider();
|
|
3035
3493
|
};
|
|
3036
|
-
const resolvedStorageKeyPrefix = (0,
|
|
3494
|
+
const resolvedStorageKeyPrefix = (0, import_react3.useMemo)(
|
|
3037
3495
|
() => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({
|
|
3038
3496
|
customerId,
|
|
3039
3497
|
indexId,
|
|
@@ -3042,24 +3500,25 @@ function useAgentChat({
|
|
|
3042
3500
|
}),
|
|
3043
3501
|
[customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
|
|
3044
3502
|
);
|
|
3045
|
-
const visitorId = (0,
|
|
3503
|
+
const visitorId = (0, import_react3.useMemo)(
|
|
3046
3504
|
() => visitorSessionId?.trim() || getOrCreateVisitorSessionId({
|
|
3047
3505
|
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
3048
3506
|
}),
|
|
3049
3507
|
[resolvedStorageKeyPrefix, visitorSessionId]
|
|
3050
3508
|
);
|
|
3051
|
-
const [state, setState] = (0,
|
|
3509
|
+
const [state, setState] = (0, import_react3.useState)(
|
|
3052
3510
|
() => stateFromConversation(
|
|
3053
3511
|
loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
|
|
3054
3512
|
initialState
|
|
3055
3513
|
)
|
|
3056
3514
|
);
|
|
3057
|
-
const pendingBookingRef = (0,
|
|
3515
|
+
const pendingBookingRef = (0, import_react3.useRef)(
|
|
3058
3516
|
loadPendingWidgetBooking(resolvedStorageKeyPrefix, visitorId)
|
|
3059
3517
|
);
|
|
3060
|
-
const runRef = (0,
|
|
3061
|
-
const clientRef = (0,
|
|
3518
|
+
const runRef = (0, import_react3.useRef)(null);
|
|
3519
|
+
const clientRef = (0, import_react3.useRef)(
|
|
3062
3520
|
createAgentClient({
|
|
3521
|
+
locationConsent: true,
|
|
3063
3522
|
customerId,
|
|
3064
3523
|
getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
|
|
3065
3524
|
indexId,
|
|
@@ -3071,8 +3530,8 @@ function useAgentChat({
|
|
|
3071
3530
|
})
|
|
3072
3531
|
);
|
|
3073
3532
|
const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${previewBuildId ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
|
|
3074
|
-
const identityRef = (0,
|
|
3075
|
-
(0,
|
|
3533
|
+
const identityRef = (0, import_react3.useRef)(identityKey);
|
|
3534
|
+
(0, import_react3.useEffect)(() => {
|
|
3076
3535
|
if (identityRef.current === identityKey) {
|
|
3077
3536
|
return;
|
|
3078
3537
|
}
|
|
@@ -3080,6 +3539,7 @@ function useAgentChat({
|
|
|
3080
3539
|
runRef.current?.abort();
|
|
3081
3540
|
runRef.current = null;
|
|
3082
3541
|
clientRef.current = createAgentClient({
|
|
3542
|
+
locationConsent: true,
|
|
3083
3543
|
customerId,
|
|
3084
3544
|
getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
|
|
3085
3545
|
indexId,
|
|
@@ -3110,7 +3570,7 @@ function useAgentChat({
|
|
|
3110
3570
|
version,
|
|
3111
3571
|
visitorId
|
|
3112
3572
|
]);
|
|
3113
|
-
(0,
|
|
3573
|
+
(0, import_react3.useEffect)(() => {
|
|
3114
3574
|
if (!hasVisitorMessages(state.messages)) return;
|
|
3115
3575
|
savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
|
|
3116
3576
|
messages: state.messages,
|
|
@@ -3130,16 +3590,77 @@ function useAgentChat({
|
|
|
3130
3590
|
state.toolResults,
|
|
3131
3591
|
visitorId
|
|
3132
3592
|
]);
|
|
3133
|
-
const
|
|
3593
|
+
const handoff = useAgentHandoff({
|
|
3594
|
+
enabled: handoffEnabled,
|
|
3595
|
+
client: clientRef.current,
|
|
3596
|
+
sessionId: clientRef.current.getActiveSessionId(),
|
|
3597
|
+
onOwnership: () => {
|
|
3598
|
+
runRef.current?.abort();
|
|
3599
|
+
runRef.current = null;
|
|
3600
|
+
setState(
|
|
3601
|
+
(prev) => prev.phase === "complete" && !prev.streamingText && !prev.pendingInputs?.length && !prev.toolSteps.length ? prev : {
|
|
3602
|
+
...prev,
|
|
3603
|
+
phase: "complete",
|
|
3604
|
+
streamingText: "",
|
|
3605
|
+
pendingInputs: [],
|
|
3606
|
+
toolSteps: [],
|
|
3607
|
+
toolResults: [],
|
|
3608
|
+
pendingOffer: null,
|
|
3609
|
+
error: null
|
|
3610
|
+
}
|
|
3611
|
+
);
|
|
3612
|
+
},
|
|
3613
|
+
onEvents: (events) => {
|
|
3614
|
+
setState((prev) => {
|
|
3615
|
+
const seen = new Set(prev.messages.map((message) => message.id));
|
|
3616
|
+
const messages = [];
|
|
3617
|
+
for (const event of events) {
|
|
3618
|
+
if (event.type === "status" || seen.has(`handoff-${event.id}`))
|
|
3619
|
+
continue;
|
|
3620
|
+
messages.push(
|
|
3621
|
+
event.type === "human.message" ? {
|
|
3622
|
+
id: `handoff-${event.id}`,
|
|
3623
|
+
role: "human",
|
|
3624
|
+
text: event.message,
|
|
3625
|
+
createdAt: Date.parse(event.createdAt),
|
|
3626
|
+
representative: event.actor
|
|
3627
|
+
} : {
|
|
3628
|
+
id: `handoff-${event.id}`,
|
|
3629
|
+
role: "visitor",
|
|
3630
|
+
text: event.message,
|
|
3631
|
+
createdAt: Date.parse(event.createdAt)
|
|
3632
|
+
}
|
|
3633
|
+
);
|
|
3634
|
+
}
|
|
3635
|
+
return messages.length ? {
|
|
3636
|
+
...prev,
|
|
3637
|
+
messages: [...prev.messages, ...messages].sort(
|
|
3638
|
+
(a, b) => a.createdAt - b.createdAt
|
|
3639
|
+
)
|
|
3640
|
+
} : prev;
|
|
3641
|
+
});
|
|
3642
|
+
}
|
|
3643
|
+
});
|
|
3644
|
+
const handoffBlocksAI = (0, import_react3.useRef)(handoff.blocksAI);
|
|
3645
|
+
handoffBlocksAI.current = handoff.blocksAI;
|
|
3646
|
+
const reset = (0, import_react3.useCallback)(() => {
|
|
3647
|
+
if (handoff.blocksAI && !handoff.canReset) return;
|
|
3134
3648
|
runRef.current?.abort();
|
|
3135
3649
|
runRef.current = null;
|
|
3136
3650
|
clientRef.current.reset();
|
|
3137
3651
|
pendingBookingRef.current = null;
|
|
3138
3652
|
clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
|
|
3139
3653
|
setState(initialState);
|
|
3140
|
-
}, [
|
|
3141
|
-
|
|
3654
|
+
}, [
|
|
3655
|
+
handoff.blocksAI,
|
|
3656
|
+
handoff.canReset,
|
|
3657
|
+
initialState,
|
|
3658
|
+
resolvedStorageKeyPrefix,
|
|
3659
|
+
visitorId
|
|
3660
|
+
]);
|
|
3661
|
+
const runTurn = (0, import_react3.useCallback)(
|
|
3142
3662
|
async (input) => {
|
|
3663
|
+
if (handoffBlocksAI.current) return null;
|
|
3143
3664
|
const {
|
|
3144
3665
|
controller,
|
|
3145
3666
|
initialText = "",
|
|
@@ -3263,6 +3784,7 @@ function useAgentChat({
|
|
|
3263
3784
|
signal
|
|
3264
3785
|
});
|
|
3265
3786
|
if (resume && finalText === null) {
|
|
3787
|
+
if (!isActiveRun() || handoffBlocksAI.current) return null;
|
|
3266
3788
|
finalText = await clientRef.current.sendTurn(visitorText, {
|
|
3267
3789
|
handlers,
|
|
3268
3790
|
signal
|
|
@@ -3295,8 +3817,12 @@ function useAgentChat({
|
|
|
3295
3817
|
messages: appendAgentTurnMessage(
|
|
3296
3818
|
prev.messages,
|
|
3297
3819
|
displayText,
|
|
3298
|
-
(prev.toolResults ?? []).filter(
|
|
3299
|
-
|
|
3820
|
+
(prev.toolResults ?? []).filter(
|
|
3821
|
+
(result) => result.kind === "search"
|
|
3822
|
+
),
|
|
3823
|
+
(prev.toolResults ?? []).filter(
|
|
3824
|
+
(result) => result.kind !== "search" && result.kind !== "input"
|
|
3825
|
+
)
|
|
3300
3826
|
),
|
|
3301
3827
|
toolResults: (prev.toolResults ?? []).filter(
|
|
3302
3828
|
(result) => result.kind === "input"
|
|
@@ -3337,7 +3863,7 @@ function useAgentChat({
|
|
|
3337
3863
|
},
|
|
3338
3864
|
[resolvedStorageKeyPrefix, visitorId]
|
|
3339
3865
|
);
|
|
3340
|
-
const rememberBooking = (0,
|
|
3866
|
+
const rememberBooking = (0, import_react3.useCallback)(
|
|
3341
3867
|
(booking) => {
|
|
3342
3868
|
const current = pendingBookingRef.current;
|
|
3343
3869
|
if (current?.eventUri === booking.eventUri && current.inviteeEmail === booking.inviteeEmail && current.inviteeUri === booking.inviteeUri) {
|
|
@@ -3348,7 +3874,7 @@ function useAgentChat({
|
|
|
3348
3874
|
},
|
|
3349
3875
|
[resolvedStorageKeyPrefix, visitorId]
|
|
3350
3876
|
);
|
|
3351
|
-
const forgetBooking = (0,
|
|
3877
|
+
const forgetBooking = (0, import_react3.useCallback)(
|
|
3352
3878
|
(eventUri) => {
|
|
3353
3879
|
const current = pendingBookingRef.current;
|
|
3354
3880
|
if (!current) return;
|
|
@@ -3358,12 +3884,21 @@ function useAgentChat({
|
|
|
3358
3884
|
},
|
|
3359
3885
|
[resolvedStorageKeyPrefix, visitorId]
|
|
3360
3886
|
);
|
|
3361
|
-
const submit = (0,
|
|
3887
|
+
const submit = (0, import_react3.useCallback)(
|
|
3362
3888
|
async (visitorText, options) => {
|
|
3363
3889
|
const trimmed = visitorText.trim();
|
|
3364
3890
|
const outgoing = options?.runtimeText ?? visitorText;
|
|
3365
3891
|
if (!outgoing.trim()) return null;
|
|
3366
3892
|
const declinedComposerFormId = options?.declinedComposerFormId?.trim();
|
|
3893
|
+
if (handoff.blocksAI) {
|
|
3894
|
+
if (!["requesting", "queued", "human"].includes(
|
|
3895
|
+
handoff.page?.status ?? ""
|
|
3896
|
+
) || handoff.busy)
|
|
3897
|
+
return null;
|
|
3898
|
+
if (!trimmed) return null;
|
|
3899
|
+
await handoff.send(trimmed);
|
|
3900
|
+
return null;
|
|
3901
|
+
}
|
|
3367
3902
|
const chatResponse = chatInputResponseForText(
|
|
3368
3903
|
state.pendingInputs ?? [],
|
|
3369
3904
|
outgoing.trim()
|
|
@@ -3465,9 +4000,10 @@ ${outgoing}` : outgoing;
|
|
|
3465
4000
|
visitorText: runtimeText
|
|
3466
4001
|
});
|
|
3467
4002
|
},
|
|
3468
|
-
[runTurn, state.pendingInputs]
|
|
4003
|
+
[handoff, runTurn, state.pendingInputs]
|
|
3469
4004
|
);
|
|
3470
|
-
const retry = (0,
|
|
4005
|
+
const retry = (0, import_react3.useCallback)(async () => {
|
|
4006
|
+
if (handoffBlocksAI.current) return;
|
|
3471
4007
|
const visitorMessage = [...state.messages].reverse().find((message) => message.role === "visitor");
|
|
3472
4008
|
if (!visitorMessage) return;
|
|
3473
4009
|
if (runRef.current) {
|
|
@@ -3500,7 +4036,8 @@ ${outgoing}` : outgoing;
|
|
|
3500
4036
|
visitorText: visitorTurnText(visitorMessage)
|
|
3501
4037
|
});
|
|
3502
4038
|
}, [runTurn, state.messages]);
|
|
3503
|
-
const regenerate = (0,
|
|
4039
|
+
const regenerate = (0, import_react3.useCallback)(async () => {
|
|
4040
|
+
if (handoffBlocksAI.current) return null;
|
|
3504
4041
|
let lastVisitorIndex = -1;
|
|
3505
4042
|
for (let index = state.messages.length - 1; index >= 0; index -= 1) {
|
|
3506
4043
|
if (state.messages[index]?.role === "visitor") {
|
|
@@ -3543,7 +4080,7 @@ ${outgoing}` : outgoing;
|
|
|
3543
4080
|
visitorText: visitorTurnText(visitorMessage)
|
|
3544
4081
|
});
|
|
3545
4082
|
}, [runTurn, state.messages]);
|
|
3546
|
-
const respondToToolInput = (0,
|
|
4083
|
+
const respondToToolInput = (0, import_react3.useCallback)(
|
|
3547
4084
|
async (surface, values) => {
|
|
3548
4085
|
await submit(`${surface.title} submitted`, {
|
|
3549
4086
|
runtimeText: [
|
|
@@ -3556,9 +4093,9 @@ ${outgoing}` : outgoing;
|
|
|
3556
4093
|
},
|
|
3557
4094
|
[submit]
|
|
3558
4095
|
);
|
|
3559
|
-
const respondToInput = (0,
|
|
4096
|
+
const respondToInput = (0, import_react3.useCallback)(
|
|
3560
4097
|
async (response) => {
|
|
3561
|
-
if (runRef.current) return;
|
|
4098
|
+
if (handoffBlocksAI.current || runRef.current) return;
|
|
3562
4099
|
const pending = state.pendingInputs?.find(
|
|
3563
4100
|
(request) => request.requestId === response.requestId
|
|
3564
4101
|
);
|
|
@@ -3586,7 +4123,8 @@ ${outgoing}` : outgoing;
|
|
|
3586
4123
|
},
|
|
3587
4124
|
[respondToToolInput, runTurn, state.pendingInputs]
|
|
3588
4125
|
);
|
|
3589
|
-
(0,
|
|
4126
|
+
(0, import_react3.useEffect)(() => {
|
|
4127
|
+
if (handoff.blocksAI) return;
|
|
3590
4128
|
const conversation = loadPersistedAgentConversation(
|
|
3591
4129
|
resolvedStorageKeyPrefix,
|
|
3592
4130
|
visitorId
|
|
@@ -3608,14 +4146,21 @@ ${outgoing}` : outgoing;
|
|
|
3608
4146
|
}
|
|
3609
4147
|
controller.abort();
|
|
3610
4148
|
};
|
|
3611
|
-
}, [
|
|
3612
|
-
|
|
4149
|
+
}, [
|
|
4150
|
+
handoff.blocksAI,
|
|
4151
|
+
identityKey,
|
|
4152
|
+
resolvedStorageKeyPrefix,
|
|
4153
|
+
runTurn,
|
|
4154
|
+
visitorId
|
|
4155
|
+
]);
|
|
4156
|
+
(0, import_react3.useEffect)(() => {
|
|
3613
4157
|
return () => {
|
|
3614
4158
|
runRef.current?.abort();
|
|
3615
4159
|
runRef.current = null;
|
|
3616
4160
|
};
|
|
3617
4161
|
}, []);
|
|
3618
4162
|
return {
|
|
4163
|
+
handoff,
|
|
3619
4164
|
state,
|
|
3620
4165
|
reset,
|
|
3621
4166
|
retry,
|
|
@@ -3637,12 +4182,12 @@ function isAgentBusy(phase) {
|
|
|
3637
4182
|
}
|
|
3638
4183
|
|
|
3639
4184
|
// src/react/hooks/useIsMobile.ts
|
|
3640
|
-
var
|
|
4185
|
+
var import_react4 = require("react");
|
|
3641
4186
|
function useIsMobile(breakpoint = 767) {
|
|
3642
|
-
const [isMobile, setIsMobile] = (0,
|
|
4187
|
+
const [isMobile, setIsMobile] = (0, import_react4.useState)(
|
|
3643
4188
|
() => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
|
|
3644
4189
|
);
|
|
3645
|
-
(0,
|
|
4190
|
+
(0, import_react4.useEffect)(() => {
|
|
3646
4191
|
const media = window.matchMedia(`(max-width: ${breakpoint}px)`);
|
|
3647
4192
|
const onChange = () => setIsMobile(media.matches);
|
|
3648
4193
|
onChange();
|
|
@@ -3670,7 +4215,7 @@ function normalizeAgentPlacement(placement) {
|
|
|
3670
4215
|
}
|
|
3671
4216
|
|
|
3672
4217
|
// src/react/components/AgentRail/AgentRail.tsx
|
|
3673
|
-
var
|
|
4218
|
+
var import_react16 = require("react");
|
|
3674
4219
|
|
|
3675
4220
|
// src/react/types/conversation.ts
|
|
3676
4221
|
var defaultAgentRailTheme = {
|
|
@@ -3753,7 +4298,7 @@ function agentThemeStyle(theme, resolvedColorScheme) {
|
|
|
3753
4298
|
}
|
|
3754
4299
|
|
|
3755
4300
|
// src/react/hooks/useAgentColorScheme.ts
|
|
3756
|
-
var
|
|
4301
|
+
var import_react5 = require("react");
|
|
3757
4302
|
var DARK_MODE_QUERY = "(prefers-color-scheme: dark)";
|
|
3758
4303
|
function subscribeToDarkMode(onChange) {
|
|
3759
4304
|
if (typeof window === "undefined" || !window.matchMedia) {
|
|
@@ -3771,7 +4316,7 @@ function getPrefersDarkMode() {
|
|
|
3771
4316
|
return typeof window !== "undefined" && Boolean(window.matchMedia?.(DARK_MODE_QUERY).matches);
|
|
3772
4317
|
}
|
|
3773
4318
|
function useAgentColorScheme(colorScheme = "auto") {
|
|
3774
|
-
const prefersDarkMode = (0,
|
|
4319
|
+
const prefersDarkMode = (0, import_react5.useSyncExternalStore)(
|
|
3775
4320
|
subscribeToDarkMode,
|
|
3776
4321
|
getPrefersDarkMode,
|
|
3777
4322
|
() => false
|
|
@@ -3783,7 +4328,7 @@ function resolveAgentColorScheme(colorScheme = "auto", prefersDarkMode) {
|
|
|
3783
4328
|
}
|
|
3784
4329
|
|
|
3785
4330
|
// src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
|
|
3786
|
-
var
|
|
4331
|
+
var import_react6 = require("react");
|
|
3787
4332
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
3788
4333
|
function joinLabels(labels) {
|
|
3789
4334
|
if (labels.length <= 1) return labels[0] ?? "";
|
|
@@ -3902,7 +4447,7 @@ function AgentActivityBubble({
|
|
|
3902
4447
|
const statusText = workSummary(steps, failed, brandLabel);
|
|
3903
4448
|
const softReview = statusText === AGENT_SOFT_REVIEW_STATUS;
|
|
3904
4449
|
const receiptId = steps.map((step) => step.id).join(":");
|
|
3905
|
-
const [expandedReceiptId, setExpandedReceiptId] = (0,
|
|
4450
|
+
const [expandedReceiptId, setExpandedReceiptId] = (0, import_react6.useState)(
|
|
3906
4451
|
null
|
|
3907
4452
|
);
|
|
3908
4453
|
const detailsOpen = !active && expandedReceiptId === receiptId;
|
|
@@ -3953,17 +4498,17 @@ function AgentActivityBubble({
|
|
|
3953
4498
|
}
|
|
3954
4499
|
|
|
3955
4500
|
// src/react/components/AnswerReceiptDialog/AnswerReceiptDialog.tsx
|
|
3956
|
-
var
|
|
4501
|
+
var import_react8 = require("react");
|
|
3957
4502
|
var import_react_dom = require("react-dom");
|
|
3958
4503
|
|
|
3959
4504
|
// src/react/components/AgentRail/AgentRailOverlayContext.tsx
|
|
3960
|
-
var
|
|
3961
|
-
var AgentRailOverlayContext = (0,
|
|
4505
|
+
var import_react7 = require("react");
|
|
4506
|
+
var AgentRailOverlayContext = (0, import_react7.createContext)(null);
|
|
3962
4507
|
function useAgentRailPortalRoots() {
|
|
3963
|
-
return (0,
|
|
4508
|
+
return (0, import_react7.useContext)(AgentRailOverlayContext);
|
|
3964
4509
|
}
|
|
3965
4510
|
function useAgentRailMenuPortalRoot() {
|
|
3966
|
-
return (0,
|
|
4511
|
+
return (0, import_react7.useContext)(AgentRailOverlayContext)?.railRef ?? null;
|
|
3967
4512
|
}
|
|
3968
4513
|
|
|
3969
4514
|
// src/react/components/AnswerReceiptDialog/AnswerReceiptDialog.tsx
|
|
@@ -3987,10 +4532,10 @@ function AnswerReceiptDialog({
|
|
|
3987
4532
|
}) {
|
|
3988
4533
|
const portalRoots = useAgentRailPortalRoots();
|
|
3989
4534
|
const overlayRoot = portalRoots?.overlayRef ?? null;
|
|
3990
|
-
const cardRef = (0,
|
|
3991
|
-
const closeButtonRef = (0,
|
|
3992
|
-
const previouslyFocusedRef = (0,
|
|
3993
|
-
(0,
|
|
4535
|
+
const cardRef = (0, import_react8.useRef)(null);
|
|
4536
|
+
const closeButtonRef = (0, import_react8.useRef)(null);
|
|
4537
|
+
const previouslyFocusedRef = (0, import_react8.useRef)(null);
|
|
4538
|
+
(0, import_react8.useEffect)(() => {
|
|
3994
4539
|
previouslyFocusedRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
3995
4540
|
closeButtonRef.current?.focus({ preventScroll: true });
|
|
3996
4541
|
const handleKeyDown = (event) => {
|
|
@@ -4075,7 +4620,7 @@ function AnswerReceiptDialog({
|
|
|
4075
4620
|
}
|
|
4076
4621
|
|
|
4077
4622
|
// src/react/components/Composer/Composer.tsx
|
|
4078
|
-
var
|
|
4623
|
+
var import_react9 = require("react");
|
|
4079
4624
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
4080
4625
|
var FORM_SUBMITTED_MESSAGE = "Shared my details";
|
|
4081
4626
|
function SendIcon() {
|
|
@@ -4137,17 +4682,17 @@ function Composer({
|
|
|
4137
4682
|
allowFormResume = true,
|
|
4138
4683
|
onSubmit
|
|
4139
4684
|
}) {
|
|
4140
|
-
const [value, setValue] = (0,
|
|
4141
|
-
const [draft, setDraft] = (0,
|
|
4142
|
-
const inputRef = (0,
|
|
4143
|
-
const firstFieldRef = (0,
|
|
4144
|
-
const formRef = (0,
|
|
4145
|
-
const formId = (0,
|
|
4685
|
+
const [value, setValue] = (0, import_react9.useState)("");
|
|
4686
|
+
const [draft, setDraft] = (0, import_react9.useState)(() => createDraft(form));
|
|
4687
|
+
const inputRef = (0, import_react9.useRef)(null);
|
|
4688
|
+
const firstFieldRef = (0, import_react9.useRef)(null);
|
|
4689
|
+
const formRef = (0, import_react9.useRef)(null);
|
|
4690
|
+
const formId = (0, import_react9.useId)();
|
|
4146
4691
|
if (form && form.id !== draft.form?.id) setDraft(createDraft(form));
|
|
4147
4692
|
const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
|
|
4148
4693
|
const activeForm = !disabled && draft.expanded ? savedForm : null;
|
|
4149
4694
|
const canSend = !disabled && Boolean(value.trim() || activeForm);
|
|
4150
|
-
(0,
|
|
4695
|
+
(0, import_react9.useEffect)(() => {
|
|
4151
4696
|
if (activeForm) firstFieldRef.current?.focus();
|
|
4152
4697
|
else if ((savedForm || draft.submitted) && !disabled)
|
|
4153
4698
|
inputRef.current?.focus();
|
|
@@ -4408,7 +4953,7 @@ function FollowUpChips({
|
|
|
4408
4953
|
}
|
|
4409
4954
|
|
|
4410
4955
|
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
4411
|
-
var
|
|
4956
|
+
var import_react11 = require("react");
|
|
4412
4957
|
|
|
4413
4958
|
// src/react/components/SearchReferences/SearchReferences.tsx
|
|
4414
4959
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
@@ -4499,7 +5044,7 @@ function SearchReferences({
|
|
|
4499
5044
|
}
|
|
4500
5045
|
|
|
4501
5046
|
// src/react/components/BookingCard/BookingCard.tsx
|
|
4502
|
-
var
|
|
5047
|
+
var import_react10 = require("react");
|
|
4503
5048
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4504
5049
|
var BOOKING_STEPS = [
|
|
4505
5050
|
{ id: "date", label: "Date" },
|
|
@@ -4554,27 +5099,27 @@ function InteractiveBookingCard({
|
|
|
4554
5099
|
offer,
|
|
4555
5100
|
onBook
|
|
4556
5101
|
}) {
|
|
4557
|
-
const fieldId = (0,
|
|
5102
|
+
const fieldId = (0, import_react10.useId)();
|
|
4558
5103
|
const defaultType = offer.eventTypes[0]?.uri ?? offer.slots[0]?.eventTypeUri ?? "";
|
|
4559
|
-
const [step, setStep] = (0,
|
|
4560
|
-
const [eventTypeUri, setEventTypeUri] = (0,
|
|
4561
|
-
const [selectedDate, setSelectedDate] = (0,
|
|
4562
|
-
const [startTime, setStartTime] = (0,
|
|
4563
|
-
const [name, setName] = (0,
|
|
4564
|
-
const [email, setEmail] = (0,
|
|
4565
|
-
const activeStepRef = (0,
|
|
4566
|
-
const previousStepRef = (0,
|
|
5104
|
+
const [step, setStep] = (0, import_react10.useState)("date");
|
|
5105
|
+
const [eventTypeUri, setEventTypeUri] = (0, import_react10.useState)(defaultType);
|
|
5106
|
+
const [selectedDate, setSelectedDate] = (0, import_react10.useState)("");
|
|
5107
|
+
const [startTime, setStartTime] = (0, import_react10.useState)("");
|
|
5108
|
+
const [name, setName] = (0, import_react10.useState)("");
|
|
5109
|
+
const [email, setEmail] = (0, import_react10.useState)("");
|
|
5110
|
+
const activeStepRef = (0, import_react10.useRef)(null);
|
|
5111
|
+
const previousStepRef = (0, import_react10.useRef)(step);
|
|
4567
5112
|
const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
|
|
4568
|
-
(0,
|
|
5113
|
+
(0, import_react10.useEffect)(() => {
|
|
4569
5114
|
if (previousStepRef.current === step) return;
|
|
4570
5115
|
previousStepRef.current = step;
|
|
4571
5116
|
activeStepRef.current?.scrollIntoView({ block: "nearest" });
|
|
4572
5117
|
}, [step]);
|
|
4573
|
-
const slots = (0,
|
|
5118
|
+
const slots = (0, import_react10.useMemo)(
|
|
4574
5119
|
() => bookingSlotsForEventType(offer.slots, eventTypeUri),
|
|
4575
5120
|
[eventTypeUri, offer.slots]
|
|
4576
5121
|
);
|
|
4577
|
-
const availableByDate = (0,
|
|
5122
|
+
const availableByDate = (0, import_react10.useMemo)(() => {
|
|
4578
5123
|
const next = /* @__PURE__ */ new Map();
|
|
4579
5124
|
for (const slot of slots) {
|
|
4580
5125
|
const key = slotDateKey(slot.startTime);
|
|
@@ -4582,7 +5127,7 @@ function InteractiveBookingCard({
|
|
|
4582
5127
|
}
|
|
4583
5128
|
return next;
|
|
4584
5129
|
}, [slots]);
|
|
4585
|
-
const [visibleMonth, setVisibleMonth] = (0,
|
|
5130
|
+
const [visibleMonth, setVisibleMonth] = (0, import_react10.useState)(
|
|
4586
5131
|
() => firstAvailableBookingMonth(slots)
|
|
4587
5132
|
);
|
|
4588
5133
|
function selectEventType(nextType) {
|
|
@@ -4595,7 +5140,7 @@ function InteractiveBookingCard({
|
|
|
4595
5140
|
)
|
|
4596
5141
|
);
|
|
4597
5142
|
}
|
|
4598
|
-
const daySlots = (0,
|
|
5143
|
+
const daySlots = (0, import_react10.useMemo)(
|
|
4599
5144
|
() => slots.filter((slot) => slotDateKey(slot.startTime) === selectedDate),
|
|
4600
5145
|
[selectedDate, slots]
|
|
4601
5146
|
);
|
|
@@ -4604,7 +5149,7 @@ function InteractiveBookingCard({
|
|
|
4604
5149
|
);
|
|
4605
5150
|
const selectedSample = availableByDate.get(selectedDate) ?? startTime;
|
|
4606
5151
|
const timeZone = formatSlotTimeZone(slots[0]?.startTime ?? selectedSample);
|
|
4607
|
-
const weekdays = (0,
|
|
5152
|
+
const weekdays = (0, import_react10.useMemo)(() => weekdayLabels(), []);
|
|
4608
5153
|
const cells = calendarCells(visibleMonth.year, visibleMonth.month);
|
|
4609
5154
|
const canPrevMonth = [...availableByDate.keys()].some((key) => {
|
|
4610
5155
|
const month = monthFromKey(key);
|
|
@@ -4890,8 +5435,8 @@ function resolveMessageUrl(safeUrl, baseUrl) {
|
|
|
4890
5435
|
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
4891
5436
|
var import_styles = require("streamdown/styles.css");
|
|
4892
5437
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
4893
|
-
function normalizeDedupeText(
|
|
4894
|
-
return
|
|
5438
|
+
function normalizeDedupeText(text3) {
|
|
5439
|
+
return text3.trim().replace(/\s+/g, " ").toLowerCase();
|
|
4895
5440
|
}
|
|
4896
5441
|
function paragraphsAreNearDuplicates(first, second) {
|
|
4897
5442
|
const left = normalizeDedupeText(first);
|
|
@@ -4907,8 +5452,8 @@ function paragraphsShareOpening(first, second) {
|
|
|
4907
5452
|
if (!opening || opening.length < 20) return false;
|
|
4908
5453
|
return second.trim().startsWith(opening);
|
|
4909
5454
|
}
|
|
4910
|
-
function collapseRepeatedText(
|
|
4911
|
-
const trimmed =
|
|
5455
|
+
function collapseRepeatedText(text3) {
|
|
5456
|
+
const trimmed = text3.trim();
|
|
4912
5457
|
if (trimmed.length < 40) return trimmed;
|
|
4913
5458
|
const paragraphs = trimmed.split(/\n{2,}/u).map((part) => part.trim()).filter(Boolean);
|
|
4914
5459
|
if (paragraphs.length === 2 && (paragraphsAreNearDuplicates(paragraphs[0], paragraphs[1]) || paragraphsShareOpening(paragraphs[0], paragraphs[1]))) {
|
|
@@ -4929,13 +5474,14 @@ function MessageBubble({
|
|
|
4929
5474
|
message,
|
|
4930
5475
|
brandLogoUrl,
|
|
4931
5476
|
bookingDisabled = false,
|
|
5477
|
+
showProvenance = false,
|
|
4932
5478
|
bookingReadOnly = false,
|
|
4933
5479
|
linkBaseUrl,
|
|
4934
5480
|
offer,
|
|
4935
5481
|
onBook
|
|
4936
5482
|
}) {
|
|
4937
5483
|
const resolvedLogoUrl = brandLogoUrl?.trim();
|
|
4938
|
-
const [failedLogoUrl, setFailedLogoUrl] = (0,
|
|
5484
|
+
const [failedLogoUrl, setFailedLogoUrl] = (0, import_react11.useState)(null);
|
|
4939
5485
|
const showBrandLogo = Boolean(resolvedLogoUrl) && failedLogoUrl !== resolvedLogoUrl;
|
|
4940
5486
|
const cards = message.role === "agent" ? extractToolCards(message.text) : [];
|
|
4941
5487
|
const extractedOffers = cards.filter(
|
|
@@ -4950,7 +5496,34 @@ function MessageBubble({
|
|
|
4950
5496
|
if (message.role === "visitor") {
|
|
4951
5497
|
const visitorText = visitorMessageDisplayText(message).trim();
|
|
4952
5498
|
if (!visitorText) return null;
|
|
4953
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.
|
|
5499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
5500
|
+
"article",
|
|
5501
|
+
{
|
|
5502
|
+
className: "message-bubble message-bubble--visitor",
|
|
5503
|
+
"aria-label": "Message from visitor",
|
|
5504
|
+
children: [
|
|
5505
|
+
showProvenance ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__speaker", children: "You \xB7 Visitor" }) : null,
|
|
5506
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "message-bubble__text", children: visitorText })
|
|
5507
|
+
]
|
|
5508
|
+
}
|
|
5509
|
+
);
|
|
5510
|
+
}
|
|
5511
|
+
if (message.role === "human") {
|
|
5512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
5513
|
+
"article",
|
|
5514
|
+
{
|
|
5515
|
+
className: "message-bubble message-bubble--human",
|
|
5516
|
+
"aria-label": `Message from ${message.representative.name}`,
|
|
5517
|
+
children: [
|
|
5518
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("strong", { className: "message-bubble__representative", children: [
|
|
5519
|
+
message.representative.name,
|
|
5520
|
+
" ",
|
|
5521
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Human representative" })
|
|
5522
|
+
] }),
|
|
5523
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "message-bubble__text", children: message.text })
|
|
5524
|
+
]
|
|
5525
|
+
}
|
|
5526
|
+
);
|
|
4954
5527
|
}
|
|
4955
5528
|
const citations = message.citations ?? [];
|
|
4956
5529
|
const agentText = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__text", children: [
|
|
@@ -4987,40 +5560,48 @@ function MessageBubble({
|
|
|
4987
5560
|
] });
|
|
4988
5561
|
if (!displayText && !message.searchResults?.length && offers.length === 0)
|
|
4989
5562
|
return null;
|
|
4990
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
5564
|
+
"article",
|
|
5565
|
+
{
|
|
5566
|
+
className: "message-bubble message-bubble--agent",
|
|
5567
|
+
"aria-label": "Message from AI assistant",
|
|
5568
|
+
children: [
|
|
5569
|
+
showProvenance ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__speaker", children: "AI assistant" }) : null,
|
|
5570
|
+
displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__agent-row", children: [
|
|
5571
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5572
|
+
"img",
|
|
5573
|
+
{
|
|
5574
|
+
src: resolvedLogoUrl,
|
|
5575
|
+
alt: "",
|
|
5576
|
+
onError: () => {
|
|
5577
|
+
setFailedLogoUrl(resolvedLogoUrl ?? null);
|
|
5578
|
+
}
|
|
5579
|
+
}
|
|
5580
|
+
) }),
|
|
5581
|
+
agentText
|
|
5582
|
+
] }) : agentText : null,
|
|
5583
|
+
offers.map((nextOffer, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5584
|
+
BookingCard,
|
|
5585
|
+
{
|
|
5586
|
+
disabled: bookingDisabled,
|
|
5587
|
+
readOnly: bookingReadOnly,
|
|
5588
|
+
offer: nextOffer,
|
|
5589
|
+
onBook
|
|
5590
|
+
},
|
|
5591
|
+
`${bookingOfferIdentityKey(nextOffer)}-${index}`
|
|
5592
|
+
))
|
|
5593
|
+
]
|
|
5594
|
+
}
|
|
5595
|
+
);
|
|
5015
5596
|
}
|
|
5016
5597
|
|
|
5017
5598
|
// src/react/components/MessageActions/MessageActions.tsx
|
|
5018
|
-
var
|
|
5599
|
+
var import_react12 = require("react");
|
|
5019
5600
|
var import_react_dom2 = require("react-dom");
|
|
5020
5601
|
|
|
5021
5602
|
// src/react/lib/speech.ts
|
|
5022
|
-
function toSpeechText(
|
|
5023
|
-
let out = hideToolCardFences(
|
|
5603
|
+
function toSpeechText(text3) {
|
|
5604
|
+
let out = hideToolCardFences(text3);
|
|
5024
5605
|
out = out.replace(/```[\s\S]*?```/g, " ");
|
|
5025
5606
|
out = out.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
|
|
5026
5607
|
out = out.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1");
|
|
@@ -5355,12 +5936,12 @@ function StopIcon() {
|
|
|
5355
5936
|
}
|
|
5356
5937
|
) });
|
|
5357
5938
|
}
|
|
5358
|
-
async function writeToClipboard(
|
|
5939
|
+
async function writeToClipboard(text3) {
|
|
5359
5940
|
try {
|
|
5360
|
-
await navigator.clipboard.writeText(
|
|
5941
|
+
await navigator.clipboard.writeText(text3);
|
|
5361
5942
|
} catch {
|
|
5362
5943
|
const textarea = document.createElement("textarea");
|
|
5363
|
-
textarea.value =
|
|
5944
|
+
textarea.value = text3;
|
|
5364
5945
|
textarea.style.position = "fixed";
|
|
5365
5946
|
textarea.style.opacity = "0";
|
|
5366
5947
|
document.body.appendChild(textarea);
|
|
@@ -5411,26 +5992,26 @@ function MessageActions({
|
|
|
5411
5992
|
speechText
|
|
5412
5993
|
}) {
|
|
5413
5994
|
const menuPortalRoot = useAgentRailMenuPortalRoot();
|
|
5414
|
-
const [copied, setCopied] = (0,
|
|
5415
|
-
const [rating, setRating] = (0,
|
|
5416
|
-
const [menuOpen, setMenuOpen] = (0,
|
|
5417
|
-
const [menuPosition, setMenuPosition] = (0,
|
|
5418
|
-
const [speaking, setSpeaking] = (0,
|
|
5419
|
-
const [speechSupported, setSpeechSupported] = (0,
|
|
5420
|
-
const copyTimerRef = (0,
|
|
5421
|
-
const menuRef = (0,
|
|
5422
|
-
const portaledMenuRef = (0,
|
|
5423
|
-
const moreButtonRef = (0,
|
|
5995
|
+
const [copied, setCopied] = (0, import_react12.useState)(false);
|
|
5996
|
+
const [rating, setRating] = (0, import_react12.useState)(null);
|
|
5997
|
+
const [menuOpen, setMenuOpen] = (0, import_react12.useState)(false);
|
|
5998
|
+
const [menuPosition, setMenuPosition] = (0, import_react12.useState)(null);
|
|
5999
|
+
const [speaking, setSpeaking] = (0, import_react12.useState)(false);
|
|
6000
|
+
const [speechSupported, setSpeechSupported] = (0, import_react12.useState)(null);
|
|
6001
|
+
const copyTimerRef = (0, import_react12.useRef)(null);
|
|
6002
|
+
const menuRef = (0, import_react12.useRef)(null);
|
|
6003
|
+
const portaledMenuRef = (0, import_react12.useRef)(null);
|
|
6004
|
+
const moreButtonRef = (0, import_react12.useRef)(null);
|
|
5424
6005
|
const answeredLabel = formatAnsweredAt(answeredAt ?? 0);
|
|
5425
6006
|
const resolvedSpeechText = speechText ?? toSpeechText(copyText);
|
|
5426
6007
|
const canOpenReceipt = Boolean(receiptSteps) && Boolean(onOpenReceipt);
|
|
5427
6008
|
const readAloudEligible = Boolean(readAloud && resolvedSpeechText);
|
|
5428
6009
|
const canReadAloud = readAloudEligible && speechSupported === true;
|
|
5429
6010
|
const showMenu = canOpenReceipt || (speechSupported === null ? readAloudEligible : canReadAloud);
|
|
5430
|
-
(0,
|
|
6011
|
+
(0, import_react12.useLayoutEffect)(() => {
|
|
5431
6012
|
setSpeechSupported(isSpeechSupported());
|
|
5432
6013
|
}, []);
|
|
5433
|
-
(0,
|
|
6014
|
+
(0, import_react12.useLayoutEffect)(() => {
|
|
5434
6015
|
if (!menuOpen || !moreButtonRef.current || !portaledMenuRef.current) {
|
|
5435
6016
|
setMenuPosition(null);
|
|
5436
6017
|
return;
|
|
@@ -5447,7 +6028,7 @@ function MessageActions({
|
|
|
5447
6028
|
})
|
|
5448
6029
|
);
|
|
5449
6030
|
}, [menuOpen, menuPortalRoot]);
|
|
5450
|
-
(0,
|
|
6031
|
+
(0, import_react12.useEffect)(() => {
|
|
5451
6032
|
const unsubscribe = subscribeSpeechInterrupts(() => setSpeaking(false));
|
|
5452
6033
|
return () => {
|
|
5453
6034
|
unsubscribe();
|
|
@@ -5457,7 +6038,7 @@ function MessageActions({
|
|
|
5457
6038
|
stopSpeech();
|
|
5458
6039
|
};
|
|
5459
6040
|
}, []);
|
|
5460
|
-
(0,
|
|
6041
|
+
(0, import_react12.useEffect)(() => {
|
|
5461
6042
|
if (!menuOpen) return;
|
|
5462
6043
|
const handlePointerDown = (event) => {
|
|
5463
6044
|
const target = event.target;
|
|
@@ -5626,7 +6207,7 @@ function MessageActions({
|
|
|
5626
6207
|
}
|
|
5627
6208
|
|
|
5628
6209
|
// src/react/components/HumanInputCard/HumanInputCard.tsx
|
|
5629
|
-
var
|
|
6210
|
+
var import_react14 = require("react");
|
|
5630
6211
|
|
|
5631
6212
|
// src/react/components/ConfirmationCard/ConfirmationCard.tsx
|
|
5632
6213
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
@@ -5668,7 +6249,7 @@ function ConfirmationCard({
|
|
|
5668
6249
|
}
|
|
5669
6250
|
|
|
5670
6251
|
// src/react/components/ToolInputCard/ToolInputCard.tsx
|
|
5671
|
-
var
|
|
6252
|
+
var import_react13 = require("react");
|
|
5672
6253
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
5673
6254
|
function isRecord5(value) {
|
|
5674
6255
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -5791,13 +6372,13 @@ function valuesMatch(left, right) {
|
|
|
5791
6372
|
}
|
|
5792
6373
|
function FieldDescription({
|
|
5793
6374
|
field,
|
|
5794
|
-
id
|
|
6375
|
+
id: id2
|
|
5795
6376
|
}) {
|
|
5796
|
-
return field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id, className: "tool-input-card__description", children: field.description }) : null;
|
|
6377
|
+
return field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: id2, className: "tool-input-card__description", children: field.description }) : null;
|
|
5797
6378
|
}
|
|
5798
6379
|
function ChoiceField({
|
|
5799
6380
|
field,
|
|
5800
|
-
id,
|
|
6381
|
+
id: id2,
|
|
5801
6382
|
value,
|
|
5802
6383
|
disabled,
|
|
5803
6384
|
describedBy,
|
|
@@ -5815,7 +6396,7 @@ function ChoiceField({
|
|
|
5815
6396
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
5816
6397
|
"select",
|
|
5817
6398
|
{
|
|
5818
|
-
id,
|
|
6399
|
+
id: id2,
|
|
5819
6400
|
value: selectedIndex >= 0 ? String(selectedIndex) : "",
|
|
5820
6401
|
disabled,
|
|
5821
6402
|
required: field.required,
|
|
@@ -5838,7 +6419,7 @@ function ChoiceField({
|
|
|
5838
6419
|
{
|
|
5839
6420
|
className: "tool-input-card__choices",
|
|
5840
6421
|
role: multiple ? "group" : "radiogroup",
|
|
5841
|
-
"aria-labelledby": `${
|
|
6422
|
+
"aria-labelledby": `${id2}-label`,
|
|
5842
6423
|
"aria-describedby": describedBy,
|
|
5843
6424
|
"aria-invalid": Boolean(error),
|
|
5844
6425
|
"aria-required": field.required,
|
|
@@ -5849,7 +6430,7 @@ function ChoiceField({
|
|
|
5849
6430
|
"input",
|
|
5850
6431
|
{
|
|
5851
6432
|
type: multiple ? "checkbox" : "radio",
|
|
5852
|
-
name:
|
|
6433
|
+
name: id2,
|
|
5853
6434
|
value: String(index),
|
|
5854
6435
|
checked,
|
|
5855
6436
|
disabled,
|
|
@@ -5877,22 +6458,22 @@ function ToolField({
|
|
|
5877
6458
|
disabled,
|
|
5878
6459
|
error,
|
|
5879
6460
|
field,
|
|
5880
|
-
id,
|
|
6461
|
+
id: id2,
|
|
5881
6462
|
value,
|
|
5882
6463
|
onBlur,
|
|
5883
6464
|
onChange
|
|
5884
6465
|
}) {
|
|
5885
6466
|
const describedBy = [
|
|
5886
|
-
field.description ? `${
|
|
5887
|
-
error ? `${
|
|
6467
|
+
field.description ? `${id2}-description` : "",
|
|
6468
|
+
error ? `${id2}-error` : ""
|
|
5888
6469
|
].filter(Boolean).join(" ");
|
|
5889
6470
|
if (field.kind === "checkbox" || field.kind === "confirmation") {
|
|
5890
6471
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "tool-input-card__field", children: [
|
|
5891
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "tool-input-card__check", htmlFor:
|
|
6472
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "tool-input-card__check", htmlFor: id2, children: [
|
|
5892
6473
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5893
6474
|
"input",
|
|
5894
6475
|
{
|
|
5895
|
-
id,
|
|
6476
|
+
id: id2,
|
|
5896
6477
|
type: "checkbox",
|
|
5897
6478
|
checked: value === true,
|
|
5898
6479
|
disabled,
|
|
@@ -5904,18 +6485,18 @@ function ToolField({
|
|
|
5904
6485
|
),
|
|
5905
6486
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
5906
6487
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: field.label }),
|
|
5907
|
-
field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${
|
|
6488
|
+
field.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id2}-description`, children: field.description }) : null
|
|
5908
6489
|
] })
|
|
5909
6490
|
] }),
|
|
5910
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${
|
|
6491
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id2}-error`, className: "tool-input-card__error", children: error }) : null
|
|
5911
6492
|
] });
|
|
5912
6493
|
}
|
|
5913
|
-
const label = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { id: `${
|
|
6494
|
+
const label = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { id: `${id2}-label`, htmlFor: id2, children: [
|
|
5914
6495
|
field.label,
|
|
5915
6496
|
field.required ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { "aria-hidden": "true", children: " *" }) : null
|
|
5916
6497
|
] });
|
|
5917
6498
|
const common = {
|
|
5918
|
-
id,
|
|
6499
|
+
id: id2,
|
|
5919
6500
|
disabled,
|
|
5920
6501
|
required: field.required,
|
|
5921
6502
|
"aria-describedby": describedBy || void 0,
|
|
@@ -5928,7 +6509,7 @@ function ToolField({
|
|
|
5928
6509
|
ChoiceField,
|
|
5929
6510
|
{
|
|
5930
6511
|
field,
|
|
5931
|
-
id,
|
|
6512
|
+
id: id2,
|
|
5932
6513
|
value,
|
|
5933
6514
|
disabled,
|
|
5934
6515
|
describedBy: describedBy || void 0,
|
|
@@ -5965,7 +6546,7 @@ function ToolField({
|
|
|
5965
6546
|
onChange: (event) => onChange(Number(event.target.value))
|
|
5966
6547
|
}
|
|
5967
6548
|
),
|
|
5968
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("output", { htmlFor:
|
|
6549
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("output", { htmlFor: id2, children: numericValue })
|
|
5969
6550
|
] });
|
|
5970
6551
|
} else {
|
|
5971
6552
|
const type = field.kind === "date-time" ? "datetime-local" : field.kind === "calendar" ? "date" : field.kind;
|
|
@@ -5989,9 +6570,9 @@ function ToolField({
|
|
|
5989
6570
|
}
|
|
5990
6571
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "tool-input-card__field", children: [
|
|
5991
6572
|
label,
|
|
5992
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldDescription, { field, id: `${
|
|
6573
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldDescription, { field, id: `${id2}-description` }),
|
|
5993
6574
|
control,
|
|
5994
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${
|
|
6575
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { id: `${id2}-error`, className: "tool-input-card__error", children: error }) : null
|
|
5995
6576
|
] });
|
|
5996
6577
|
}
|
|
5997
6578
|
function ToolInputCard({
|
|
@@ -5999,11 +6580,11 @@ function ToolInputCard({
|
|
|
5999
6580
|
surface,
|
|
6000
6581
|
onSubmit
|
|
6001
6582
|
}) {
|
|
6002
|
-
const [values, setValues] = (0,
|
|
6583
|
+
const [values, setValues] = (0, import_react13.useState)(
|
|
6003
6584
|
() => initialValues(surface)
|
|
6004
6585
|
);
|
|
6005
|
-
const [touched, setTouched] = (0,
|
|
6006
|
-
const [submitted, setSubmitted] = (0,
|
|
6586
|
+
const [touched, setTouched] = (0, import_react13.useState)(() => /* @__PURE__ */ new Set());
|
|
6587
|
+
const [submitted, setSubmitted] = (0, import_react13.useState)(false);
|
|
6007
6588
|
const errors = Object.fromEntries(
|
|
6008
6589
|
surface.fields.map((field) => [
|
|
6009
6590
|
field.path,
|
|
@@ -6096,7 +6677,7 @@ function HumanInputCard({
|
|
|
6096
6677
|
request,
|
|
6097
6678
|
onRespond
|
|
6098
6679
|
}) {
|
|
6099
|
-
const [
|
|
6680
|
+
const [text3, setText] = (0, import_react14.useState)("");
|
|
6100
6681
|
const options = request.options ?? [];
|
|
6101
6682
|
const showText = request.display === "text" || request.allowFreeform && options.length === 0;
|
|
6102
6683
|
if (request.ui) {
|
|
@@ -6121,7 +6702,7 @@ function HumanInputCard({
|
|
|
6121
6702
|
}
|
|
6122
6703
|
function submitText(event) {
|
|
6123
6704
|
event.preventDefault();
|
|
6124
|
-
const value =
|
|
6705
|
+
const value = text3.trim();
|
|
6125
6706
|
if (!value || disabled) return;
|
|
6126
6707
|
onRespond?.({ requestId: request.requestId, text: value });
|
|
6127
6708
|
}
|
|
@@ -6139,12 +6720,12 @@ function HumanInputCard({
|
|
|
6139
6720
|
"input",
|
|
6140
6721
|
{
|
|
6141
6722
|
id: `human-input-text-${request.requestId}`,
|
|
6142
|
-
value:
|
|
6723
|
+
value: text3,
|
|
6143
6724
|
disabled,
|
|
6144
6725
|
onChange: (event) => setText(event.target.value)
|
|
6145
6726
|
}
|
|
6146
6727
|
),
|
|
6147
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", disabled: disabled || !
|
|
6728
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", disabled: disabled || !text3.trim(), children: "Send" })
|
|
6148
6729
|
] })
|
|
6149
6730
|
] }) : null,
|
|
6150
6731
|
!showText && options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "human-input-card__unavailable", role: "status", children: "This request can\u2019t be answered here." }) : null
|
|
@@ -6153,31 +6734,173 @@ function HumanInputCard({
|
|
|
6153
6734
|
);
|
|
6154
6735
|
}
|
|
6155
6736
|
|
|
6156
|
-
// src/react/components/
|
|
6737
|
+
// src/react/components/LocationConsent/LocationConsent.tsx
|
|
6738
|
+
var import_react15 = require("react");
|
|
6739
|
+
|
|
6740
|
+
// src/runtime/location-consent.ts
|
|
6741
|
+
function isLocationConsentRequest(request) {
|
|
6742
|
+
return request.kind === "tool-approval" && request.action.toolName === "request_location";
|
|
6743
|
+
}
|
|
6744
|
+
function preciseLocationResponse(requestId, position) {
|
|
6745
|
+
const { latitude, longitude, accuracy } = position.coords;
|
|
6746
|
+
if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90 || !Number.isFinite(longitude) || longitude < -180 || longitude > 180 || !Number.isFinite(accuracy) || accuracy < 0 || !Number.isFinite(position.timestamp)) {
|
|
6747
|
+
throw new Error("Your device returned an invalid location.");
|
|
6748
|
+
}
|
|
6749
|
+
return {
|
|
6750
|
+
requestId,
|
|
6751
|
+
optionId: "approve",
|
|
6752
|
+
text: JSON.stringify({
|
|
6753
|
+
status: "shared",
|
|
6754
|
+
location: {
|
|
6755
|
+
source: "device",
|
|
6756
|
+
latitude,
|
|
6757
|
+
longitude,
|
|
6758
|
+
accuracyMeters: accuracy,
|
|
6759
|
+
capturedAt: new Date(position.timestamp).toISOString(),
|
|
6760
|
+
consentedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6761
|
+
scope: "conversation"
|
|
6762
|
+
}
|
|
6763
|
+
})
|
|
6764
|
+
};
|
|
6765
|
+
}
|
|
6766
|
+
function getPreciseLocation(geolocation) {
|
|
6767
|
+
return new Promise(
|
|
6768
|
+
(resolve, reject) => geolocation.getCurrentPosition(
|
|
6769
|
+
resolve,
|
|
6770
|
+
(error) => reject(
|
|
6771
|
+
new Error(
|
|
6772
|
+
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."
|
|
6773
|
+
)
|
|
6774
|
+
),
|
|
6775
|
+
{ enableHighAccuracy: true, maximumAge: 0, timeout: 1e4 }
|
|
6776
|
+
)
|
|
6777
|
+
);
|
|
6778
|
+
}
|
|
6779
|
+
|
|
6780
|
+
// src/react/components/LocationConsent/LocationConsent.tsx
|
|
6157
6781
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6782
|
+
function LocationConsent({
|
|
6783
|
+
request,
|
|
6784
|
+
onRespond
|
|
6785
|
+
}) {
|
|
6786
|
+
const [preference, setPreference] = (0, import_react15.useState)("unset");
|
|
6787
|
+
const [locating, setLocating] = (0, import_react15.useState)(false);
|
|
6788
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
6789
|
+
const respond = (0, import_react15.useRef)(onRespond);
|
|
6790
|
+
const answered = (0, import_react15.useRef)(null);
|
|
6791
|
+
const requestId = request?.requestId;
|
|
6792
|
+
(0, import_react15.useEffect)(() => {
|
|
6793
|
+
respond.current = onRespond;
|
|
6794
|
+
}, [onRespond]);
|
|
6795
|
+
(0, import_react15.useEffect)(() => {
|
|
6796
|
+
if (!requestId || preference === "unset" || answered.current === requestId || !respond.current)
|
|
6797
|
+
return;
|
|
6798
|
+
if (preference === "off") {
|
|
6799
|
+
setLocating(false);
|
|
6800
|
+
answered.current = requestId;
|
|
6801
|
+
respond.current({
|
|
6802
|
+
requestId,
|
|
6803
|
+
optionId: "approve",
|
|
6804
|
+
text: JSON.stringify({ status: "declined" })
|
|
6805
|
+
});
|
|
6806
|
+
return;
|
|
6807
|
+
}
|
|
6808
|
+
let cancelled = false;
|
|
6809
|
+
const pendingId = requestId;
|
|
6810
|
+
setLocating(true);
|
|
6811
|
+
setError(null);
|
|
6812
|
+
async function locate() {
|
|
6813
|
+
try {
|
|
6814
|
+
if (!Reflect.has(navigator, "geolocation"))
|
|
6815
|
+
throw new Error("Location sharing isn\u2019t available in this browser.");
|
|
6816
|
+
const position = await getPreciseLocation(navigator.geolocation);
|
|
6817
|
+
if (cancelled) return;
|
|
6818
|
+
const response = preciseLocationResponse(pendingId, position);
|
|
6819
|
+
answered.current = pendingId;
|
|
6820
|
+
respond.current?.(response);
|
|
6821
|
+
} catch (failure) {
|
|
6822
|
+
if (cancelled) return;
|
|
6823
|
+
setPreference("unset");
|
|
6824
|
+
setError(
|
|
6825
|
+
failure instanceof Error ? failure.message : "Location sharing failed. Try again or continue without sharing."
|
|
6826
|
+
);
|
|
6827
|
+
} finally {
|
|
6828
|
+
if (!cancelled) setLocating(false);
|
|
6829
|
+
}
|
|
6830
|
+
}
|
|
6831
|
+
void locate();
|
|
6832
|
+
return () => {
|
|
6833
|
+
cancelled = true;
|
|
6834
|
+
};
|
|
6835
|
+
}, [requestId, preference]);
|
|
6836
|
+
const isLocating = Boolean(requestId) && preference === "on" && locating;
|
|
6837
|
+
if (!request && preference === "unset") return null;
|
|
6838
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: "location-consent", "aria-label": "Location sharing", children: [
|
|
6839
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "location-consent__copy", children: [
|
|
6840
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: isLocating ? "Getting your location\u2026" : request ? "Get better results" : "Precise location" }),
|
|
6841
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: isLocating ? "Allow location access in your browser." : request ? "Share your precise location" : preference === "on" ? "On for location-aware answers" : "Off for this chat" })
|
|
6842
|
+
] }),
|
|
6843
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "location-consent__actions", children: [
|
|
6844
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6845
|
+
"button",
|
|
6846
|
+
{
|
|
6847
|
+
type: "button",
|
|
6848
|
+
role: "switch",
|
|
6849
|
+
className: "location-consent__toggle",
|
|
6850
|
+
"aria-label": "Share precise location",
|
|
6851
|
+
"aria-checked": preference === "on",
|
|
6852
|
+
"aria-busy": isLocating,
|
|
6853
|
+
disabled: !onRespond,
|
|
6854
|
+
onClick: () => {
|
|
6855
|
+
setError(null);
|
|
6856
|
+
setPreference(preference === "on" ? "off" : "on");
|
|
6857
|
+
},
|
|
6858
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", {})
|
|
6859
|
+
}
|
|
6860
|
+
),
|
|
6861
|
+
request && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6862
|
+
"button",
|
|
6863
|
+
{
|
|
6864
|
+
type: "button",
|
|
6865
|
+
className: "location-consent__decline",
|
|
6866
|
+
disabled: !onRespond,
|
|
6867
|
+
onClick: () => {
|
|
6868
|
+
setError(null);
|
|
6869
|
+
setPreference("off");
|
|
6870
|
+
},
|
|
6871
|
+
children: "No thanks"
|
|
6872
|
+
}
|
|
6873
|
+
)
|
|
6874
|
+
] }),
|
|
6875
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { role: "alert", className: "location-consent__error", children: error })
|
|
6876
|
+
] });
|
|
6877
|
+
}
|
|
6878
|
+
|
|
6879
|
+
// src/react/components/CollectionResultCard/CollectionResultCard.tsx
|
|
6880
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
6158
6881
|
function CollectionResultCard({
|
|
6159
6882
|
result
|
|
6160
6883
|
}) {
|
|
6161
6884
|
const empty = result.items.length === 0;
|
|
6162
|
-
return /* @__PURE__ */ (0,
|
|
6885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
6163
6886
|
"section",
|
|
6164
6887
|
{
|
|
6165
6888
|
className: `collection-result-card tool-result-card tool-result-card--${result.status}`,
|
|
6166
6889
|
"aria-label": result.title,
|
|
6167
6890
|
role: result.status === "completed" ? "status" : "alert",
|
|
6168
6891
|
children: [
|
|
6169
|
-
/* @__PURE__ */ (0,
|
|
6170
|
-
/* @__PURE__ */ (0,
|
|
6171
|
-
/* @__PURE__ */ (0,
|
|
6892
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
6893
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6894
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
|
|
6172
6895
|
] }),
|
|
6173
|
-
empty ? /* @__PURE__ */ (0,
|
|
6174
|
-
/* @__PURE__ */ (0,
|
|
6175
|
-
item.description ? /* @__PURE__ */ (0,
|
|
6176
|
-
item.details?.length ? /* @__PURE__ */ (0,
|
|
6177
|
-
/* @__PURE__ */ (0,
|
|
6178
|
-
/* @__PURE__ */ (0,
|
|
6896
|
+
empty ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "collection-result-card__empty", children: "No matching record for the email you shared." }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("ul", { className: "collection-result-card__list", children: result.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("li", { children: [
|
|
6897
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "collection-result-card__item-title", children: item.title }),
|
|
6898
|
+
item.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: item.description }) : null,
|
|
6899
|
+
item.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: item.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
6900
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
|
|
6901
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
|
|
6179
6902
|
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6180
|
-
item.href ? /* @__PURE__ */ (0,
|
|
6903
|
+
item.href ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("a", { href: item.href, target: "_blank", rel: "noreferrer", children: "Open record" }) : null
|
|
6181
6904
|
] }, item.title)) })
|
|
6182
6905
|
]
|
|
6183
6906
|
}
|
|
@@ -6185,23 +6908,23 @@ function CollectionResultCard({
|
|
|
6185
6908
|
}
|
|
6186
6909
|
|
|
6187
6910
|
// src/react/components/EntityResultCard/EntityResultCard.tsx
|
|
6188
|
-
var
|
|
6911
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
6189
6912
|
function EntityResultCard({
|
|
6190
6913
|
result
|
|
6191
6914
|
}) {
|
|
6192
6915
|
const compact = !result.description && !result.details?.length && !result.links?.length;
|
|
6193
6916
|
const collapsible = result.status === "completed" && Boolean(result.details?.length) && !result.links?.length;
|
|
6194
|
-
const heading = /* @__PURE__ */ (0,
|
|
6195
|
-
/* @__PURE__ */ (0,
|
|
6196
|
-
/* @__PURE__ */ (0,
|
|
6917
|
+
const heading = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "tool-result-card__heading", children: [
|
|
6918
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6919
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: result.title })
|
|
6197
6920
|
] });
|
|
6198
|
-
const content = /* @__PURE__ */ (0,
|
|
6199
|
-
result.description ? /* @__PURE__ */ (0,
|
|
6200
|
-
result.details?.length ? /* @__PURE__ */ (0,
|
|
6201
|
-
/* @__PURE__ */ (0,
|
|
6202
|
-
/* @__PURE__ */ (0,
|
|
6921
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
6922
|
+
result.description ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { children: result.description }) : null,
|
|
6923
|
+
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
|
|
6924
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { children: detail.label }),
|
|
6925
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { children: detail.value })
|
|
6203
6926
|
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6204
|
-
result.links?.length ? /* @__PURE__ */ (0,
|
|
6927
|
+
result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6205
6928
|
"a",
|
|
6206
6929
|
{
|
|
6207
6930
|
href: link.href,
|
|
@@ -6213,12 +6936,12 @@ function EntityResultCard({
|
|
|
6213
6936
|
)) }) : null
|
|
6214
6937
|
] });
|
|
6215
6938
|
if (collapsible) {
|
|
6216
|
-
return /* @__PURE__ */ (0,
|
|
6217
|
-
/* @__PURE__ */ (0,
|
|
6939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("details", { className: "entity-result-card tool-result-card entity-result-card--disclosure", children: [
|
|
6940
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("summary", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { role: "status", children: heading }) }),
|
|
6218
6941
|
content
|
|
6219
6942
|
] });
|
|
6220
6943
|
}
|
|
6221
|
-
return /* @__PURE__ */ (0,
|
|
6944
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
6222
6945
|
"section",
|
|
6223
6946
|
{
|
|
6224
6947
|
className: `entity-result-card tool-result-card tool-result-card--${result.status}${compact ? " entity-result-card--compact" : ""}`,
|
|
@@ -6233,24 +6956,24 @@ function EntityResultCard({
|
|
|
6233
6956
|
}
|
|
6234
6957
|
|
|
6235
6958
|
// src/react/components/SignatureResultCard/SignatureResultCard.tsx
|
|
6236
|
-
var
|
|
6959
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
6237
6960
|
function SignatureResultCard({
|
|
6238
6961
|
result
|
|
6239
6962
|
}) {
|
|
6240
6963
|
const primaryLink = result.links?.[0];
|
|
6241
|
-
return /* @__PURE__ */ (0,
|
|
6964
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
6242
6965
|
"section",
|
|
6243
6966
|
{
|
|
6244
6967
|
className: `signature-result-card tool-result-card tool-result-card--${result.status}`,
|
|
6245
6968
|
"aria-label": result.title,
|
|
6246
6969
|
children: [
|
|
6247
|
-
/* @__PURE__ */ (0,
|
|
6248
|
-
/* @__PURE__ */ (0,
|
|
6249
|
-
/* @__PURE__ */ (0,
|
|
6970
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
6971
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6972
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: result.title })
|
|
6250
6973
|
] }),
|
|
6251
|
-
result.statusLabel ? /* @__PURE__ */ (0,
|
|
6252
|
-
result.description ? /* @__PURE__ */ (0,
|
|
6253
|
-
primaryLink ? /* @__PURE__ */ (0,
|
|
6974
|
+
result.statusLabel ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "signature-result-card__badge", children: result.statusLabel }) : null,
|
|
6975
|
+
result.description ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: result.description }) : null,
|
|
6976
|
+
primaryLink ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
6254
6977
|
"a",
|
|
6255
6978
|
{
|
|
6256
6979
|
className: "signature-result-card__cta",
|
|
@@ -6266,27 +6989,27 @@ function SignatureResultCard({
|
|
|
6266
6989
|
}
|
|
6267
6990
|
|
|
6268
6991
|
// src/react/components/ToolResultCard/ToolResultCard.tsx
|
|
6269
|
-
var
|
|
6992
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
6270
6993
|
function ToolResultCard({
|
|
6271
6994
|
result
|
|
6272
6995
|
}) {
|
|
6273
|
-
return /* @__PURE__ */ (0,
|
|
6996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
6274
6997
|
"section",
|
|
6275
6998
|
{
|
|
6276
6999
|
className: `tool-result-card tool-result-card--${result.status}`,
|
|
6277
7000
|
"aria-label": result.title,
|
|
6278
7001
|
role: result.status === "completed" ? "status" : "alert",
|
|
6279
7002
|
children: [
|
|
6280
|
-
/* @__PURE__ */ (0,
|
|
6281
|
-
/* @__PURE__ */ (0,
|
|
6282
|
-
/* @__PURE__ */ (0,
|
|
7003
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
7004
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
7005
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: result.title })
|
|
6283
7006
|
] }),
|
|
6284
|
-
result.description ? /* @__PURE__ */ (0,
|
|
6285
|
-
result.details?.length ? /* @__PURE__ */ (0,
|
|
6286
|
-
/* @__PURE__ */ (0,
|
|
6287
|
-
/* @__PURE__ */ (0,
|
|
7007
|
+
result.description ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: result.description }) : null,
|
|
7008
|
+
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
|
|
7009
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { children: detail.label }),
|
|
7010
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { children: detail.value })
|
|
6288
7011
|
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6289
|
-
result.links?.length ? /* @__PURE__ */ (0,
|
|
7012
|
+
result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
6290
7013
|
"a",
|
|
6291
7014
|
{
|
|
6292
7015
|
href: link.href,
|
|
@@ -6302,14 +7025,14 @@ function ToolResultCard({
|
|
|
6302
7025
|
}
|
|
6303
7026
|
|
|
6304
7027
|
// src/react/components/VisitorToolResultView/VisitorToolResultView.tsx
|
|
6305
|
-
var
|
|
7028
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
6306
7029
|
function VisitorToolResultView({
|
|
6307
7030
|
disabled = false,
|
|
6308
7031
|
onToolInput,
|
|
6309
7032
|
result
|
|
6310
7033
|
}) {
|
|
6311
7034
|
if (result.kind === "input") {
|
|
6312
|
-
return /* @__PURE__ */ (0,
|
|
7035
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6313
7036
|
ToolInputCard,
|
|
6314
7037
|
{
|
|
6315
7038
|
disabled,
|
|
@@ -6319,16 +7042,16 @@ function VisitorToolResultView({
|
|
|
6319
7042
|
);
|
|
6320
7043
|
}
|
|
6321
7044
|
if (result.kind === "entity") {
|
|
6322
|
-
return /* @__PURE__ */ (0,
|
|
7045
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(EntityResultCard, { result });
|
|
6323
7046
|
}
|
|
6324
7047
|
if (result.kind === "collection") {
|
|
6325
|
-
return /* @__PURE__ */ (0,
|
|
7048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CollectionResultCard, { result });
|
|
6326
7049
|
}
|
|
6327
7050
|
if (result.kind === "signature") {
|
|
6328
|
-
return /* @__PURE__ */ (0,
|
|
7051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SignatureResultCard, { result });
|
|
6329
7052
|
}
|
|
6330
7053
|
if (result.kind === "summary") {
|
|
6331
|
-
return /* @__PURE__ */ (0,
|
|
7054
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ToolResultCard, { result });
|
|
6332
7055
|
}
|
|
6333
7056
|
return null;
|
|
6334
7057
|
}
|
|
@@ -6337,9 +7060,9 @@ function isRenderableVisitorToolResult(result) {
|
|
|
6337
7060
|
}
|
|
6338
7061
|
|
|
6339
7062
|
// src/react/components/AgentRail/AgentRail.tsx
|
|
6340
|
-
var
|
|
7063
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
6341
7064
|
function MinimizeIcon() {
|
|
6342
|
-
return /* @__PURE__ */ (0,
|
|
7065
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6343
7066
|
"path",
|
|
6344
7067
|
{
|
|
6345
7068
|
d: "M3.5 8h9",
|
|
@@ -6350,7 +7073,7 @@ function MinimizeIcon() {
|
|
|
6350
7073
|
) });
|
|
6351
7074
|
}
|
|
6352
7075
|
function CloseIcon2() {
|
|
6353
|
-
return /* @__PURE__ */ (0,
|
|
7076
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6354
7077
|
"path",
|
|
6355
7078
|
{
|
|
6356
7079
|
d: "M4 4l8 8M12 4l-8 8",
|
|
@@ -6361,7 +7084,7 @@ function CloseIcon2() {
|
|
|
6361
7084
|
) });
|
|
6362
7085
|
}
|
|
6363
7086
|
function NewChatIcon() {
|
|
6364
|
-
return /* @__PURE__ */ (0,
|
|
7087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6365
7088
|
"path",
|
|
6366
7089
|
{
|
|
6367
7090
|
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",
|
|
@@ -6373,7 +7096,7 @@ function NewChatIcon() {
|
|
|
6373
7096
|
) });
|
|
6374
7097
|
}
|
|
6375
7098
|
function ExpandIcon() {
|
|
6376
|
-
return /* @__PURE__ */ (0,
|
|
7099
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6377
7100
|
"path",
|
|
6378
7101
|
{
|
|
6379
7102
|
d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
|
|
@@ -6385,7 +7108,7 @@ function ExpandIcon() {
|
|
|
6385
7108
|
) });
|
|
6386
7109
|
}
|
|
6387
7110
|
function RestoreIcon() {
|
|
6388
|
-
return /* @__PURE__ */ (0,
|
|
7111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6389
7112
|
"path",
|
|
6390
7113
|
{
|
|
6391
7114
|
d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
|
|
@@ -6397,7 +7120,7 @@ function RestoreIcon() {
|
|
|
6397
7120
|
) });
|
|
6398
7121
|
}
|
|
6399
7122
|
function ChevronDownIcon() {
|
|
6400
|
-
return /* @__PURE__ */ (0,
|
|
7123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6401
7124
|
"path",
|
|
6402
7125
|
{
|
|
6403
7126
|
d: "M4 6.5l4 4 4-4",
|
|
@@ -6411,6 +7134,7 @@ function ChevronDownIcon() {
|
|
|
6411
7134
|
var DEFAULT_DISCLAIMER_LABEL = "Agent can make mistakes. Check important info.";
|
|
6412
7135
|
function AgentRail({
|
|
6413
7136
|
state,
|
|
7137
|
+
handoff,
|
|
6414
7138
|
theme,
|
|
6415
7139
|
colorScheme = "auto",
|
|
6416
7140
|
brandLabel = "",
|
|
@@ -6436,43 +7160,51 @@ function AgentRail({
|
|
|
6436
7160
|
onInputResponse,
|
|
6437
7161
|
onToolInput
|
|
6438
7162
|
}) {
|
|
6439
|
-
const railRef = (0,
|
|
6440
|
-
const overlayRef = (0,
|
|
6441
|
-
const transcriptRef = (0,
|
|
6442
|
-
const responseRef = (0,
|
|
6443
|
-
const threadRef = (0,
|
|
6444
|
-
const lastScrolledVisitorIdRef = (0,
|
|
6445
|
-
const pinnedToBottomRef = (0,
|
|
6446
|
-
const smoothScrollToLatestRef = (0,
|
|
6447
|
-
const lockedTranscriptScrollTopRef = (0,
|
|
6448
|
-
const [showJumpToLatest, setShowJumpToLatest] = (0,
|
|
6449
|
-
const [receiptOpen, setReceiptOpen] = (0,
|
|
7163
|
+
const railRef = (0, import_react16.useRef)(null);
|
|
7164
|
+
const overlayRef = (0, import_react16.useRef)(null);
|
|
7165
|
+
const transcriptRef = (0, import_react16.useRef)(null);
|
|
7166
|
+
const responseRef = (0, import_react16.useRef)(null);
|
|
7167
|
+
const threadRef = (0, import_react16.useRef)(null);
|
|
7168
|
+
const lastScrolledVisitorIdRef = (0, import_react16.useRef)(void 0);
|
|
7169
|
+
const pinnedToBottomRef = (0, import_react16.useRef)(true);
|
|
7170
|
+
const smoothScrollToLatestRef = (0, import_react16.useRef)(false);
|
|
7171
|
+
const lockedTranscriptScrollTopRef = (0, import_react16.useRef)(null);
|
|
7172
|
+
const [showJumpToLatest, setShowJumpToLatest] = (0, import_react16.useState)(false);
|
|
7173
|
+
const [receiptOpen, setReceiptOpen] = (0, import_react16.useState)(false);
|
|
6450
7174
|
const resolvedBrandLabel = brandLabel.trim();
|
|
6451
7175
|
const resolvedBrandLogoUrl = brandLogoUrl?.trim();
|
|
6452
7176
|
const resolvedDisclaimerLabel = disclaimerLabel === void 0 ? DEFAULT_DISCLAIMER_LABEL : disclaimerLabel;
|
|
6453
|
-
const [failedLogoUrl, setFailedLogoUrl] = (0,
|
|
7177
|
+
const [failedLogoUrl, setFailedLogoUrl] = (0, import_react16.useState)(null);
|
|
6454
7178
|
const showBrandLogo = Boolean(resolvedBrandLogoUrl) && failedLogoUrl !== resolvedBrandLogoUrl;
|
|
6455
7179
|
const resolvedColorScheme = useAgentColorScheme(colorScheme);
|
|
6456
7180
|
const railStyle = agentThemeStyle(theme, resolvedColorScheme);
|
|
7181
|
+
const handoffActive = Boolean(handoff?.blocksAI);
|
|
7182
|
+
const handoffStatus = handoff?.page?.status;
|
|
7183
|
+
const locationRequest = handoffActive ? void 0 : state.pendingInputs?.find(isLocationConsentRequest);
|
|
6457
7184
|
const pendingInputRequests = (state.pendingInputs ?? []).filter(
|
|
6458
|
-
(request) => shouldRenderVisitorInputCard(request) && (!state.pendingOffer || request.kind === "tool-approval")
|
|
7185
|
+
(request) => !handoffActive && !isLocationConsentRequest(request) && shouldRenderVisitorInputCard(request) && (!state.pendingOffer || request.kind === "tool-approval")
|
|
6459
7186
|
);
|
|
6460
|
-
const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming" || state.phase === "waiting-input" && pendingInputRequests.length > 0;
|
|
6461
|
-
const semanticSurfaceDisabled = isBusy && state.phase !== "waiting-input";
|
|
7187
|
+
const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming" || state.phase === "waiting-input" && (pendingInputRequests.length > 0 || Boolean(locationRequest));
|
|
7188
|
+
const semanticSurfaceDisabled = handoffActive || isBusy && state.phase !== "waiting-input";
|
|
6462
7189
|
const visitorToolResults = (state.toolResults ?? []).filter(
|
|
6463
7190
|
isRenderableVisitorToolResult
|
|
6464
7191
|
);
|
|
6465
7192
|
const activeVisitorToolInput = [...visitorToolResults].reverse().find((result) => result.kind === "input");
|
|
6466
7193
|
const visibleVisitorToolResults = activeVisitorToolInput ? [activeVisitorToolInput] : visitorToolResults;
|
|
6467
|
-
const activityActive = state.toolSteps.some(
|
|
7194
|
+
const activityActive = state.toolSteps.some(
|
|
7195
|
+
(step) => step.state === "active"
|
|
7196
|
+
);
|
|
6468
7197
|
const showActivity = state.toolSteps.length > 0 && pendingInputRequests.length === 0 && !state.pendingOffer && (activityActive || isBusy && !state.streamingText);
|
|
6469
|
-
const activitySteps = activityActive || !isBusy || state.streamingText ? state.toolSteps : [
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
7198
|
+
const activitySteps = activityActive || !isBusy || state.streamingText ? state.toolSteps : [
|
|
7199
|
+
...state.toolSteps,
|
|
7200
|
+
{
|
|
7201
|
+
id: "preparing-answer",
|
|
7202
|
+
kind: "tool",
|
|
7203
|
+
label: "Preparing your answer",
|
|
7204
|
+
detail: "Preparing your answer",
|
|
7205
|
+
state: "active"
|
|
7206
|
+
}
|
|
7207
|
+
];
|
|
6476
7208
|
const hasVisitorMessages2 = state.messages.some(
|
|
6477
7209
|
(message) => message.role === "visitor"
|
|
6478
7210
|
);
|
|
@@ -6501,7 +7233,7 @@ function AgentRail({
|
|
|
6501
7233
|
}
|
|
6502
7234
|
}
|
|
6503
7235
|
const lastIsAgent = lastMessage?.role === "agent";
|
|
6504
|
-
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
7236
|
+
const showMessageActions = !handoffActive && state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
6505
7237
|
const streamingMessage = state.streamingText && !lastIsAgent ? {
|
|
6506
7238
|
createdAt: 0,
|
|
6507
7239
|
id: "streaming-response",
|
|
@@ -6543,7 +7275,7 @@ function AgentRail({
|
|
|
6543
7275
|
...visibleVisitorToolResults
|
|
6544
7276
|
].reverse().find((result) => result.kind !== "input")?.id;
|
|
6545
7277
|
const receiptSteps = answerReceipt && state.toolSteps.length > 0 ? state.toolSteps : void 0;
|
|
6546
|
-
(0,
|
|
7278
|
+
(0, import_react16.useEffect)(() => {
|
|
6547
7279
|
if (state.phase !== "complete") {
|
|
6548
7280
|
setReceiptOpen(false);
|
|
6549
7281
|
}
|
|
@@ -6565,7 +7297,7 @@ function AgentRail({
|
|
|
6565
7297
|
onFollowUpSelect?.(label);
|
|
6566
7298
|
}
|
|
6567
7299
|
const latestVisitorId = visibleMessages[lastVisitorIndex]?.id;
|
|
6568
|
-
(0,
|
|
7300
|
+
(0, import_react16.useEffect)(() => {
|
|
6569
7301
|
const node = transcriptRef.current;
|
|
6570
7302
|
if (!node) return;
|
|
6571
7303
|
if (latestVisitorId !== lastScrolledVisitorIdRef.current) {
|
|
@@ -6595,7 +7327,7 @@ function AgentRail({
|
|
|
6595
7327
|
state.followUps,
|
|
6596
7328
|
state.journey
|
|
6597
7329
|
]);
|
|
6598
|
-
(0,
|
|
7330
|
+
(0, import_react16.useEffect)(() => {
|
|
6599
7331
|
const node = transcriptRef.current;
|
|
6600
7332
|
if (!node) return;
|
|
6601
7333
|
const handleScroll = () => {
|
|
@@ -6609,7 +7341,7 @@ function AgentRail({
|
|
|
6609
7341
|
handleScroll();
|
|
6610
7342
|
return () => node.removeEventListener("scroll", handleScroll);
|
|
6611
7343
|
}, []);
|
|
6612
|
-
(0,
|
|
7344
|
+
(0, import_react16.useEffect)(() => {
|
|
6613
7345
|
if (!receiptOpen) {
|
|
6614
7346
|
lockedTranscriptScrollTopRef.current = null;
|
|
6615
7347
|
return;
|
|
@@ -6647,7 +7379,7 @@ function AgentRail({
|
|
|
6647
7379
|
window.setTimeout(settle, 900);
|
|
6648
7380
|
node.scrollTo({ top: node.scrollHeight, behavior: "smooth" });
|
|
6649
7381
|
}
|
|
6650
|
-
return /* @__PURE__ */ (0,
|
|
7382
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6651
7383
|
"aside",
|
|
6652
7384
|
{
|
|
6653
7385
|
ref: railRef,
|
|
@@ -6661,244 +7393,305 @@ function AgentRail({
|
|
|
6661
7393
|
autoFocus: mobileFullscreen || expanded,
|
|
6662
7394
|
role: mobileFullscreen || expanded ? "dialog" : void 0,
|
|
6663
7395
|
tabIndex: mobileFullscreen || expanded ? -1 : void 0,
|
|
6664
|
-
children: /* @__PURE__ */ (0,
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
7396
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(AgentRailOverlayContext.Provider, { value: { railRef, overlayRef }, children: [
|
|
7397
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__surface", inert: receiptOpen || void 0, children: [
|
|
7398
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__brand-row", children: [
|
|
7399
|
+
onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7400
|
+
"button",
|
|
7401
|
+
{
|
|
7402
|
+
type: "button",
|
|
7403
|
+
className: "agent-rail__collapse",
|
|
7404
|
+
"aria-label": "Collapse assist",
|
|
7405
|
+
onClick: onCollapse,
|
|
7406
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MinimizeIcon, {})
|
|
7407
|
+
}
|
|
7408
|
+
) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7409
|
+
"button",
|
|
7410
|
+
{
|
|
7411
|
+
type: "button",
|
|
7412
|
+
className: "agent-rail__close",
|
|
7413
|
+
"aria-label": "Close agent",
|
|
7414
|
+
onClick: onClose,
|
|
7415
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CloseIcon2, {})
|
|
7416
|
+
}
|
|
7417
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
|
|
7418
|
+
resolvedBrandLabel || showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "agent-rail__identity", children: [
|
|
7419
|
+
showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7420
|
+
"img",
|
|
7421
|
+
{
|
|
7422
|
+
className: "agent-rail__brand-logo",
|
|
7423
|
+
src: resolvedBrandLogoUrl,
|
|
7424
|
+
alt: "",
|
|
7425
|
+
onError: () => {
|
|
7426
|
+
setFailedLogoUrl(resolvedBrandLogoUrl ?? null);
|
|
6688
7427
|
}
|
|
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
|
-
|
|
7428
|
+
}
|
|
7429
|
+
) }) : null,
|
|
7430
|
+
resolvedBrandLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-rail__brand-label", children: resolvedBrandLabel }) : null
|
|
7431
|
+
] }) : null,
|
|
7432
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "agent-rail__actions", children: [
|
|
7433
|
+
onReset ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7434
|
+
"button",
|
|
7435
|
+
{
|
|
7436
|
+
type: "button",
|
|
7437
|
+
className: "agent-rail__new-chat",
|
|
7438
|
+
"aria-label": "Start a new conversation",
|
|
7439
|
+
disabled: !hasVisitorMessages2 || handoffActive && !handoff?.canReset,
|
|
7440
|
+
onClick: handleReset,
|
|
7441
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NewChatIcon, {})
|
|
7442
|
+
}
|
|
7443
|
+
) : null,
|
|
7444
|
+
onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7445
|
+
"button",
|
|
7446
|
+
{
|
|
7447
|
+
type: "button",
|
|
7448
|
+
className: "agent-rail__expand",
|
|
7449
|
+
"aria-label": expanded ? "Exit full screen" : "Open full screen",
|
|
7450
|
+
onClick: onExpandToggle,
|
|
7451
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ExpandIcon, {})
|
|
7452
|
+
}
|
|
7453
|
+
) : null
|
|
7454
|
+
] })
|
|
7455
|
+
] }) }),
|
|
7456
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: threadRef, className: "agent-rail__thread", children: [
|
|
7457
|
+
!hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
7458
|
+
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7459
|
+
MessageBubble,
|
|
7460
|
+
{
|
|
7461
|
+
showProvenance: Boolean(
|
|
7462
|
+
handoff?.page?.enabled || handoffActive
|
|
7463
|
+
),
|
|
7464
|
+
message: greeting,
|
|
7465
|
+
bookingDisabled: isBusy || handoffActive,
|
|
7466
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7467
|
+
onBook
|
|
7468
|
+
}
|
|
7469
|
+
) : null,
|
|
7470
|
+
showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7471
|
+
FollowUpChips,
|
|
7472
|
+
{
|
|
7473
|
+
suggestions: state.followUps,
|
|
7474
|
+
disabled: isBusy || handoffActive,
|
|
7475
|
+
label: "Start here",
|
|
7476
|
+
onSelect: (suggestion) => handleFollowUpSelect(suggestion.label)
|
|
7477
|
+
}
|
|
7478
|
+
) }) : null,
|
|
7479
|
+
showActivity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7480
|
+
AgentActivityBubble,
|
|
7481
|
+
{
|
|
7482
|
+
brandLabel: resolvedBrandLabel,
|
|
7483
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7484
|
+
failed: state.phase === "error",
|
|
7485
|
+
steps: activitySteps
|
|
7486
|
+
}
|
|
7487
|
+
) : null,
|
|
7488
|
+
visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7489
|
+
VisitorToolResultView,
|
|
7490
|
+
{
|
|
7491
|
+
result,
|
|
7492
|
+
disabled: semanticSurfaceDisabled,
|
|
7493
|
+
onToolInput
|
|
7494
|
+
},
|
|
7495
|
+
result.id
|
|
7496
|
+
)),
|
|
7497
|
+
pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7498
|
+
HumanInputCard,
|
|
7499
|
+
{
|
|
7500
|
+
request,
|
|
7501
|
+
onRespond: onInputResponse
|
|
7502
|
+
},
|
|
7503
|
+
request.requestId
|
|
7504
|
+
))
|
|
7505
|
+
] }) : null,
|
|
7506
|
+
transcriptMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
7507
|
+
"div",
|
|
7508
|
+
{
|
|
7509
|
+
ref: index === lastVisitorIndex + 1 ? responseRef : void 0,
|
|
7510
|
+
className: "agent-rail__turn-block",
|
|
7511
|
+
children: [
|
|
7512
|
+
message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7513
|
+
VisitorToolResultView,
|
|
6718
7514
|
{
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
}
|
|
6725
|
-
) : null
|
|
6726
|
-
] })
|
|
6727
|
-
] }) }),
|
|
6728
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: threadRef, className: "agent-rail__thread", children: [
|
|
6729
|
-
!hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
6730
|
-
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
7515
|
+
result
|
|
7516
|
+
},
|
|
7517
|
+
result.id
|
|
7518
|
+
)) : null,
|
|
7519
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
6731
7520
|
MessageBubble,
|
|
6732
7521
|
{
|
|
6733
|
-
|
|
6734
|
-
|
|
7522
|
+
showProvenance: Boolean(
|
|
7523
|
+
handoff?.page?.enabled || handoffActive
|
|
7524
|
+
),
|
|
7525
|
+
message,
|
|
7526
|
+
bookingDisabled: isBusy || handoffActive,
|
|
6735
7527
|
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7528
|
+
offer: index === transcriptMessages.length - 1 ? state.pendingOffer : void 0,
|
|
6736
7529
|
onBook
|
|
6737
7530
|
}
|
|
6738
|
-
)
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
{
|
|
6742
|
-
suggestions: state.followUps,
|
|
6743
|
-
disabled: isBusy,
|
|
6744
|
-
label: "Start here",
|
|
6745
|
-
onSelect: (suggestion) => handleFollowUpSelect(suggestion.label)
|
|
6746
|
-
}
|
|
6747
|
-
) }) : null,
|
|
6748
|
-
showActivity ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6749
|
-
AgentActivityBubble,
|
|
7531
|
+
),
|
|
7532
|
+
index === lastAgentIndex && showMessageActions && message.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7533
|
+
MessageActions,
|
|
6750
7534
|
{
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
7535
|
+
answeredAt: message.createdAt,
|
|
7536
|
+
copyText: hideToolCardFences(message.text).trim() || message.text,
|
|
7537
|
+
readAloud,
|
|
7538
|
+
receiptSteps,
|
|
7539
|
+
onOpenReceipt: receiptSteps ? openReceipt : void 0,
|
|
7540
|
+
onRegenerate: onRegenerate ? handleRegenerate : void 0,
|
|
7541
|
+
onFeedback: onFeedback ? (rating) => onFeedback(rating, message) : void 0
|
|
6755
7542
|
}
|
|
6756
7543
|
) : null,
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: state.error })
|
|
6841
|
-
] }),
|
|
6842
|
-
onRetry ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
|
|
6843
|
-
] }) : null
|
|
6844
|
-
] }) }),
|
|
6845
|
-
showDisclaimerLabel ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: disclaimerLink ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6846
|
-
"a",
|
|
7544
|
+
index === lastVisitorIndex ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
7545
|
+
showActivity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7546
|
+
AgentActivityBubble,
|
|
7547
|
+
{
|
|
7548
|
+
brandLabel: resolvedBrandLabel,
|
|
7549
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
7550
|
+
failed: state.phase === "error",
|
|
7551
|
+
steps: activitySteps
|
|
7552
|
+
}
|
|
7553
|
+
) : null,
|
|
7554
|
+
visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7555
|
+
VisitorToolResultView,
|
|
7556
|
+
{
|
|
7557
|
+
result,
|
|
7558
|
+
disabled: semanticSurfaceDisabled,
|
|
7559
|
+
onToolInput
|
|
7560
|
+
},
|
|
7561
|
+
result.id
|
|
7562
|
+
)),
|
|
7563
|
+
pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7564
|
+
HumanInputCard,
|
|
7565
|
+
{
|
|
7566
|
+
request,
|
|
7567
|
+
onRespond: onInputResponse
|
|
7568
|
+
},
|
|
7569
|
+
request.requestId
|
|
7570
|
+
))
|
|
7571
|
+
] }) : null
|
|
7572
|
+
]
|
|
7573
|
+
},
|
|
7574
|
+
message.role === "agent" && transcriptMessages[index - 1]?.role === "visitor" ? `answer-${transcriptMessages[index - 1]?.id}` : message.id
|
|
7575
|
+
)),
|
|
7576
|
+
waitingForBooking ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(BookingCardLoader, {}) : null,
|
|
7577
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
|
|
7578
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
|
|
7579
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: "Something went wrong" }),
|
|
7580
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: state.error })
|
|
7581
|
+
] }),
|
|
7582
|
+
onRetry ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
|
|
7583
|
+
] }) : null
|
|
7584
|
+
] }) }),
|
|
7585
|
+
showDisclaimerLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: disclaimerLink ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7586
|
+
"a",
|
|
7587
|
+
{
|
|
7588
|
+
href: disclaimerLink,
|
|
7589
|
+
rel: "noopener noreferrer",
|
|
7590
|
+
target: "_blank",
|
|
7591
|
+
children: resolvedDisclaimerLabel
|
|
7592
|
+
}
|
|
7593
|
+
) : resolvedDisclaimerLabel }) }) : null,
|
|
7594
|
+
handoff && (handoff.page?.enabled || handoffActive) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__handoff", children: [
|
|
7595
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", "aria-live": "polite", children: !handoff.page ? "Checking conversation\u2026" : handoffStatus === "human" ? "Connected with support" : handoffStatus === "queued" ? "Waiting for a representative" : handoffStatus === "requesting" ? "Connecting you to support\u2026" : handoffStatus === "resolved" ? "Your conversation with support has ended" : handoffStatus === "failed" ? "We couldn\u2019t connect you to support" : "Need a person?" }),
|
|
7596
|
+
handoffStatus === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7597
|
+
"button",
|
|
7598
|
+
{
|
|
7599
|
+
type: "button",
|
|
7600
|
+
disabled: handoff.busy || handoff.hasPending || isBusy,
|
|
7601
|
+
onClick: () => void handoff.start(),
|
|
7602
|
+
children: "Talk to a person"
|
|
7603
|
+
}
|
|
7604
|
+
) : null,
|
|
7605
|
+
handoffStatus === "resolved" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7606
|
+
"button",
|
|
7607
|
+
{
|
|
7608
|
+
type: "button",
|
|
7609
|
+
disabled: handoff.busy || handoff.hasPending,
|
|
7610
|
+
onClick: () => void handoff.returnToAI(),
|
|
7611
|
+
children: "Return to AI"
|
|
7612
|
+
}
|
|
7613
|
+
) : null,
|
|
7614
|
+
handoffStatus === "failed" && onReset ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7615
|
+
"button",
|
|
7616
|
+
{
|
|
7617
|
+
type: "button",
|
|
7618
|
+
disabled: !handoff.canReset,
|
|
7619
|
+
onClick: handleReset,
|
|
7620
|
+
children: "Start a new conversation"
|
|
7621
|
+
}
|
|
7622
|
+
) : null,
|
|
7623
|
+
handoff.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { role: "alert", children: [
|
|
7624
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: handoff.error }),
|
|
7625
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7626
|
+
"button",
|
|
6847
7627
|
{
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
children:
|
|
7628
|
+
type: "button",
|
|
7629
|
+
disabled: handoff.busy,
|
|
7630
|
+
onClick: () => void handoff.retry(),
|
|
7631
|
+
children: "Retry"
|
|
6852
7632
|
}
|
|
6853
|
-
)
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
Composer,
|
|
6868
|
-
{
|
|
6869
|
-
variant: expanded || mobileFullscreen ? "dock" : "default",
|
|
6870
|
-
disabled: isBusy,
|
|
6871
|
-
form: composerForm && lastMessage ? { ...composerForm, id: `${lastMessage.id}:${composerForm.id}` } : null,
|
|
6872
|
-
allowFormResume: !state.pendingOffer && !waitingForBooking && !hasPendingConfirmation,
|
|
6873
|
-
placeholder: composerPlaceholder,
|
|
6874
|
-
onSubmit: handleSubmit
|
|
6875
|
-
},
|
|
6876
|
-
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
6877
|
-
),
|
|
6878
|
-
poweredByLabel ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: poweredByLabel }) }) }) : null
|
|
6879
|
-
] })
|
|
6880
|
-
] }),
|
|
6881
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: overlayRef, className: "agent-rail__overlay" }),
|
|
6882
|
-
receiptOpen && receiptSteps ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6883
|
-
AnswerReceiptDialog,
|
|
7633
|
+
)
|
|
7634
|
+
] }) : null
|
|
7635
|
+
] }) : null,
|
|
7636
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
|
|
7637
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7638
|
+
LocationConsent,
|
|
7639
|
+
{
|
|
7640
|
+
request: locationRequest,
|
|
7641
|
+
onRespond: onInputResponse
|
|
7642
|
+
},
|
|
7643
|
+
state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
|
|
7644
|
+
),
|
|
7645
|
+
showJumpToLatest ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7646
|
+
"button",
|
|
6884
7647
|
{
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
7648
|
+
type: "button",
|
|
7649
|
+
className: "agent-rail__jump-to-latest",
|
|
7650
|
+
"aria-label": "Jump to the latest message",
|
|
7651
|
+
title: "Jump to the latest message",
|
|
7652
|
+
onClick: scrollToLatest,
|
|
7653
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChevronDownIcon, {})
|
|
6888
7654
|
}
|
|
6889
|
-
) : null
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
7655
|
+
) : null,
|
|
7656
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7657
|
+
Composer,
|
|
7658
|
+
{
|
|
7659
|
+
variant: expanded || mobileFullscreen ? "dock" : "default",
|
|
7660
|
+
disabled: isBusy || Boolean(handoff?.busy || handoff?.hasPending) || handoffActive && !["requesting", "queued", "human"].includes(
|
|
7661
|
+
handoffStatus ?? ""
|
|
7662
|
+
),
|
|
7663
|
+
form: !handoffActive && composerForm && lastMessage ? {
|
|
7664
|
+
...composerForm,
|
|
7665
|
+
id: `${lastMessage.id}:${composerForm.id}`
|
|
7666
|
+
} : null,
|
|
7667
|
+
allowFormResume: !handoffActive && !state.pendingOffer && !waitingForBooking && !hasPendingConfirmation,
|
|
7668
|
+
placeholder: handoffActive ? "Message support\u2026" : composerPlaceholder,
|
|
7669
|
+
onSubmit: handleSubmit
|
|
7670
|
+
},
|
|
7671
|
+
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
7672
|
+
),
|
|
7673
|
+
poweredByLabel ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: poweredByLabel }) }) }) : null
|
|
7674
|
+
] })
|
|
7675
|
+
] }),
|
|
7676
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: overlayRef, className: "agent-rail__overlay" }),
|
|
7677
|
+
receiptOpen && receiptSteps ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7678
|
+
AnswerReceiptDialog,
|
|
7679
|
+
{
|
|
7680
|
+
brandLabel: resolvedBrandLabel,
|
|
7681
|
+
onClose: () => setReceiptOpen(false),
|
|
7682
|
+
steps: receiptSteps
|
|
7683
|
+
}
|
|
7684
|
+
) : null
|
|
7685
|
+
] })
|
|
6893
7686
|
}
|
|
6894
7687
|
);
|
|
6895
7688
|
}
|
|
6896
7689
|
|
|
6897
7690
|
// src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
|
|
6898
|
-
var
|
|
6899
|
-
var
|
|
7691
|
+
var import_react17 = require("react");
|
|
7692
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
6900
7693
|
function ChatSparkIcon() {
|
|
6901
|
-
return /* @__PURE__ */ (0,
|
|
7694
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
6902
7695
|
"svg",
|
|
6903
7696
|
{
|
|
6904
7697
|
className: "assist-edge-tab__chat-spark",
|
|
@@ -6906,7 +7699,7 @@ function ChatSparkIcon() {
|
|
|
6906
7699
|
fill: "none",
|
|
6907
7700
|
"aria-hidden": "true",
|
|
6908
7701
|
children: [
|
|
6909
|
-
/* @__PURE__ */ (0,
|
|
7702
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6910
7703
|
"path",
|
|
6911
7704
|
{
|
|
6912
7705
|
className: "assist-edge-tab__spark assist-edge-tab__spark--a",
|
|
@@ -6914,7 +7707,7 @@ function ChatSparkIcon() {
|
|
|
6914
7707
|
fill: "currentColor"
|
|
6915
7708
|
}
|
|
6916
7709
|
),
|
|
6917
|
-
/* @__PURE__ */ (0,
|
|
7710
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6918
7711
|
"path",
|
|
6919
7712
|
{
|
|
6920
7713
|
className: "assist-edge-tab__spark assist-edge-tab__spark--b",
|
|
@@ -6922,8 +7715,8 @@ function ChatSparkIcon() {
|
|
|
6922
7715
|
fill: "currentColor"
|
|
6923
7716
|
}
|
|
6924
7717
|
),
|
|
6925
|
-
/* @__PURE__ */ (0,
|
|
6926
|
-
/* @__PURE__ */ (0,
|
|
7718
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("g", { className: "assist-edge-tab__bot", children: [
|
|
7719
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6927
7720
|
"path",
|
|
6928
7721
|
{
|
|
6929
7722
|
d: "M11.15 5.2V3.05",
|
|
@@ -6932,8 +7725,8 @@ function ChatSparkIcon() {
|
|
|
6932
7725
|
strokeLinecap: "round"
|
|
6933
7726
|
}
|
|
6934
7727
|
),
|
|
6935
|
-
/* @__PURE__ */ (0,
|
|
6936
|
-
/* @__PURE__ */ (0,
|
|
7728
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("circle", { cx: "11.15", cy: "2.45", r: "0.85", fill: "currentColor" }),
|
|
7729
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6937
7730
|
"rect",
|
|
6938
7731
|
{
|
|
6939
7732
|
x: "3.55",
|
|
@@ -6945,7 +7738,7 @@ function ChatSparkIcon() {
|
|
|
6945
7738
|
strokeWidth: "1.9"
|
|
6946
7739
|
}
|
|
6947
7740
|
),
|
|
6948
|
-
/* @__PURE__ */ (0,
|
|
7741
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6949
7742
|
"circle",
|
|
6950
7743
|
{
|
|
6951
7744
|
className: "assist-edge-tab__eye",
|
|
@@ -6955,7 +7748,7 @@ function ChatSparkIcon() {
|
|
|
6955
7748
|
fill: "currentColor"
|
|
6956
7749
|
}
|
|
6957
7750
|
),
|
|
6958
|
-
/* @__PURE__ */ (0,
|
|
7751
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6959
7752
|
"circle",
|
|
6960
7753
|
{
|
|
6961
7754
|
className: "assist-edge-tab__eye assist-edge-tab__eye--r",
|
|
@@ -6976,10 +7769,10 @@ function TabMarkIcon({
|
|
|
6976
7769
|
}) {
|
|
6977
7770
|
const custom = customIconUrl?.trim();
|
|
6978
7771
|
const logo = logoUrl?.trim();
|
|
6979
|
-
const [customFailed, setCustomFailed] = (0,
|
|
6980
|
-
const [logoFailed, setLogoFailed] = (0,
|
|
7772
|
+
const [customFailed, setCustomFailed] = (0, import_react17.useState)(false);
|
|
7773
|
+
const [logoFailed, setLogoFailed] = (0, import_react17.useState)(false);
|
|
6981
7774
|
if (custom && !customFailed) {
|
|
6982
|
-
return /* @__PURE__ */ (0,
|
|
7775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6983
7776
|
"img",
|
|
6984
7777
|
{
|
|
6985
7778
|
alt: "",
|
|
@@ -6991,7 +7784,7 @@ function TabMarkIcon({
|
|
|
6991
7784
|
);
|
|
6992
7785
|
}
|
|
6993
7786
|
if (logo && !logoFailed) {
|
|
6994
|
-
return /* @__PURE__ */ (0,
|
|
7787
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
6995
7788
|
"img",
|
|
6996
7789
|
{
|
|
6997
7790
|
alt: "",
|
|
@@ -7002,10 +7795,10 @@ function TabMarkIcon({
|
|
|
7002
7795
|
}
|
|
7003
7796
|
);
|
|
7004
7797
|
}
|
|
7005
|
-
return /* @__PURE__ */ (0,
|
|
7798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChatSparkIcon, {});
|
|
7006
7799
|
}
|
|
7007
7800
|
function ChevronLeftIcon() {
|
|
7008
|
-
return /* @__PURE__ */ (0,
|
|
7801
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
7009
7802
|
"path",
|
|
7010
7803
|
{
|
|
7011
7804
|
d: "M10 4L6 8l4 4",
|
|
@@ -7017,7 +7810,7 @@ function ChevronLeftIcon() {
|
|
|
7017
7810
|
) });
|
|
7018
7811
|
}
|
|
7019
7812
|
function ChevronDownIcon2() {
|
|
7020
|
-
return /* @__PURE__ */ (0,
|
|
7813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
7021
7814
|
"path",
|
|
7022
7815
|
{
|
|
7023
7816
|
d: "M4 6l4 4 4-4",
|
|
@@ -7029,7 +7822,7 @@ function ChevronDownIcon2() {
|
|
|
7029
7822
|
) });
|
|
7030
7823
|
}
|
|
7031
7824
|
function DragDots() {
|
|
7032
|
-
return /* @__PURE__ */ (0,
|
|
7825
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("i", {}, index)) });
|
|
7033
7826
|
}
|
|
7034
7827
|
var VARIANT_COPY = {
|
|
7035
7828
|
outline: { label: "Ask anything", aria: "Ask anything" },
|
|
@@ -7084,7 +7877,7 @@ function AssistEdgeTab({
|
|
|
7084
7877
|
...!pill && resolvedTextColor ? { "--as-text": resolvedTextColor } : {},
|
|
7085
7878
|
colorScheme: chromeScheme
|
|
7086
7879
|
};
|
|
7087
|
-
return /* @__PURE__ */ (0,
|
|
7880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
7088
7881
|
"button",
|
|
7089
7882
|
{
|
|
7090
7883
|
type: "button",
|
|
@@ -7096,13 +7889,13 @@ function AssistEdgeTab({
|
|
|
7096
7889
|
tabIndex: visible ? 0 : -1,
|
|
7097
7890
|
onClick: onOpen,
|
|
7098
7891
|
children: [
|
|
7099
|
-
pill ? /* @__PURE__ */ (0,
|
|
7100
|
-
/* @__PURE__ */ (0,
|
|
7892
|
+
pill ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
7893
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
7101
7894
|
"span",
|
|
7102
7895
|
{
|
|
7103
7896
|
className: `assist-edge-tab__mark assist-edge-tab__mark--chip${mobile ? " assist-edge-tab__mark--mobile" : ""}`,
|
|
7104
7897
|
"aria-hidden": "true",
|
|
7105
|
-
children: /* @__PURE__ */ (0,
|
|
7898
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
7106
7899
|
TabMarkIcon,
|
|
7107
7900
|
{
|
|
7108
7901
|
customIconUrl,
|
|
@@ -7112,12 +7905,12 @@ function AssistEdgeTab({
|
|
|
7112
7905
|
)
|
|
7113
7906
|
}
|
|
7114
7907
|
),
|
|
7115
|
-
/* @__PURE__ */ (0,
|
|
7116
|
-
/* @__PURE__ */ (0,
|
|
7117
|
-
visibleSubLabel ? /* @__PURE__ */ (0,
|
|
7908
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "assist-edge-tab__text", children: [
|
|
7909
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7910
|
+
visibleSubLabel ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__sublabel", children: visibleSubLabel }) : null
|
|
7118
7911
|
] })
|
|
7119
|
-
] }) : variant === "outline" ? /* @__PURE__ */ (0,
|
|
7120
|
-
/* @__PURE__ */ (0,
|
|
7912
|
+
] }) : variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
7913
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
7121
7914
|
TabMarkIcon,
|
|
7122
7915
|
{
|
|
7123
7916
|
customIconUrl,
|
|
@@ -7125,16 +7918,16 @@ function AssistEdgeTab({
|
|
|
7125
7918
|
},
|
|
7126
7919
|
markSourceKey
|
|
7127
7920
|
) }),
|
|
7128
|
-
/* @__PURE__ */ (0,
|
|
7129
|
-
/* @__PURE__ */ (0,
|
|
7921
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7922
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChevronDownIcon2, {})
|
|
7130
7923
|
] }) : null,
|
|
7131
|
-
!pill && variant === "ask" ? /* @__PURE__ */ (0,
|
|
7132
|
-
/* @__PURE__ */ (0,
|
|
7133
|
-
/* @__PURE__ */ (0,
|
|
7134
|
-
/* @__PURE__ */ (0,
|
|
7924
|
+
!pill && variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
7925
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChevronLeftIcon, {}),
|
|
7926
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7927
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DragDots, {})
|
|
7135
7928
|
] }) : null,
|
|
7136
|
-
!pill && variant === "fill" ? /* @__PURE__ */ (0,
|
|
7137
|
-
/* @__PURE__ */ (0,
|
|
7929
|
+
!pill && variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
7930
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
7138
7931
|
TabMarkIcon,
|
|
7139
7932
|
{
|
|
7140
7933
|
customIconUrl,
|
|
@@ -7142,8 +7935,8 @@ function AssistEdgeTab({
|
|
|
7142
7935
|
},
|
|
7143
7936
|
markSourceKey
|
|
7144
7937
|
) }),
|
|
7145
|
-
/* @__PURE__ */ (0,
|
|
7146
|
-
/* @__PURE__ */ (0,
|
|
7938
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
|
|
7939
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ChevronLeftIcon, {})
|
|
7147
7940
|
] }) : null
|
|
7148
7941
|
]
|
|
7149
7942
|
}
|
|
@@ -7165,8 +7958,8 @@ function findPrecedingVisitorText(messages, agentMessageId) {
|
|
|
7165
7958
|
}
|
|
7166
7959
|
return void 0;
|
|
7167
7960
|
}
|
|
7168
|
-
function normalizeAgentFeedbackAnswerText(
|
|
7169
|
-
const normalized =
|
|
7961
|
+
function normalizeAgentFeedbackAnswerText(text3) {
|
|
7962
|
+
const normalized = text3.replace(/\s+/g, " ").trim();
|
|
7170
7963
|
if (!normalized) return void 0;
|
|
7171
7964
|
return normalized.length > 4e3 ? `${normalized.slice(0, 3997)}...` : normalized;
|
|
7172
7965
|
}
|
|
@@ -7207,7 +8000,7 @@ function sendAgentAnswerFeedback(eventUrl, event) {
|
|
|
7207
8000
|
}
|
|
7208
8001
|
|
|
7209
8002
|
// src/react/components/AgentWidget/AgentWidget.tsx
|
|
7210
|
-
var
|
|
8003
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
7211
8004
|
function AgentWidget({
|
|
7212
8005
|
indexId,
|
|
7213
8006
|
customerId,
|
|
@@ -7226,9 +8019,9 @@ function AgentWidget({
|
|
|
7226
8019
|
}) {
|
|
7227
8020
|
const isMobile = useIsMobile();
|
|
7228
8021
|
const placement = normalizeAgentPlacement(placementInput);
|
|
7229
|
-
const railSlotRef = (0,
|
|
7230
|
-
const [railCollapsed, setRailCollapsed] = (0,
|
|
7231
|
-
const [railExpanded, setRailExpanded] = (0,
|
|
8022
|
+
const railSlotRef = (0, import_react18.useRef)(null);
|
|
8023
|
+
const [railCollapsed, setRailCollapsed] = (0, import_react18.useState)(defaultCollapsed);
|
|
8024
|
+
const [railExpanded, setRailExpanded] = (0, import_react18.useState)(false);
|
|
7232
8025
|
const pageShiftActive = shouldApplyPageShift({
|
|
7233
8026
|
pageShift,
|
|
7234
8027
|
isMobile,
|
|
@@ -7281,7 +8074,7 @@ function AgentWidget({
|
|
|
7281
8074
|
} : {},
|
|
7282
8075
|
...branding?.colors?.border ? { border: branding.colors.border } : {}
|
|
7283
8076
|
};
|
|
7284
|
-
(0,
|
|
8077
|
+
(0, import_react18.useEffect)(() => {
|
|
7285
8078
|
if (!registerPanelController) return;
|
|
7286
8079
|
registerAgentPanelController(customerId, {
|
|
7287
8080
|
open: () => setRailCollapsed(false),
|
|
@@ -7316,7 +8109,7 @@ function AgentWidget({
|
|
|
7316
8109
|
})
|
|
7317
8110
|
);
|
|
7318
8111
|
}
|
|
7319
|
-
(0,
|
|
8112
|
+
(0, import_react18.useEffect)(() => {
|
|
7320
8113
|
if (railCollapsed) return;
|
|
7321
8114
|
const handleKeyDown = (event) => {
|
|
7322
8115
|
if (event.key === "Tab" && (isMobile || railExpanded)) {
|
|
@@ -7350,19 +8143,19 @@ function AgentWidget({
|
|
|
7350
8143
|
window.addEventListener("keydown", handleKeyDown);
|
|
7351
8144
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
7352
8145
|
}, [isMobile, railCollapsed, railExpanded]);
|
|
7353
|
-
return /* @__PURE__ */ (0,
|
|
7354
|
-
/* @__PURE__ */ (0,
|
|
8146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "webless-agent-root", children: [
|
|
8147
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
7355
8148
|
"div",
|
|
7356
8149
|
{
|
|
7357
8150
|
className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
|
|
7358
|
-
children: /* @__PURE__ */ (0,
|
|
8151
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
7359
8152
|
"div",
|
|
7360
8153
|
{
|
|
7361
8154
|
ref: railSlotRef,
|
|
7362
8155
|
className: "webless-agent-root__rail-slot",
|
|
7363
8156
|
inert: railCollapsed || void 0,
|
|
7364
8157
|
"aria-hidden": railCollapsed,
|
|
7365
|
-
children: /* @__PURE__ */ (0,
|
|
8158
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
7366
8159
|
AgentRail,
|
|
7367
8160
|
{
|
|
7368
8161
|
theme,
|
|
@@ -7399,7 +8192,7 @@ function AgentWidget({
|
|
|
7399
8192
|
)
|
|
7400
8193
|
}
|
|
7401
8194
|
),
|
|
7402
|
-
railCollapsed ? /* @__PURE__ */ (0,
|
|
8195
|
+
railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
7403
8196
|
AssistEdgeTab,
|
|
7404
8197
|
{
|
|
7405
8198
|
variant: placement.variant,
|
|
@@ -7439,12 +8232,12 @@ function readUnpublishedPreviewBuildId(href) {
|
|
|
7439
8232
|
}
|
|
7440
8233
|
|
|
7441
8234
|
// src/embed/AgentWidget.tsx
|
|
7442
|
-
var
|
|
8235
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
7443
8236
|
function AgentWidget2({
|
|
7444
8237
|
manifest
|
|
7445
8238
|
}) {
|
|
7446
8239
|
const defaultCollapsed = manifest.version !== "unpublished";
|
|
7447
|
-
return /* @__PURE__ */ (0,
|
|
8240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7448
8241
|
AgentWidget,
|
|
7449
8242
|
{
|
|
7450
8243
|
indexId: manifest.indexId,
|
|
@@ -7569,7 +8362,7 @@ function normalizeAgentBranding(branding) {
|
|
|
7569
8362
|
}
|
|
7570
8363
|
|
|
7571
8364
|
// src/embed/mount.tsx
|
|
7572
|
-
var
|
|
8365
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
7573
8366
|
var mountedHandles = /* @__PURE__ */ new Map();
|
|
7574
8367
|
var latestCustomerId = null;
|
|
7575
8368
|
function resolveMountHost(manifest, script) {
|
|
@@ -7598,8 +8391,8 @@ function mountAgent(input) {
|
|
|
7598
8391
|
const mountTarget = resolveMountHost(manifest, input.script ?? null);
|
|
7599
8392
|
const host = createHost(manifest.customerId);
|
|
7600
8393
|
mountTarget.append(host);
|
|
7601
|
-
const root = (0,
|
|
7602
|
-
root.render(/* @__PURE__ */ (0,
|
|
8394
|
+
const root = (0, import_client7.createRoot)(host);
|
|
8395
|
+
root.render(/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AgentWidget2, { manifest }));
|
|
7603
8396
|
const handle = {
|
|
7604
8397
|
customerId: manifest.customerId,
|
|
7605
8398
|
manifest,
|
|
@@ -7625,9 +8418,9 @@ function mountAgent(input) {
|
|
|
7625
8418
|
return handle;
|
|
7626
8419
|
}
|
|
7627
8420
|
function unmountAgent(customerId) {
|
|
7628
|
-
const
|
|
7629
|
-
if (!
|
|
7630
|
-
const handle = mountedHandles.get(
|
|
8421
|
+
const id2 = customerId ?? latestCustomerId;
|
|
8422
|
+
if (!id2) return false;
|
|
8423
|
+
const handle = mountedHandles.get(id2);
|
|
7631
8424
|
if (!handle) return false;
|
|
7632
8425
|
handle.unmount();
|
|
7633
8426
|
return true;
|