@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/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
|
}
|
|
@@ -365,457 +688,250 @@ function loadPersistedAgentSession(visitorSessionId, options) {
|
|
|
365
688
|
}
|
|
366
689
|
function savePersistedAgentSession(visitorSessionId, sessionId, streamIndex, options) {
|
|
367
690
|
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !sessionId.trim()) {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
const prefix = resolvePrefix(options);
|
|
371
|
-
sessionStorage.setItem(runtimeSessionIdKey(visitorSessionId, prefix), sessionId);
|
|
372
|
-
sessionStorage.setItem(
|
|
373
|
-
runtimeStreamIndexKey(visitorSessionId, prefix),
|
|
374
|
-
String(Math.max(0, streamIndex))
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
function savePersistedAgentTurnMessage(visitorSessionId, message, options) {
|
|
378
|
-
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !message) {
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
const prefix = resolvePrefix(options);
|
|
382
|
-
sessionStorage.setItem(runtimeLastMessageKey(visitorSessionId, prefix), message);
|
|
383
|
-
}
|
|
384
|
-
function clearPersistedAgentSession(visitorSessionId, options) {
|
|
385
|
-
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return;
|
|
386
|
-
const prefix = resolvePrefix(options);
|
|
387
|
-
sessionStorage.removeItem(runtimeSessionIdKey(visitorSessionId, prefix));
|
|
388
|
-
sessionStorage.removeItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
389
|
-
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// src/runtime/subagent-child-stream.ts
|
|
393
|
-
var INITIAL_RETRY_DELAY_MS = 100;
|
|
394
|
-
var MAX_RETRY_DELAY_MS = 2e3;
|
|
395
|
-
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
396
|
-
function isRecord2(value) {
|
|
397
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
398
|
-
}
|
|
399
|
-
function parseError(value) {
|
|
400
|
-
if (!isRecord2(value)) return void 0;
|
|
401
|
-
const { code, message } = value;
|
|
402
|
-
if (typeof code !== "string" || typeof message !== "string") {
|
|
403
|
-
return void 0;
|
|
404
|
-
}
|
|
405
|
-
return { code, message };
|
|
406
|
-
}
|
|
407
|
-
function parseChildStreamEvent(value) {
|
|
408
|
-
if (!isRecord2(value) || typeof value.type !== "string") {
|
|
409
|
-
return { type: "other" };
|
|
410
|
-
}
|
|
411
|
-
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
412
|
-
return { type: "session.boundary" };
|
|
413
|
-
}
|
|
414
|
-
if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
|
|
415
|
-
return parseChildStreamEvent(value.data.event);
|
|
416
|
-
}
|
|
417
|
-
if (value.type === "subagent.called" && isRecord2(value.data)) {
|
|
418
|
-
const { childStreamPath } = value.data;
|
|
419
|
-
if (typeof childStreamPath === "string") {
|
|
420
|
-
return { childStreamPath, type: "subagent.called" };
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if (value.type !== "action.result" || !isRecord2(value.data)) {
|
|
424
|
-
return { type: "other" };
|
|
425
|
-
}
|
|
426
|
-
const { data } = value;
|
|
427
|
-
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
428
|
-
return { type: "other" };
|
|
429
|
-
}
|
|
430
|
-
if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
|
|
431
|
-
return { type: "other" };
|
|
432
|
-
}
|
|
433
|
-
const result = data.result;
|
|
434
|
-
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
435
|
-
return { type: "other" };
|
|
436
|
-
}
|
|
437
|
-
const error = parseError(data.error);
|
|
438
|
-
return {
|
|
439
|
-
type: "action.result",
|
|
440
|
-
hasOutput: Object.hasOwn(result, "output"),
|
|
441
|
-
result: {
|
|
442
|
-
callId: result.callId,
|
|
443
|
-
toolName: result.toolName,
|
|
444
|
-
status: data.status,
|
|
445
|
-
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
446
|
-
...error ? { error } : {}
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
async function* readNdjsonStream(body) {
|
|
451
|
-
const reader = body.getReader();
|
|
452
|
-
const decoder = new TextDecoder();
|
|
453
|
-
let buffer = "";
|
|
454
|
-
try {
|
|
455
|
-
while (true) {
|
|
456
|
-
const { done, value } = await reader.read();
|
|
457
|
-
buffer += decoder.decode(value, { stream: !done });
|
|
458
|
-
const lines = buffer.split("\n");
|
|
459
|
-
buffer = lines.pop() ?? "";
|
|
460
|
-
for (const line of lines) {
|
|
461
|
-
const trimmed2 = line.trim();
|
|
462
|
-
if (!trimmed2) continue;
|
|
463
|
-
try {
|
|
464
|
-
const parsed = JSON.parse(trimmed2);
|
|
465
|
-
yield parsed;
|
|
466
|
-
} catch {
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
if (done) break;
|
|
470
|
-
}
|
|
471
|
-
const trimmed = buffer.trim();
|
|
472
|
-
if (trimmed) {
|
|
473
|
-
try {
|
|
474
|
-
const parsed = JSON.parse(trimmed);
|
|
475
|
-
yield parsed;
|
|
476
|
-
} catch {
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
} finally {
|
|
480
|
-
reader.releaseLock();
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
function streamPathAt(path, streamIndex) {
|
|
484
|
-
if (streamIndex === 0) return path;
|
|
485
|
-
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
486
|
-
}
|
|
487
|
-
function abortableDelay(delayMs, signal) {
|
|
488
|
-
if (signal.aborted) return Promise.resolve();
|
|
489
|
-
return new Promise((resolve) => {
|
|
490
|
-
const finish = () => {
|
|
491
|
-
clearTimeout(timeout);
|
|
492
|
-
signal.removeEventListener("abort", finish);
|
|
493
|
-
resolve();
|
|
494
|
-
};
|
|
495
|
-
const timeout = setTimeout(finish, delayMs);
|
|
496
|
-
signal.addEventListener("abort", finish, { once: true });
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
var SubagentChildStreamCoordinator = class {
|
|
500
|
-
constructor(client, handlers, parentSignal) {
|
|
501
|
-
this.client = client;
|
|
502
|
-
this.handlers = handlers;
|
|
503
|
-
this.parentSignal = parentSignal;
|
|
504
|
-
}
|
|
505
|
-
client;
|
|
506
|
-
handlers;
|
|
507
|
-
parentSignal;
|
|
508
|
-
controllers = /* @__PURE__ */ new Map();
|
|
509
|
-
tasks = /* @__PURE__ */ new Map();
|
|
510
|
-
begin(event) {
|
|
511
|
-
this.beginPath(event.data.childStreamPath);
|
|
512
|
-
}
|
|
513
|
-
async waitForAll() {
|
|
514
|
-
let observedTaskCount = -1;
|
|
515
|
-
while (observedTaskCount !== this.tasks.size) {
|
|
516
|
-
observedTaskCount = this.tasks.size;
|
|
517
|
-
await Promise.all(this.tasks.values());
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
abortAll() {
|
|
521
|
-
for (const controller of this.controllers.values()) controller.abort();
|
|
522
|
-
this.controllers.clear();
|
|
523
|
-
}
|
|
524
|
-
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)
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const prefix = resolvePrefix(options);
|
|
694
|
+
sessionStorage.setItem(runtimeSessionIdKey(visitorSessionId, prefix), sessionId);
|
|
695
|
+
sessionStorage.setItem(
|
|
696
|
+
runtimeStreamIndexKey(visitorSessionId, prefix),
|
|
697
|
+
String(Math.max(0, streamIndex))
|
|
615
698
|
);
|
|
616
|
-
seen.delete(value);
|
|
617
|
-
return valid;
|
|
618
699
|
}
|
|
619
|
-
function
|
|
620
|
-
if (typeof
|
|
621
|
-
return
|
|
700
|
+
function savePersistedAgentTurnMessage(visitorSessionId, message, options) {
|
|
701
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !message) {
|
|
702
|
+
return;
|
|
622
703
|
}
|
|
623
|
-
|
|
704
|
+
const prefix = resolvePrefix(options);
|
|
705
|
+
sessionStorage.setItem(runtimeLastMessageKey(visitorSessionId, prefix), message);
|
|
624
706
|
}
|
|
625
|
-
function
|
|
626
|
-
|
|
707
|
+
function clearPersistedAgentSession(visitorSessionId, options) {
|
|
708
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return;
|
|
709
|
+
const prefix = resolvePrefix(options);
|
|
710
|
+
sessionStorage.removeItem(runtimeSessionIdKey(visitorSessionId, prefix));
|
|
711
|
+
sessionStorage.removeItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
712
|
+
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
627
713
|
}
|
|
628
|
-
|
|
629
|
-
|
|
714
|
+
|
|
715
|
+
// src/runtime/subagent-child-stream.ts
|
|
716
|
+
var INITIAL_RETRY_DELAY_MS = 100;
|
|
717
|
+
var MAX_RETRY_DELAY_MS = 2e3;
|
|
718
|
+
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
719
|
+
function isRecord4(value) {
|
|
720
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
630
721
|
}
|
|
631
|
-
function
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
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);
|
|
722
|
+
function parseError(value) {
|
|
723
|
+
if (!isRecord4(value)) return void 0;
|
|
724
|
+
const { code, message } = value;
|
|
725
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
726
|
+
return void 0;
|
|
727
|
+
}
|
|
728
|
+
return { code, message };
|
|
649
729
|
}
|
|
650
|
-
function
|
|
651
|
-
if (!
|
|
652
|
-
|
|
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;
|
|
730
|
+
function parseChildStreamEvent(value) {
|
|
731
|
+
if (!isRecord4(value) || typeof value.type !== "string") {
|
|
732
|
+
return { type: "other" };
|
|
669
733
|
}
|
|
670
|
-
if (
|
|
671
|
-
|
|
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;
|
|
734
|
+
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
735
|
+
return { type: "session.boundary" };
|
|
685
736
|
}
|
|
686
|
-
if (value.
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
if (value.
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
-
}
|
|
737
|
+
if (value.type === "subagent.event" && isRecord4(value.data) && Object.hasOwn(value.data, "event")) {
|
|
738
|
+
return parseChildStreamEvent(value.data.event);
|
|
739
|
+
}
|
|
740
|
+
if (value.type === "subagent.called" && isRecord4(value.data)) {
|
|
741
|
+
const { childStreamPath } = value.data;
|
|
742
|
+
if (typeof childStreamPath === "string") {
|
|
743
|
+
return { childStreamPath, type: "subagent.called" };
|
|
705
744
|
}
|
|
706
745
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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;
|
|
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 };
|
|
728
757
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
758
|
+
if (value.type !== "action.result" || !isRecord4(value.data)) {
|
|
759
|
+
return { type: "other" };
|
|
760
|
+
}
|
|
761
|
+
const { data } = value;
|
|
762
|
+
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
763
|
+
return { type: "other" };
|
|
764
|
+
}
|
|
765
|
+
if (!isRecord4(data.result) || data.result.kind !== "tool-result") {
|
|
766
|
+
return { type: "other" };
|
|
767
|
+
}
|
|
768
|
+
const result = data.result;
|
|
769
|
+
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
770
|
+
return { type: "other" };
|
|
736
771
|
}
|
|
772
|
+
const error = parseError(data.error);
|
|
737
773
|
return {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
774
|
+
type: "action.result",
|
|
775
|
+
hasOutput: Object.hasOwn(result, "output"),
|
|
776
|
+
result: {
|
|
777
|
+
callId: result.callId,
|
|
778
|
+
toolName: result.toolName,
|
|
779
|
+
status: result.isError === true ? "failed" : data.status,
|
|
780
|
+
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
781
|
+
...error ? { error } : {}
|
|
782
|
+
}
|
|
742
783
|
};
|
|
743
784
|
}
|
|
744
|
-
function
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
785
|
+
async function* readNdjsonStream(body) {
|
|
786
|
+
const reader = body.getReader();
|
|
787
|
+
const decoder = new TextDecoder();
|
|
788
|
+
let buffer = "";
|
|
789
|
+
try {
|
|
790
|
+
while (true) {
|
|
791
|
+
const { done, value } = await reader.read();
|
|
792
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
793
|
+
const lines = buffer.split("\n");
|
|
794
|
+
buffer = lines.pop() ?? "";
|
|
795
|
+
for (const line of lines) {
|
|
796
|
+
const trimmed2 = line.trim();
|
|
797
|
+
if (!trimmed2) continue;
|
|
798
|
+
try {
|
|
799
|
+
const parsed = JSON.parse(trimmed2);
|
|
800
|
+
yield parsed;
|
|
801
|
+
} catch {
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
if (done) break;
|
|
805
|
+
}
|
|
806
|
+
const trimmed = buffer.trim();
|
|
807
|
+
if (trimmed) {
|
|
808
|
+
try {
|
|
809
|
+
const parsed = JSON.parse(trimmed);
|
|
810
|
+
yield parsed;
|
|
811
|
+
} catch {
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
} finally {
|
|
815
|
+
reader.releaseLock();
|
|
750
816
|
}
|
|
751
|
-
return {
|
|
752
|
-
id: value.id,
|
|
753
|
-
label
|
|
754
|
-
};
|
|
755
817
|
}
|
|
756
|
-
function
|
|
757
|
-
if (
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
"
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
818
|
+
function streamPathAt(path, streamIndex) {
|
|
819
|
+
if (streamIndex === 0) return path;
|
|
820
|
+
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
821
|
+
}
|
|
822
|
+
function abortableDelay(delayMs, signal) {
|
|
823
|
+
if (signal.aborted) return Promise.resolve();
|
|
824
|
+
return new Promise((resolve) => {
|
|
825
|
+
const finish = () => {
|
|
826
|
+
clearTimeout(timeout);
|
|
827
|
+
signal.removeEventListener("abort", finish);
|
|
828
|
+
resolve();
|
|
829
|
+
};
|
|
830
|
+
const timeout = setTimeout(finish, delayMs);
|
|
831
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
var SubagentChildStreamCoordinator = class {
|
|
835
|
+
constructor(client, handlers, parentSignal) {
|
|
836
|
+
this.client = client;
|
|
837
|
+
this.handlers = handlers;
|
|
838
|
+
this.parentSignal = parentSignal;
|
|
839
|
+
}
|
|
840
|
+
client;
|
|
841
|
+
handlers;
|
|
842
|
+
parentSignal;
|
|
843
|
+
controllers = /* @__PURE__ */ new Map();
|
|
844
|
+
tasks = /* @__PURE__ */ new Map();
|
|
845
|
+
begin(event) {
|
|
846
|
+
this.beginPath(event.data.childStreamPath);
|
|
774
847
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
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;
|
|
848
|
+
async waitForAll() {
|
|
849
|
+
let observedTaskCount = -1;
|
|
850
|
+
while (observedTaskCount !== this.tasks.size) {
|
|
851
|
+
observedTaskCount = this.tasks.size;
|
|
852
|
+
await Promise.all(this.tasks.values());
|
|
853
|
+
}
|
|
784
854
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
if (steps?.some((step) => step === null)) return null;
|
|
789
|
-
const actions = value.actions === void 0 ? void 0 : Array.isArray(value.actions) && value.actions.length <= 8 ? value.actions.map(parseAction) : null;
|
|
790
|
-
if (actions?.some((action) => action === null)) return null;
|
|
791
|
-
if (value.description !== void 0 && !description) return null;
|
|
792
|
-
if (value.operationId !== void 0 && !operationId) return null;
|
|
793
|
-
if (value.requestId !== void 0 && !requestId) return null;
|
|
794
|
-
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
795
|
-
const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
|
|
796
|
-
if (value.values !== void 0) {
|
|
797
|
-
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
798
|
-
return null;
|
|
855
|
+
abortAll() {
|
|
856
|
+
for (const controller of this.controllers.values()) controller.abort();
|
|
857
|
+
this.controllers.clear();
|
|
799
858
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
859
|
+
beginPath(childStreamPath) {
|
|
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);
|
|
878
|
+
}
|
|
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
|
+
}
|
|
933
|
+
}
|
|
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: [
|
|
@@ -4767,6 +4857,7 @@ function MessageBubble({
|
|
|
4767
4857
|
offers.length > 0 ? sanitizeBookingOfferCopy(visibleText) : looksLikeBookingAvailabilityDump(visibleText) ? sanitizeBookingOfferCopy(visibleText) : visibleText || (isStreaming ? "" : message.text)
|
|
4768
4858
|
);
|
|
4769
4859
|
if (message.role === "visitor") {
|
|
4860
|
+
if (!message.text.trim()) return null;
|
|
4770
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 }) });
|
|
4771
4862
|
}
|
|
4772
4863
|
const citations = message.citations ?? [];
|
|
@@ -4785,8 +4876,8 @@ function MessageBubble({
|
|
|
4785
4876
|
children: displayText
|
|
4786
4877
|
}
|
|
4787
4878
|
),
|
|
4788
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SearchReferences, { results: message.searchResults ?? [] }),
|
|
4789
|
-
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: [
|
|
4790
4881
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4791
4882
|
"span",
|
|
4792
4883
|
{
|
|
@@ -4798,6 +4889,7 @@ function MessageBubble({
|
|
|
4798
4889
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: citation.label })
|
|
4799
4890
|
] }) }, citation.id)) }) : null
|
|
4800
4891
|
] });
|
|
4892
|
+
if (!displayText && !message.searchResults?.length && offers.length === 0) return null;
|
|
4801
4893
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: "message-bubble message-bubble--agent", children: [
|
|
4802
4894
|
displayText || message.searchResults?.length ? showBrandLogo ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "message-bubble__agent-row", children: [
|
|
4803
4895
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "message-bubble__agent-avatar", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -5975,6 +6067,7 @@ function CollectionResultCard({
|
|
|
5975
6067
|
{
|
|
5976
6068
|
className: `collection-result-card tool-result-card tool-result-card--${result.status}`,
|
|
5977
6069
|
"aria-label": result.title,
|
|
6070
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
5978
6071
|
children: [
|
|
5979
6072
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
5980
6073
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -5999,31 +6092,44 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
|
5999
6092
|
function EntityResultCard({
|
|
6000
6093
|
result
|
|
6001
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
|
+
}
|
|
6002
6124
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
6003
6125
|
"section",
|
|
6004
6126
|
{
|
|
6005
|
-
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" : ""}`,
|
|
6006
6128
|
"aria-label": result.title,
|
|
6129
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
6007
6130
|
children: [
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: result.title })
|
|
6011
|
-
] }),
|
|
6012
|
-
result.description ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: result.description }) : null,
|
|
6013
|
-
result.details?.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { children: result.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
6014
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: detail.label }),
|
|
6015
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: detail.value })
|
|
6016
|
-
] }, `${detail.label}:${detail.value}`)) }) : null,
|
|
6017
|
-
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)(
|
|
6018
|
-
"a",
|
|
6019
|
-
{
|
|
6020
|
-
href: link.href,
|
|
6021
|
-
target: "_blank",
|
|
6022
|
-
rel: "noreferrer",
|
|
6023
|
-
children: link.label
|
|
6024
|
-
},
|
|
6025
|
-
link.href
|
|
6026
|
-
)) }) : null
|
|
6131
|
+
heading,
|
|
6132
|
+
content
|
|
6027
6133
|
]
|
|
6028
6134
|
}
|
|
6029
6135
|
);
|
|
@@ -6072,6 +6178,7 @@ function ToolResultCard({
|
|
|
6072
6178
|
{
|
|
6073
6179
|
className: `tool-result-card tool-result-card--${result.status}`,
|
|
6074
6180
|
"aria-label": result.title,
|
|
6181
|
+
role: result.status === "completed" ? "status" : "alert",
|
|
6075
6182
|
children: [
|
|
6076
6183
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "tool-result-card__heading", children: [
|
|
6077
6184
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "tool-result-card__status", "aria-hidden": "true" }),
|
|
@@ -6235,6 +6342,9 @@ function AgentRail({
|
|
|
6235
6342
|
const railRef = (0, import_react14.useRef)(null);
|
|
6236
6343
|
const overlayRef = (0, import_react14.useRef)(null);
|
|
6237
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);
|
|
6238
6348
|
const pinnedToBottomRef = (0, import_react14.useRef)(true);
|
|
6239
6349
|
const smoothScrollToLatestRef = (0, import_react14.useRef)(false);
|
|
6240
6350
|
const lockedTranscriptScrollTopRef = (0, import_react14.useRef)(null);
|
|
@@ -6258,7 +6368,7 @@ function AgentRail({
|
|
|
6258
6368
|
const activeVisitorToolInput = [...visitorToolResults].reverse().find((result) => result.kind === "input");
|
|
6259
6369
|
const visibleVisitorToolResults = activeVisitorToolInput ? [activeVisitorToolInput] : visitorToolResults;
|
|
6260
6370
|
const activityActive = state.toolSteps.some((step) => step.state === "active");
|
|
6261
|
-
const showActivity = state.toolSteps.length > 0 &&
|
|
6371
|
+
const showActivity = state.toolSteps.length > 0 && pendingInputRequests.length === 0 && !state.pendingOffer && activityActive;
|
|
6262
6372
|
const hasVisitorMessages2 = state.messages.some(
|
|
6263
6373
|
(message) => message.role === "visitor"
|
|
6264
6374
|
);
|
|
@@ -6287,7 +6397,7 @@ function AgentRail({
|
|
|
6287
6397
|
}
|
|
6288
6398
|
}
|
|
6289
6399
|
const lastIsAgent = lastMessage?.role === "agent";
|
|
6290
|
-
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2;
|
|
6400
|
+
const showMessageActions = state.phase === "complete" && lastIsAgent && hasVisitorMessages2 && Boolean(hideToolCardFences(lastMessage.text).trim());
|
|
6291
6401
|
const streamingMessage = state.phase === "streaming" && state.streamingText && !lastIsAgent ? {
|
|
6292
6402
|
createdAt: 0,
|
|
6293
6403
|
id: "streaming-response",
|
|
@@ -6317,15 +6427,21 @@ function AgentRail({
|
|
|
6317
6427
|
hasPendingConfirmation,
|
|
6318
6428
|
enabled: lastIsAgent && !isBusy
|
|
6319
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;
|
|
6320
6436
|
const receiptSteps = answerReceipt && state.toolSteps.length > 0 ? state.toolSteps : void 0;
|
|
6321
6437
|
(0, import_react14.useEffect)(() => {
|
|
6322
6438
|
if (state.phase !== "complete") {
|
|
6323
6439
|
setReceiptOpen(false);
|
|
6324
6440
|
}
|
|
6325
6441
|
}, [state.phase]);
|
|
6326
|
-
function handleSubmit(message) {
|
|
6442
|
+
function handleSubmit(message, options) {
|
|
6327
6443
|
setReceiptOpen(false);
|
|
6328
|
-
onSubmit?.(message);
|
|
6444
|
+
onSubmit?.(message, options);
|
|
6329
6445
|
}
|
|
6330
6446
|
function handleRegenerate() {
|
|
6331
6447
|
setReceiptOpen(false);
|
|
@@ -6339,15 +6455,31 @@ function AgentRail({
|
|
|
6339
6455
|
setReceiptOpen(false);
|
|
6340
6456
|
onFollowUpSelect?.(label);
|
|
6341
6457
|
}
|
|
6458
|
+
const latestVisitorId = visibleMessages[lastVisitorIndex]?.id;
|
|
6342
6459
|
(0, import_react14.useEffect)(() => {
|
|
6343
6460
|
const node = transcriptRef.current;
|
|
6344
6461
|
if (!node) return;
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
node.scrollTop = node.scrollHeight;
|
|
6462
|
+
if (latestVisitorId !== lastScrolledVisitorIdRef.current) {
|
|
6463
|
+
lastScrolledVisitorIdRef.current = latestVisitorId;
|
|
6464
|
+
pinnedToBottomRef.current = true;
|
|
6349
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();
|
|
6350
6481
|
}, [
|
|
6482
|
+
latestVisitorId,
|
|
6351
6483
|
state.messages,
|
|
6352
6484
|
state.toolSteps,
|
|
6353
6485
|
state.streamingText,
|
|
@@ -6368,18 +6500,6 @@ function AgentRail({
|
|
|
6368
6500
|
handleScroll();
|
|
6369
6501
|
return () => node.removeEventListener("scroll", handleScroll);
|
|
6370
6502
|
}, []);
|
|
6371
|
-
(0, import_react14.useEffect)(() => {
|
|
6372
|
-
const node = transcriptRef.current;
|
|
6373
|
-
if (!node) return;
|
|
6374
|
-
const observer = new ResizeObserver(() => {
|
|
6375
|
-
if (node.clientHeight === 0) return;
|
|
6376
|
-
if (pinnedToBottomRef.current) {
|
|
6377
|
-
node.scrollTo({ top: node.scrollHeight, behavior: "instant" });
|
|
6378
|
-
}
|
|
6379
|
-
});
|
|
6380
|
-
observer.observe(node);
|
|
6381
|
-
return () => observer.disconnect();
|
|
6382
|
-
}, []);
|
|
6383
6503
|
(0, import_react14.useEffect)(() => {
|
|
6384
6504
|
if (!receiptOpen) {
|
|
6385
6505
|
lockedTranscriptScrollTopRef.current = null;
|
|
@@ -6496,7 +6616,7 @@ function AgentRail({
|
|
|
6496
6616
|
) : null
|
|
6497
6617
|
] })
|
|
6498
6618
|
] }) }),
|
|
6499
|
-
/* @__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: [
|
|
6500
6620
|
!hasVisitorMessages2 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__welcome", "aria-label": "Welcome", children: [
|
|
6501
6621
|
greeting?.role === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6502
6622
|
MessageBubble,
|
|
@@ -6543,59 +6663,68 @@ function AgentRail({
|
|
|
6543
6663
|
request.requestId
|
|
6544
6664
|
))
|
|
6545
6665
|
] }) : null,
|
|
6546
|
-
visibleMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
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)(
|
|
6599
6728
|
MessageBubble,
|
|
6600
6729
|
{
|
|
6601
6730
|
message: streamingMessage,
|
|
@@ -6604,7 +6733,7 @@ function AgentRail({
|
|
|
6604
6733
|
offer: state.pendingOffer,
|
|
6605
6734
|
onBook
|
|
6606
6735
|
}
|
|
6607
|
-
) : null,
|
|
6736
|
+
) }) : null,
|
|
6608
6737
|
waitingForBooking ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BookingCardLoader, {}) : null,
|
|
6609
6738
|
state.error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "agent-rail__error", role: "alert", children: [
|
|
6610
6739
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
@@ -6645,7 +6774,7 @@ function AgentRail({
|
|
|
6645
6774
|
placeholder: composerPlaceholder,
|
|
6646
6775
|
onSubmit: handleSubmit
|
|
6647
6776
|
},
|
|
6648
|
-
state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
|
|
6777
|
+
`${state.messages.find((message) => message.role === "visitor")?.id ?? "empty"}:${latestResultId ?? ""}`
|
|
6649
6778
|
),
|
|
6650
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
|
|
6651
6780
|
] })
|
|
@@ -7013,9 +7142,9 @@ function AgentWidget({
|
|
|
7013
7142
|
});
|
|
7014
7143
|
return () => unregisterAgentPanelController(customerId);
|
|
7015
7144
|
}, [customerId, registerPanelController, reset, submit]);
|
|
7016
|
-
async function handleSubmit(message) {
|
|
7145
|
+
async function handleSubmit(message, options) {
|
|
7017
7146
|
if (isMobile) setRailCollapsed(false);
|
|
7018
|
-
await submit(message);
|
|
7147
|
+
await submit(message, options);
|
|
7019
7148
|
}
|
|
7020
7149
|
function handleFeedback(rating, message) {
|
|
7021
7150
|
if (!analytics) return;
|
|
@@ -7269,6 +7398,7 @@ function AgentTranscript({
|
|
|
7269
7398
|
},
|
|
7270
7399
|
message.id
|
|
7271
7400
|
);
|
|
7401
|
+
if (message.role === "visitor" && !message.text.trim()) return null;
|
|
7272
7402
|
const date = new Date(message.createdAt);
|
|
7273
7403
|
const validTimestamp = Number.isFinite(date.getTime());
|
|
7274
7404
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
@@ -7280,6 +7410,7 @@ function AgentTranscript({
|
|
|
7280
7410
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: message.role === "visitor" ? visitorLabel : agentLabel }),
|
|
7281
7411
|
validTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("time", { dateTime: date.toISOString(), children: formatTimestamp(message.createdAt) }) : null
|
|
7282
7412
|
] }),
|
|
7413
|
+
message.role === "agent" ? message.toolResults?.map((result) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(VisitorToolResultView, { result }, result.id)) : null,
|
|
7283
7414
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7284
7415
|
MessageBubble,
|
|
7285
7416
|
{
|