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