@webless/agent 0.9.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 +6 -0
- package/dist/{chunk-QMTI5646.js → chunk-3E632FNE.js} +332 -203
- package/dist/chunk-3E632FNE.js.map +1 -0
- package/dist/{chunk-5BCSXCLT.js → chunk-TCO62TRN.js} +40 -2
- package/dist/chunk-TCO62TRN.js.map +1 -0
- package/dist/embed.cjs +754 -625
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.css +60 -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 +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +43 -4
- 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 +79 -67
- package/dist/presentation.cjs.map +1 -1
- package/dist/presentation.d.cts +1 -1
- package/dist/presentation.d.ts +1 -1
- package/dist/presentation.js +7 -3
- package/dist/presentation.js.map +1 -1
- package/dist/react.cjs +756 -625
- package/dist/react.cjs.map +1 -1
- package/dist/react.css +60 -10
- package/dist/react.css.map +1 -1
- package/dist/react.d.cts +3 -3
- package/dist/react.d.ts +3 -3
- package/dist/react.js +3 -1
- package/dist/react.js.map +1 -1
- package/dist/{types-ohWeTG9i.d.cts → types-sLEIYDqm.d.cts} +1 -1
- package/dist/{types-ohWeTG9i.d.ts → types-sLEIYDqm.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-5BCSXCLT.js.map +0 -1
- package/dist/chunk-QMTI5646.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
|
}
|
|
@@ -383,457 +706,250 @@ function loadPersistedAgentSession(visitorSessionId, options) {
|
|
|
383
706
|
}
|
|
384
707
|
function savePersistedAgentSession(visitorSessionId, sessionId, streamIndex, options) {
|
|
385
708
|
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !sessionId.trim()) {
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
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)
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const prefix = resolvePrefix(options);
|
|
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: [
|
|
@@ -4769,6 +4859,7 @@ function MessageBubble({
|
|
|
4769
4859
|
offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
|
|
4770
4860
|
);
|
|
4771
4861
|
if (message.role === "visitor") {
|
|
4862
|
+
if (!message.text.trim()) return null;
|
|
4772
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 }) });
|
|
4773
4864
|
}
|
|
4774
4865
|
const citations = message.citations ?? [];
|
|
@@ -4787,8 +4878,8 @@ function MessageBubble({
|
|
|
4787
4878
|
children: displayText
|
|
4788
4879
|
}
|
|
4789
4880
|
),
|
|
4790
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchReferences, { results: message.searchResults ?? [] }),
|
|
4791
|
-
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: [
|
|
4792
4883
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4793
4884
|
"span",
|
|
4794
4885
|
{
|
|
@@ -4800,6 +4891,7 @@ function MessageBubble({
|
|
|
4800
4891
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: citation.label })
|
|
4801
4892
|
] }) }, citation.id)) }) : null
|
|
4802
4893
|
] });
|
|
4894
|
+
if (!displayText && !message.searchResults?.length && offers.length === 0) return null;
|
|
4803
4895
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
|
|
4804
4896
|
displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__agent-row", children: [
|
|
4805
4897
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -5977,6 +6069,7 @@ function CollectionResultCard({
|
|
|
5977
6069
|
{
|
|
5978
6070
|
className: `collection-result-card tool-result-card tool-result-card--${result.status}`,
|
|
5979
6071
|
"aria-label": result.title,
|
|
6072
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
5980
6073
|
children: [
|
|
5981
6074
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
5982
6075
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -6001,31 +6094,44 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
|
6001
6094
|
function EntityResultCard({
|
|
6002
6095
|
result
|
|
6003
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
|
+
}
|
|
6004
6126
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
6005
6127
|
"section",
|
|
6006
6128
|
{
|
|
6007
|
-
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" : ""}`,
|
|
6008
6130
|
"aria-label": result.title,
|
|
6131
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
6009
6132
|
children: [
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
|
|
6013
|
-
] }),
|
|
6014
|
-
result.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: result.description }) : null,
|
|
6015
|
-
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
6016
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
|
|
6017
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
|
|
6018
|
-
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6019
|
-
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)(
|
|
6020
|
-
"a",
|
|
6021
|
-
{
|
|
6022
|
-
href: link.href,
|
|
6023
|
-
target: "_blank",
|
|
6024
|
-
rel: "noreferrer",
|
|
6025
|
-
children: link.label
|
|
6026
|
-
},
|
|
6027
|
-
link.href
|
|
6028
|
-
)) }) : null
|
|
6133
|
+
heading,
|
|
6134
|
+
content
|
|
6029
6135
|
]
|
|
6030
6136
|
}
|
|
6031
6137
|
);
|
|
@@ -6074,6 +6180,7 @@ function ToolResultCard({
|
|
|
6074
6180
|
{
|
|
6075
6181
|
className: `tool-result-card tool-result-card--${result.status}`,
|
|
6076
6182
|
"aria-label": result.title,
|
|
6183
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
6077
6184
|
children: [
|
|
6078
6185
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
6079
6186
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -6237,6 +6344,9 @@ function AgentRail({
|
|
|
6237
6344
|
const railRef = (0, import_react14.useRef)(null);
|
|
6238
6345
|
const overlayRef = (0, import_react14.useRef)(null);
|
|
6239
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);
|
|
6240
6350
|
const pinnedToBottomRef = (0, import_react14.useRef)(true);
|
|
6241
6351
|
const smoothScrollToLatestRef = (0, import_react14.useRef)(false);
|
|
6242
6352
|
const lockedTranscriptScrollTopRef = (0, import_react14.useRef)(null);
|
|
@@ -6260,7 +6370,7 @@ function AgentRail({
|
|
|
6260
6370
|
const activeVisitorToolInput = [...visitorToolResults].reverse().find((result) => result.kind === "input");
|
|
6261
6371
|
const visibleVisitorToolResults = activeVisitorToolInput ? [activeVisitorToolInput] : visitorToolResults;
|
|
6262
6372
|
const activityActive = state.toolSteps.some((step) => step.state === "active");
|
|
6263
|
-
const showActivity = state.toolSteps.length > 0 &&
|
|
6373
|
+
const showActivity = state.toolSteps.length > 0 && pendingInputRequests.length === 0 && !state.pendingOffer && activityActive;
|
|
6264
6374
|
const hasVisitorMessages2 = state.messages.some(
|
|
6265
6375
|
(message) => message.role === "visitor"
|
|
6266
6376
|
);
|
|
@@ -6289,7 +6399,7 @@ function AgentRail({
|
|
|
6289
6399
|
}
|
|
6290
6400
|
}
|
|
6291
6401
|
const lastIsAgent = lastMessage?.role === "agent";
|
|
6292
|
-
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2;
|
|
6402
|
+
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
6293
6403
|
const streamingMessage = state.phase === "streaming" && state.streamingText && !lastIsAgent ? {
|
|
6294
6404
|
createdAt: 0,
|
|
6295
6405
|
id: "streaming-response",
|
|
@@ -6319,15 +6429,21 @@ function AgentRail({
|
|
|
6319
6429
|
hasPendingConfirmation,
|
|
6320
6430
|
enabled: lastIsAgent && !isBusy
|
|
6321
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;
|
|
6322
6438
|
const receiptSteps = answerReceipt && state.toolSteps.length > 0 ? state.toolSteps : void 0;
|
|
6323
6439
|
(0, import_react14.useEffect)(() => {
|
|
6324
6440
|
if (state.phase !== "complete") {
|
|
6325
6441
|
setReceiptOpen(false);
|
|
6326
6442
|
}
|
|
6327
6443
|
}, [state.phase]);
|
|
6328
|
-
function handleSubmit(message) {
|
|
6444
|
+
function handleSubmit(message, options) {
|
|
6329
6445
|
setReceiptOpen(false);
|
|
6330
|
-
onSubmit?.(message);
|
|
6446
|
+
onSubmit?.(message, options);
|
|
6331
6447
|
}
|
|
6332
6448
|
function handleRegenerate() {
|
|
6333
6449
|
setReceiptOpen(false);
|
|
@@ -6341,15 +6457,31 @@ function AgentRail({
|
|
|
6341
6457
|
setReceiptOpen(false);
|
|
6342
6458
|
onFollowUpSelect?.(label);
|
|
6343
6459
|
}
|
|
6460
|
+
const latestVisitorId = visibleMessages[lastVisitorIndex]?.id;
|
|
6344
6461
|
(0, import_react14.useEffect)(() => {
|
|
6345
6462
|
const node = transcriptRef.current;
|
|
6346
6463
|
if (!node) return;
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
node.scrollTop = node.scrollHeight;
|
|
6464
|
+
if (latestVisitorId !== lastScrolledVisitorIdRef.current) {
|
|
6465
|
+
lastScrolledVisitorIdRef.current = latestVisitorId;
|
|
6466
|
+
pinnedToBottomRef.current = true;
|
|
6351
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();
|
|
6352
6483
|
}, [
|
|
6484
|
+
latestVisitorId,
|
|
6353
6485
|
state.messages,
|
|
6354
6486
|
state.toolSteps,
|
|
6355
6487
|
state.streamingText,
|
|
@@ -6370,18 +6502,6 @@ function AgentRail({
|
|
|
6370
6502
|
handleScroll();
|
|
6371
6503
|
return () => node.removeEventListener("scroll", handleScroll);
|
|
6372
6504
|
}, []);
|
|
6373
|
-
(0, import_react14.useEffect)(() => {
|
|
6374
|
-
const node = transcriptRef.current;
|
|
6375
|
-
if (!node) return;
|
|
6376
|
-
const observer = new ResizeObserver(() => {
|
|
6377
|
-
if (node.clientHeight === 0) return;
|
|
6378
|
-
if (pinnedToBottomRef.current) {
|
|
6379
|
-
node.scrollTo({ top: node.scrollHeight, behavior: "instant" });
|
|
6380
|
-
}
|
|
6381
|
-
});
|
|
6382
|
-
observer.observe(node);
|
|
6383
|
-
return () => observer.disconnect();
|
|
6384
|
-
}, []);
|
|
6385
6505
|
(0, import_react14.useEffect)(() => {
|
|
6386
6506
|
if (!receiptOpen) {
|
|
6387
6507
|
lockedTranscriptScrollTopRef.current = null;
|
|
@@ -6498,7 +6618,7 @@ function AgentRail({
|
|
|
6498
6618
|
) : null
|
|
6499
6619
|
] })
|
|
6500
6620
|
] }) }),
|
|
6501
|
-
/* @__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: [
|
|
6502
6622
|
!hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
6503
6623
|
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6504
6624
|
MessageBubble,
|
|
@@ -6545,59 +6665,68 @@ function AgentRail({
|
|
|
6545
6665
|
request.requestId
|
|
6546
6666
|
))
|
|
6547
6667
|
] }) : null,
|
|
6548
|
-
visibleMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
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
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
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)(
|
|
6601
6730
|
MessageBubble,
|
|
6602
6731
|
{
|
|
6603
6732
|
message: streamingMessage,
|
|
@@ -6606,7 +6735,7 @@ function AgentRail({
|
|
|
6606
6735
|
offer: state.pendingOffer,
|
|
6607
6736
|
onBook
|
|
6608
6737
|
}
|
|
6609
|
-
) : null,
|
|
6738
|
+
) }) : null,
|
|
6610
6739
|
waitingForBooking ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BookingCardLoader, {}) : null,
|
|
6611
6740
|
state.error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
|
|
6612
6741
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
@@ -6647,7 +6776,7 @@ function AgentRail({
|
|
|
6647
6776
|
placeholder: composerPlaceholder,
|
|
6648
6777
|
onSubmit: handleSubmit
|
|
6649
6778
|
},
|
|
6650
|
-
state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
|
|
6779
|
+
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
6651
6780
|
),
|
|
6652
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
|
|
6653
6782
|
] })
|
|
@@ -7015,9 +7144,9 @@ function AgentWidget({
|
|
|
7015
7144
|
});
|
|
7016
7145
|
return () => unregisterAgentPanelController(customerId);
|
|
7017
7146
|
}, [customerId, registerPanelController, reset, submit]);
|
|
7018
|
-
async function handleSubmit(message) {
|
|
7147
|
+
async function handleSubmit(message, options) {
|
|
7019
7148
|
if (isMobile) setRailCollapsed(false);
|
|
7020
|
-
await submit(message);
|
|
7149
|
+
await submit(message, options);
|
|
7021
7150
|
}
|
|
7022
7151
|
function handleFeedback(rating, message) {
|
|
7023
7152
|
if (!analytics) return;
|