@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/react.cjs
CHANGED
|
@@ -131,6 +131,329 @@ function usePageShift(input) {
|
|
|
131
131
|
// src/react/hooks/useAgentChat.ts
|
|
132
132
|
var import_react2 = require("react");
|
|
133
133
|
|
|
134
|
+
// src/runtime/tool-ui.ts
|
|
135
|
+
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
136
|
+
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
137
|
+
var AGENT_STRUCTURED_TOOL_INPUT_HEADER = "Webless-Structured-Tool-Input-JSON:";
|
|
138
|
+
function formatAgentStructuredToolInput(surface, values) {
|
|
139
|
+
const payload = {
|
|
140
|
+
schemaVersion: AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION,
|
|
141
|
+
toolSlug: surface.toolSlug,
|
|
142
|
+
...surface.operationId ? { operationId: surface.operationId } : {},
|
|
143
|
+
values
|
|
144
|
+
};
|
|
145
|
+
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
146
|
+
}
|
|
147
|
+
function isRecord(value) {
|
|
148
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
149
|
+
}
|
|
150
|
+
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
151
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
155
|
+
if (typeof value !== "object") return false;
|
|
156
|
+
if (seen.has(value)) return false;
|
|
157
|
+
seen.add(value);
|
|
158
|
+
const valid = Array.isArray(value) ? value.every((item) => isJsonValue(item, seen)) : Object.entries(value).every(
|
|
159
|
+
([key, item]) => typeof key === "string" && isJsonValue(item, seen)
|
|
160
|
+
);
|
|
161
|
+
seen.delete(value);
|
|
162
|
+
return valid;
|
|
163
|
+
}
|
|
164
|
+
function boundedString(value, max) {
|
|
165
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.length > max) {
|
|
166
|
+
return void 0;
|
|
167
|
+
}
|
|
168
|
+
return value.trim();
|
|
169
|
+
}
|
|
170
|
+
function numberValue(value) {
|
|
171
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
172
|
+
}
|
|
173
|
+
function integerValue(value) {
|
|
174
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 8e3 ? value : void 0;
|
|
175
|
+
}
|
|
176
|
+
function isFieldKind(value) {
|
|
177
|
+
return typeof value === "string" && [
|
|
178
|
+
"text",
|
|
179
|
+
"textarea",
|
|
180
|
+
"email",
|
|
181
|
+
"number",
|
|
182
|
+
"select",
|
|
183
|
+
"multi-select",
|
|
184
|
+
"checkbox",
|
|
185
|
+
"confirmation",
|
|
186
|
+
"radio",
|
|
187
|
+
"date",
|
|
188
|
+
"time",
|
|
189
|
+
"date-time",
|
|
190
|
+
"calendar",
|
|
191
|
+
"range",
|
|
192
|
+
"json"
|
|
193
|
+
].includes(value);
|
|
194
|
+
}
|
|
195
|
+
function parseField(value) {
|
|
196
|
+
if (!isRecord(value)) return null;
|
|
197
|
+
if (!hasOnlyKeys(value, [
|
|
198
|
+
"description",
|
|
199
|
+
"kind",
|
|
200
|
+
"label",
|
|
201
|
+
"max",
|
|
202
|
+
"maxItems",
|
|
203
|
+
"maxLength",
|
|
204
|
+
"min",
|
|
205
|
+
"minLength",
|
|
206
|
+
"options",
|
|
207
|
+
"path",
|
|
208
|
+
"placeholder",
|
|
209
|
+
"required",
|
|
210
|
+
"step",
|
|
211
|
+
"defaultValue"
|
|
212
|
+
])) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
if (!isFieldKind(value.kind)) return null;
|
|
216
|
+
const path = boundedString(value.path, 160);
|
|
217
|
+
const label = boundedString(value.label, 160);
|
|
218
|
+
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
219
|
+
const placeholder = value.placeholder === void 0 || typeof value.placeholder !== "string" ? void 0 : value.placeholder;
|
|
220
|
+
const required = value.required === void 0 || typeof value.required !== "boolean" ? void 0 : value.required;
|
|
221
|
+
const min = value.min === void 0 ? void 0 : numberValue(value.min);
|
|
222
|
+
const max = value.max === void 0 ? void 0 : numberValue(value.max);
|
|
223
|
+
const maxItems = value.maxItems === void 0 ? void 0 : integerValue(value.maxItems);
|
|
224
|
+
const step = value.step === void 0 ? void 0 : numberValue(value.step);
|
|
225
|
+
const minLength = value.minLength === void 0 ? void 0 : integerValue(value.minLength);
|
|
226
|
+
const maxLength = value.maxLength === void 0 ? void 0 : integerValue(value.maxLength);
|
|
227
|
+
const defaultValue = value.defaultValue === void 0 || !isJsonValue(value.defaultValue) ? void 0 : value.defaultValue;
|
|
228
|
+
if (!path || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || !label) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
if (value.description !== void 0 && !description) return null;
|
|
232
|
+
if (value.placeholder !== void 0 && placeholder === void 0) return null;
|
|
233
|
+
if (value.required !== void 0 && required === void 0) return null;
|
|
234
|
+
if (value.min !== void 0 && min === void 0) return null;
|
|
235
|
+
if (value.max !== void 0 && max === void 0) return null;
|
|
236
|
+
if (value.maxItems !== void 0 && (maxItems === void 0 || maxItems < 1 || maxItems > 100))
|
|
237
|
+
return null;
|
|
238
|
+
if (value.step !== void 0 && step === void 0) return null;
|
|
239
|
+
if (value.minLength !== void 0 && minLength === void 0) return null;
|
|
240
|
+
if (value.maxLength !== void 0 && maxLength === void 0) return null;
|
|
241
|
+
if (value.defaultValue !== void 0 && defaultValue === void 0)
|
|
242
|
+
return null;
|
|
243
|
+
if (value.options !== void 0) {
|
|
244
|
+
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
245
|
+
return null;
|
|
246
|
+
for (const option of value.options) {
|
|
247
|
+
if (!isRecord(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
kind: value.kind,
|
|
254
|
+
path,
|
|
255
|
+
label,
|
|
256
|
+
...description ? { description } : {},
|
|
257
|
+
...placeholder !== void 0 ? { placeholder } : {},
|
|
258
|
+
...required !== void 0 ? { required } : {},
|
|
259
|
+
...defaultValue !== void 0 ? { defaultValue } : {},
|
|
260
|
+
...value.options !== void 0 ? { options: value.options } : {},
|
|
261
|
+
...min !== void 0 ? { min } : {},
|
|
262
|
+
...max !== void 0 ? { max } : {},
|
|
263
|
+
...maxItems !== void 0 ? { maxItems } : {},
|
|
264
|
+
...step !== void 0 ? { step } : {},
|
|
265
|
+
...minLength !== void 0 ? { minLength } : {},
|
|
266
|
+
...maxLength !== void 0 ? { maxLength } : {}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function parseStep(value) {
|
|
270
|
+
if (!isRecord(value)) return null;
|
|
271
|
+
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
const id = boundedString(value.id, 80);
|
|
275
|
+
const label = boundedString(value.label, 160);
|
|
276
|
+
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
277
|
+
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(
|
|
278
|
+
(path) => typeof path !== "string" || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || path.length > 160
|
|
279
|
+
)) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
id,
|
|
284
|
+
label,
|
|
285
|
+
fieldPaths: value.fieldPaths,
|
|
286
|
+
...description ? { description } : {}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function parseAction(value) {
|
|
290
|
+
if (!isRecord(value)) return null;
|
|
291
|
+
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
292
|
+
const label = boundedString(value.label, 80);
|
|
293
|
+
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
id: value.id,
|
|
298
|
+
label
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function parseAgentToolUiSurface(value) {
|
|
302
|
+
if (!isRecord(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
303
|
+
return null;
|
|
304
|
+
if (!hasOnlyKeys(value, [
|
|
305
|
+
"actions",
|
|
306
|
+
"description",
|
|
307
|
+
"fields",
|
|
308
|
+
"id",
|
|
309
|
+
"operationId",
|
|
310
|
+
"requestId",
|
|
311
|
+
"schemaVersion",
|
|
312
|
+
"steps",
|
|
313
|
+
"submitLabel",
|
|
314
|
+
"title",
|
|
315
|
+
"toolSlug",
|
|
316
|
+
"values"
|
|
317
|
+
])) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
const id = boundedString(value.id, 200);
|
|
321
|
+
const title = boundedString(value.title, 200);
|
|
322
|
+
const toolSlug = boundedString(value.toolSlug, 200);
|
|
323
|
+
const description = value.description === void 0 ? void 0 : boundedString(value.description, 800);
|
|
324
|
+
const operationId = value.operationId === void 0 ? void 0 : boundedString(value.operationId, 200);
|
|
325
|
+
const requestId = value.requestId === void 0 ? void 0 : boundedString(value.requestId, 200);
|
|
326
|
+
const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
|
|
327
|
+
if (!id || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
const fields = value.fields.map(parseField);
|
|
331
|
+
if (fields.some((field) => field === null)) return null;
|
|
332
|
+
const steps = value.steps === void 0 ? void 0 : Array.isArray(value.steps) && value.steps.length <= 8 ? value.steps.map(parseStep) : null;
|
|
333
|
+
if (steps?.some((step) => step === null)) return null;
|
|
334
|
+
const actions = value.actions === void 0 ? void 0 : Array.isArray(value.actions) && value.actions.length <= 8 ? value.actions.map(parseAction) : null;
|
|
335
|
+
if (actions?.some((action) => action === null)) return null;
|
|
336
|
+
if (value.description !== void 0 && !description) return null;
|
|
337
|
+
if (value.operationId !== void 0 && !operationId) return null;
|
|
338
|
+
if (value.requestId !== void 0 && !requestId) return null;
|
|
339
|
+
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
340
|
+
const values = value.values !== void 0 && isRecord(value.values) ? value.values : void 0;
|
|
341
|
+
if (value.values !== void 0) {
|
|
342
|
+
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
schemaVersion: AGENT_TOOL_UI_SCHEMA_VERSION,
|
|
347
|
+
id,
|
|
348
|
+
title,
|
|
349
|
+
toolSlug,
|
|
350
|
+
fields,
|
|
351
|
+
...actions ? { actions } : {},
|
|
352
|
+
...description ? { description } : {},
|
|
353
|
+
...operationId ? { operationId } : {},
|
|
354
|
+
...requestId ? { requestId } : {},
|
|
355
|
+
...submitLabel ? { submitLabel } : {},
|
|
356
|
+
...steps ? { steps } : {},
|
|
357
|
+
...values ? { values } : {}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function hasOnlyKeys(value, allowed) {
|
|
361
|
+
const allowedKeys = new Set(allowed);
|
|
362
|
+
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// src/runtime/tool-result-envelope.ts
|
|
366
|
+
var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
367
|
+
"schemaVersion",
|
|
368
|
+
"output",
|
|
369
|
+
"presentationKinds",
|
|
370
|
+
"ui"
|
|
371
|
+
]);
|
|
372
|
+
function isRecord2(value) {
|
|
373
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
374
|
+
}
|
|
375
|
+
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
376
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
380
|
+
if (typeof value !== "object") return false;
|
|
381
|
+
if (seen.has(value)) return false;
|
|
382
|
+
seen.add(value);
|
|
383
|
+
const valid = Array.isArray(value) ? value.every((item) => isJsonValue2(item, seen)) : Object.entries(value).every(
|
|
384
|
+
([key, item]) => typeof key === "string" && isJsonValue2(item, seen)
|
|
385
|
+
);
|
|
386
|
+
seen.delete(value);
|
|
387
|
+
return valid;
|
|
388
|
+
}
|
|
389
|
+
function decodeEnvelope(value) {
|
|
390
|
+
if (typeof value !== "string") return value;
|
|
391
|
+
try {
|
|
392
|
+
return JSON.parse(value);
|
|
393
|
+
} catch {
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function parseAgentToolResultEnvelope(value) {
|
|
398
|
+
const decoded = decodeEnvelope(value);
|
|
399
|
+
if (!isRecord2(decoded)) return null;
|
|
400
|
+
const keys = Object.keys(decoded);
|
|
401
|
+
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) {
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
const presentationKinds = decoded.presentationKinds.flatMap((kind) => {
|
|
405
|
+
if (typeof kind !== "string") return [];
|
|
406
|
+
const normalized = kind.trim();
|
|
407
|
+
return normalized && normalized.length <= 128 ? [normalized] : [];
|
|
408
|
+
});
|
|
409
|
+
if (presentationKinds.length !== decoded.presentationKinds.length) {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
const ui = decoded.ui === void 0 ? void 0 : parseAgentToolUiSurface(decoded.ui);
|
|
413
|
+
if (decoded.ui !== void 0 && !ui) return null;
|
|
414
|
+
return {
|
|
415
|
+
schemaVersion: "webless.tool-result.v1",
|
|
416
|
+
output: decoded.output,
|
|
417
|
+
presentationKinds,
|
|
418
|
+
...ui ? { ui } : {}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/runtime/connected-tool-work.ts
|
|
423
|
+
var HUBSPOT_ACTION_LABELS = {
|
|
424
|
+
HUBSPOT_LIST_CONTACTS: "Checking your details",
|
|
425
|
+
HUBSPOT_CREATE_CONTACT: "Saving your details",
|
|
426
|
+
HUBSPOT_UPDATE_CONTACT: "Updating your details",
|
|
427
|
+
HUBSPOT_CREATE_COMPANY: "Saving your company details"
|
|
428
|
+
};
|
|
429
|
+
function connectedToolWork(action) {
|
|
430
|
+
const slug = action.toolName === "COMPOSIO_MULTI_EXECUTE_TOOL" ? action.input.toolSlug : action.toolName;
|
|
431
|
+
if (typeof slug !== "string") return null;
|
|
432
|
+
const detail = HUBSPOT_ACTION_LABELS[slug];
|
|
433
|
+
return detail ? {
|
|
434
|
+
id: action.callId,
|
|
435
|
+
kind: "tool",
|
|
436
|
+
label: "Contact details",
|
|
437
|
+
detail,
|
|
438
|
+
state: "active"
|
|
439
|
+
} : null;
|
|
440
|
+
}
|
|
441
|
+
function toolResultFailed(result) {
|
|
442
|
+
if (result.status !== "completed") return true;
|
|
443
|
+
const output = parseAgentToolResultEnvelope(result.output)?.output ?? result.output;
|
|
444
|
+
if (typeof output !== "object" || output === null || Array.isArray(output))
|
|
445
|
+
return false;
|
|
446
|
+
return "error" in output && Boolean(output.error) || "providerError" in output && Boolean(output.providerError);
|
|
447
|
+
}
|
|
448
|
+
function completeConnectedToolWork(item, result) {
|
|
449
|
+
const failed = toolResultFailed(result);
|
|
450
|
+
return {
|
|
451
|
+
...item,
|
|
452
|
+
state: failed ? "error" : "completed",
|
|
453
|
+
detail: failed ? "Action could not be confirmed" : "Action completed"
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
134
457
|
// src/runtime/client.ts
|
|
135
458
|
var import_client2 = require("eve/client");
|
|
136
459
|
|
|
@@ -157,11 +480,11 @@ function localBootstrapOrigins(origin) {
|
|
|
157
480
|
...LOCAL_LOOPBACK_ORIGINS.filter((candidate) => candidate !== normalized)
|
|
158
481
|
];
|
|
159
482
|
}
|
|
160
|
-
function
|
|
483
|
+
function isRecord3(value) {
|
|
161
484
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
162
485
|
}
|
|
163
486
|
function parseBootstrapResponse(value, indexId, now) {
|
|
164
|
-
if (!
|
|
487
|
+
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) {
|
|
165
488
|
throw new Error("Agent Runtime returned an invalid access response.");
|
|
166
489
|
}
|
|
167
490
|
const expiresAt = Date.parse(value.expiresAt);
|
|
@@ -181,7 +504,7 @@ async function readBootstrapError(response) {
|
|
|
181
504
|
const fallback = `Agent Runtime is unavailable (${response.status}).`;
|
|
182
505
|
try {
|
|
183
506
|
const value = await response.json();
|
|
184
|
-
return
|
|
507
|
+
return isRecord3(value) && typeof value.error === "string" && value.error ? value.error : fallback;
|
|
185
508
|
} catch {
|
|
186
509
|
return fallback;
|
|
187
510
|
}
|
|
@@ -393,11 +716,11 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
393
716
|
var INITIAL_RETRY_DELAY_MS = 100;
|
|
394
717
|
var MAX_RETRY_DELAY_MS = 2e3;
|
|
395
718
|
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
396
|
-
function
|
|
719
|
+
function isRecord4(value) {
|
|
397
720
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
398
721
|
}
|
|
399
722
|
function parseError(value) {
|
|
400
|
-
if (!
|
|
723
|
+
if (!isRecord4(value)) return void 0;
|
|
401
724
|
const { code, message } = value;
|
|
402
725
|
if (typeof code !== "string" || typeof message !== "string") {
|
|
403
726
|
return void 0;
|
|
@@ -405,29 +728,41 @@ function parseError(value) {
|
|
|
405
728
|
return { code, message };
|
|
406
729
|
}
|
|
407
730
|
function parseChildStreamEvent(value) {
|
|
408
|
-
if (!
|
|
731
|
+
if (!isRecord4(value) || typeof value.type !== "string") {
|
|
409
732
|
return { type: "other" };
|
|
410
733
|
}
|
|
411
734
|
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
412
735
|
return { type: "session.boundary" };
|
|
413
736
|
}
|
|
414
|
-
if (value.type === "subagent.event" &&
|
|
737
|
+
if (value.type === "subagent.event" && isRecord4(value.data) && Object.hasOwn(value.data, "event")) {
|
|
415
738
|
return parseChildStreamEvent(value.data.event);
|
|
416
739
|
}
|
|
417
|
-
if (value.type === "subagent.called" &&
|
|
740
|
+
if (value.type === "subagent.called" && isRecord4(value.data)) {
|
|
418
741
|
const { childStreamPath } = value.data;
|
|
419
742
|
if (typeof childStreamPath === "string") {
|
|
420
743
|
return { childStreamPath, type: "subagent.called" };
|
|
421
744
|
}
|
|
422
745
|
}
|
|
423
|
-
if (value.type
|
|
746
|
+
if (value.type === "actions.requested" && isRecord4(value.data) && Array.isArray(value.data.actions)) {
|
|
747
|
+
const items = value.data.actions.flatMap((action) => {
|
|
748
|
+
if (!isRecord4(action) || action.kind !== "tool-call" || typeof action.callId !== "string" || typeof action.toolName !== "string" || !isRecord4(action.input)) return [];
|
|
749
|
+
const item = connectedToolWork({
|
|
750
|
+
callId: action.callId,
|
|
751
|
+
toolName: action.toolName,
|
|
752
|
+
input: action.input
|
|
753
|
+
});
|
|
754
|
+
return item ? [item] : [];
|
|
755
|
+
});
|
|
756
|
+
return { type: "actions.requested", items };
|
|
757
|
+
}
|
|
758
|
+
if (value.type !== "action.result" || !isRecord4(value.data)) {
|
|
424
759
|
return { type: "other" };
|
|
425
760
|
}
|
|
426
761
|
const { data } = value;
|
|
427
762
|
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
428
763
|
return { type: "other" };
|
|
429
764
|
}
|
|
430
|
-
if (!
|
|
765
|
+
if (!isRecord4(data.result) || data.result.kind !== "tool-result") {
|
|
431
766
|
return { type: "other" };
|
|
432
767
|
}
|
|
433
768
|
const result = data.result;
|
|
@@ -441,7 +776,7 @@ function parseChildStreamEvent(value) {
|
|
|
441
776
|
result: {
|
|
442
777
|
callId: result.callId,
|
|
443
778
|
toolName: result.toolName,
|
|
444
|
-
status: data.status,
|
|
779
|
+
status: result.isError === true ? "failed" : data.status,
|
|
445
780
|
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
446
781
|
...error ? { error } : {}
|
|
447
782
|
}
|
|
@@ -522,300 +857,81 @@ var SubagentChildStreamCoordinator = class {
|
|
|
522
857
|
this.controllers.clear();
|
|
523
858
|
}
|
|
524
859
|
beginPath(childStreamPath) {
|
|
525
|
-
if (this.tasks.has(childStreamPath)) return;
|
|
526
|
-
const controller = new AbortController();
|
|
527
|
-
const abort = () => controller.abort();
|
|
528
|
-
if (this.parentSignal.aborted) {
|
|
529
|
-
controller.abort();
|
|
530
|
-
} else {
|
|
531
|
-
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
532
|
-
}
|
|
533
|
-
this.controllers.set(childStreamPath, controller);
|
|
534
|
-
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
535
|
-
() => {
|
|
536
|
-
this.parentSignal.removeEventListener("abort", abort);
|
|
537
|
-
if (this.controllers.get(childStreamPath) === controller) {
|
|
538
|
-
this.controllers.delete(childStreamPath);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
);
|
|
542
|
-
this.tasks.set(childStreamPath, task);
|
|
543
|
-
}
|
|
544
|
-
async consume(path, signal) {
|
|
545
|
-
let streamIndex = 0;
|
|
546
|
-
let consecutiveRetries = 0;
|
|
547
|
-
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
548
|
-
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
549
|
-
let receivedEvent = false;
|
|
550
|
-
try {
|
|
551
|
-
const response = await this.client.fetch(
|
|
552
|
-
streamPathAt(path, streamIndex),
|
|
553
|
-
{
|
|
554
|
-
cache: "no-store",
|
|
555
|
-
signal
|
|
556
|
-
}
|
|
557
|
-
);
|
|
558
|
-
if (!response.ok || response.body === null) {
|
|
559
|
-
await response.body?.cancel().catch(() => {
|
|
560
|
-
});
|
|
561
|
-
throw new Error(`Child stream returned ${response.status}.`);
|
|
562
|
-
}
|
|
563
|
-
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
564
|
-
if (signal.aborted) return;
|
|
565
|
-
receivedEvent = true;
|
|
566
|
-
streamIndex += 1;
|
|
567
|
-
const event = parseChildStreamEvent(rawEvent);
|
|
568
|
-
if (event.type === "session.boundary") return;
|
|
569
|
-
if (event.type === "subagent.called") {
|
|
570
|
-
this.beginPath(event.childStreamPath);
|
|
571
|
-
continue;
|
|
572
|
-
}
|
|
573
|
-
if (event.type !== "action.result") continue;
|
|
574
|
-
this.handlers.onToolResult?.(event.result);
|
|
575
|
-
if (event.hasOutput) {
|
|
576
|
-
this.handlers.onActionResult?.(event.result.output);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
} catch {
|
|
580
|
-
if (signal.aborted) return;
|
|
581
|
-
}
|
|
582
|
-
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
583
|
-
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
584
|
-
await abortableDelay(retryDelayMs, signal);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
// src/runtime/tool-ui.ts
|
|
590
|
-
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
591
|
-
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
592
|
-
var AGENT_STRUCTURED_TOOL_INPUT_HEADER = "Webless-Structured-Tool-Input-JSON:";
|
|
593
|
-
function formatAgentStructuredToolInput(surface, values) {
|
|
594
|
-
const payload = {
|
|
595
|
-
schemaVersion: AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION,
|
|
596
|
-
toolSlug: surface.toolSlug,
|
|
597
|
-
...surface.operationId ? { operationId: surface.operationId } : {},
|
|
598
|
-
values
|
|
599
|
-
};
|
|
600
|
-
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
601
|
-
}
|
|
602
|
-
function isRecord3(value) {
|
|
603
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
604
|
-
}
|
|
605
|
-
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
606
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
607
|
-
return true;
|
|
608
|
-
}
|
|
609
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
610
|
-
if (typeof value !== "object") return false;
|
|
611
|
-
if (seen.has(value)) return false;
|
|
612
|
-
seen.add(value);
|
|
613
|
-
const valid = Array.isArray(value) ? value.every((item) => isJsonValue(item, seen)) : Object.entries(value).every(
|
|
614
|
-
([key, item]) => typeof key === "string" && isJsonValue(item, seen)
|
|
615
|
-
);
|
|
616
|
-
seen.delete(value);
|
|
617
|
-
return valid;
|
|
618
|
-
}
|
|
619
|
-
function boundedString(value, max) {
|
|
620
|
-
if (typeof value !== "string" || value.trim().length === 0 || value.length > max) {
|
|
621
|
-
return void 0;
|
|
622
|
-
}
|
|
623
|
-
return value.trim();
|
|
624
|
-
}
|
|
625
|
-
function numberValue(value) {
|
|
626
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
627
|
-
}
|
|
628
|
-
function integerValue(value) {
|
|
629
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 8e3 ? value : void 0;
|
|
630
|
-
}
|
|
631
|
-
function isFieldKind(value) {
|
|
632
|
-
return typeof value === "string" && [
|
|
633
|
-
"text",
|
|
634
|
-
"textarea",
|
|
635
|
-
"email",
|
|
636
|
-
"number",
|
|
637
|
-
"select",
|
|
638
|
-
"multi-select",
|
|
639
|
-
"checkbox",
|
|
640
|
-
"confirmation",
|
|
641
|
-
"radio",
|
|
642
|
-
"date",
|
|
643
|
-
"time",
|
|
644
|
-
"date-time",
|
|
645
|
-
"calendar",
|
|
646
|
-
"range",
|
|
647
|
-
"json"
|
|
648
|
-
].includes(value);
|
|
649
|
-
}
|
|
650
|
-
function parseField(value) {
|
|
651
|
-
if (!isRecord3(value)) return null;
|
|
652
|
-
if (!hasOnlyKeys(value, [
|
|
653
|
-
"description",
|
|
654
|
-
"kind",
|
|
655
|
-
"label",
|
|
656
|
-
"max",
|
|
657
|
-
"maxItems",
|
|
658
|
-
"maxLength",
|
|
659
|
-
"min",
|
|
660
|
-
"minLength",
|
|
661
|
-
"options",
|
|
662
|
-
"path",
|
|
663
|
-
"placeholder",
|
|
664
|
-
"required",
|
|
665
|
-
"step",
|
|
666
|
-
"defaultValue"
|
|
667
|
-
])) {
|
|
668
|
-
return null;
|
|
669
|
-
}
|
|
670
|
-
if (!isFieldKind(value.kind)) return null;
|
|
671
|
-
const path = boundedString(value.path, 160);
|
|
672
|
-
const label = boundedString(value.label, 160);
|
|
673
|
-
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
674
|
-
const placeholder = value.placeholder === void 0 || typeof value.placeholder !== "string" ? void 0 : value.placeholder;
|
|
675
|
-
const required = value.required === void 0 || typeof value.required !== "boolean" ? void 0 : value.required;
|
|
676
|
-
const min = value.min === void 0 ? void 0 : numberValue(value.min);
|
|
677
|
-
const max = value.max === void 0 ? void 0 : numberValue(value.max);
|
|
678
|
-
const maxItems = value.maxItems === void 0 ? void 0 : integerValue(value.maxItems);
|
|
679
|
-
const step = value.step === void 0 ? void 0 : numberValue(value.step);
|
|
680
|
-
const minLength = value.minLength === void 0 ? void 0 : integerValue(value.minLength);
|
|
681
|
-
const maxLength = value.maxLength === void 0 ? void 0 : integerValue(value.maxLength);
|
|
682
|
-
const defaultValue = value.defaultValue === void 0 || !isJsonValue(value.defaultValue) ? void 0 : value.defaultValue;
|
|
683
|
-
if (!path || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || !label) {
|
|
684
|
-
return null;
|
|
685
|
-
}
|
|
686
|
-
if (value.description !== void 0 && !description) return null;
|
|
687
|
-
if (value.placeholder !== void 0 && placeholder === void 0) return null;
|
|
688
|
-
if (value.required !== void 0 && required === void 0) return null;
|
|
689
|
-
if (value.min !== void 0 && min === void 0) return null;
|
|
690
|
-
if (value.max !== void 0 && max === void 0) return null;
|
|
691
|
-
if (value.maxItems !== void 0 && (maxItems === void 0 || maxItems < 1 || maxItems > 100))
|
|
692
|
-
return null;
|
|
693
|
-
if (value.step !== void 0 && step === void 0) return null;
|
|
694
|
-
if (value.minLength !== void 0 && minLength === void 0) return null;
|
|
695
|
-
if (value.maxLength !== void 0 && maxLength === void 0) return null;
|
|
696
|
-
if (value.defaultValue !== void 0 && defaultValue === void 0)
|
|
697
|
-
return null;
|
|
698
|
-
if (value.options !== void 0) {
|
|
699
|
-
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
700
|
-
return null;
|
|
701
|
-
for (const option of value.options) {
|
|
702
|
-
if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
703
|
-
return null;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
return {
|
|
708
|
-
kind: value.kind,
|
|
709
|
-
path,
|
|
710
|
-
label,
|
|
711
|
-
...description ? { description } : {},
|
|
712
|
-
...placeholder !== void 0 ? { placeholder } : {},
|
|
713
|
-
...required !== void 0 ? { required } : {},
|
|
714
|
-
...defaultValue !== void 0 ? { defaultValue } : {},
|
|
715
|
-
...value.options !== void 0 ? { options: value.options } : {},
|
|
716
|
-
...min !== void 0 ? { min } : {},
|
|
717
|
-
...max !== void 0 ? { max } : {},
|
|
718
|
-
...maxItems !== void 0 ? { maxItems } : {},
|
|
719
|
-
...step !== void 0 ? { step } : {},
|
|
720
|
-
...minLength !== void 0 ? { minLength } : {},
|
|
721
|
-
...maxLength !== void 0 ? { maxLength } : {}
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
function parseStep(value) {
|
|
725
|
-
if (!isRecord3(value)) return null;
|
|
726
|
-
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
727
|
-
return null;
|
|
728
|
-
}
|
|
729
|
-
const id = boundedString(value.id, 80);
|
|
730
|
-
const label = boundedString(value.label, 160);
|
|
731
|
-
const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
|
|
732
|
-
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(
|
|
733
|
-
(path) => typeof path !== "string" || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || path.length > 160
|
|
734
|
-
)) {
|
|
735
|
-
return null;
|
|
736
|
-
}
|
|
737
|
-
return {
|
|
738
|
-
id,
|
|
739
|
-
label,
|
|
740
|
-
fieldPaths: value.fieldPaths,
|
|
741
|
-
...description ? { description } : {}
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
function parseAction(value) {
|
|
745
|
-
if (!isRecord3(value)) return null;
|
|
746
|
-
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
747
|
-
const label = boundedString(value.label, 80);
|
|
748
|
-
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
749
|
-
return null;
|
|
750
|
-
}
|
|
751
|
-
return {
|
|
752
|
-
id: value.id,
|
|
753
|
-
label
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
function parseAgentToolUiSurface(value) {
|
|
757
|
-
if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
758
|
-
return null;
|
|
759
|
-
if (!hasOnlyKeys(value, [
|
|
760
|
-
"actions",
|
|
761
|
-
"description",
|
|
762
|
-
"fields",
|
|
763
|
-
"id",
|
|
764
|
-
"operationId",
|
|
765
|
-
"requestId",
|
|
766
|
-
"schemaVersion",
|
|
767
|
-
"steps",
|
|
768
|
-
"submitLabel",
|
|
769
|
-
"title",
|
|
770
|
-
"toolSlug",
|
|
771
|
-
"values"
|
|
772
|
-
])) {
|
|
773
|
-
return null;
|
|
774
|
-
}
|
|
775
|
-
const id = boundedString(value.id, 200);
|
|
776
|
-
const title = boundedString(value.title, 200);
|
|
777
|
-
const toolSlug = boundedString(value.toolSlug, 200);
|
|
778
|
-
const description = value.description === void 0 ? void 0 : boundedString(value.description, 800);
|
|
779
|
-
const operationId = value.operationId === void 0 ? void 0 : boundedString(value.operationId, 200);
|
|
780
|
-
const requestId = value.requestId === void 0 ? void 0 : boundedString(value.requestId, 200);
|
|
781
|
-
const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
|
|
782
|
-
if (!id || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
|
|
783
|
-
return null;
|
|
860
|
+
if (this.tasks.has(childStreamPath)) return;
|
|
861
|
+
const controller = new AbortController();
|
|
862
|
+
const abort = () => controller.abort();
|
|
863
|
+
if (this.parentSignal.aborted) {
|
|
864
|
+
controller.abort();
|
|
865
|
+
} else {
|
|
866
|
+
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
867
|
+
}
|
|
868
|
+
this.controllers.set(childStreamPath, controller);
|
|
869
|
+
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
870
|
+
() => {
|
|
871
|
+
this.parentSignal.removeEventListener("abort", abort);
|
|
872
|
+
if (this.controllers.get(childStreamPath) === controller) {
|
|
873
|
+
this.controllers.delete(childStreamPath);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
);
|
|
877
|
+
this.tasks.set(childStreamPath, task);
|
|
784
878
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
879
|
+
async consume(path, signal) {
|
|
880
|
+
const workItems = /* @__PURE__ */ new Map();
|
|
881
|
+
let streamIndex = 0;
|
|
882
|
+
let consecutiveRetries = 0;
|
|
883
|
+
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
884
|
+
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
885
|
+
let receivedEvent = false;
|
|
886
|
+
try {
|
|
887
|
+
const response = await this.client.fetch(
|
|
888
|
+
streamPathAt(path, streamIndex),
|
|
889
|
+
{
|
|
890
|
+
cache: "no-store",
|
|
891
|
+
signal
|
|
892
|
+
}
|
|
893
|
+
);
|
|
894
|
+
if (!response.ok || response.body === null) {
|
|
895
|
+
await response.body?.cancel().catch(() => {
|
|
896
|
+
});
|
|
897
|
+
throw new Error(`Child stream returned ${response.status}.`);
|
|
898
|
+
}
|
|
899
|
+
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
900
|
+
if (signal.aborted) return;
|
|
901
|
+
receivedEvent = true;
|
|
902
|
+
streamIndex += 1;
|
|
903
|
+
const event = parseChildStreamEvent(rawEvent);
|
|
904
|
+
if (event.type === "session.boundary") return;
|
|
905
|
+
if (event.type === "subagent.called") {
|
|
906
|
+
this.beginPath(event.childStreamPath);
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
if (event.type === "actions.requested") {
|
|
910
|
+
for (const item2 of event.items) {
|
|
911
|
+
workItems.set(item2.id, item2);
|
|
912
|
+
this.handlers.onWork?.(item2);
|
|
913
|
+
}
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
if (event.type !== "action.result") continue;
|
|
917
|
+
const item = workItems.get(event.result.callId);
|
|
918
|
+
if (item) {
|
|
919
|
+
this.handlers.onWork?.(completeConnectedToolWork(item, event.result));
|
|
920
|
+
}
|
|
921
|
+
this.handlers.onToolResult?.(event.result);
|
|
922
|
+
if (event.hasOutput) {
|
|
923
|
+
this.handlers.onActionResult?.(event.result.output);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
} catch {
|
|
927
|
+
if (signal.aborted) return;
|
|
928
|
+
}
|
|
929
|
+
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
930
|
+
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
931
|
+
await abortableDelay(retryDelayMs, signal);
|
|
932
|
+
}
|
|
799
933
|
}
|
|
800
|
-
|
|
801
|
-
schemaVersion: AGENT_TOOL_UI_SCHEMA_VERSION,
|
|
802
|
-
id,
|
|
803
|
-
title,
|
|
804
|
-
toolSlug,
|
|
805
|
-
fields,
|
|
806
|
-
...actions ? { actions } : {},
|
|
807
|
-
...description ? { description } : {},
|
|
808
|
-
...operationId ? { operationId } : {},
|
|
809
|
-
...requestId ? { requestId } : {},
|
|
810
|
-
...submitLabel ? { submitLabel } : {},
|
|
811
|
-
...steps ? { steps } : {},
|
|
812
|
-
...values ? { values } : {}
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
function hasOnlyKeys(value, allowed) {
|
|
816
|
-
const allowedKeys = new Set(allowed);
|
|
817
|
-
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
818
|
-
}
|
|
934
|
+
};
|
|
819
935
|
|
|
820
936
|
// src/runtime/client.ts
|
|
821
937
|
function isTurnBoundary(event) {
|
|
@@ -849,7 +965,7 @@ function emitActionResult(event, handlers) {
|
|
|
849
965
|
handlers.onToolResult?.({
|
|
850
966
|
callId: result.callId,
|
|
851
967
|
toolName: result.toolName,
|
|
852
|
-
status: event.data.status,
|
|
968
|
+
status: result.isError ? "failed" : event.data.status,
|
|
853
969
|
output: result.output,
|
|
854
970
|
...event.data.error ? { error: event.data.error } : {}
|
|
855
971
|
});
|
|
@@ -975,9 +1091,13 @@ function requestedWorkItem(action) {
|
|
|
975
1091
|
state: "active"
|
|
976
1092
|
};
|
|
977
1093
|
}
|
|
978
|
-
return null;
|
|
1094
|
+
return action.kind === "tool-call" ? connectedToolWork(action) : null;
|
|
979
1095
|
}
|
|
980
1096
|
function applyWorkEvent(event, handlers, workItems) {
|
|
1097
|
+
if (event.type === "subagent.event") {
|
|
1098
|
+
applyWorkEvent(event.data.event, handlers, workItems);
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
981
1101
|
if (event.type === "step.started" && workItems.size === 0) {
|
|
982
1102
|
emitWorkItem(
|
|
983
1103
|
{
|
|
@@ -1036,6 +1156,15 @@ function applyWorkEvent(event, handlers, workItems) {
|
|
|
1036
1156
|
const { result, status } = event.data;
|
|
1037
1157
|
const current = workItems.get(result.callId);
|
|
1038
1158
|
if (!current) return;
|
|
1159
|
+
if (current.kind === "tool" && result.kind === "tool-result") {
|
|
1160
|
+
emitWorkItem(completeConnectedToolWork(current, {
|
|
1161
|
+
callId: result.callId,
|
|
1162
|
+
toolName: result.toolName,
|
|
1163
|
+
status: result.isError ? "failed" : status,
|
|
1164
|
+
output: result.output
|
|
1165
|
+
}), handlers, workItems);
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1039
1168
|
const failed = status !== "completed" || result.isError === true;
|
|
1040
1169
|
emitWorkItem(
|
|
1041
1170
|
{
|
|
@@ -2073,10 +2202,15 @@ function parseMessage(value) {
|
|
|
2073
2202
|
const result = parseToolResult(value2);
|
|
2074
2203
|
return result?.kind === "search" ? [result] : [];
|
|
2075
2204
|
}) : [];
|
|
2205
|
+
const toolResults = Array.isArray(record2.toolResults) ? record2.toolResults.flatMap((value2) => {
|
|
2206
|
+
const result = parseToolResult(value2);
|
|
2207
|
+
return result && result.kind !== "search" && result.kind !== "input" ? [result] : [];
|
|
2208
|
+
}) : [];
|
|
2076
2209
|
return {
|
|
2077
2210
|
id: record2.id,
|
|
2078
2211
|
role: "agent",
|
|
2079
2212
|
...searchResults.length ? { searchResults } : {},
|
|
2213
|
+
...toolResults.length ? { toolResults } : {},
|
|
2080
2214
|
text: record2.text,
|
|
2081
2215
|
createdAt: record2.createdAt
|
|
2082
2216
|
};
|
|
@@ -2084,7 +2218,7 @@ function parseMessage(value) {
|
|
|
2084
2218
|
function parseToolStep(value) {
|
|
2085
2219
|
if (typeof value !== "object" || value === null) return null;
|
|
2086
2220
|
const record2 = value;
|
|
2087
|
-
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") {
|
|
2221
|
+
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") {
|
|
2088
2222
|
return null;
|
|
2089
2223
|
}
|
|
2090
2224
|
return {
|
|
@@ -2145,6 +2279,15 @@ function parseInputRequest(value) {
|
|
|
2145
2279
|
...ui ? { ui } : {}
|
|
2146
2280
|
};
|
|
2147
2281
|
}
|
|
2282
|
+
function parseResultDetails(value) {
|
|
2283
|
+
if (!Array.isArray(value)) return [];
|
|
2284
|
+
return value.slice(0, 6).flatMap((item) => {
|
|
2285
|
+
if (typeof item !== "object" || item === null) return [];
|
|
2286
|
+
const detail = item;
|
|
2287
|
+
if (typeof detail.label !== "string" || typeof detail.value !== "string") return [];
|
|
2288
|
+
return [{ label: detail.label.slice(0, 240), value: detail.value.slice(0, 240) }];
|
|
2289
|
+
});
|
|
2290
|
+
}
|
|
2148
2291
|
function parseToolResult(value) {
|
|
2149
2292
|
if (typeof value !== "object" || value === null) return null;
|
|
2150
2293
|
const record2 = value;
|
|
@@ -2180,6 +2323,7 @@ function parseToolResult(value) {
|
|
|
2180
2323
|
status: record2.status,
|
|
2181
2324
|
kind: "entity",
|
|
2182
2325
|
title: record2.title,
|
|
2326
|
+
details: parseResultDetails(record2.details),
|
|
2183
2327
|
...typeof record2.description === "string" ? { description: record2.description } : {}
|
|
2184
2328
|
};
|
|
2185
2329
|
}
|
|
@@ -2223,6 +2367,7 @@ function parseToolResult(value) {
|
|
|
2223
2367
|
status: record2.status,
|
|
2224
2368
|
kind: "summary",
|
|
2225
2369
|
title: record2.title,
|
|
2370
|
+
details: parseResultDetails(record2.details),
|
|
2226
2371
|
...typeof record2.description === "string" ? { description: record2.description } : {}
|
|
2227
2372
|
};
|
|
2228
2373
|
}
|
|
@@ -2327,63 +2472,6 @@ function clearPendingWidgetBooking(storageKeyPrefix, visitorSessionId) {
|
|
|
2327
2472
|
);
|
|
2328
2473
|
}
|
|
2329
2474
|
|
|
2330
|
-
// src/runtime/tool-result-envelope.ts
|
|
2331
|
-
var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
2332
|
-
"schemaVersion",
|
|
2333
|
-
"output",
|
|
2334
|
-
"presentationKinds",
|
|
2335
|
-
"ui"
|
|
2336
|
-
]);
|
|
2337
|
-
function isRecord4(value) {
|
|
2338
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2339
|
-
}
|
|
2340
|
-
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
2341
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
2342
|
-
return true;
|
|
2343
|
-
}
|
|
2344
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
2345
|
-
if (typeof value !== "object") return false;
|
|
2346
|
-
if (seen.has(value)) return false;
|
|
2347
|
-
seen.add(value);
|
|
2348
|
-
const valid = Array.isArray(value) ? value.every((item) => isJsonValue2(item, seen)) : Object.entries(value).every(
|
|
2349
|
-
([key, item]) => typeof key === "string" && isJsonValue2(item, seen)
|
|
2350
|
-
);
|
|
2351
|
-
seen.delete(value);
|
|
2352
|
-
return valid;
|
|
2353
|
-
}
|
|
2354
|
-
function decodeEnvelope(value) {
|
|
2355
|
-
if (typeof value !== "string") return value;
|
|
2356
|
-
try {
|
|
2357
|
-
return JSON.parse(value);
|
|
2358
|
-
} catch {
|
|
2359
|
-
return null;
|
|
2360
|
-
}
|
|
2361
|
-
}
|
|
2362
|
-
function parseAgentToolResultEnvelope(value) {
|
|
2363
|
-
const decoded = decodeEnvelope(value);
|
|
2364
|
-
if (!isRecord4(decoded)) return null;
|
|
2365
|
-
const keys = Object.keys(decoded);
|
|
2366
|
-
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) {
|
|
2367
|
-
return null;
|
|
2368
|
-
}
|
|
2369
|
-
const presentationKinds = decoded.presentationKinds.flatMap((kind) => {
|
|
2370
|
-
if (typeof kind !== "string") return [];
|
|
2371
|
-
const normalized = kind.trim();
|
|
2372
|
-
return normalized && normalized.length <= 128 ? [normalized] : [];
|
|
2373
|
-
});
|
|
2374
|
-
if (presentationKinds.length !== decoded.presentationKinds.length) {
|
|
2375
|
-
return null;
|
|
2376
|
-
}
|
|
2377
|
-
const ui = decoded.ui === void 0 ? void 0 : parseAgentToolUiSurface(decoded.ui);
|
|
2378
|
-
if (decoded.ui !== void 0 && !ui) return null;
|
|
2379
|
-
return {
|
|
2380
|
-
schemaVersion: "webless.tool-result.v1",
|
|
2381
|
-
output: decoded.output,
|
|
2382
|
-
presentationKinds,
|
|
2383
|
-
...ui ? { ui } : {}
|
|
2384
|
-
};
|
|
2385
|
-
}
|
|
2386
|
-
|
|
2387
2475
|
// src/react/lib/tool-result.ts
|
|
2388
2476
|
var MAX_TEXT_LENGTH = 240;
|
|
2389
2477
|
var MAX_DETAILS = 6;
|
|
@@ -2618,6 +2706,9 @@ function finalizeSummaryPresentation(result, proposed) {
|
|
|
2618
2706
|
};
|
|
2619
2707
|
}
|
|
2620
2708
|
function presentVisitorToolResult(result, registry = []) {
|
|
2709
|
+
if (result.status === "completed" && toolResultFailed(result)) {
|
|
2710
|
+
result = { ...result, status: "failed" };
|
|
2711
|
+
}
|
|
2621
2712
|
if (result.toolName === "search_discovery" && result.status === "completed") {
|
|
2622
2713
|
const envelope2 = parseAgentToolResultEnvelope(result.output);
|
|
2623
2714
|
const search = parseAgentSearchDiscoveryOutput(
|
|
@@ -2654,7 +2745,7 @@ function presentVisitorToolResult(result, registry = []) {
|
|
|
2654
2745
|
surface: envelope.ui
|
|
2655
2746
|
};
|
|
2656
2747
|
}
|
|
2657
|
-
if (!proposed) {
|
|
2748
|
+
if (!proposed || result.status !== "completed" && proposed.kind !== "summary") {
|
|
2658
2749
|
if (result.status === "failed" || result.status === "rejected") {
|
|
2659
2750
|
return {
|
|
2660
2751
|
id: result.callId,
|
|
@@ -2777,14 +2868,15 @@ function isNearDuplicateAssistantText(left, right) {
|
|
|
2777
2868
|
shorter.slice(0, Math.floor(shorter.length * 0.85))
|
|
2778
2869
|
);
|
|
2779
2870
|
}
|
|
2780
|
-
function appendAgentTurnMessage(messages, displayText, searchResults = []) {
|
|
2871
|
+
function appendAgentTurnMessage(messages, displayText, searchResults = [], toolResults = []) {
|
|
2781
2872
|
const trimmed = displayText.trim();
|
|
2782
|
-
if (!trimmed && searchResults.length === 0) return [...messages];
|
|
2873
|
+
if (!trimmed && searchResults.length === 0 && toolResults.length === 0) return [...messages];
|
|
2783
2874
|
const agentMessage = {
|
|
2784
2875
|
id: `agent-${Date.now()}`,
|
|
2785
2876
|
role: "agent",
|
|
2786
2877
|
text: trimmed,
|
|
2787
2878
|
...searchResults.length ? { searchResults } : {},
|
|
2879
|
+
...toolResults.length ? { toolResults } : {},
|
|
2788
2880
|
createdAt: Date.now()
|
|
2789
2881
|
};
|
|
2790
2882
|
const last = messages.at(-1);
|
|
@@ -3166,10 +3258,11 @@ function useAgentChat({
|
|
|
3166
3258
|
messages: appendAgentTurnMessage(
|
|
3167
3259
|
prev.messages,
|
|
3168
3260
|
displayText,
|
|
3169
|
-
(prev.toolResults ?? []).filter((result) => result.kind === "search")
|
|
3261
|
+
(prev.toolResults ?? []).filter((result) => result.kind === "search"),
|
|
3262
|
+
(prev.toolResults ?? []).filter((result) => result.kind !== "search" && result.kind !== "input")
|
|
3170
3263
|
),
|
|
3171
3264
|
toolResults: (prev.toolResults ?? []).filter(
|
|
3172
|
-
(result) => result.kind
|
|
3265
|
+
(result) => result.kind === "input"
|
|
3173
3266
|
),
|
|
3174
3267
|
toolSteps: completeActivePlanning(prev.toolSteps),
|
|
3175
3268
|
streamingText: "",
|
|
@@ -3231,16 +3324,18 @@ function useAgentChat({
|
|
|
3231
3324
|
const submit = (0, import_react2.useCallback)(
|
|
3232
3325
|
async (visitorText, options) => {
|
|
3233
3326
|
const trimmed = visitorText.trim();
|
|
3234
|
-
|
|
3327
|
+
const outgoing = options?.runtimeText ?? visitorText;
|
|
3328
|
+
if (!outgoing.trim()) return null;
|
|
3235
3329
|
const chatResponse = chatInputResponseForText(
|
|
3236
3330
|
state.pendingInputs ?? [],
|
|
3237
|
-
|
|
3331
|
+
outgoing.trim()
|
|
3238
3332
|
);
|
|
3239
3333
|
if (chatResponse) {
|
|
3240
3334
|
const visitorMessage2 = {
|
|
3241
3335
|
id: `visitor-${Date.now()}`,
|
|
3242
3336
|
role: "visitor",
|
|
3243
3337
|
text: trimmed,
|
|
3338
|
+
...outgoing !== trimmed ? { runtimeText: outgoing } : {},
|
|
3244
3339
|
createdAt: Date.now()
|
|
3245
3340
|
};
|
|
3246
3341
|
if (runRef.current) {
|
|
@@ -3280,7 +3375,6 @@ function useAgentChat({
|
|
|
3280
3375
|
const controller = new AbortController();
|
|
3281
3376
|
runRef.current = controller;
|
|
3282
3377
|
const booking = pendingBookingRef.current;
|
|
3283
|
-
const outgoing = options?.runtimeText ?? visitorText;
|
|
3284
3378
|
const runtimeText = booking ? `${visitorBookingPrefix(booking)}
|
|
3285
3379
|
|
|
3286
3380
|
${outgoing}` : outgoing;
|
|
@@ -3659,6 +3753,10 @@ function joinLabels(labels) {
|
|
|
3659
3753
|
return `${labels.slice(0, -1).join(", ")} and ${labels.at(-1) ?? ""}`;
|
|
3660
3754
|
}
|
|
3661
3755
|
function workSummary(steps, failed, brandLabel) {
|
|
3756
|
+
const activeTool = [...steps].reverse().find(
|
|
3757
|
+
(step) => step.kind === "tool" && step.state === "active"
|
|
3758
|
+
);
|
|
3759
|
+
if (activeTool) return activeTool.detail ?? "Working on your request";
|
|
3662
3760
|
const activeSpecialists = steps.filter(
|
|
3663
3761
|
(step) => step.kind === "specialist" && step.state === "active"
|
|
3664
3762
|
);
|
|
@@ -3986,11 +4084,15 @@ function Composer({
|
|
|
3986
4084
|
const trimmed = value.trim();
|
|
3987
4085
|
if (!trimmed || disabled) return;
|
|
3988
4086
|
const shareDismissal = savedForm && !draft.dismissalSent;
|
|
3989
|
-
|
|
3990
|
-
|
|
4087
|
+
if (shareDismissal) {
|
|
4088
|
+
onSubmit?.(trimmed, {
|
|
4089
|
+
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.
|
|
3991
4090
|
|
|
3992
|
-
${trimmed}`
|
|
3993
|
-
|
|
4091
|
+
${trimmed}`
|
|
4092
|
+
});
|
|
4093
|
+
} else {
|
|
4094
|
+
onSubmit?.(trimmed);
|
|
4095
|
+
}
|
|
3994
4096
|
if (shareDismissal)
|
|
3995
4097
|
setDraft((current) => ({ ...current, dismissalSent: true }));
|
|
3996
4098
|
setValue("");
|
|
@@ -4007,7 +4109,9 @@ ${trimmed}` : trimmed
|
|
|
4007
4109
|
if (control instanceof HTMLElement) control.focus();
|
|
4008
4110
|
return;
|
|
4009
4111
|
}
|
|
4010
|
-
onSubmit?.(
|
|
4112
|
+
onSubmit?.("", {
|
|
4113
|
+
runtimeText: formatComposerFormMessage(activeForm, draft.values)
|
|
4114
|
+
});
|
|
4011
4115
|
setDraft((current) => ({
|
|
4012
4116
|
...current,
|
|
4013
4117
|
values: emptyValues(activeForm),
|
|
@@ -4271,25 +4375,11 @@ function SearchReferences({
|
|
|
4271
4375
|
});
|
|
4272
4376
|
if (!sources.length && !actions.length) return null;
|
|
4273
4377
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "search-references", children: [
|
|
4274
|
-
sources.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("
|
|
4275
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("
|
|
4276
|
-
"Sources",
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
{
|
|
4280
|
-
viewBox: "0 0 24 24",
|
|
4281
|
-
width: "14",
|
|
4282
|
-
height: "14",
|
|
4283
|
-
fill: "none",
|
|
4284
|
-
stroke: "currentColor",
|
|
4285
|
-
strokeWidth: "1.75",
|
|
4286
|
-
"aria-hidden": "true",
|
|
4287
|
-
children: [
|
|
4288
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "12", cy: "12", r: "9" }),
|
|
4289
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 11v6M12 7v1" })
|
|
4290
|
-
]
|
|
4291
|
-
}
|
|
4292
|
-
) })
|
|
4378
|
+
sources.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "search-references__disclosure", "aria-label": "Sources", children: [
|
|
4379
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("summary", { className: "search-references__heading", children: [
|
|
4380
|
+
"Sources (",
|
|
4381
|
+
sources.length,
|
|
4382
|
+
")"
|
|
4293
4383
|
] }),
|
|
4294
4384
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "search-references__list", children: sources.map((source) => {
|
|
4295
4385
|
const content = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
@@ -4367,7 +4457,23 @@ function calendarCells(year, month) {
|
|
|
4367
4457
|
function BookingCardLoader() {
|
|
4368
4458
|
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" }) });
|
|
4369
4459
|
}
|
|
4370
|
-
function BookingCard({
|
|
4460
|
+
function BookingCard(props) {
|
|
4461
|
+
if (!props.readOnly) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(InteractiveBookingCard, { ...props });
|
|
4462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "booking-card", "aria-label": "Recorded available times", children: [
|
|
4463
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "booking-card__title", children: "Available times offered" }),
|
|
4464
|
+
props.offer.slots.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { children: props.offer.slots.map((slot, index) => {
|
|
4465
|
+
const eventType = props.offer.eventTypes.find(
|
|
4466
|
+
(item) => item.uri === slot.eventTypeUri
|
|
4467
|
+
);
|
|
4468
|
+
const label = Number.isFinite(Date.parse(slot.startTime)) ? formatSlotLabel(slot.startTime) : "Time unavailable";
|
|
4469
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
|
|
4470
|
+
eventType ? `${eventType.name} \xB7 ` : "",
|
|
4471
|
+
label
|
|
4472
|
+
] }, `${slot.eventTypeUri ?? ""}:${slot.startTime}:${index}`);
|
|
4473
|
+
}) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: "No available times were recorded." })
|
|
4474
|
+
] });
|
|
4475
|
+
}
|
|
4476
|
+
function InteractiveBookingCard({
|
|
4371
4477
|
disabled = false,
|
|
4372
4478
|
offer,
|
|
4373
4479
|
onBook
|
|
@@ -4733,6 +4839,7 @@ function MessageBubble({
|
|
|
4733
4839
|
message,
|
|
4734
4840
|
brandLogoUrl,
|
|
4735
4841
|
bookingDisabled = false,
|
|
4842
|
+
bookingReadOnly = false,
|
|
4736
4843
|
offer,
|
|
4737
4844
|
onBook
|
|
4738
4845
|
}) {
|
|
@@ -4750,6 +4857,7 @@ function MessageBubble({
|
|
|
4750
4857
|
offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
|
|
4751
4858
|
);
|
|
4752
4859
|
if (message.role === "visitor") {
|
|
4860
|
+
if (!message.text.trim()) return null;
|
|
4753
4861
|
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 }) });
|
|
4754
4862
|
}
|
|
4755
4863
|
const citations = message.citations ?? [];
|
|
@@ -4768,8 +4876,8 @@ function MessageBubble({
|
|
|
4768
4876
|
children: displayText
|
|
4769
4877
|
}
|
|
4770
4878
|
),
|
|
4771
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchReferences, { results: message.searchResults ?? [] }),
|
|
4772
|
-
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: [
|
|
4879
|
+
!isStreaming ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchReferences, { results: message.searchResults ?? [] }) : null,
|
|
4880
|
+
!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: [
|
|
4773
4881
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4774
4882
|
"span",
|
|
4775
4883
|
{
|
|
@@ -4781,6 +4889,7 @@ function MessageBubble({
|
|
|
4781
4889
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: citation.label })
|
|
4782
4890
|
] }) }, citation.id)) }) : null
|
|
4783
4891
|
] });
|
|
4892
|
+
if (!displayText && !message.searchResults?.length && offers.length === 0) return null;
|
|
4784
4893
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
|
|
4785
4894
|
displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__agent-row", children: [
|
|
4786
4895
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -4799,6 +4908,7 @@ function MessageBubble({
|
|
|
4799
4908
|
BookingCard,
|
|
4800
4909
|
{
|
|
4801
4910
|
disabled: bookingDisabled,
|
|
4911
|
+
readOnly: bookingReadOnly,
|
|
4802
4912
|
offer: nextOffer,
|
|
4803
4913
|
onBook
|
|
4804
4914
|
},
|
|
@@ -5957,6 +6067,7 @@ function CollectionResultCard({
|
|
|
5957
6067
|
{
|
|
5958
6068
|
className: `collection-result-card tool-result-card tool-result-card--${result.status}`,
|
|
5959
6069
|
"aria-label": result.title,
|
|
6070
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
5960
6071
|
children: [
|
|
5961
6072
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
5962
6073
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -5981,31 +6092,44 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
|
5981
6092
|
function EntityResultCard({
|
|
5982
6093
|
result
|
|
5983
6094
|
}) {
|
|
6095
|
+
const compact = !result.description && !result.details?.length && !result.links?.length;
|
|
6096
|
+
const collapsible = result.status === "completed" && Boolean(result.details?.length) && !result.links?.length;
|
|
6097
|
+
const heading = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "tool-result-card__heading", children: [
|
|
6098
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
6099
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
|
|
6100
|
+
] });
|
|
6101
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
6102
|
+
result.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: result.description }) : null,
|
|
6103
|
+
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
6104
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
|
|
6105
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
|
|
6106
|
+
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6107
|
+
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)(
|
|
6108
|
+
"a",
|
|
6109
|
+
{
|
|
6110
|
+
href: link.href,
|
|
6111
|
+
target: "_blank",
|
|
6112
|
+
rel: "noreferrer",
|
|
6113
|
+
children: link.label
|
|
6114
|
+
},
|
|
6115
|
+
link.href
|
|
6116
|
+
)) }) : null
|
|
6117
|
+
] });
|
|
6118
|
+
if (collapsible) {
|
|
6119
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("details", { className: "entity-result-card tool-result-card entity-result-card--disclosure", children: [
|
|
6120
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("summary", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { role: "status", children: heading }) }),
|
|
6121
|
+
content
|
|
6122
|
+
] });
|
|
6123
|
+
}
|
|
5984
6124
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
5985
6125
|
"section",
|
|
5986
6126
|
{
|
|
5987
|
-
className: `entity-result-card tool-result-card tool-result-card--${result.status}`,
|
|
6127
|
+
className: `entity-result-card tool-result-card tool-result-card--${result.status}${compact ? " entity-result-card--compact" : ""}`,
|
|
5988
6128
|
"aria-label": result.title,
|
|
6129
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
5989
6130
|
children: [
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
|
|
5993
|
-
] }),
|
|
5994
|
-
result.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: result.description }) : null,
|
|
5995
|
-
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
5996
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
|
|
5997
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
|
|
5998
|
-
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
5999
|
-
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)(
|
|
6000
|
-
"a",
|
|
6001
|
-
{
|
|
6002
|
-
href: link.href,
|
|
6003
|
-
target: "_blank",
|
|
6004
|
-
rel: "noreferrer",
|
|
6005
|
-
children: link.label
|
|
6006
|
-
},
|
|
6007
|
-
link.href
|
|
6008
|
-
)) }) : null
|
|
6131
|
+
heading,
|
|
6132
|
+
content
|
|
6009
6133
|
]
|
|
6010
6134
|
}
|
|
6011
6135
|
);
|
|
@@ -6054,6 +6178,7 @@ function ToolResultCard({
|
|
|
6054
6178
|
{
|
|
6055
6179
|
className: `tool-result-card tool-result-card--${result.status}`,
|
|
6056
6180
|
"aria-label": result.title,
|
|
6181
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
6057
6182
|
children: [
|
|
6058
6183
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
6059
6184
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -6217,6 +6342,9 @@ function AgentRail({
|
|
|
6217
6342
|
const railRef = (0, import_react14.useRef)(null);
|
|
6218
6343
|
const overlayRef = (0, import_react14.useRef)(null);
|
|
6219
6344
|
const transcriptRef = (0, import_react14.useRef)(null);
|
|
6345
|
+
const responseRef = (0, import_react14.useRef)(null);
|
|
6346
|
+
const threadRef = (0, import_react14.useRef)(null);
|
|
6347
|
+
const lastScrolledVisitorIdRef = (0, import_react14.useRef)(void 0);
|
|
6220
6348
|
const pinnedToBottomRef = (0, import_react14.useRef)(true);
|
|
6221
6349
|
const smoothScrollToLatestRef = (0, import_react14.useRef)(false);
|
|
6222
6350
|
const lockedTranscriptScrollTopRef = (0, import_react14.useRef)(null);
|
|
@@ -6240,7 +6368,7 @@ function AgentRail({
|
|
|
6240
6368
|
const activeVisitorToolInput = [...visitorToolResults].reverse().find((result) => result.kind === "input");
|
|
6241
6369
|
const visibleVisitorToolResults = activeVisitorToolInput ? [activeVisitorToolInput] : visitorToolResults;
|
|
6242
6370
|
const activityActive = state.toolSteps.some((step) => step.state === "active");
|
|
6243
|
-
const showActivity = state.toolSteps.length > 0 &&
|
|
6371
|
+
const showActivity = state.toolSteps.length > 0 && pendingInputRequests.length === 0 && !state.pendingOffer && activityActive;
|
|
6244
6372
|
const hasVisitorMessages2 = state.messages.some(
|
|
6245
6373
|
(message) => message.role === "visitor"
|
|
6246
6374
|
);
|
|
@@ -6269,7 +6397,7 @@ function AgentRail({
|
|
|
6269
6397
|
}
|
|
6270
6398
|
}
|
|
6271
6399
|
const lastIsAgent = lastMessage?.role === "agent";
|
|
6272
|
-
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2;
|
|
6400
|
+
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
6273
6401
|
const streamingMessage = state.phase === "streaming" && state.streamingText && !lastIsAgent ? {
|
|
6274
6402
|
createdAt: 0,
|
|
6275
6403
|
id: "streaming-response",
|
|
@@ -6299,15 +6427,21 @@ function AgentRail({
|
|
|
6299
6427
|
hasPendingConfirmation,
|
|
6300
6428
|
enabled: lastIsAgent && !isBusy
|
|
6301
6429
|
});
|
|
6430
|
+
const latestResultId = [
|
|
6431
|
+
...visibleMessages.flatMap(
|
|
6432
|
+
(message) => message.role === "agent" ? message.toolResults ?? [] : []
|
|
6433
|
+
),
|
|
6434
|
+
...visibleVisitorToolResults
|
|
6435
|
+
].reverse().find((result) => result.kind !== "input")?.id;
|
|
6302
6436
|
const receiptSteps = answerReceipt && state.toolSteps.length > 0 ? state.toolSteps : void 0;
|
|
6303
6437
|
(0, import_react14.useEffect)(() => {
|
|
6304
6438
|
if (state.phase !== "complete") {
|
|
6305
6439
|
setReceiptOpen(false);
|
|
6306
6440
|
}
|
|
6307
6441
|
}, [state.phase]);
|
|
6308
|
-
function handleSubmit(message) {
|
|
6442
|
+
function handleSubmit(message, options) {
|
|
6309
6443
|
setReceiptOpen(false);
|
|
6310
|
-
onSubmit?.(message);
|
|
6444
|
+
onSubmit?.(message, options);
|
|
6311
6445
|
}
|
|
6312
6446
|
function handleRegenerate() {
|
|
6313
6447
|
setReceiptOpen(false);
|
|
@@ -6321,15 +6455,31 @@ function AgentRail({
|
|
|
6321
6455
|
setReceiptOpen(false);
|
|
6322
6456
|
onFollowUpSelect?.(label);
|
|
6323
6457
|
}
|
|
6458
|
+
const latestVisitorId = visibleMessages[lastVisitorIndex]?.id;
|
|
6324
6459
|
(0, import_react14.useEffect)(() => {
|
|
6325
6460
|
const node = transcriptRef.current;
|
|
6326
6461
|
if (!node) return;
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
node.scrollTop = node.scrollHeight;
|
|
6462
|
+
if (latestVisitorId !== lastScrolledVisitorIdRef.current) {
|
|
6463
|
+
lastScrolledVisitorIdRef.current = latestVisitorId;
|
|
6464
|
+
pinnedToBottomRef.current = true;
|
|
6331
6465
|
}
|
|
6466
|
+
const followResponse = () => {
|
|
6467
|
+
if (node.clientHeight === 0 || !pinnedToBottomRef.current) return;
|
|
6468
|
+
const bottom = Math.max(0, node.scrollHeight - node.clientHeight);
|
|
6469
|
+
const response = responseRef.current;
|
|
6470
|
+
const responseTop = response ? node.scrollTop + response.getBoundingClientRect().top - node.getBoundingClientRect().top : bottom;
|
|
6471
|
+
node.scrollTop = Math.max(node.scrollTop, Math.min(bottom, responseTop));
|
|
6472
|
+
const pinned = bottom - node.scrollTop < 48;
|
|
6473
|
+
pinnedToBottomRef.current = pinned;
|
|
6474
|
+
setShowJumpToLatest(!pinned);
|
|
6475
|
+
};
|
|
6476
|
+
followResponse();
|
|
6477
|
+
const observer = new ResizeObserver(followResponse);
|
|
6478
|
+
observer.observe(node);
|
|
6479
|
+
if (threadRef.current) observer.observe(threadRef.current);
|
|
6480
|
+
return () => observer.disconnect();
|
|
6332
6481
|
}, [
|
|
6482
|
+
latestVisitorId,
|
|
6333
6483
|
state.messages,
|
|
6334
6484
|
state.toolSteps,
|
|
6335
6485
|
state.streamingText,
|
|
@@ -6350,18 +6500,6 @@ function AgentRail({
|
|
|
6350
6500
|
handleScroll();
|
|
6351
6501
|
return () => node.removeEventListener("scroll", handleScroll);
|
|
6352
6502
|
}, []);
|
|
6353
|
-
(0, import_react14.useEffect)(() => {
|
|
6354
|
-
const node = transcriptRef.current;
|
|
6355
|
-
if (!node) return;
|
|
6356
|
-
const observer = new ResizeObserver(() => {
|
|
6357
|
-
if (node.clientHeight === 0) return;
|
|
6358
|
-
if (pinnedToBottomRef.current) {
|
|
6359
|
-
node.scrollTo({ top: node.scrollHeight, behavior: "instant" });
|
|
6360
|
-
}
|
|
6361
|
-
});
|
|
6362
|
-
observer.observe(node);
|
|
6363
|
-
return () => observer.disconnect();
|
|
6364
|
-
}, []);
|
|
6365
6503
|
(0, import_react14.useEffect)(() => {
|
|
6366
6504
|
if (!receiptOpen) {
|
|
6367
6505
|
lockedTranscriptScrollTopRef.current = null;
|
|
@@ -6478,7 +6616,7 @@ function AgentRail({
|
|
|
6478
6616
|
) : null
|
|
6479
6617
|
] })
|
|
6480
6618
|
] }) }),
|
|
6481
|
-
/* @__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: [
|
|
6619
|
+
/* @__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: [
|
|
6482
6620
|
!hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
6483
6621
|
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6484
6622
|
MessageBubble,
|
|
@@ -6525,59 +6663,68 @@ function AgentRail({
|
|
|
6525
6663
|
request.requestId
|
|
6526
6664
|
))
|
|
6527
6665
|
] }) : null,
|
|
6528
|
-
visibleMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
6529
|
-
|
|
6530
|
-
|
|
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
|
-
|
|
6666
|
+
visibleMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
6667
|
+
"div",
|
|
6668
|
+
{
|
|
6669
|
+
ref: index === lastVisitorIndex + 1 ? responseRef : void 0,
|
|
6670
|
+
className: "agent-rail__turn-block",
|
|
6671
|
+
children: [
|
|
6672
|
+
message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VisitorToolResultView, { result }, result.id)) : null,
|
|
6673
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6674
|
+
MessageBubble,
|
|
6675
|
+
{
|
|
6676
|
+
message,
|
|
6677
|
+
bookingDisabled: isBusy,
|
|
6678
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
6679
|
+
offer: index === lastAgentIndex ? state.pendingOffer : void 0,
|
|
6680
|
+
onBook
|
|
6681
|
+
}
|
|
6682
|
+
),
|
|
6683
|
+
index === lastAgentIndex && showMessageActions && message.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6684
|
+
MessageActions,
|
|
6685
|
+
{
|
|
6686
|
+
answeredAt: message.createdAt,
|
|
6687
|
+
copyText: hideToolCardFences(message.text).trim() || message.text,
|
|
6688
|
+
readAloud,
|
|
6689
|
+
receiptSteps,
|
|
6690
|
+
onOpenReceipt: receiptSteps ? openReceipt : void 0,
|
|
6691
|
+
onRegenerate: onRegenerate ? handleRegenerate : void 0,
|
|
6692
|
+
onFeedback: onFeedback ? (rating) => onFeedback(rating, message) : void 0
|
|
6693
|
+
}
|
|
6694
|
+
) : null,
|
|
6695
|
+
index === lastVisitorIndex ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
6696
|
+
showActivity ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6697
|
+
AgentActivityBubble,
|
|
6698
|
+
{
|
|
6699
|
+
brandLabel: resolvedBrandLabel,
|
|
6700
|
+
brandLogoUrl: showBrandLogo ? resolvedBrandLogoUrl : void 0,
|
|
6701
|
+
failed: state.phase === "error",
|
|
6702
|
+
steps: state.toolSteps
|
|
6703
|
+
}
|
|
6704
|
+
) : null,
|
|
6705
|
+
visibleVisitorToolResults.map((result) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6706
|
+
VisitorToolResultView,
|
|
6707
|
+
{
|
|
6708
|
+
result,
|
|
6709
|
+
disabled: semanticSurfaceDisabled,
|
|
6710
|
+
onToolInput
|
|
6711
|
+
},
|
|
6712
|
+
result.id
|
|
6713
|
+
)),
|
|
6714
|
+
pendingInputRequests.slice(0, 1).map((request) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6715
|
+
HumanInputCard,
|
|
6716
|
+
{
|
|
6717
|
+
request,
|
|
6718
|
+
onRespond: onInputResponse
|
|
6719
|
+
},
|
|
6720
|
+
request.requestId
|
|
6721
|
+
))
|
|
6722
|
+
] }) : null
|
|
6723
|
+
]
|
|
6724
|
+
},
|
|
6725
|
+
message.id
|
|
6726
|
+
)),
|
|
6727
|
+
streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: responseRef, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6581
6728
|
MessageBubble,
|
|
6582
6729
|
{
|
|
6583
6730
|
message: streamingMessage,
|
|
@@ -6586,7 +6733,7 @@ function AgentRail({
|
|
|
6586
6733
|
offer: state.pendingOffer,
|
|
6587
6734
|
onBook
|
|
6588
6735
|
}
|
|
6589
|
-
) : null,
|
|
6736
|
+
) }) : null,
|
|
6590
6737
|
waitingForBooking ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BookingCardLoader, {}) : null,
|
|
6591
6738
|
state.error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
|
|
6592
6739
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
@@ -6627,7 +6774,7 @@ function AgentRail({
|
|
|
6627
6774
|
placeholder: composerPlaceholder,
|
|
6628
6775
|
onSubmit: handleSubmit
|
|
6629
6776
|
},
|
|
6630
|
-
state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
|
|
6777
|
+
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
6631
6778
|
),
|
|
6632
6779
|
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
|
|
6633
6780
|
] })
|
|
@@ -6995,9 +7142,9 @@ function AgentWidget({
|
|
|
6995
7142
|
});
|
|
6996
7143
|
return () => unregisterAgentPanelController(customerId);
|
|
6997
7144
|
}, [customerId, registerPanelController, reset, submit]);
|
|
6998
|
-
async function handleSubmit(message) {
|
|
7145
|
+
async function handleSubmit(message, options) {
|
|
6999
7146
|
if (isMobile) setRailCollapsed(false);
|
|
7000
|
-
await submit(message);
|
|
7147
|
+
await submit(message, options);
|
|
7001
7148
|
}
|
|
7002
7149
|
function handleFeedback(rating, message) {
|
|
7003
7150
|
if (!analytics) return;
|
|
@@ -7125,8 +7272,86 @@ function AgentWidget({
|
|
|
7125
7272
|
] });
|
|
7126
7273
|
}
|
|
7127
7274
|
|
|
7128
|
-
// src/react/components/AgentTranscript/
|
|
7275
|
+
// src/react/components/AgentTranscript/TranscriptActivity.tsx
|
|
7129
7276
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
7277
|
+
var statusLabels = {
|
|
7278
|
+
started: "No result recorded",
|
|
7279
|
+
completed: "",
|
|
7280
|
+
failed: "Failed",
|
|
7281
|
+
rejected: "Rejected"
|
|
7282
|
+
};
|
|
7283
|
+
function RecordedResult({
|
|
7284
|
+
result
|
|
7285
|
+
}) {
|
|
7286
|
+
if (result.kind === "search") return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SearchReferences, { results: [result] });
|
|
7287
|
+
if (result.kind === "booking") {
|
|
7288
|
+
const card = result.card;
|
|
7289
|
+
if (card.type === "booking_offer")
|
|
7290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(BookingCard, { readOnly: true, offer: card });
|
|
7291
|
+
if (card.type === "booking_confirmed")
|
|
7292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { children: [
|
|
7293
|
+
"Booking confirmed",
|
|
7294
|
+
card.startTime ? ` \xB7 ${card.startTime}` : ""
|
|
7295
|
+
] });
|
|
7296
|
+
if (card.type === "booking_canceled") return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: "Booking canceled" });
|
|
7297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: "Information requested" });
|
|
7298
|
+
}
|
|
7299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(VisitorToolResultView, { disabled: true, result });
|
|
7300
|
+
}
|
|
7301
|
+
function TranscriptActivity({
|
|
7302
|
+
activity,
|
|
7303
|
+
formatTimestamp
|
|
7304
|
+
}) {
|
|
7305
|
+
const date = new Date(activity.createdAt);
|
|
7306
|
+
const validTimestamp = Number.isFinite(date.getTime());
|
|
7307
|
+
const result = activity.result?.kind === "hidden" ? void 0 : activity.result;
|
|
7308
|
+
const heading = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
7309
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: activity.category === "specialist" ? `Specialist \xB7 ${activity.label}` : activity.label }),
|
|
7310
|
+
activity.status !== "completed" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "agent-transcript__activity-status", children: statusLabels[activity.status] }) : null,
|
|
7311
|
+
validTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("time", { dateTime: date.toISOString(), children: formatTimestamp(activity.createdAt) }) : null
|
|
7312
|
+
] });
|
|
7313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { className: "agent-transcript__activity", "data-status": activity.status, children: result ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("details", { children: [
|
|
7314
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("summary", { className: "agent-transcript__activity-heading", children: heading }),
|
|
7315
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "agent-transcript__activity-result", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(RecordedResult, { result }) })
|
|
7316
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "agent-transcript__activity-heading", children: heading }) });
|
|
7317
|
+
}
|
|
7318
|
+
|
|
7319
|
+
// src/react/components/AgentTranscript/group-activities.ts
|
|
7320
|
+
function groupTranscriptActivities(activities) {
|
|
7321
|
+
const calls = /* @__PURE__ */ new Map();
|
|
7322
|
+
for (const activity of activities) {
|
|
7323
|
+
const key = `${activity.category}:${activity.callId}`;
|
|
7324
|
+
const previous = calls.get(key);
|
|
7325
|
+
if (!previous) {
|
|
7326
|
+
calls.set(key, {
|
|
7327
|
+
latest: activity,
|
|
7328
|
+
id: activity.id,
|
|
7329
|
+
startedAt: activity.createdAt,
|
|
7330
|
+
label: activity.label
|
|
7331
|
+
});
|
|
7332
|
+
continue;
|
|
7333
|
+
}
|
|
7334
|
+
const previousHasResult = previous.latest.status !== "started";
|
|
7335
|
+
const nextHasResult = activity.status !== "started";
|
|
7336
|
+
const useNext = nextHasResult && !previousHasResult || nextHasResult === previousHasResult && activity.createdAt >= previous.latest.createdAt;
|
|
7337
|
+
const latest = useNext ? activity : previous.latest;
|
|
7338
|
+
calls.set(key, {
|
|
7339
|
+
latest,
|
|
7340
|
+
id: previous.id,
|
|
7341
|
+
startedAt: Math.min(previous.startedAt, activity.createdAt),
|
|
7342
|
+
label: activity.createdAt < previous.startedAt ? activity.label : previous.label
|
|
7343
|
+
});
|
|
7344
|
+
}
|
|
7345
|
+
return [...calls.values()].map(({ latest, id, startedAt, label }) => ({
|
|
7346
|
+
...latest,
|
|
7347
|
+
id,
|
|
7348
|
+
label,
|
|
7349
|
+
createdAt: startedAt
|
|
7350
|
+
}));
|
|
7351
|
+
}
|
|
7352
|
+
|
|
7353
|
+
// src/react/components/AgentTranscript/AgentTranscript.tsx
|
|
7354
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
7130
7355
|
var timestampFormat = new Intl.DateTimeFormat("en-US", {
|
|
7131
7356
|
month: "short",
|
|
7132
7357
|
day: "numeric",
|
|
@@ -7139,6 +7364,7 @@ function defaultTimestamp(createdAt) {
|
|
|
7139
7364
|
}
|
|
7140
7365
|
function AgentTranscript({
|
|
7141
7366
|
messages,
|
|
7367
|
+
activities = [],
|
|
7142
7368
|
theme,
|
|
7143
7369
|
colorScheme,
|
|
7144
7370
|
agentLabel = "Agent",
|
|
@@ -7147,7 +7373,14 @@ function AgentTranscript({
|
|
|
7147
7373
|
formatTimestamp = defaultTimestamp
|
|
7148
7374
|
}) {
|
|
7149
7375
|
const scheme = useAgentColorScheme(colorScheme);
|
|
7150
|
-
|
|
7376
|
+
const entries = [
|
|
7377
|
+
...messages.map((message) => ({ kind: "message", ...message })),
|
|
7378
|
+
...groupTranscriptActivities(activities).map((activity) => ({
|
|
7379
|
+
kind: "activity",
|
|
7380
|
+
...activity
|
|
7381
|
+
}))
|
|
7382
|
+
].sort((left, right) => left.createdAt - right.createdAt);
|
|
7383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7151
7384
|
"ol",
|
|
7152
7385
|
{
|
|
7153
7386
|
className: "webless-agent-root agent-transcript not-typeset",
|
|
@@ -7155,22 +7388,34 @@ function AgentTranscript({
|
|
|
7155
7388
|
"data-color-scheme": scheme,
|
|
7156
7389
|
"aria-label": label,
|
|
7157
7390
|
style: agentThemeStyle(theme, scheme),
|
|
7158
|
-
children:
|
|
7391
|
+
children: entries.map((message) => {
|
|
7392
|
+
if (message.kind === "activity")
|
|
7393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7394
|
+
TranscriptActivity,
|
|
7395
|
+
{
|
|
7396
|
+
activity: message,
|
|
7397
|
+
formatTimestamp
|
|
7398
|
+
},
|
|
7399
|
+
message.id
|
|
7400
|
+
);
|
|
7401
|
+
if (message.role === "visitor" && !message.text.trim()) return null;
|
|
7159
7402
|
const date = new Date(message.createdAt);
|
|
7160
7403
|
const validTimestamp = Number.isFinite(date.getTime());
|
|
7161
|
-
return /* @__PURE__ */ (0,
|
|
7404
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
7162
7405
|
"li",
|
|
7163
7406
|
{
|
|
7164
7407
|
className: `agent-transcript__message agent-transcript__message--${message.role}`,
|
|
7165
7408
|
children: [
|
|
7166
|
-
/* @__PURE__ */ (0,
|
|
7167
|
-
/* @__PURE__ */ (0,
|
|
7168
|
-
validTimestamp ? /* @__PURE__ */ (0,
|
|
7409
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "agent-transcript__meta", children: [
|
|
7410
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: message.role === "visitor" ? visitorLabel : agentLabel }),
|
|
7411
|
+
validTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("time", { dateTime: date.toISOString(), children: formatTimestamp(message.createdAt) }) : null
|
|
7169
7412
|
] }),
|
|
7170
|
-
/* @__PURE__ */ (0,
|
|
7413
|
+
message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(VisitorToolResultView, { result }, result.id)) : null,
|
|
7414
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7171
7415
|
MessageBubble,
|
|
7172
7416
|
{
|
|
7173
7417
|
message: message.role === "agent" ? { ...message, streaming: false } : message,
|
|
7418
|
+
bookingReadOnly: true,
|
|
7174
7419
|
bookingDisabled: true
|
|
7175
7420
|
}
|
|
7176
7421
|
)
|