@webless/agent 0.8.0 → 0.9.1
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 +39 -5
- package/dist/{chunk-JZPXXG76.js → chunk-3E632FNE.js} +354 -204
- package/dist/chunk-3E632FNE.js.map +1 -0
- package/dist/chunk-TCO62TRN.js +335 -0
- package/dist/chunk-TCO62TRN.js.map +1 -0
- package/dist/embed.cjs +770 -623
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.css +102 -10
- package/dist/embed.css.map +1 -1
- package/dist/embed.d.cts +3 -9
- package/dist/embed.d.ts +3 -9
- package/dist/embed.js +1 -1
- package/dist/index.cjs +752 -680
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -180
- package/dist/index.d.ts +3 -180
- package/dist/index.js +51 -291
- package/dist/index.js.map +1 -1
- package/dist/{manifest-DgjT8-tW.d.cts → panel-controller-D_XIQa1U.d.cts} +9 -2
- package/dist/{manifest-DgjT8-tW.d.ts → panel-controller-D_XIQa1U.d.ts} +9 -2
- package/dist/presentation.cjs +862 -0
- package/dist/presentation.cjs.map +1 -0
- package/dist/presentation.d.cts +160 -0
- package/dist/presentation.d.ts +160 -0
- package/dist/presentation.js +553 -0
- package/dist/presentation.js.map +1 -0
- package/dist/react.cjs +749 -504
- package/dist/react.cjs.map +1 -1
- package/dist/react.css +102 -10
- package/dist/react.css.map +1 -1
- package/dist/react.d.cts +16 -5
- package/dist/react.d.ts +16 -5
- package/dist/react.js +110 -9
- package/dist/react.js.map +1 -1
- package/dist/types-sLEIYDqm.d.cts +181 -0
- package/dist/types-sLEIYDqm.d.ts +181 -0
- package/package.json +7 -2
- package/dist/chunk-JZPXXG76.js.map +0 -1
package/dist/embed.cjs
CHANGED
|
@@ -149,6 +149,329 @@ function usePageShift(input) {
|
|
|
149
149
|
// src/react/hooks/useAgentChat.ts
|
|
150
150
|
var import_react2 = require("react");
|
|
151
151
|
|
|
152
|
+
// src/runtime/tool-ui.ts
|
|
153
|
+
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
154
|
+
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
155
|
+
var AGENT_STRUCTURED_TOOL_INPUT_HEADER = "Webless-Structured-Tool-Input-JSON:";
|
|
156
|
+
function formatAgentStructuredToolInput(surface, values) {
|
|
157
|
+
const payload = {
|
|
158
|
+
schemaVersion: AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION,
|
|
159
|
+
toolSlug: surface.toolSlug,
|
|
160
|
+
...surface.operationId ? { operationId: surface.operationId } : {},
|
|
161
|
+
values
|
|
162
|
+
};
|
|
163
|
+
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
164
|
+
}
|
|
165
|
+
function isRecord(value) {
|
|
166
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
167
|
+
}
|
|
168
|
+
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
169
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
173
|
+
if (typeof value !== "object") return false;
|
|
174
|
+
if (seen.has(value)) return false;
|
|
175
|
+
seen.add(value);
|
|
176
|
+
const valid = Array.isArray(value) ? value.every((item) => isJsonValue(item, seen)) : Object.entries(value).every(
|
|
177
|
+
([key, item]) => typeof key === "string" && isJsonValue(item, seen)
|
|
178
|
+
);
|
|
179
|
+
seen.delete(value);
|
|
180
|
+
return valid;
|
|
181
|
+
}
|
|
182
|
+
function boundedString(value, max) {
|
|
183
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.length > max) {
|
|
184
|
+
return void 0;
|
|
185
|
+
}
|
|
186
|
+
return value.trim();
|
|
187
|
+
}
|
|
188
|
+
function numberValue(value) {
|
|
189
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
190
|
+
}
|
|
191
|
+
function integerValue(value) {
|
|
192
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 8e3 ? value : void 0;
|
|
193
|
+
}
|
|
194
|
+
function isFieldKind(value) {
|
|
195
|
+
return typeof value === "string" && [
|
|
196
|
+
"text",
|
|
197
|
+
"textarea",
|
|
198
|
+
"email",
|
|
199
|
+
"number",
|
|
200
|
+
"select",
|
|
201
|
+
"multi-select",
|
|
202
|
+
"checkbox",
|
|
203
|
+
"confirmation",
|
|
204
|
+
"radio",
|
|
205
|
+
"date",
|
|
206
|
+
"time",
|
|
207
|
+
"date-time",
|
|
208
|
+
"calendar",
|
|
209
|
+
"range",
|
|
210
|
+
"json"
|
|
211
|
+
].includes(value);
|
|
212
|
+
}
|
|
213
|
+
function parseField(value) {
|
|
214
|
+
if (!isRecord(value)) return null;
|
|
215
|
+
if (!hasOnlyKeys(value, [
|
|
216
|
+
"description",
|
|
217
|
+
"kind",
|
|
218
|
+
"label",
|
|
219
|
+
"max",
|
|
220
|
+
"maxItems",
|
|
221
|
+
"maxLength",
|
|
222
|
+
"min",
|
|
223
|
+
"minLength",
|
|
224
|
+
"options",
|
|
225
|
+
"path",
|
|
226
|
+
"placeholder",
|
|
227
|
+
"required",
|
|
228
|
+
"step",
|
|
229
|
+
"defaultValue"
|
|
230
|
+
])) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
if (!isFieldKind(value.kind)) return null;
|
|
234
|
+
const path = boundedString(value.path, 160);
|
|
235
|
+
const label = boundedString(value.label, 160);
|
|
236
|
+
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
237
|
+
const placeholder = value.placeholder === void 0 || typeof value.placeholder !== "string" ? void 0 : value.placeholder;
|
|
238
|
+
const required = value.required === void 0 || typeof value.required !== "boolean" ? void 0 : value.required;
|
|
239
|
+
const min = value.min === void 0 ? void 0 : numberValue(value.min);
|
|
240
|
+
const max = value.max === void 0 ? void 0 : numberValue(value.max);
|
|
241
|
+
const maxItems = value.maxItems === void 0 ? void 0 : integerValue(value.maxItems);
|
|
242
|
+
const step = value.step === void 0 ? void 0 : numberValue(value.step);
|
|
243
|
+
const minLength = value.minLength === void 0 ? void 0 : integerValue(value.minLength);
|
|
244
|
+
const maxLength = value.maxLength === void 0 ? void 0 : integerValue(value.maxLength);
|
|
245
|
+
const defaultValue = value.defaultValue === void 0 || !isJsonValue(value.defaultValue) ? void 0 : value.defaultValue;
|
|
246
|
+
if (!path || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || !label) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
if (value.description !== void 0 && !description) return null;
|
|
250
|
+
if (value.placeholder !== void 0 && placeholder === void 0) return null;
|
|
251
|
+
if (value.required !== void 0 && required === void 0) return null;
|
|
252
|
+
if (value.min !== void 0 && min === void 0) return null;
|
|
253
|
+
if (value.max !== void 0 && max === void 0) return null;
|
|
254
|
+
if (value.maxItems !== void 0 && (maxItems === void 0 || maxItems < 1 || maxItems > 100))
|
|
255
|
+
return null;
|
|
256
|
+
if (value.step !== void 0 && step === void 0) return null;
|
|
257
|
+
if (value.minLength !== void 0 && minLength === void 0) return null;
|
|
258
|
+
if (value.maxLength !== void 0 && maxLength === void 0) return null;
|
|
259
|
+
if (value.defaultValue !== void 0 && defaultValue === void 0)
|
|
260
|
+
return null;
|
|
261
|
+
if (value.options !== void 0) {
|
|
262
|
+
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
263
|
+
return null;
|
|
264
|
+
for (const option of value.options) {
|
|
265
|
+
if (!isRecord(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
kind: value.kind,
|
|
272
|
+
path,
|
|
273
|
+
label,
|
|
274
|
+
...description ? { description } : {},
|
|
275
|
+
...placeholder !== void 0 ? { placeholder } : {},
|
|
276
|
+
...required !== void 0 ? { required } : {},
|
|
277
|
+
...defaultValue !== void 0 ? { defaultValue } : {},
|
|
278
|
+
...value.options !== void 0 ? { options: value.options } : {},
|
|
279
|
+
...min !== void 0 ? { min } : {},
|
|
280
|
+
...max !== void 0 ? { max } : {},
|
|
281
|
+
...maxItems !== void 0 ? { maxItems } : {},
|
|
282
|
+
...step !== void 0 ? { step } : {},
|
|
283
|
+
...minLength !== void 0 ? { minLength } : {},
|
|
284
|
+
...maxLength !== void 0 ? { maxLength } : {}
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function parseStep(value) {
|
|
288
|
+
if (!isRecord(value)) return null;
|
|
289
|
+
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
const id = boundedString(value.id, 80);
|
|
293
|
+
const label = boundedString(value.label, 160);
|
|
294
|
+
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
295
|
+
if (!id || !/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(id) || !label || value.description !== void 0 && !description || !Array.isArray(value.fieldPaths) || value.fieldPaths.length < 1 || value.fieldPaths.length > 32 || value.fieldPaths.some(
|
|
296
|
+
(path) => typeof path !== "string" || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || path.length > 160
|
|
297
|
+
)) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
id,
|
|
302
|
+
label,
|
|
303
|
+
fieldPaths: value.fieldPaths,
|
|
304
|
+
...description ? { description } : {}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function parseAction(value) {
|
|
308
|
+
if (!isRecord(value)) return null;
|
|
309
|
+
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
310
|
+
const label = boundedString(value.label, 80);
|
|
311
|
+
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
id: value.id,
|
|
316
|
+
label
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
function parseAgentToolUiSurface(value) {
|
|
320
|
+
if (!isRecord(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
321
|
+
return null;
|
|
322
|
+
if (!hasOnlyKeys(value, [
|
|
323
|
+
"actions",
|
|
324
|
+
"description",
|
|
325
|
+
"fields",
|
|
326
|
+
"id",
|
|
327
|
+
"operationId",
|
|
328
|
+
"requestId",
|
|
329
|
+
"schemaVersion",
|
|
330
|
+
"steps",
|
|
331
|
+
"submitLabel",
|
|
332
|
+
"title",
|
|
333
|
+
"toolSlug",
|
|
334
|
+
"values"
|
|
335
|
+
])) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
const id = boundedString(value.id, 200);
|
|
339
|
+
const title = boundedString(value.title, 200);
|
|
340
|
+
const toolSlug = boundedString(value.toolSlug, 200);
|
|
341
|
+
const description = value.description === void 0 ? void 0 : boundedString(value.description, 800);
|
|
342
|
+
const operationId = value.operationId === void 0 ? void 0 : boundedString(value.operationId, 200);
|
|
343
|
+
const requestId = value.requestId === void 0 ? void 0 : boundedString(value.requestId, 200);
|
|
344
|
+
const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
|
|
345
|
+
if (!id || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
const fields = value.fields.map(parseField);
|
|
349
|
+
if (fields.some((field) => field === null)) return null;
|
|
350
|
+
const steps = value.steps === void 0 ? void 0 : Array.isArray(value.steps) && value.steps.length <= 8 ? value.steps.map(parseStep) : null;
|
|
351
|
+
if (steps?.some((step) => step === null)) return null;
|
|
352
|
+
const actions = value.actions === void 0 ? void 0 : Array.isArray(value.actions) && value.actions.length <= 8 ? value.actions.map(parseAction) : null;
|
|
353
|
+
if (actions?.some((action) => action === null)) return null;
|
|
354
|
+
if (value.description !== void 0 && !description) return null;
|
|
355
|
+
if (value.operationId !== void 0 && !operationId) return null;
|
|
356
|
+
if (value.requestId !== void 0 && !requestId) return null;
|
|
357
|
+
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
358
|
+
const values = value.values !== void 0 && isRecord(value.values) ? value.values : void 0;
|
|
359
|
+
if (value.values !== void 0) {
|
|
360
|
+
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
schemaVersion: AGENT_TOOL_UI_SCHEMA_VERSION,
|
|
365
|
+
id,
|
|
366
|
+
title,
|
|
367
|
+
toolSlug,
|
|
368
|
+
fields,
|
|
369
|
+
...actions ? { actions } : {},
|
|
370
|
+
...description ? { description } : {},
|
|
371
|
+
...operationId ? { operationId } : {},
|
|
372
|
+
...requestId ? { requestId } : {},
|
|
373
|
+
...submitLabel ? { submitLabel } : {},
|
|
374
|
+
...steps ? { steps } : {},
|
|
375
|
+
...values ? { values } : {}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function hasOnlyKeys(value, allowed) {
|
|
379
|
+
const allowedKeys = new Set(allowed);
|
|
380
|
+
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/runtime/tool-result-envelope.ts
|
|
384
|
+
var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
385
|
+
"schemaVersion",
|
|
386
|
+
"output",
|
|
387
|
+
"presentationKinds",
|
|
388
|
+
"ui"
|
|
389
|
+
]);
|
|
390
|
+
function isRecord2(value) {
|
|
391
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
392
|
+
}
|
|
393
|
+
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
394
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
398
|
+
if (typeof value !== "object") return false;
|
|
399
|
+
if (seen.has(value)) return false;
|
|
400
|
+
seen.add(value);
|
|
401
|
+
const valid = Array.isArray(value) ? value.every((item) => isJsonValue2(item, seen)) : Object.entries(value).every(
|
|
402
|
+
([key, item]) => typeof key === "string" && isJsonValue2(item, seen)
|
|
403
|
+
);
|
|
404
|
+
seen.delete(value);
|
|
405
|
+
return valid;
|
|
406
|
+
}
|
|
407
|
+
function decodeEnvelope(value) {
|
|
408
|
+
if (typeof value !== "string") return value;
|
|
409
|
+
try {
|
|
410
|
+
return JSON.parse(value);
|
|
411
|
+
} catch {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function parseAgentToolResultEnvelope(value) {
|
|
416
|
+
const decoded = decodeEnvelope(value);
|
|
417
|
+
if (!isRecord2(decoded)) return null;
|
|
418
|
+
const keys = Object.keys(decoded);
|
|
419
|
+
if (keys.some((key) => !ENVELOPE_KEYS.has(key)) || decoded.schemaVersion !== "webless.tool-result.v1" || !isJsonValue2(decoded.output) || !Array.isArray(decoded.presentationKinds) || decoded.presentationKinds.length < 1 || decoded.presentationKinds.length > 16) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
const presentationKinds = decoded.presentationKinds.flatMap((kind) => {
|
|
423
|
+
if (typeof kind !== "string") return [];
|
|
424
|
+
const normalized = kind.trim();
|
|
425
|
+
return normalized && normalized.length <= 128 ? [normalized] : [];
|
|
426
|
+
});
|
|
427
|
+
if (presentationKinds.length !== decoded.presentationKinds.length) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
const ui = decoded.ui === void 0 ? void 0 : parseAgentToolUiSurface(decoded.ui);
|
|
431
|
+
if (decoded.ui !== void 0 && !ui) return null;
|
|
432
|
+
return {
|
|
433
|
+
schemaVersion: "webless.tool-result.v1",
|
|
434
|
+
output: decoded.output,
|
|
435
|
+
presentationKinds,
|
|
436
|
+
...ui ? { ui } : {}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/runtime/connected-tool-work.ts
|
|
441
|
+
var HUBSPOT_ACTION_LABELS = {
|
|
442
|
+
HUBSPOT_LIST_CONTACTS: "Checking your details",
|
|
443
|
+
HUBSPOT_CREATE_CONTACT: "Saving your details",
|
|
444
|
+
HUBSPOT_UPDATE_CONTACT: "Updating your details",
|
|
445
|
+
HUBSPOT_CREATE_COMPANY: "Saving your company details"
|
|
446
|
+
};
|
|
447
|
+
function connectedToolWork(action) {
|
|
448
|
+
const slug = action.toolName === "COMPOSIO_MULTI_EXECUTE_TOOL" ? action.input.toolSlug : action.toolName;
|
|
449
|
+
if (typeof slug !== "string") return null;
|
|
450
|
+
const detail = HUBSPOT_ACTION_LABELS[slug];
|
|
451
|
+
return detail ? {
|
|
452
|
+
id: action.callId,
|
|
453
|
+
kind: "tool",
|
|
454
|
+
label: "Contact details",
|
|
455
|
+
detail,
|
|
456
|
+
state: "active"
|
|
457
|
+
} : null;
|
|
458
|
+
}
|
|
459
|
+
function toolResultFailed(result) {
|
|
460
|
+
if (result.status !== "completed") return true;
|
|
461
|
+
const output = parseAgentToolResultEnvelope(result.output)?.output ?? result.output;
|
|
462
|
+
if (typeof output !== "object" || output === null || Array.isArray(output))
|
|
463
|
+
return false;
|
|
464
|
+
return "error" in output && Boolean(output.error) || "providerError" in output && Boolean(output.providerError);
|
|
465
|
+
}
|
|
466
|
+
function completeConnectedToolWork(item, result) {
|
|
467
|
+
const failed = toolResultFailed(result);
|
|
468
|
+
return {
|
|
469
|
+
...item,
|
|
470
|
+
state: failed ? "error" : "completed",
|
|
471
|
+
detail: failed ? "Action could not be confirmed" : "Action completed"
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
152
475
|
// src/runtime/client.ts
|
|
153
476
|
var import_client2 = require("eve/client");
|
|
154
477
|
|
|
@@ -175,11 +498,11 @@ function localBootstrapOrigins(origin) {
|
|
|
175
498
|
...LOCAL_LOOPBACK_ORIGINS.filter((candidate) => candidate !== normalized)
|
|
176
499
|
];
|
|
177
500
|
}
|
|
178
|
-
function
|
|
501
|
+
function isRecord3(value) {
|
|
179
502
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
180
503
|
}
|
|
181
504
|
function parseBootstrapResponse(value, indexId, now) {
|
|
182
|
-
if (!
|
|
505
|
+
if (!isRecord3(value) || value.apiVersion !== "webless.ai/agent-runtime-bootstrap/v1" || typeof value.accessToken !== "string" || !value.accessToken || typeof value.expiresAt !== "string" || !isRecord3(value.identity) || value.identity.indexId !== indexId || typeof value.identity.revision !== "string" || !value.identity.revision || typeof value.identity.tenantId !== "string" || !value.identity.tenantId || typeof value.origin !== "string" || !value.origin || value.tokenType !== "Bearer" || typeof value.visitorSubject !== "string" || !value.visitorSubject) {
|
|
183
506
|
throw new Error("Agent Runtime returned an invalid access response.");
|
|
184
507
|
}
|
|
185
508
|
const expiresAt = Date.parse(value.expiresAt);
|
|
@@ -199,7 +522,7 @@ async function readBootstrapError(response) {
|
|
|
199
522
|
const fallback = `Agent Runtime is unavailable (${response.status}).`;
|
|
200
523
|
try {
|
|
201
524
|
const value = await response.json();
|
|
202
|
-
return
|
|
525
|
+
return isRecord3(value) && typeof value.error === "string" && value.error ? value.error : fallback;
|
|
203
526
|
} catch {
|
|
204
527
|
return fallback;
|
|
205
528
|
}
|
|
@@ -386,454 +709,247 @@ function savePersistedAgentSession(visitorSessionId, sessionId, streamIndex, opt
|
|
|
386
709
|
return;
|
|
387
710
|
}
|
|
388
711
|
const prefix = resolvePrefix(options);
|
|
389
|
-
sessionStorage.setItem(runtimeSessionIdKey(visitorSessionId, prefix), sessionId);
|
|
390
|
-
sessionStorage.setItem(
|
|
391
|
-
runtimeStreamIndexKey(visitorSessionId, prefix),
|
|
392
|
-
String(Math.max(0, streamIndex))
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
function savePersistedAgentTurnMessage(visitorSessionId, message, options) {
|
|
396
|
-
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !message) {
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
const prefix = resolvePrefix(options);
|
|
400
|
-
sessionStorage.setItem(runtimeLastMessageKey(visitorSessionId, prefix), message);
|
|
401
|
-
}
|
|
402
|
-
function clearPersistedAgentSession(visitorSessionId, options) {
|
|
403
|
-
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return;
|
|
404
|
-
const prefix = resolvePrefix(options);
|
|
405
|
-
sessionStorage.removeItem(runtimeSessionIdKey(visitorSessionId, prefix));
|
|
406
|
-
sessionStorage.removeItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
407
|
-
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// src/runtime/subagent-child-stream.ts
|
|
411
|
-
var INITIAL_RETRY_DELAY_MS = 100;
|
|
412
|
-
var MAX_RETRY_DELAY_MS = 2e3;
|
|
413
|
-
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
414
|
-
function isRecord2(value) {
|
|
415
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
416
|
-
}
|
|
417
|
-
function parseError(value) {
|
|
418
|
-
if (!isRecord2(value)) return void 0;
|
|
419
|
-
const { code, message } = value;
|
|
420
|
-
if (typeof code !== "string" || typeof message !== "string") {
|
|
421
|
-
return void 0;
|
|
422
|
-
}
|
|
423
|
-
return { code, message };
|
|
424
|
-
}
|
|
425
|
-
function parseChildStreamEvent(value) {
|
|
426
|
-
if (!isRecord2(value) || typeof value.type !== "string") {
|
|
427
|
-
return { type: "other" };
|
|
428
|
-
}
|
|
429
|
-
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
430
|
-
return { type: "session.boundary" };
|
|
431
|
-
}
|
|
432
|
-
if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
|
|
433
|
-
return parseChildStreamEvent(value.data.event);
|
|
434
|
-
}
|
|
435
|
-
if (value.type === "subagent.called" && isRecord2(value.data)) {
|
|
436
|
-
const { childStreamPath } = value.data;
|
|
437
|
-
if (typeof childStreamPath === "string") {
|
|
438
|
-
return { childStreamPath, type: "subagent.called" };
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
if (value.type !== "action.result" || !isRecord2(value.data)) {
|
|
442
|
-
return { type: "other" };
|
|
443
|
-
}
|
|
444
|
-
const { data } = value;
|
|
445
|
-
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
446
|
-
return { type: "other" };
|
|
447
|
-
}
|
|
448
|
-
if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
|
|
449
|
-
return { type: "other" };
|
|
450
|
-
}
|
|
451
|
-
const result = data.result;
|
|
452
|
-
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
453
|
-
return { type: "other" };
|
|
454
|
-
}
|
|
455
|
-
const error = parseError(data.error);
|
|
456
|
-
return {
|
|
457
|
-
type: "action.result",
|
|
458
|
-
hasOutput: Object.hasOwn(result, "output"),
|
|
459
|
-
result: {
|
|
460
|
-
callId: result.callId,
|
|
461
|
-
toolName: result.toolName,
|
|
462
|
-
status: data.status,
|
|
463
|
-
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
464
|
-
...error ? { error } : {}
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
async function* readNdjsonStream(body) {
|
|
469
|
-
const reader = body.getReader();
|
|
470
|
-
const decoder = new TextDecoder();
|
|
471
|
-
let buffer = "";
|
|
472
|
-
try {
|
|
473
|
-
while (true) {
|
|
474
|
-
const { done, value } = await reader.read();
|
|
475
|
-
buffer += decoder.decode(value, { stream: !done });
|
|
476
|
-
const lines = buffer.split("\n");
|
|
477
|
-
buffer = lines.pop() ?? "";
|
|
478
|
-
for (const line of lines) {
|
|
479
|
-
const trimmed2 = line.trim();
|
|
480
|
-
if (!trimmed2) continue;
|
|
481
|
-
try {
|
|
482
|
-
const parsed = JSON.parse(trimmed2);
|
|
483
|
-
yield parsed;
|
|
484
|
-
} catch {
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
if (done) break;
|
|
488
|
-
}
|
|
489
|
-
const trimmed = buffer.trim();
|
|
490
|
-
if (trimmed) {
|
|
491
|
-
try {
|
|
492
|
-
const parsed = JSON.parse(trimmed);
|
|
493
|
-
yield parsed;
|
|
494
|
-
} catch {
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
} finally {
|
|
498
|
-
reader.releaseLock();
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
function streamPathAt(path, streamIndex) {
|
|
502
|
-
if (streamIndex === 0) return path;
|
|
503
|
-
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
504
|
-
}
|
|
505
|
-
function abortableDelay(delayMs, signal) {
|
|
506
|
-
if (signal.aborted) return Promise.resolve();
|
|
507
|
-
return new Promise((resolve) => {
|
|
508
|
-
const finish = () => {
|
|
509
|
-
clearTimeout(timeout);
|
|
510
|
-
signal.removeEventListener("abort", finish);
|
|
511
|
-
resolve();
|
|
512
|
-
};
|
|
513
|
-
const timeout = setTimeout(finish, delayMs);
|
|
514
|
-
signal.addEventListener("abort", finish, { once: true });
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
var SubagentChildStreamCoordinator = class {
|
|
518
|
-
constructor(client, handlers, parentSignal) {
|
|
519
|
-
this.client = client;
|
|
520
|
-
this.handlers = handlers;
|
|
521
|
-
this.parentSignal = parentSignal;
|
|
522
|
-
}
|
|
523
|
-
client;
|
|
524
|
-
handlers;
|
|
525
|
-
parentSignal;
|
|
526
|
-
controllers = /* @__PURE__ */ new Map();
|
|
527
|
-
tasks = /* @__PURE__ */ new Map();
|
|
528
|
-
begin(event) {
|
|
529
|
-
this.beginPath(event.data.childStreamPath);
|
|
530
|
-
}
|
|
531
|
-
async waitForAll() {
|
|
532
|
-
let observedTaskCount = -1;
|
|
533
|
-
while (observedTaskCount !== this.tasks.size) {
|
|
534
|
-
observedTaskCount = this.tasks.size;
|
|
535
|
-
await Promise.all(this.tasks.values());
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
abortAll() {
|
|
539
|
-
for (const controller of this.controllers.values()) controller.abort();
|
|
540
|
-
this.controllers.clear();
|
|
541
|
-
}
|
|
542
|
-
beginPath(childStreamPath) {
|
|
543
|
-
if (this.tasks.has(childStreamPath)) return;
|
|
544
|
-
const controller = new AbortController();
|
|
545
|
-
const abort = () => controller.abort();
|
|
546
|
-
if (this.parentSignal.aborted) {
|
|
547
|
-
controller.abort();
|
|
548
|
-
} else {
|
|
549
|
-
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
550
|
-
}
|
|
551
|
-
this.controllers.set(childStreamPath, controller);
|
|
552
|
-
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
553
|
-
() => {
|
|
554
|
-
this.parentSignal.removeEventListener("abort", abort);
|
|
555
|
-
if (this.controllers.get(childStreamPath) === controller) {
|
|
556
|
-
this.controllers.delete(childStreamPath);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
);
|
|
560
|
-
this.tasks.set(childStreamPath, task);
|
|
561
|
-
}
|
|
562
|
-
async consume(path, signal) {
|
|
563
|
-
let streamIndex = 0;
|
|
564
|
-
let consecutiveRetries = 0;
|
|
565
|
-
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
566
|
-
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
567
|
-
let receivedEvent = false;
|
|
568
|
-
try {
|
|
569
|
-
const response = await this.client.fetch(
|
|
570
|
-
streamPathAt(path, streamIndex),
|
|
571
|
-
{
|
|
572
|
-
cache: "no-store",
|
|
573
|
-
signal
|
|
574
|
-
}
|
|
575
|
-
);
|
|
576
|
-
if (!response.ok || response.body === null) {
|
|
577
|
-
await response.body?.cancel().catch(() => {
|
|
578
|
-
});
|
|
579
|
-
throw new Error(`Child stream returned ${response.status}.`);
|
|
580
|
-
}
|
|
581
|
-
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
582
|
-
if (signal.aborted) return;
|
|
583
|
-
receivedEvent = true;
|
|
584
|
-
streamIndex += 1;
|
|
585
|
-
const event = parseChildStreamEvent(rawEvent);
|
|
586
|
-
if (event.type === "session.boundary") return;
|
|
587
|
-
if (event.type === "subagent.called") {
|
|
588
|
-
this.beginPath(event.childStreamPath);
|
|
589
|
-
continue;
|
|
590
|
-
}
|
|
591
|
-
if (event.type !== "action.result") continue;
|
|
592
|
-
this.handlers.onToolResult?.(event.result);
|
|
593
|
-
if (event.hasOutput) {
|
|
594
|
-
this.handlers.onActionResult?.(event.result.output);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
} catch {
|
|
598
|
-
if (signal.aborted) return;
|
|
599
|
-
}
|
|
600
|
-
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
601
|
-
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
602
|
-
await abortableDelay(retryDelayMs, signal);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
// src/runtime/tool-ui.ts
|
|
608
|
-
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
609
|
-
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
610
|
-
var AGENT_STRUCTURED_TOOL_INPUT_HEADER = "Webless-Structured-Tool-Input-JSON:";
|
|
611
|
-
function formatAgentStructuredToolInput(surface, values) {
|
|
612
|
-
const payload = {
|
|
613
|
-
schemaVersion: AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION,
|
|
614
|
-
toolSlug: surface.toolSlug,
|
|
615
|
-
...surface.operationId ? { operationId: surface.operationId } : {},
|
|
616
|
-
values
|
|
617
|
-
};
|
|
618
|
-
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
619
|
-
}
|
|
620
|
-
function isRecord3(value) {
|
|
621
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
622
|
-
}
|
|
623
|
-
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
624
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
625
|
-
return true;
|
|
626
|
-
}
|
|
627
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
628
|
-
if (typeof value !== "object") return false;
|
|
629
|
-
if (seen.has(value)) return false;
|
|
630
|
-
seen.add(value);
|
|
631
|
-
const valid = Array.isArray(value) ? value.every((item) => isJsonValue(item, seen)) : Object.entries(value).every(
|
|
632
|
-
([key, item]) => typeof key === "string" && isJsonValue(item, seen)
|
|
712
|
+
sessionStorage.setItem(runtimeSessionIdKey(visitorSessionId, prefix), sessionId);
|
|
713
|
+
sessionStorage.setItem(
|
|
714
|
+
runtimeStreamIndexKey(visitorSessionId, prefix),
|
|
715
|
+
String(Math.max(0, streamIndex))
|
|
633
716
|
);
|
|
634
|
-
seen.delete(value);
|
|
635
|
-
return valid;
|
|
636
717
|
}
|
|
637
|
-
function
|
|
638
|
-
if (typeof
|
|
639
|
-
return
|
|
718
|
+
function savePersistedAgentTurnMessage(visitorSessionId, message, options) {
|
|
719
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !message) {
|
|
720
|
+
return;
|
|
640
721
|
}
|
|
641
|
-
|
|
722
|
+
const prefix = resolvePrefix(options);
|
|
723
|
+
sessionStorage.setItem(runtimeLastMessageKey(visitorSessionId, prefix), message);
|
|
642
724
|
}
|
|
643
|
-
function
|
|
644
|
-
|
|
725
|
+
function clearPersistedAgentSession(visitorSessionId, options) {
|
|
726
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return;
|
|
727
|
+
const prefix = resolvePrefix(options);
|
|
728
|
+
sessionStorage.removeItem(runtimeSessionIdKey(visitorSessionId, prefix));
|
|
729
|
+
sessionStorage.removeItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
730
|
+
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
645
731
|
}
|
|
646
|
-
|
|
647
|
-
|
|
732
|
+
|
|
733
|
+
// src/runtime/subagent-child-stream.ts
|
|
734
|
+
var INITIAL_RETRY_DELAY_MS = 100;
|
|
735
|
+
var MAX_RETRY_DELAY_MS = 2e3;
|
|
736
|
+
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
737
|
+
function isRecord4(value) {
|
|
738
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
648
739
|
}
|
|
649
|
-
function
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
"multi-select",
|
|
657
|
-
"checkbox",
|
|
658
|
-
"confirmation",
|
|
659
|
-
"radio",
|
|
660
|
-
"date",
|
|
661
|
-
"time",
|
|
662
|
-
"date-time",
|
|
663
|
-
"calendar",
|
|
664
|
-
"range",
|
|
665
|
-
"json"
|
|
666
|
-
].includes(value);
|
|
740
|
+
function parseError(value) {
|
|
741
|
+
if (!isRecord4(value)) return void 0;
|
|
742
|
+
const { code, message } = value;
|
|
743
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
744
|
+
return void 0;
|
|
745
|
+
}
|
|
746
|
+
return { code, message };
|
|
667
747
|
}
|
|
668
|
-
function
|
|
669
|
-
if (!
|
|
670
|
-
|
|
671
|
-
"description",
|
|
672
|
-
"kind",
|
|
673
|
-
"label",
|
|
674
|
-
"max",
|
|
675
|
-
"maxItems",
|
|
676
|
-
"maxLength",
|
|
677
|
-
"min",
|
|
678
|
-
"minLength",
|
|
679
|
-
"options",
|
|
680
|
-
"path",
|
|
681
|
-
"placeholder",
|
|
682
|
-
"required",
|
|
683
|
-
"step",
|
|
684
|
-
"defaultValue"
|
|
685
|
-
])) {
|
|
686
|
-
return null;
|
|
748
|
+
function parseChildStreamEvent(value) {
|
|
749
|
+
if (!isRecord4(value) || typeof value.type !== "string") {
|
|
750
|
+
return { type: "other" };
|
|
687
751
|
}
|
|
688
|
-
if (
|
|
689
|
-
|
|
690
|
-
const label = boundedString(value.label, 160);
|
|
691
|
-
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
692
|
-
const placeholder = value.placeholder === void 0 || typeof value.placeholder !== "string" ? void 0 : value.placeholder;
|
|
693
|
-
const required = value.required === void 0 || typeof value.required !== "boolean" ? void 0 : value.required;
|
|
694
|
-
const min = value.min === void 0 ? void 0 : numberValue(value.min);
|
|
695
|
-
const max = value.max === void 0 ? void 0 : numberValue(value.max);
|
|
696
|
-
const maxItems = value.maxItems === void 0 ? void 0 : integerValue(value.maxItems);
|
|
697
|
-
const step = value.step === void 0 ? void 0 : numberValue(value.step);
|
|
698
|
-
const minLength = value.minLength === void 0 ? void 0 : integerValue(value.minLength);
|
|
699
|
-
const maxLength = value.maxLength === void 0 ? void 0 : integerValue(value.maxLength);
|
|
700
|
-
const defaultValue = value.defaultValue === void 0 || !isJsonValue(value.defaultValue) ? void 0 : value.defaultValue;
|
|
701
|
-
if (!path || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || !label) {
|
|
702
|
-
return null;
|
|
752
|
+
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
753
|
+
return { type: "session.boundary" };
|
|
703
754
|
}
|
|
704
|
-
if (value.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
if (value.
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (value.step !== void 0 && step === void 0) return null;
|
|
712
|
-
if (value.minLength !== void 0 && minLength === void 0) return null;
|
|
713
|
-
if (value.maxLength !== void 0 && maxLength === void 0) return null;
|
|
714
|
-
if (value.defaultValue !== void 0 && defaultValue === void 0)
|
|
715
|
-
return null;
|
|
716
|
-
if (value.options !== void 0) {
|
|
717
|
-
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
718
|
-
return null;
|
|
719
|
-
for (const option of value.options) {
|
|
720
|
-
if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
721
|
-
return null;
|
|
722
|
-
}
|
|
755
|
+
if (value.type === "subagent.event" && isRecord4(value.data) && Object.hasOwn(value.data, "event")) {
|
|
756
|
+
return parseChildStreamEvent(value.data.event);
|
|
757
|
+
}
|
|
758
|
+
if (value.type === "subagent.called" && isRecord4(value.data)) {
|
|
759
|
+
const { childStreamPath } = value.data;
|
|
760
|
+
if (typeof childStreamPath === "string") {
|
|
761
|
+
return { childStreamPath, type: "subagent.called" };
|
|
723
762
|
}
|
|
724
763
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
...maxItems !== void 0 ? { maxItems } : {},
|
|
737
|
-
...step !== void 0 ? { step } : {},
|
|
738
|
-
...minLength !== void 0 ? { minLength } : {},
|
|
739
|
-
...maxLength !== void 0 ? { maxLength } : {}
|
|
740
|
-
};
|
|
741
|
-
}
|
|
742
|
-
function parseStep(value) {
|
|
743
|
-
if (!isRecord3(value)) return null;
|
|
744
|
-
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
745
|
-
return null;
|
|
764
|
+
if (value.type === "actions.requested" && isRecord4(value.data) && Array.isArray(value.data.actions)) {
|
|
765
|
+
const items = value.data.actions.flatMap((action) => {
|
|
766
|
+
if (!isRecord4(action) || action.kind !== "tool-call" || typeof action.callId !== "string" || typeof action.toolName !== "string" || !isRecord4(action.input)) return [];
|
|
767
|
+
const item = connectedToolWork({
|
|
768
|
+
callId: action.callId,
|
|
769
|
+
toolName: action.toolName,
|
|
770
|
+
input: action.input
|
|
771
|
+
});
|
|
772
|
+
return item ? [item] : [];
|
|
773
|
+
});
|
|
774
|
+
return { type: "actions.requested", items };
|
|
746
775
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
776
|
+
if (value.type !== "action.result" || !isRecord4(value.data)) {
|
|
777
|
+
return { type: "other" };
|
|
778
|
+
}
|
|
779
|
+
const { data } = value;
|
|
780
|
+
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
781
|
+
return { type: "other" };
|
|
782
|
+
}
|
|
783
|
+
if (!isRecord4(data.result) || data.result.kind !== "tool-result") {
|
|
784
|
+
return { type: "other" };
|
|
785
|
+
}
|
|
786
|
+
const result = data.result;
|
|
787
|
+
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
788
|
+
return { type: "other" };
|
|
754
789
|
}
|
|
790
|
+
const error = parseError(data.error);
|
|
755
791
|
return {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
792
|
+
type: "action.result",
|
|
793
|
+
hasOutput: Object.hasOwn(result, "output"),
|
|
794
|
+
result: {
|
|
795
|
+
callId: result.callId,
|
|
796
|
+
toolName: result.toolName,
|
|
797
|
+
status: result.isError === true ? "failed" : data.status,
|
|
798
|
+
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
799
|
+
...error ? { error } : {}
|
|
800
|
+
}
|
|
760
801
|
};
|
|
761
802
|
}
|
|
762
|
-
function
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
803
|
+
async function* readNdjsonStream(body) {
|
|
804
|
+
const reader = body.getReader();
|
|
805
|
+
const decoder = new TextDecoder();
|
|
806
|
+
let buffer = "";
|
|
807
|
+
try {
|
|
808
|
+
while (true) {
|
|
809
|
+
const { done, value } = await reader.read();
|
|
810
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
811
|
+
const lines = buffer.split("\n");
|
|
812
|
+
buffer = lines.pop() ?? "";
|
|
813
|
+
for (const line of lines) {
|
|
814
|
+
const trimmed2 = line.trim();
|
|
815
|
+
if (!trimmed2) continue;
|
|
816
|
+
try {
|
|
817
|
+
const parsed = JSON.parse(trimmed2);
|
|
818
|
+
yield parsed;
|
|
819
|
+
} catch {
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (done) break;
|
|
823
|
+
}
|
|
824
|
+
const trimmed = buffer.trim();
|
|
825
|
+
if (trimmed) {
|
|
826
|
+
try {
|
|
827
|
+
const parsed = JSON.parse(trimmed);
|
|
828
|
+
yield parsed;
|
|
829
|
+
} catch {
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
} finally {
|
|
833
|
+
reader.releaseLock();
|
|
768
834
|
}
|
|
769
|
-
return {
|
|
770
|
-
id: value.id,
|
|
771
|
-
label
|
|
772
|
-
};
|
|
773
835
|
}
|
|
774
|
-
function
|
|
775
|
-
if (
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
"
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
836
|
+
function streamPathAt(path, streamIndex) {
|
|
837
|
+
if (streamIndex === 0) return path;
|
|
838
|
+
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
839
|
+
}
|
|
840
|
+
function abortableDelay(delayMs, signal) {
|
|
841
|
+
if (signal.aborted) return Promise.resolve();
|
|
842
|
+
return new Promise((resolve) => {
|
|
843
|
+
const finish = () => {
|
|
844
|
+
clearTimeout(timeout);
|
|
845
|
+
signal.removeEventListener("abort", finish);
|
|
846
|
+
resolve();
|
|
847
|
+
};
|
|
848
|
+
const timeout = setTimeout(finish, delayMs);
|
|
849
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
var SubagentChildStreamCoordinator = class {
|
|
853
|
+
constructor(client, handlers, parentSignal) {
|
|
854
|
+
this.client = client;
|
|
855
|
+
this.handlers = handlers;
|
|
856
|
+
this.parentSignal = parentSignal;
|
|
857
|
+
}
|
|
858
|
+
client;
|
|
859
|
+
handlers;
|
|
860
|
+
parentSignal;
|
|
861
|
+
controllers = /* @__PURE__ */ new Map();
|
|
862
|
+
tasks = /* @__PURE__ */ new Map();
|
|
863
|
+
begin(event) {
|
|
864
|
+
this.beginPath(event.data.childStreamPath);
|
|
792
865
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
|
|
800
|
-
if (!id || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
|
|
801
|
-
return null;
|
|
866
|
+
async waitForAll() {
|
|
867
|
+
let observedTaskCount = -1;
|
|
868
|
+
while (observedTaskCount !== this.tasks.size) {
|
|
869
|
+
observedTaskCount = this.tasks.size;
|
|
870
|
+
await Promise.all(this.tasks.values());
|
|
871
|
+
}
|
|
802
872
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (steps?.some((step) => step === null)) return null;
|
|
807
|
-
const actions = value.actions === void 0 ? void 0 : Array.isArray(value.actions) && value.actions.length <= 8 ? value.actions.map(parseAction) : null;
|
|
808
|
-
if (actions?.some((action) => action === null)) return null;
|
|
809
|
-
if (value.description !== void 0 && !description) return null;
|
|
810
|
-
if (value.operationId !== void 0 && !operationId) return null;
|
|
811
|
-
if (value.requestId !== void 0 && !requestId) return null;
|
|
812
|
-
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
813
|
-
const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
|
|
814
|
-
if (value.values !== void 0) {
|
|
815
|
-
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
816
|
-
return null;
|
|
873
|
+
abortAll() {
|
|
874
|
+
for (const controller of this.controllers.values()) controller.abort();
|
|
875
|
+
this.controllers.clear();
|
|
817
876
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
877
|
+
beginPath(childStreamPath) {
|
|
878
|
+
if (this.tasks.has(childStreamPath)) return;
|
|
879
|
+
const controller = new AbortController();
|
|
880
|
+
const abort = () => controller.abort();
|
|
881
|
+
if (this.parentSignal.aborted) {
|
|
882
|
+
controller.abort();
|
|
883
|
+
} else {
|
|
884
|
+
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
885
|
+
}
|
|
886
|
+
this.controllers.set(childStreamPath, controller);
|
|
887
|
+
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
888
|
+
() => {
|
|
889
|
+
this.parentSignal.removeEventListener("abort", abort);
|
|
890
|
+
if (this.controllers.get(childStreamPath) === controller) {
|
|
891
|
+
this.controllers.delete(childStreamPath);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
);
|
|
895
|
+
this.tasks.set(childStreamPath, task);
|
|
896
|
+
}
|
|
897
|
+
async consume(path, signal) {
|
|
898
|
+
const workItems = /* @__PURE__ */ new Map();
|
|
899
|
+
let streamIndex = 0;
|
|
900
|
+
let consecutiveRetries = 0;
|
|
901
|
+
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
902
|
+
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
903
|
+
let receivedEvent = false;
|
|
904
|
+
try {
|
|
905
|
+
const response = await this.client.fetch(
|
|
906
|
+
streamPathAt(path, streamIndex),
|
|
907
|
+
{
|
|
908
|
+
cache: "no-store",
|
|
909
|
+
signal
|
|
910
|
+
}
|
|
911
|
+
);
|
|
912
|
+
if (!response.ok || response.body === null) {
|
|
913
|
+
await response.body?.cancel().catch(() => {
|
|
914
|
+
});
|
|
915
|
+
throw new Error(`Child stream returned ${response.status}.`);
|
|
916
|
+
}
|
|
917
|
+
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
918
|
+
if (signal.aborted) return;
|
|
919
|
+
receivedEvent = true;
|
|
920
|
+
streamIndex += 1;
|
|
921
|
+
const event = parseChildStreamEvent(rawEvent);
|
|
922
|
+
if (event.type === "session.boundary") return;
|
|
923
|
+
if (event.type === "subagent.called") {
|
|
924
|
+
this.beginPath(event.childStreamPath);
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
if (event.type === "actions.requested") {
|
|
928
|
+
for (const item2 of event.items) {
|
|
929
|
+
workItems.set(item2.id, item2);
|
|
930
|
+
this.handlers.onWork?.(item2);
|
|
931
|
+
}
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
if (event.type !== "action.result") continue;
|
|
935
|
+
const item = workItems.get(event.result.callId);
|
|
936
|
+
if (item) {
|
|
937
|
+
this.handlers.onWork?.(completeConnectedToolWork(item, event.result));
|
|
938
|
+
}
|
|
939
|
+
this.handlers.onToolResult?.(event.result);
|
|
940
|
+
if (event.hasOutput) {
|
|
941
|
+
this.handlers.onActionResult?.(event.result.output);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
} catch {
|
|
945
|
+
if (signal.aborted) return;
|
|
946
|
+
}
|
|
947
|
+
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
948
|
+
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
949
|
+
await abortableDelay(retryDelayMs, signal);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
};
|
|
837
953
|
|
|
838
954
|
// src/runtime/client.ts
|
|
839
955
|
function isTurnBoundary(event) {
|
|
@@ -867,7 +983,7 @@ function emitActionResult(event, handlers) {
|
|
|
867
983
|
handlers.onToolResult?.({
|
|
868
984
|
callId: result.callId,
|
|
869
985
|
toolName: result.toolName,
|
|
870
|
-
status: event.data.status,
|
|
986
|
+
status: result.isError ? "failed" : event.data.status,
|
|
871
987
|
output: result.output,
|
|
872
988
|
...event.data.error ? { error: event.data.error } : {}
|
|
873
989
|
});
|
|
@@ -993,9 +1109,13 @@ function requestedWorkItem(action) {
|
|
|
993
1109
|
state: "active"
|
|
994
1110
|
};
|
|
995
1111
|
}
|
|
996
|
-
return null;
|
|
1112
|
+
return action.kind === "tool-call" ? connectedToolWork(action) : null;
|
|
997
1113
|
}
|
|
998
1114
|
function applyWorkEvent(event, handlers, workItems) {
|
|
1115
|
+
if (event.type === "subagent.event") {
|
|
1116
|
+
applyWorkEvent(event.data.event, handlers, workItems);
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
999
1119
|
if (event.type === "step.started" && workItems.size === 0) {
|
|
1000
1120
|
emitWorkItem(
|
|
1001
1121
|
{
|
|
@@ -1054,6 +1174,15 @@ function applyWorkEvent(event, handlers, workItems) {
|
|
|
1054
1174
|
const { result, status } = event.data;
|
|
1055
1175
|
const current = workItems.get(result.callId);
|
|
1056
1176
|
if (!current) return;
|
|
1177
|
+
if (current.kind === "tool" && result.kind === "tool-result") {
|
|
1178
|
+
emitWorkItem(completeConnectedToolWork(current, {
|
|
1179
|
+
callId: result.callId,
|
|
1180
|
+
toolName: result.toolName,
|
|
1181
|
+
status: result.isError ? "failed" : status,
|
|
1182
|
+
output: result.output
|
|
1183
|
+
}), handlers, workItems);
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1057
1186
|
const failed = status !== "completed" || result.isError === true;
|
|
1058
1187
|
emitWorkItem(
|
|
1059
1188
|
{
|
|
@@ -2091,10 +2220,15 @@ function parseMessage(value) {
|
|
|
2091
2220
|
const result = parseToolResult(value2);
|
|
2092
2221
|
return result?.kind === "search" ? [result] : [];
|
|
2093
2222
|
}) : [];
|
|
2223
|
+
const toolResults = Array.isArray(record2.toolResults) ? record2.toolResults.flatMap((value2) => {
|
|
2224
|
+
const result = parseToolResult(value2);
|
|
2225
|
+
return result && result.kind !== "search" && result.kind !== "input" ? [result] : [];
|
|
2226
|
+
}) : [];
|
|
2094
2227
|
return {
|
|
2095
2228
|
id: record2.id,
|
|
2096
2229
|
role: "agent",
|
|
2097
2230
|
...searchResults.length ? { searchResults } : {},
|
|
2231
|
+
...toolResults.length ? { toolResults } : {},
|
|
2098
2232
|
text: record2.text,
|
|
2099
2233
|
createdAt: record2.createdAt
|
|
2100
2234
|
};
|
|
@@ -2102,7 +2236,7 @@ function parseMessage(value) {
|
|
|
2102
2236
|
function parseToolStep(value) {
|
|
2103
2237
|
if (typeof value !== "object" || value === null) return null;
|
|
2104
2238
|
const record2 = value;
|
|
2105
|
-
if (typeof record2.id !== "string" || record2.kind !== "planning" && record2.kind !== "search" && record2.kind !== "specialist" || typeof record2.label !== "string" || record2.state !== "completed" && record2.state !== "active" && record2.state !== "pending" && record2.state !== "error") {
|
|
2239
|
+
if (typeof record2.id !== "string" || record2.kind !== "planning" && record2.kind !== "search" && record2.kind !== "specialist" && record2.kind !== "tool" || typeof record2.label !== "string" || record2.state !== "completed" && record2.state !== "active" && record2.state !== "pending" && record2.state !== "error") {
|
|
2106
2240
|
return null;
|
|
2107
2241
|
}
|
|
2108
2242
|
return {
|
|
@@ -2163,6 +2297,15 @@ function parseInputRequest(value) {
|
|
|
2163
2297
|
...ui ? { ui } : {}
|
|
2164
2298
|
};
|
|
2165
2299
|
}
|
|
2300
|
+
function parseResultDetails(value) {
|
|
2301
|
+
if (!Array.isArray(value)) return [];
|
|
2302
|
+
return value.slice(0, 6).flatMap((item) => {
|
|
2303
|
+
if (typeof item !== "object" || item === null) return [];
|
|
2304
|
+
const detail = item;
|
|
2305
|
+
if (typeof detail.label !== "string" || typeof detail.value !== "string") return [];
|
|
2306
|
+
return [{ label: detail.label.slice(0, 240), value: detail.value.slice(0, 240) }];
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2166
2309
|
function parseToolResult(value) {
|
|
2167
2310
|
if (typeof value !== "object" || value === null) return null;
|
|
2168
2311
|
const record2 = value;
|
|
@@ -2198,6 +2341,7 @@ function parseToolResult(value) {
|
|
|
2198
2341
|
status: record2.status,
|
|
2199
2342
|
kind: "entity",
|
|
2200
2343
|
title: record2.title,
|
|
2344
|
+
details: parseResultDetails(record2.details),
|
|
2201
2345
|
...typeof record2.description === "string" ? { description: record2.description } : {}
|
|
2202
2346
|
};
|
|
2203
2347
|
}
|
|
@@ -2241,6 +2385,7 @@ function parseToolResult(value) {
|
|
|
2241
2385
|
status: record2.status,
|
|
2242
2386
|
kind: "summary",
|
|
2243
2387
|
title: record2.title,
|
|
2388
|
+
details: parseResultDetails(record2.details),
|
|
2244
2389
|
...typeof record2.description === "string" ? { description: record2.description } : {}
|
|
2245
2390
|
};
|
|
2246
2391
|
}
|
|
@@ -2345,63 +2490,6 @@ function clearPendingWidgetBooking(storageKeyPrefix, visitorSessionId) {
|
|
|
2345
2490
|
);
|
|
2346
2491
|
}
|
|
2347
2492
|
|
|
2348
|
-
// src/runtime/tool-result-envelope.ts
|
|
2349
|
-
var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
2350
|
-
"schemaVersion",
|
|
2351
|
-
"output",
|
|
2352
|
-
"presentationKinds",
|
|
2353
|
-
"ui"
|
|
2354
|
-
]);
|
|
2355
|
-
function isRecord4(value) {
|
|
2356
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2357
|
-
}
|
|
2358
|
-
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
2359
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
2360
|
-
return true;
|
|
2361
|
-
}
|
|
2362
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
2363
|
-
if (typeof value !== "object") return false;
|
|
2364
|
-
if (seen.has(value)) return false;
|
|
2365
|
-
seen.add(value);
|
|
2366
|
-
const valid = Array.isArray(value) ? value.every((item) => isJsonValue2(item, seen)) : Object.entries(value).every(
|
|
2367
|
-
([key, item]) => typeof key === "string" && isJsonValue2(item, seen)
|
|
2368
|
-
);
|
|
2369
|
-
seen.delete(value);
|
|
2370
|
-
return valid;
|
|
2371
|
-
}
|
|
2372
|
-
function decodeEnvelope(value) {
|
|
2373
|
-
if (typeof value !== "string") return value;
|
|
2374
|
-
try {
|
|
2375
|
-
return JSON.parse(value);
|
|
2376
|
-
} catch {
|
|
2377
|
-
return null;
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
|
-
function parseAgentToolResultEnvelope(value) {
|
|
2381
|
-
const decoded = decodeEnvelope(value);
|
|
2382
|
-
if (!isRecord4(decoded)) return null;
|
|
2383
|
-
const keys = Object.keys(decoded);
|
|
2384
|
-
if (keys.some((key) => !ENVELOPE_KEYS.has(key)) || decoded.schemaVersion !== "webless.tool-result.v1" || !isJsonValue2(decoded.output) || !Array.isArray(decoded.presentationKinds) || decoded.presentationKinds.length < 1 || decoded.presentationKinds.length > 16) {
|
|
2385
|
-
return null;
|
|
2386
|
-
}
|
|
2387
|
-
const presentationKinds = decoded.presentationKinds.flatMap((kind) => {
|
|
2388
|
-
if (typeof kind !== "string") return [];
|
|
2389
|
-
const normalized = kind.trim();
|
|
2390
|
-
return normalized && normalized.length <= 128 ? [normalized] : [];
|
|
2391
|
-
});
|
|
2392
|
-
if (presentationKinds.length !== decoded.presentationKinds.length) {
|
|
2393
|
-
return null;
|
|
2394
|
-
}
|
|
2395
|
-
const ui = decoded.ui === void 0 ? void 0 : parseAgentToolUiSurface(decoded.ui);
|
|
2396
|
-
if (decoded.ui !== void 0 && !ui) return null;
|
|
2397
|
-
return {
|
|
2398
|
-
schemaVersion: "webless.tool-result.v1",
|
|
2399
|
-
output: decoded.output,
|
|
2400
|
-
presentationKinds,
|
|
2401
|
-
...ui ? { ui } : {}
|
|
2402
|
-
};
|
|
2403
|
-
}
|
|
2404
|
-
|
|
2405
2493
|
// src/react/lib/tool-result.ts
|
|
2406
2494
|
var MAX_TEXT_LENGTH = 240;
|
|
2407
2495
|
var MAX_DETAILS = 6;
|
|
@@ -2636,6 +2724,9 @@ function finalizeSummaryPresentation(result, proposed) {
|
|
|
2636
2724
|
};
|
|
2637
2725
|
}
|
|
2638
2726
|
function presentVisitorToolResult(result, registry = []) {
|
|
2727
|
+
if (result.status === "completed" && toolResultFailed(result)) {
|
|
2728
|
+
result = { ...result, status: "failed" };
|
|
2729
|
+
}
|
|
2639
2730
|
if (result.toolName === "search_discovery" && result.status === "completed") {
|
|
2640
2731
|
const envelope2 = parseAgentToolResultEnvelope(result.output);
|
|
2641
2732
|
const search = parseAgentSearchDiscoveryOutput(
|
|
@@ -2672,7 +2763,7 @@ function presentVisitorToolResult(result, registry = []) {
|
|
|
2672
2763
|
surface: envelope.ui
|
|
2673
2764
|
};
|
|
2674
2765
|
}
|
|
2675
|
-
if (!proposed) {
|
|
2766
|
+
if (!proposed || result.status !== "completed" && proposed.kind !== "summary") {
|
|
2676
2767
|
if (result.status === "failed" || result.status === "rejected") {
|
|
2677
2768
|
return {
|
|
2678
2769
|
id: result.callId,
|
|
@@ -2795,14 +2886,15 @@ function isNearDuplicateAssistantText(left, right) {
|
|
|
2795
2886
|
shorter.slice(0, Math.floor(shorter.length * 0.85))
|
|
2796
2887
|
);
|
|
2797
2888
|
}
|
|
2798
|
-
function appendAgentTurnMessage(messages, displayText, searchResults = []) {
|
|
2889
|
+
function appendAgentTurnMessage(messages, displayText, searchResults = [], toolResults = []) {
|
|
2799
2890
|
const trimmed = displayText.trim();
|
|
2800
|
-
if (!trimmed && searchResults.length === 0) return [...messages];
|
|
2891
|
+
if (!trimmed && searchResults.length === 0 && toolResults.length === 0) return [...messages];
|
|
2801
2892
|
const agentMessage = {
|
|
2802
2893
|
id: `agent-${Date.now()}`,
|
|
2803
2894
|
role: "agent",
|
|
2804
2895
|
text: trimmed,
|
|
2805
2896
|
...searchResults.length ? { searchResults } : {},
|
|
2897
|
+
...toolResults.length ? { toolResults } : {},
|
|
2806
2898
|
createdAt: Date.now()
|
|
2807
2899
|
};
|
|
2808
2900
|
const last = messages.at(-1);
|
|
@@ -3184,10 +3276,11 @@ function useAgentChat({
|
|
|
3184
3276
|
messages: appendAgentTurnMessage(
|
|
3185
3277
|
prev.messages,
|
|
3186
3278
|
displayText,
|
|
3187
|
-
(prev.toolResults ?? []).filter((result) => result.kind === "search")
|
|
3279
|
+
(prev.toolResults ?? []).filter((result) => result.kind === "search"),
|
|
3280
|
+
(prev.toolResults ?? []).filter((result) => result.kind !== "search" && result.kind !== "input")
|
|
3188
3281
|
),
|
|
3189
3282
|
toolResults: (prev.toolResults ?? []).filter(
|
|
3190
|
-
(result) => result.kind
|
|
3283
|
+
(result) => result.kind === "input"
|
|
3191
3284
|
),
|
|
3192
3285
|
toolSteps: completeActivePlanning(prev.toolSteps),
|
|
3193
3286
|
streamingText: "",
|
|
@@ -3249,16 +3342,18 @@ function useAgentChat({
|
|
|
3249
3342
|
const submit = (0, import_react2.useCallback)(
|
|
3250
3343
|
async (visitorText, options) => {
|
|
3251
3344
|
const trimmed = visitorText.trim();
|
|
3252
|
-
|
|
3345
|
+
const outgoing = options?.runtimeText ?? visitorText;
|
|
3346
|
+
if (!outgoing.trim()) return null;
|
|
3253
3347
|
const chatResponse = chatInputResponseForText(
|
|
3254
3348
|
state.pendingInputs ?? [],
|
|
3255
|
-
|
|
3349
|
+
outgoing.trim()
|
|
3256
3350
|
);
|
|
3257
3351
|
if (chatResponse) {
|
|
3258
3352
|
const visitorMessage2 = {
|
|
3259
3353
|
id: `visitor-${Date.now()}`,
|
|
3260
3354
|
role: "visitor",
|
|
3261
3355
|
text: trimmed,
|
|
3356
|
+
...outgoing !== trimmed ? { runtimeText: outgoing } : {},
|
|
3262
3357
|
createdAt: Date.now()
|
|
3263
3358
|
};
|
|
3264
3359
|
if (runRef.current) {
|
|
@@ -3298,7 +3393,6 @@ function useAgentChat({
|
|
|
3298
3393
|
const controller = new AbortController();
|
|
3299
3394
|
runRef.current = controller;
|
|
3300
3395
|
const booking = pendingBookingRef.current;
|
|
3301
|
-
const outgoing = options?.runtimeText ?? visitorText;
|
|
3302
3396
|
const runtimeText = booking ? `${visitorBookingPrefix(booking)}
|
|
3303
3397
|
|
|
3304
3398
|
${outgoing}` : outgoing;
|
|
@@ -3661,6 +3755,10 @@ function joinLabels(labels) {
|
|
|
3661
3755
|
return `${labels.slice(0, -1).join(", ")} and ${labels.at(-1) ?? ""}`;
|
|
3662
3756
|
}
|
|
3663
3757
|
function workSummary(steps, failed, brandLabel) {
|
|
3758
|
+
const activeTool = [...steps].reverse().find(
|
|
3759
|
+
(step) => step.kind === "tool" && step.state === "active"
|
|
3760
|
+
);
|
|
3761
|
+
if (activeTool) return activeTool.detail ?? "Working on your request";
|
|
3664
3762
|
const activeSpecialists = steps.filter(
|
|
3665
3763
|
(step) => step.kind === "specialist" && step.state === "active"
|
|
3666
3764
|
);
|
|
@@ -3988,11 +4086,15 @@ function Composer({
|
|
|
3988
4086
|
const trimmed = value.trim();
|
|
3989
4087
|
if (!trimmed || disabled) return;
|
|
3990
4088
|
const shareDismissal = savedForm && !draft.dismissalSent;
|
|
3991
|
-
|
|
3992
|
-
|
|
4089
|
+
if (shareDismissal) {
|
|
4090
|
+
onSubmit?.(trimmed, {
|
|
4091
|
+
runtimeText: `I'd like to keep chatting without sharing the requested details for now. Please don't ask for them again unless I choose to proceed with something that needs them.
|
|
3993
4092
|
|
|
3994
|
-
${trimmed}`
|
|
3995
|
-
|
|
4093
|
+
${trimmed}`
|
|
4094
|
+
});
|
|
4095
|
+
} else {
|
|
4096
|
+
onSubmit?.(trimmed);
|
|
4097
|
+
}
|
|
3996
4098
|
if (shareDismissal)
|
|
3997
4099
|
setDraft((current) => ({ ...current, dismissalSent: true }));
|
|
3998
4100
|
setValue("");
|
|
@@ -4009,7 +4111,9 @@ ${trimmed}` : trimmed
|
|
|
4009
4111
|
if (control instanceof HTMLElement) control.focus();
|
|
4010
4112
|
return;
|
|
4011
4113
|
}
|
|
4012
|
-
onSubmit?.(
|
|
4114
|
+
onSubmit?.("", {
|
|
4115
|
+
runtimeText: formatComposerFormMessage(activeForm, draft.values)
|
|
4116
|
+
});
|
|
4013
4117
|
setDraft((current) => ({
|
|
4014
4118
|
...current,
|
|
4015
4119
|
values: emptyValues(activeForm),
|
|
@@ -4273,25 +4377,11 @@ function SearchReferences({
|
|
|
4273
4377
|
});
|
|
4274
4378
|
if (!sources.length && !actions.length) return null;
|
|
4275
4379
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "search-references", children: [
|
|
4276
|
-
sources.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("
|
|
4277
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("
|
|
4278
|
-
"Sources",
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
{
|
|
4282
|
-
viewBox: "0 0 24 24",
|
|
4283
|
-
width: "14",
|
|
4284
|
-
height: "14",
|
|
4285
|
-
fill: "none",
|
|
4286
|
-
stroke: "currentColor",
|
|
4287
|
-
strokeWidth: "1.75",
|
|
4288
|
-
"aria-hidden": "true",
|
|
4289
|
-
children: [
|
|
4290
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "12", cy: "12", r: "9" }),
|
|
4291
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 11v6M12 7v1" })
|
|
4292
|
-
]
|
|
4293
|
-
}
|
|
4294
|
-
) })
|
|
4380
|
+
sources.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "search-references__disclosure", "aria-label": "Sources", children: [
|
|
4381
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("summary", { className: "search-references__heading", children: [
|
|
4382
|
+
"Sources (",
|
|
4383
|
+
sources.length,
|
|
4384
|
+
")"
|
|
4295
4385
|
] }),
|
|
4296
4386
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "search-references__list", children: sources.map((source) => {
|
|
4297
4387
|
const content = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
@@ -4369,7 +4459,23 @@ function calendarCells(year, month) {
|
|
|
4369
4459
|
function BookingCardLoader() {
|
|
4370
4460
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("section", { className: "booking-card", "aria-label": "Book a meeting", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "booking-card__loading", role: "status", children: "Finding available times\u2026" }) });
|
|
4371
4461
|
}
|
|
4372
|
-
function BookingCard({
|
|
4462
|
+
function BookingCard(props) {
|
|
4463
|
+
if (!props.readOnly) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(InteractiveBookingCard, { ...props });
|
|
4464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "booking-card", "aria-label": "Recorded available times", children: [
|
|
4465
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "booking-card__title", children: "Available times offered" }),
|
|
4466
|
+
props.offer.slots.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { children: props.offer.slots.map((slot, index) => {
|
|
4467
|
+
const eventType = props.offer.eventTypes.find(
|
|
4468
|
+
(item) => item.uri === slot.eventTypeUri
|
|
4469
|
+
);
|
|
4470
|
+
const label = Number.isFinite(Date.parse(slot.startTime)) ? formatSlotLabel(slot.startTime) : "Time unavailable";
|
|
4471
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
4472
|
+
eventType ? `${eventType.name} \xB7 ` : "",
|
|
4473
|
+
label
|
|
4474
|
+
] }, `${slot.eventTypeUri ?? ""}:${slot.startTime}:${index}`);
|
|
4475
|
+
}) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: "No available times were recorded." })
|
|
4476
|
+
] });
|
|
4477
|
+
}
|
|
4478
|
+
function InteractiveBookingCard({
|
|
4373
4479
|
disabled = false,
|
|
4374
4480
|
offer,
|
|
4375
4481
|
onBook
|
|
@@ -4735,6 +4841,7 @@ function MessageBubble({
|
|
|
4735
4841
|
message,
|
|
4736
4842
|
brandLogoUrl,
|
|
4737
4843
|
bookingDisabled = false,
|
|
4844
|
+
bookingReadOnly = false,
|
|
4738
4845
|
offer,
|
|
4739
4846
|
onBook
|
|
4740
4847
|
}) {
|
|
@@ -4752,6 +4859,7 @@ function MessageBubble({
|
|
|
4752
4859
|
offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
|
|
4753
4860
|
);
|
|
4754
4861
|
if (message.role === "visitor") {
|
|
4862
|
+
if (!message.text.trim()) return null;
|
|
4755
4863
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "message-bubble__text", children: message.text }) });
|
|
4756
4864
|
}
|
|
4757
4865
|
const citations = message.citations ?? [];
|
|
@@ -4770,8 +4878,8 @@ function MessageBubble({
|
|
|
4770
4878
|
children: displayText
|
|
4771
4879
|
}
|
|
4772
4880
|
),
|
|
4773
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchReferences, { results: message.searchResults ?? [] }),
|
|
4774
|
-
citations.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: "message-bubble__sources", "aria-label": "Sources", children: citations.map((citation) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("a", { href: citation.url, target: "_blank", rel: "noreferrer", children: [
|
|
4881
|
+
!isStreaming ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchReferences, { results: message.searchResults ?? [] }) : null,
|
|
4882
|
+
!isStreaming && citations.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: "message-bubble__sources", "aria-label": "Sources", children: citations.map((citation) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("a", { href: citation.url, target: "_blank", rel: "noreferrer", children: [
|
|
4775
4883
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4776
4884
|
"span",
|
|
4777
4885
|
{
|
|
@@ -4783,6 +4891,7 @@ function MessageBubble({
|
|
|
4783
4891
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: citation.label })
|
|
4784
4892
|
] }) }, citation.id)) }) : null
|
|
4785
4893
|
] });
|
|
4894
|
+
if (!displayText && !message.searchResults?.length && offers.length === 0) return null;
|
|
4786
4895
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
|
|
4787
4896
|
displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__agent-row", children: [
|
|
4788
4897
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -4801,6 +4910,7 @@ function MessageBubble({
|
|
|
4801
4910
|
BookingCard,
|
|
4802
4911
|
{
|
|
4803
4912
|
disabled: bookingDisabled,
|
|
4913
|
+
readOnly: bookingReadOnly,
|
|
4804
4914
|
offer: nextOffer,
|
|
4805
4915
|
onBook
|
|
4806
4916
|
},
|
|
@@ -5959,6 +6069,7 @@ function CollectionResultCard({
|
|
|
5959
6069
|
{
|
|
5960
6070
|
className: `collection-result-card tool-result-card tool-result-card--${result.status}`,
|
|
5961
6071
|
"aria-label": result.title,
|
|
6072
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
5962
6073
|
children: [
|
|
5963
6074
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
5964
6075
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -5983,31 +6094,44 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
|
5983
6094
|
function EntityResultCard({
|
|
5984
6095
|
result
|
|
5985
6096
|
}) {
|
|
6097
|
+
const compact = !result.description && !result.details?.length && !result.links?.length;
|
|
6098
|
+
const collapsible = result.status === "completed" && Boolean(result.details?.length) && !result.links?.length;
|
|
6099
|
+
const heading = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "tool-result-card__heading", children: [
|
|
6100
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6101
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
|
|
6102
|
+
] });
|
|
6103
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
6104
|
+
result.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: result.description }) : null,
|
|
6105
|
+
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
6106
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
|
|
6107
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
|
|
6108
|
+
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6109
|
+
result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
6110
|
+
"a",
|
|
6111
|
+
{
|
|
6112
|
+
href: link.href,
|
|
6113
|
+
target: "_blank",
|
|
6114
|
+
rel: "noreferrer",
|
|
6115
|
+
children: link.label
|
|
6116
|
+
},
|
|
6117
|
+
link.href
|
|
6118
|
+
)) }) : null
|
|
6119
|
+
] });
|
|
6120
|
+
if (collapsible) {
|
|
6121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("details", { className: "entity-result-card tool-result-card entity-result-card--disclosure", children: [
|
|
6122
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("summary", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { role: "status", children: heading }) }),
|
|
6123
|
+
content
|
|
6124
|
+
] });
|
|
6125
|
+
}
|
|
5986
6126
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
5987
6127
|
"section",
|
|
5988
6128
|
{
|
|
5989
|
-
className: `entity-result-card tool-result-card tool-result-card--${result.status}`,
|
|
6129
|
+
className: `entity-result-card tool-result-card tool-result-card--${result.status}${compact ? " entity-result-card--compact" : ""}`,
|
|
5990
6130
|
"aria-label": result.title,
|
|
6131
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
5991
6132
|
children: [
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
|
|
5995
|
-
] }),
|
|
5996
|
-
result.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: result.description }) : null,
|
|
5997
|
-
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
5998
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
|
|
5999
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
|
|
6000
|
-
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6001
|
-
result.links?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "tool-result-card__links", children: result.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
6002
|
-
"a",
|
|
6003
|
-
{
|
|
6004
|
-
href: link.href,
|
|
6005
|
-
target: "_blank",
|
|
6006
|
-
rel: "noreferrer",
|
|
6007
|
-
children: link.label
|
|
6008
|
-
},
|
|
6009
|
-
link.href
|
|
6010
|
-
)) }) : null
|
|
6133
|
+
heading,
|
|
6134
|
+
content
|
|
6011
6135
|
]
|
|
6012
6136
|
}
|
|
6013
6137
|
);
|
|
@@ -6056,6 +6180,7 @@ function ToolResultCard({
|
|
|
6056
6180
|
{
|
|
6057
6181
|
className: `tool-result-card tool-result-card--${result.status}`,
|
|
6058
6182
|
"aria-label": result.title,
|
|
6183
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
6059
6184
|
children: [
|
|
6060
6185
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
6061
6186
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -6219,6 +6344,9 @@ function AgentRail({
|
|
|
6219
6344
|
const railRef = (0, import_react14.useRef)(null);
|
|
6220
6345
|
const overlayRef = (0, import_react14.useRef)(null);
|
|
6221
6346
|
const transcriptRef = (0, import_react14.useRef)(null);
|
|
6347
|
+
const responseRef = (0, import_react14.useRef)(null);
|
|
6348
|
+
const threadRef = (0, import_react14.useRef)(null);
|
|
6349
|
+
const lastScrolledVisitorIdRef = (0, import_react14.useRef)(void 0);
|
|
6222
6350
|
const pinnedToBottomRef = (0, import_react14.useRef)(true);
|
|
6223
6351
|
const smoothScrollToLatestRef = (0, import_react14.useRef)(false);
|
|
6224
6352
|
const lockedTranscriptScrollTopRef = (0, import_react14.useRef)(null);
|
|
@@ -6242,7 +6370,7 @@ function AgentRail({
|
|
|
6242
6370
|
const activeVisitorToolInput = [...visitorToolResults].reverse().find((result) => result.kind === "input");
|
|
6243
6371
|
const visibleVisitorToolResults = activeVisitorToolInput ? [activeVisitorToolInput] : visitorToolResults;
|
|
6244
6372
|
const activityActive = state.toolSteps.some((step) => step.state === "active");
|
|
6245
|
-
const showActivity = state.toolSteps.length > 0 &&
|
|
6373
|
+
const showActivity = state.toolSteps.length > 0 && pendingInputRequests.length === 0 && !state.pendingOffer && activityActive;
|
|
6246
6374
|
const hasVisitorMessages2 = state.messages.some(
|
|
6247
6375
|
(message) => message.role === "visitor"
|
|
6248
6376
|
);
|
|
@@ -6271,7 +6399,7 @@ function AgentRail({
|
|
|
6271
6399
|
}
|
|
6272
6400
|
}
|
|
6273
6401
|
const lastIsAgent = lastMessage?.role === "agent";
|
|
6274
|
-
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2;
|
|
6402
|
+
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
6275
6403
|
const streamingMessage = state.phase === "streaming" && state.streamingText && !lastIsAgent ? {
|
|
6276
6404
|
createdAt: 0,
|
|
6277
6405
|
id: "streaming-response",
|
|
@@ -6301,15 +6429,21 @@ function AgentRail({
|
|
|
6301
6429
|
hasPendingConfirmation,
|
|
6302
6430
|
enabled: lastIsAgent && !isBusy
|
|
6303
6431
|
});
|
|
6432
|
+
const latestResultId = [
|
|
6433
|
+
...visibleMessages.flatMap(
|
|
6434
|
+
(message) => message.role === "agent" ? message.toolResults ?? [] : []
|
|
6435
|
+
),
|
|
6436
|
+
...visibleVisitorToolResults
|
|
6437
|
+
].reverse().find((result) => result.kind !== "input")?.id;
|
|
6304
6438
|
const receiptSteps = answerReceipt && state.toolSteps.length > 0 ? state.toolSteps : void 0;
|
|
6305
6439
|
(0, import_react14.useEffect)(() => {
|
|
6306
6440
|
if (state.phase !== "complete") {
|
|
6307
6441
|
setReceiptOpen(false);
|
|
6308
6442
|
}
|
|
6309
6443
|
}, [state.phase]);
|
|
6310
|
-
function handleSubmit(message) {
|
|
6444
|
+
function handleSubmit(message, options) {
|
|
6311
6445
|
setReceiptOpen(false);
|
|
6312
|
-
onSubmit?.(message);
|
|
6446
|
+
onSubmit?.(message, options);
|
|
6313
6447
|
}
|
|
6314
6448
|
function handleRegenerate() {
|
|
6315
6449
|
setReceiptOpen(false);
|
|
@@ -6323,15 +6457,31 @@ function AgentRail({
|
|
|
6323
6457
|
setReceiptOpen(false);
|
|
6324
6458
|
onFollowUpSelect?.(label);
|
|
6325
6459
|
}
|
|
6460
|
+
const latestVisitorId = visibleMessages[lastVisitorIndex]?.id;
|
|
6326
6461
|
(0, import_react14.useEffect)(() => {
|
|
6327
6462
|
const node = transcriptRef.current;
|
|
6328
6463
|
if (!node) return;
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
node.scrollTop = node.scrollHeight;
|
|
6464
|
+
if (latestVisitorId !== lastScrolledVisitorIdRef.current) {
|
|
6465
|
+
lastScrolledVisitorIdRef.current = latestVisitorId;
|
|
6466
|
+
pinnedToBottomRef.current = true;
|
|
6333
6467
|
}
|
|
6468
|
+
const followResponse = () => {
|
|
6469
|
+
if (node.clientHeight === 0 || !pinnedToBottomRef.current) return;
|
|
6470
|
+
const bottom = Math.max(0, node.scrollHeight - node.clientHeight);
|
|
6471
|
+
const response = responseRef.current;
|
|
6472
|
+
const responseTop = response ? node.scrollTop + response.getBoundingClientRect().top - node.getBoundingClientRect().top : bottom;
|
|
6473
|
+
node.scrollTop = Math.max(node.scrollTop, Math.min(bottom, responseTop));
|
|
6474
|
+
const pinned = bottom - node.scrollTop < 48;
|
|
6475
|
+
pinnedToBottomRef.current = pinned;
|
|
6476
|
+
setShowJumpToLatest(!pinned);
|
|
6477
|
+
};
|
|
6478
|
+
followResponse();
|
|
6479
|
+
const observer = new ResizeObserver(followResponse);
|
|
6480
|
+
observer.observe(node);
|
|
6481
|
+
if (threadRef.current) observer.observe(threadRef.current);
|
|
6482
|
+
return () => observer.disconnect();
|
|
6334
6483
|
}, [
|
|
6484
|
+
latestVisitorId,
|
|
6335
6485
|
state.messages,
|
|
6336
6486
|
state.toolSteps,
|
|
6337
6487
|
state.streamingText,
|
|
@@ -6352,18 +6502,6 @@ function AgentRail({
|
|
|
6352
6502
|
handleScroll();
|
|
6353
6503
|
return () => node.removeEventListener("scroll", handleScroll);
|
|
6354
6504
|
}, []);
|
|
6355
|
-
(0, import_react14.useEffect)(() => {
|
|
6356
|
-
const node = transcriptRef.current;
|
|
6357
|
-
if (!node) return;
|
|
6358
|
-
const observer = new ResizeObserver(() => {
|
|
6359
|
-
if (node.clientHeight === 0) return;
|
|
6360
|
-
if (pinnedToBottomRef.current) {
|
|
6361
|
-
node.scrollTo({ top: node.scrollHeight, behavior: "instant" });
|
|
6362
|
-
}
|
|
6363
|
-
});
|
|
6364
|
-
observer.observe(node);
|
|
6365
|
-
return () => observer.disconnect();
|
|
6366
|
-
}, []);
|
|
6367
6505
|
(0, import_react14.useEffect)(() => {
|
|
6368
6506
|
if (!receiptOpen) {
|
|
6369
6507
|
lockedTranscriptScrollTopRef.current = null;
|
|
@@ -6480,7 +6618,7 @@ function AgentRail({
|
|
|
6480
6618
|
) : null
|
|
6481
6619
|
] })
|
|
6482
6620
|
] }) }),
|
|
6483
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "agent-rail__thread", children: [
|
|
6621
|
+
/* @__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: [
|
|
6484
6622
|
!hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
6485
6623
|
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6486
6624
|
MessageBubble,
|
|
@@ -6527,59 +6665,68 @@ function AgentRail({
|
|
|
6527
6665
|
request.requestId
|
|
6528
6666
|
))
|
|
6529
6667
|
] }) : null,
|
|
6530
|
-
visibleMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6668
|
+
visibleMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
6669
|
+
"div",
|
|
6670
|
+
{
|
|
6671
|
+
ref: index === lastVisitorIndex + 1 ? responseRef : void 0,
|
|
6672
|
+
className: "agent-rail__turn-block",
|
|
6673
|
+
children: [
|
|
6674
|
+
message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VisitorToolResultView, { result }, result.id)) : null,
|
|
6675
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6676
|
+
MessageBubble,
|
|
6677
|
+
{
|
|
6678
|
+
message,
|
|
6679
|
+
bookingDisabled: isBusy,
|
|
6680
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
6681
|
+
offer: index === lastAgentIndex ? state.pendingOffer : void 0,
|
|
6682
|
+
onBook
|
|
6683
|
+
}
|
|
6684
|
+
),
|
|
6685
|
+
index === lastAgentIndex && showMessageActions && message.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6686
|
+
MessageActions,
|
|
6687
|
+
{
|
|
6688
|
+
answeredAt: message.createdAt,
|
|
6689
|
+
copyText: hideToolCardFences(message.text).trim() || message.text,
|
|
6690
|
+
readAloud,
|
|
6691
|
+
receiptSteps,
|
|
6692
|
+
onOpenReceipt: receiptSteps ? openReceipt : void 0,
|
|
6693
|
+
onRegenerate: onRegenerate ? handleRegenerate : void 0,
|
|
6694
|
+
onFeedback: onFeedback ? (rating) => onFeedback(rating, message) : void 0
|
|
6695
|
+
}
|
|
6696
|
+
) : null,
|
|
6697
|
+
index === lastVisitorIndex ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
6698
|
+
showActivity ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6699
|
+
AgentActivityBubble,
|
|
6700
|
+
{
|
|
6701
|
+
brandLabel: resolvedBrandLabel,
|
|
6702
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
6703
|
+
failed: state.phase === "error",
|
|
6704
|
+
steps: state.toolSteps
|
|
6705
|
+
}
|
|
6706
|
+
) : null,
|
|
6707
|
+
visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6708
|
+
VisitorToolResultView,
|
|
6709
|
+
{
|
|
6710
|
+
result,
|
|
6711
|
+
disabled: semanticSurfaceDisabled,
|
|
6712
|
+
onToolInput
|
|
6713
|
+
},
|
|
6714
|
+
result.id
|
|
6715
|
+
)),
|
|
6716
|
+
pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6717
|
+
HumanInputCard,
|
|
6718
|
+
{
|
|
6719
|
+
request,
|
|
6720
|
+
onRespond: onInputResponse
|
|
6721
|
+
},
|
|
6722
|
+
request.requestId
|
|
6723
|
+
))
|
|
6724
|
+
] }) : null
|
|
6725
|
+
]
|
|
6726
|
+
},
|
|
6727
|
+
message.id
|
|
6728
|
+
)),
|
|
6729
|
+
streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: responseRef, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6583
6730
|
MessageBubble,
|
|
6584
6731
|
{
|
|
6585
6732
|
message: streamingMessage,
|
|
@@ -6588,7 +6735,7 @@ function AgentRail({
|
|
|
6588
6735
|
offer: state.pendingOffer,
|
|
6589
6736
|
onBook
|
|
6590
6737
|
}
|
|
6591
|
-
) : null,
|
|
6738
|
+
) }) : null,
|
|
6592
6739
|
waitingForBooking ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BookingCardLoader, {}) : null,
|
|
6593
6740
|
state.error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
|
|
6594
6741
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
@@ -6629,7 +6776,7 @@ function AgentRail({
|
|
|
6629
6776
|
placeholder: composerPlaceholder,
|
|
6630
6777
|
onSubmit: handleSubmit
|
|
6631
6778
|
},
|
|
6632
|
-
state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
|
|
6779
|
+
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
6633
6780
|
),
|
|
6634
6781
|
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
|
|
6635
6782
|
] })
|
|
@@ -6997,9 +7144,9 @@ function AgentWidget({
|
|
|
6997
7144
|
});
|
|
6998
7145
|
return () => unregisterAgentPanelController(customerId);
|
|
6999
7146
|
}, [customerId, registerPanelController, reset, submit]);
|
|
7000
|
-
async function handleSubmit(message) {
|
|
7147
|
+
async function handleSubmit(message, options) {
|
|
7001
7148
|
if (isMobile) setRailCollapsed(false);
|
|
7002
|
-
await submit(message);
|
|
7149
|
+
await submit(message, options);
|
|
7003
7150
|
}
|
|
7004
7151
|
function handleFeedback(rating, message) {
|
|
7005
7152
|
if (!analytics) return;
|