@webless/agent 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,11 +47,12 @@ function createAgentRuntimeCapability(options) {
47
47
  let pendingBootstrap;
48
48
  const bootstrap = async () => {
49
49
  let previewGrant;
50
+ const previewBuildId = options.previewBuildId?.trim();
50
51
  if (options.version === "unpublished") {
51
- previewGrant = (await options.getUnpublishedPreviewGrant?.())?.trim();
52
- if (!previewGrant) {
52
+ previewGrant = previewBuildId ? void 0 : (await options.getUnpublishedPreviewGrant?.())?.trim();
53
+ if (!previewGrant && !previewBuildId) {
53
54
  throw new Error(
54
- "An unpublished preview grant is required to use the Agent Runtime preview."
55
+ "Unpublished preview authorization is required to use the Agent Runtime preview."
55
56
  );
56
57
  }
57
58
  }
@@ -61,6 +62,7 @@ function createAgentRuntimeCapability(options) {
61
62
  body: JSON.stringify({
62
63
  clientSessionId: options.visitorSessionId,
63
64
  indexId: options.indexId,
65
+ ...previewBuildId ? { previewBuildId } : {},
64
66
  ...previewGrant ? { previewGrant } : {},
65
67
  version: options.version
66
68
  }),
@@ -269,13 +271,15 @@ function emitWorkItem(item, handlers, workItems) {
269
271
  handlers.onWork?.(item);
270
272
  handlers.onStep?.(item.label, item.detail);
271
273
  }
272
- function completePlanning(handlers, workItems) {
274
+ function completePlanning(handlers, workItems, nextItems = []) {
273
275
  const planning = workItems.get("planning");
274
276
  if (!planning || planning.state !== "active") return;
277
+ const specialists = nextItems.filter((item) => item.kind === "specialist");
278
+ const detail = specialists.length === 1 ? `Delegating to ${specialists[0]?.label}` : specialists.length > 1 ? `Delegating to ${specialists.length} specialists` : nextItems.some((item) => item.kind === "search") ? "Using built-in Search & Discovery" : "Picked the best way to help";
275
279
  emitWorkItem(
276
280
  {
277
281
  ...planning,
278
- detail: "Picked the best way to help",
282
+ detail,
279
283
  state: "completed"
280
284
  },
281
285
  handlers,
@@ -325,11 +329,12 @@ function applyWorkEvent(event, handlers, workItems) {
325
329
  return;
326
330
  }
327
331
  if (event.type === "actions.requested") {
328
- completePlanning(handlers, workItems);
329
- for (const action of event.data.actions) {
332
+ const nextItems = event.data.actions.flatMap((action) => {
330
333
  const item = requestedWorkItem(action);
331
- if (item) emitWorkItem(item, handlers, workItems);
332
- }
334
+ return item ? [item] : [];
335
+ });
336
+ completePlanning(handlers, workItems, nextItems);
337
+ for (const item of nextItems) emitWorkItem(item, handlers, workItems);
333
338
  return;
334
339
  }
335
340
  if (event.type === "subagent.called") {
@@ -380,7 +385,7 @@ function applyWorkEvent(event, handlers, workItems) {
380
385
  );
381
386
  }
382
387
  var AgentSession = class {
383
- constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, getUnpublishedPreviewGrant) {
388
+ constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, previewBuildId, getUnpublishedPreviewGrant) {
384
389
  this.indexId = indexId;
385
390
  this.version = version;
386
391
  this.runtimeOrigin = runtimeOrigin;
@@ -389,6 +394,7 @@ var AgentSession = class {
389
394
  this.capability = createAgentRuntimeCapability({
390
395
  getUnpublishedPreviewGrant,
391
396
  indexId,
397
+ previewBuildId,
392
398
  runtimeOrigin,
393
399
  version,
394
400
  visitorSessionId
@@ -633,6 +639,7 @@ function createAgentClient(options) {
633
639
  runtimeOrigin,
634
640
  visitorSessionId,
635
641
  storeOptions,
642
+ options.previewBuildId,
636
643
  options.getUnpublishedPreviewGrant
637
644
  );
638
645
  return {
@@ -660,10 +667,15 @@ function createAgentClient(options) {
660
667
  // src/runtime/errors.ts
661
668
  import { ClientError as ClientError3 } from "eve/client";
662
669
  var TRANSIENT_AGENT_ERROR_MESSAGE = "I couldn\u2019t finish that answer. Please try again.";
670
+ var PREVIEW_AUTHORIZATION_ERROR_MESSAGE = "This preview could not be authorized. Open the latest preview from Webless.";
663
671
  function isTransientRuntimeMessage(message) {
664
672
  const normalized = message.trim().toLowerCase();
665
673
  return normalized.includes("empty response from runtime") || normalized.includes("failed to fetch") || normalized.includes("networkerror") || normalized.includes("load failed");
666
674
  }
675
+ function isPreviewAuthorizationMessage(message) {
676
+ const normalized = message.trim().toLowerCase();
677
+ return normalized.includes("unpublished preview authorization") || normalized.includes("unpublished preview grant") || normalized.includes("agent studio preview grant") || normalized.includes("preview authorization");
678
+ }
667
679
  function formatAgentError(error) {
668
680
  if (error instanceof ClientError3) {
669
681
  if (error.status === 401 && error.code === "index_required") {
@@ -675,6 +687,9 @@ function formatAgentError(error) {
675
687
  if (error.status === 409 && error.code === "session_not_active") {
676
688
  return "Session expired \u2014 send a new message to start again.";
677
689
  }
690
+ if (error.message && isPreviewAuthorizationMessage(error.message)) {
691
+ return PREVIEW_AUTHORIZATION_ERROR_MESSAGE;
692
+ }
678
693
  if (error.status >= 500 || error.message && isTransientRuntimeMessage(error.message)) {
679
694
  return TRANSIENT_AGENT_ERROR_MESSAGE;
680
695
  }
@@ -684,6 +699,9 @@ function formatAgentError(error) {
684
699
  return "";
685
700
  }
686
701
  if (error instanceof Error) {
702
+ if (isPreviewAuthorizationMessage(error.message)) {
703
+ return PREVIEW_AUTHORIZATION_ERROR_MESSAGE;
704
+ }
687
705
  return isTransientRuntimeMessage(error.message) ? TRANSIENT_AGENT_ERROR_MESSAGE : error.message;
688
706
  }
689
707
  return TRANSIENT_AGENT_ERROR_MESSAGE;
@@ -795,6 +813,7 @@ function useAgentChat({
795
813
  customerId,
796
814
  getUnpublishedPreviewGrant,
797
815
  indexId,
816
+ previewBuildId,
798
817
  version,
799
818
  runtimeOrigin,
800
819
  visitorSessionId,
@@ -845,13 +864,14 @@ function useAgentChat({
845
864
  customerId,
846
865
  getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
847
866
  indexId,
867
+ previewBuildId,
848
868
  version,
849
869
  runtimeOrigin,
850
870
  visitorSessionId: visitorId,
851
871
  storageKeyPrefix: resolvedStorageKeyPrefix
852
872
  })
853
873
  );
854
- const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
874
+ const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${previewBuildId ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
855
875
  const identityRef = useRef(identityKey);
856
876
  useEffect(() => {
857
877
  if (identityRef.current === identityKey) {
@@ -864,6 +884,7 @@ function useAgentChat({
864
884
  customerId,
865
885
  getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
866
886
  indexId,
887
+ previewBuildId,
867
888
  version,
868
889
  runtimeOrigin,
869
890
  visitorSessionId: visitorId,
@@ -880,6 +901,7 @@ function useAgentChat({
880
901
  identityKey,
881
902
  indexId,
882
903
  initialState,
904
+ previewBuildId,
883
905
  runtimeOrigin,
884
906
  resolvedStorageKeyPrefix,
885
907
  version,
@@ -983,8 +1005,8 @@ function useAgentChat({
983
1005
  if (!message) return;
984
1006
  setState((prev) => ({
985
1007
  ...prev,
986
- phase: "complete",
987
- toolSteps: prev.toolSteps.map(
1008
+ phase: "error",
1009
+ toolSteps: prev.toolSteps.length === 1 && prev.toolSteps[0]?.kind === "planning" ? [] : prev.toolSteps.map(
988
1010
  (step) => step.state === "active" ? {
989
1011
  ...step,
990
1012
  detail: "Couldn\u2019t complete this step",
@@ -1034,6 +1056,37 @@ function useAgentChat({
1034
1056
  },
1035
1057
  [runTurn]
1036
1058
  );
1059
+ const retry = useCallback(async () => {
1060
+ const visitorMessage = [...state.messages].reverse().find((message) => message.role === "visitor");
1061
+ if (!visitorMessage) return;
1062
+ if (runRef.current) {
1063
+ runRef.current.abort();
1064
+ clientRef.current.cancelActive();
1065
+ }
1066
+ const controller = new AbortController();
1067
+ runRef.current = controller;
1068
+ setState((prev) => ({
1069
+ ...prev,
1070
+ phase: "thinking",
1071
+ toolSteps: [
1072
+ {
1073
+ id: "planning",
1074
+ kind: "planning",
1075
+ label: "Understanding your question",
1076
+ state: "active"
1077
+ }
1078
+ ],
1079
+ journey: null,
1080
+ followUps: [],
1081
+ streamingText: "",
1082
+ error: null
1083
+ }));
1084
+ await runTurn({
1085
+ controller,
1086
+ resume: false,
1087
+ visitorText: visitorMessage.text
1088
+ });
1089
+ }, [runTurn, state.messages]);
1037
1090
  useEffect(() => {
1038
1091
  const conversation = loadPersistedAgentConversation(
1039
1092
  resolvedStorageKeyPrefix,
@@ -1066,6 +1119,7 @@ function useAgentChat({
1066
1119
  return {
1067
1120
  state,
1068
1121
  reset,
1122
+ retry,
1069
1123
  submit,
1070
1124
  visitorSessionId: visitorId,
1071
1125
  sessionId: clientRef.current.getActiveSessionId()
@@ -1123,15 +1177,17 @@ var defaultAgentRailTheme = {
1123
1177
  };
1124
1178
 
1125
1179
  // src/react/components/AgentRail/AgentRail.tsx
1126
- import { useEffect as useEffect2, useRef as useRef3 } from "react";
1180
+ import { useEffect as useEffect2, useId, useRef as useRef3 } from "react";
1127
1181
 
1128
1182
  // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
1129
- import { jsx, jsxs } from "react/jsx-runtime";
1130
- function workSummary(steps) {
1183
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1184
+ function workSummary(steps, failed, brandLabel) {
1131
1185
  const active = [...steps].reverse().find((step) => step.state === "active");
1132
- if (active?.kind === "specialist") return `Working with ${active.label}`;
1186
+ if (active?.kind === "specialist")
1187
+ return `${active.label} is reviewing your question`;
1133
1188
  if (active?.kind === "search") return "Searching this site";
1134
- if (active) return active.label;
1189
+ if (active) return `${brandLabel} is choosing the best way to help`;
1190
+ if (failed) return "Couldn\u2019t complete this request";
1135
1191
  const hasError = steps.some((step) => step.state === "error");
1136
1192
  const specialists = steps.filter(
1137
1193
  (step) => step.kind === "specialist" && step.state === "completed"
@@ -1141,49 +1197,122 @@ function workSummary(steps) {
1141
1197
  );
1142
1198
  if (hasError) return "Answered with available information";
1143
1199
  if (specialists.length > 1)
1144
- return `Consulted ${specialists.length} specialists`;
1145
- if (specialists.length === 1) return `Consulted ${specialists[0]?.label}`;
1146
- if (searched) return "Searched this site";
1147
- return "Prepared a response";
1200
+ return `Answer prepared with ${specialists.length} specialists`;
1201
+ if (specialists.length === 1)
1202
+ return `Answer prepared with ${specialists[0]?.label}`;
1203
+ if (searched) return "Answer prepared from this site";
1204
+ return "Answer ready";
1205
+ }
1206
+ function stepLabel(step, brandLabel) {
1207
+ return step.kind === "planning" ? brandLabel : step.label;
1208
+ }
1209
+ function stepDetail(step, steps) {
1210
+ if (step.kind !== "planning" || step.state !== "completed") {
1211
+ return step.detail;
1212
+ }
1213
+ const specialists = steps.filter((item) => item.kind === "specialist");
1214
+ if (specialists.length === 1) return `Delegated to ${specialists[0]?.label}`;
1215
+ if (specialists.length > 1)
1216
+ return `Delegated to ${specialists.length} specialists`;
1217
+ if (steps.some((item) => item.kind === "search"))
1218
+ return "Used built-in Search & Discovery";
1219
+ return step.detail;
1220
+ }
1221
+ function SearchIcon() {
1222
+ return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
1223
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "3.75", stroke: "currentColor", strokeWidth: "1.4" }),
1224
+ /* @__PURE__ */ jsx(
1225
+ "path",
1226
+ {
1227
+ d: "m10 10 3 3",
1228
+ stroke: "currentColor",
1229
+ strokeWidth: "1.4",
1230
+ strokeLinecap: "round"
1231
+ }
1232
+ )
1233
+ ] });
1148
1234
  }
1149
- function AgentActivityBubble({ steps }) {
1235
+ function PlanningIcon() {
1236
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
1237
+ "path",
1238
+ {
1239
+ d: "M4 4.5h8M4 8h5.5M4 11.5h7",
1240
+ stroke: "currentColor",
1241
+ strokeWidth: "1.4",
1242
+ strokeLinecap: "round"
1243
+ }
1244
+ ) });
1245
+ }
1246
+ function AgentActivityBubble({
1247
+ brandLabel = "Webless Guide",
1248
+ brandLogoUrl,
1249
+ failed = false,
1250
+ steps
1251
+ }) {
1150
1252
  const active = steps.some((step) => step.state === "active");
1253
+ const delegated = steps.some((step) => step.kind === "specialist");
1151
1254
  return /* @__PURE__ */ jsxs("article", { className: "agent-activity-bubble", children: [
1152
1255
  /* @__PURE__ */ jsxs("p", { className: "agent-activity-bubble__status", "aria-live": "polite", children: [
1153
1256
  /* @__PURE__ */ jsx(
1154
1257
  "span",
1155
1258
  {
1156
- className: `agent-activity-bubble__pulse${active ? " is-active" : ""}`,
1259
+ className: `agent-activity-bubble__pulse${active ? " is-active" : failed ? " is-error" : ""}`,
1157
1260
  "aria-hidden": "true"
1158
1261
  }
1159
1262
  ),
1160
- workSummary(steps)
1263
+ workSummary(steps, failed, brandLabel)
1161
1264
  ] }),
1162
- /* @__PURE__ */ jsxs("details", { className: "agent-activity-bubble__details", open: active, children: [
1163
- /* @__PURE__ */ jsx("summary", { children: "Work details" }),
1164
- /* @__PURE__ */ jsx("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => /* @__PURE__ */ jsxs(
1165
- "li",
1166
- {
1167
- className: "agent-activity-bubble__step",
1168
- "data-state": step.state,
1169
- children: [
1170
- /* @__PURE__ */ jsx(
1171
- "span",
1265
+ /* @__PURE__ */ jsxs(
1266
+ "details",
1267
+ {
1268
+ className: "agent-activity-bubble__details",
1269
+ open: active || delegated,
1270
+ children: [
1271
+ /* @__PURE__ */ jsx("summary", { children: failed ? "What happened" : active ? "Working" : "How this answer was prepared" }),
1272
+ /* @__PURE__ */ jsx("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => {
1273
+ const detail = stepDetail(step, steps);
1274
+ return /* @__PURE__ */ jsxs(
1275
+ "li",
1172
1276
  {
1173
- className: "agent-activity-bubble__step-icon",
1174
- "aria-hidden": "true",
1175
- children: step.state === "completed" ? "\u2713" : step.state === "error" ? "!" : ""
1176
- }
1177
- ),
1178
- /* @__PURE__ */ jsxs("span", { className: "agent-activity-bubble__step-copy", children: [
1179
- /* @__PURE__ */ jsx("strong", { children: step.label }),
1180
- step.detail ? /* @__PURE__ */ jsx("small", { children: step.detail }) : null
1181
- ] })
1182
- ]
1183
- },
1184
- step.id
1185
- )) })
1186
- ] })
1277
+ className: "agent-activity-bubble__step",
1278
+ "data-kind": step.kind,
1279
+ "data-state": step.state,
1280
+ children: [
1281
+ /* @__PURE__ */ jsx(
1282
+ "span",
1283
+ {
1284
+ className: "agent-activity-bubble__step-icon",
1285
+ "aria-hidden": "true",
1286
+ children: step.kind === "planning" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1287
+ /* @__PURE__ */ jsx(PlanningIcon, {}),
1288
+ brandLogoUrl ? /* @__PURE__ */ jsx(
1289
+ "img",
1290
+ {
1291
+ src: brandLogoUrl,
1292
+ alt: "",
1293
+ onError: (event) => {
1294
+ event.currentTarget.hidden = true;
1295
+ }
1296
+ }
1297
+ ) : null
1298
+ ] }) : step.kind === "search" ? /* @__PURE__ */ jsx(SearchIcon, {}) : step.label.slice(0, 1).toUpperCase()
1299
+ }
1300
+ ),
1301
+ /* @__PURE__ */ jsxs("span", { className: "agent-activity-bubble__step-copy", children: [
1302
+ /* @__PURE__ */ jsxs("span", { className: "agent-activity-bubble__step-heading", children: [
1303
+ /* @__PURE__ */ jsx("strong", { children: stepLabel(step, brandLabel) }),
1304
+ /* @__PURE__ */ jsx("small", { children: step.kind === "specialist" ? "Specialist" : step.kind === "search" ? "Built-in capability" : "Supervisor" })
1305
+ ] }),
1306
+ detail ? /* @__PURE__ */ jsx("span", { className: "agent-activity-bubble__step-detail", children: detail }) : null
1307
+ ] })
1308
+ ]
1309
+ },
1310
+ step.id
1311
+ );
1312
+ }) })
1313
+ ]
1314
+ }
1315
+ )
1187
1316
  ] });
1188
1317
  }
1189
1318
 
@@ -1322,6 +1451,29 @@ function MinimizeIcon() {
1322
1451
  }
1323
1452
  ) });
1324
1453
  }
1454
+ function CloseIcon() {
1455
+ return /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(
1456
+ "path",
1457
+ {
1458
+ d: "M4 4l8 8M12 4l-8 8",
1459
+ stroke: "currentColor",
1460
+ strokeWidth: "1.5",
1461
+ strokeLinecap: "round"
1462
+ }
1463
+ ) });
1464
+ }
1465
+ function NewChatIcon() {
1466
+ return /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(
1467
+ "path",
1468
+ {
1469
+ d: "M9.5 3.5h3v3M12.25 3.75 8 8M7 4H4.5A1.5 1.5 0 0 0 3 5.5v6A1.5 1.5 0 0 0 4.5 13h6a1.5 1.5 0 0 0 1.5-1.5V9",
1470
+ stroke: "currentColor",
1471
+ strokeWidth: "1.4",
1472
+ strokeLinecap: "round",
1473
+ strokeLinejoin: "round"
1474
+ }
1475
+ ) });
1476
+ }
1325
1477
  function ExpandIcon() {
1326
1478
  return /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(
1327
1479
  "path",
@@ -1358,10 +1510,13 @@ function AgentRail({
1358
1510
  onCollapse,
1359
1511
  onClose,
1360
1512
  onExpandToggle,
1513
+ onReset,
1514
+ onRetry,
1361
1515
  onSubmit,
1362
1516
  onFollowUpSelect
1363
1517
  }) {
1364
1518
  const transcriptRef = useRef3(null);
1519
+ const welcomeTitleId = useId();
1365
1520
  const resolvedTheme = { ...defaultAgentRailTheme, ...theme };
1366
1521
  const railStyle = {
1367
1522
  "--rail-width": resolvedTheme.railMaxWidth,
@@ -1388,7 +1543,13 @@ function AgentRail({
1388
1543
  (message) => message.role === "visitor"
1389
1544
  );
1390
1545
  const showIdleFollowUps = !hasVisitorMessages2 && state.followUps.length > 0;
1391
- const showDockFollowUps = expanded && showIdleFollowUps;
1546
+ const greeting = state.messages.find(
1547
+ (message) => message.role === "agent" && message.id === "greeting"
1548
+ );
1549
+ const visibleMessages = hasVisitorMessages2 ? state.messages.filter((message) => message.id !== "greeting") : [];
1550
+ const lastMessage = visibleMessages.at(-1);
1551
+ const completedAnswer = showActivity && state.phase === "complete" && lastMessage?.role === "agent" ? lastMessage : null;
1552
+ const transcriptMessages = completedAnswer ? visibleMessages.slice(0, -1) : visibleMessages;
1392
1553
  const streamingMessage = state.phase === "streaming" && state.streamingText ? {
1393
1554
  createdAt: 0,
1394
1555
  id: "streaming-response",
@@ -1413,6 +1574,10 @@ function AgentRail({
1413
1574
  className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
1414
1575
  style: railStyle,
1415
1576
  "aria-label": "Agent conversation",
1577
+ "aria-modal": mobileFullscreen || expanded ? true : void 0,
1578
+ autoFocus: mobileFullscreen || expanded,
1579
+ role: mobileFullscreen || expanded ? "dialog" : void 0,
1580
+ tabIndex: mobileFullscreen || expanded ? -1 : void 0,
1416
1581
  children: [
1417
1582
  /* @__PURE__ */ jsx5("header", { className: "agent-rail__header", children: /* @__PURE__ */ jsxs4("div", { className: "agent-rail__brand-row", children: [
1418
1583
  onCollapse ? /* @__PURE__ */ jsx5(
@@ -1431,7 +1596,7 @@ function AgentRail({
1431
1596
  className: "agent-rail__close",
1432
1597
  "aria-label": "Close agent",
1433
1598
  onClick: onClose,
1434
- children: /* @__PURE__ */ jsx5(MinimizeIcon, {})
1599
+ children: /* @__PURE__ */ jsx5(CloseIcon, {})
1435
1600
  }
1436
1601
  ) : /* @__PURE__ */ jsx5("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
1437
1602
  /* @__PURE__ */ jsxs4("span", { className: "agent-rail__identity", children: [
@@ -1451,75 +1616,102 @@ function AgentRail({
1451
1616
  ] }),
1452
1617
  /* @__PURE__ */ jsx5("span", { className: "agent-rail__brand-label", children: brandLabel })
1453
1618
  ] }),
1454
- onExpandToggle ? /* @__PURE__ */ jsx5(
1455
- "button",
1456
- {
1457
- type: "button",
1458
- className: "agent-rail__expand",
1459
- "aria-label": expanded ? "Restore assist panel" : "Expand assist panel",
1460
- onClick: onExpandToggle,
1461
- children: expanded ? /* @__PURE__ */ jsx5(RestoreIcon, {}) : /* @__PURE__ */ jsx5(ExpandIcon, {})
1462
- }
1463
- ) : /* @__PURE__ */ jsx5("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1619
+ /* @__PURE__ */ jsxs4("span", { className: "agent-rail__actions", children: [
1620
+ onReset ? /* @__PURE__ */ jsx5(
1621
+ "button",
1622
+ {
1623
+ type: "button",
1624
+ className: "agent-rail__new-chat",
1625
+ "aria-label": "Start a new conversation",
1626
+ disabled: !hasVisitorMessages2,
1627
+ onClick: onReset,
1628
+ children: /* @__PURE__ */ jsx5(NewChatIcon, {})
1629
+ }
1630
+ ) : null,
1631
+ onExpandToggle ? /* @__PURE__ */ jsx5(
1632
+ "button",
1633
+ {
1634
+ type: "button",
1635
+ className: "agent-rail__expand",
1636
+ "aria-label": expanded ? "Exit focus view" : "Open focus view",
1637
+ onClick: onExpandToggle,
1638
+ children: expanded ? /* @__PURE__ */ jsx5(RestoreIcon, {}) : /* @__PURE__ */ jsx5(ExpandIcon, {})
1639
+ }
1640
+ ) : null
1641
+ ] })
1464
1642
  ] }) }),
1465
- /* @__PURE__ */ jsxs4("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1466
- state.messages.map((message) => /* @__PURE__ */ jsx5(MessageBubble, { message }, message.id)),
1467
- streamingMessage ? /* @__PURE__ */ jsx5(MessageBubble, { message: streamingMessage }) : null,
1468
- showActivity ? /* @__PURE__ */ jsx5(AgentActivityBubble, { steps: state.toolSteps }) : null,
1469
- !expanded && showIdleFollowUps ? /* @__PURE__ */ jsx5("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ jsx5(
1470
- FollowUpChips,
1643
+ /* @__PURE__ */ jsx5("div", { ref: transcriptRef, className: "agent-rail__transcript", children: /* @__PURE__ */ jsxs4("div", { className: "agent-rail__thread", children: [
1644
+ !hasVisitorMessages2 ? /* @__PURE__ */ jsxs4(
1645
+ "section",
1471
1646
  {
1472
- suggestions: state.followUps,
1473
- disabled: isBusy,
1474
- label: "Try asking",
1475
- onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1476
- }
1477
- ) }) : null,
1478
- state.error ? /* @__PURE__ */ jsx5(
1479
- "p",
1480
- {
1481
- role: "alert",
1482
- style: { fontSize: 13, color: "var(--as-danger)", margin: 0 },
1483
- children: state.error
1484
- }
1485
- ) : null
1486
- ] }),
1487
- expanded ? /* @__PURE__ */ jsxs4("div", { className: "agent-rail__dock-wrap", children: [
1488
- showDockFollowUps ? /* @__PURE__ */ jsx5("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ jsx5(
1489
- FollowUpChips,
1490
- {
1491
- variant: "dock",
1492
- suggestions: state.followUps,
1493
- disabled: isBusy,
1494
- onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1647
+ className: "agent-rail__welcome",
1648
+ "aria-labelledby": welcomeTitleId,
1649
+ children: [
1650
+ /* @__PURE__ */ jsxs4("span", { className: "agent-rail__welcome-mark", "aria-hidden": "true", children: [
1651
+ brandLabel.slice(0, 1).toUpperCase(),
1652
+ brandLogoUrl ? /* @__PURE__ */ jsx5(
1653
+ "img",
1654
+ {
1655
+ className: "agent-rail__welcome-logo",
1656
+ src: brandLogoUrl,
1657
+ alt: "",
1658
+ onError: (event) => {
1659
+ event.currentTarget.hidden = true;
1660
+ }
1661
+ }
1662
+ ) : null
1663
+ ] }),
1664
+ /* @__PURE__ */ jsxs4("div", { className: "agent-rail__welcome-copy", children: [
1665
+ /* @__PURE__ */ jsx5("h2", { id: welcomeTitleId, children: "What can I help you find?" }),
1666
+ greeting?.role === "agent" ? /* @__PURE__ */ jsx5("p", { children: greeting.text }) : null
1667
+ ] }),
1668
+ showIdleFollowUps ? /* @__PURE__ */ jsx5("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ jsx5(
1669
+ FollowUpChips,
1670
+ {
1671
+ suggestions: state.followUps,
1672
+ disabled: isBusy,
1673
+ label: "Start here",
1674
+ onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1675
+ }
1676
+ ) }) : null
1677
+ ]
1495
1678
  }
1496
- ) }) : null,
1497
- /* @__PURE__ */ jsx5("div", { className: "agent-rail__dock", children: /* @__PURE__ */ jsx5(
1498
- Composer,
1679
+ ) : null,
1680
+ transcriptMessages.map((message) => /* @__PURE__ */ jsx5(MessageBubble, { message }, message.id)),
1681
+ showActivity ? /* @__PURE__ */ jsx5(
1682
+ AgentActivityBubble,
1499
1683
  {
1500
- variant: "dock",
1501
- disabled: isBusy,
1502
- placeholder: composerPlaceholder,
1503
- onSubmit
1684
+ brandLabel,
1685
+ brandLogoUrl,
1686
+ failed: state.phase === "error",
1687
+ steps: state.toolSteps
1504
1688
  }
1505
- ) }),
1506
- /* @__PURE__ */ jsxs4("div", { className: "agent-rail__footer", children: [
1507
- /* @__PURE__ */ jsx5("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1508
- /* @__PURE__ */ jsx5("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1509
- ] })
1510
- ] }) : /* @__PURE__ */ jsxs4("div", { className: "agent-rail__composer-wrap", children: [
1689
+ ) : null,
1690
+ streamingMessage ? /* @__PURE__ */ jsx5(MessageBubble, { message: streamingMessage }) : null,
1691
+ completedAnswer ? /* @__PURE__ */ jsx5(MessageBubble, { message: completedAnswer }) : null,
1692
+ state.error ? /* @__PURE__ */ jsxs4("section", { className: "agent-rail__error", role: "alert", children: [
1693
+ /* @__PURE__ */ jsxs4("div", { children: [
1694
+ /* @__PURE__ */ jsx5("strong", { children: "Something went wrong" }),
1695
+ /* @__PURE__ */ jsx5("p", { children: state.error })
1696
+ ] }),
1697
+ onRetry ? /* @__PURE__ */ jsx5("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
1698
+ ] }) : null
1699
+ ] }) }),
1700
+ /* @__PURE__ */ jsxs4("div", { className: "agent-rail__composer-wrap", children: [
1511
1701
  /* @__PURE__ */ jsx5(
1512
1702
  Composer,
1513
1703
  {
1704
+ variant: expanded || mobileFullscreen ? "dock" : "default",
1514
1705
  disabled: isBusy,
1515
1706
  placeholder: composerPlaceholder,
1516
1707
  onSubmit
1517
1708
  }
1518
1709
  ),
1519
- /* @__PURE__ */ jsxs4("div", { className: "agent-rail__footer", children: [
1520
- /* @__PURE__ */ jsx5("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1521
- /* @__PURE__ */ jsx5("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1522
- ] })
1710
+ /* @__PURE__ */ jsx5("div", { className: "agent-rail__footer", children: /* @__PURE__ */ jsxs4("p", { children: [
1711
+ /* @__PURE__ */ jsx5("span", { children: "AI can make mistakes." }),
1712
+ /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: " \xB7 " }),
1713
+ /* @__PURE__ */ jsx5("span", { children: poweredByLabel })
1714
+ ] }) })
1523
1715
  ] })
1524
1716
  ]
1525
1717
  }
@@ -1527,7 +1719,7 @@ function AgentRail({
1527
1719
  }
1528
1720
 
1529
1721
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
1530
- import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1722
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1531
1723
  function SparklesIcon() {
1532
1724
  return /* @__PURE__ */ jsxs5(
1533
1725
  "svg",
@@ -1603,7 +1795,12 @@ function AssistEdgeTab({
1603
1795
  label,
1604
1796
  logoUrl,
1605
1797
  brandColor,
1798
+ brandForeground,
1799
+ borderColor,
1606
1800
  fontFamily,
1801
+ mobile = false,
1802
+ surfaceColor,
1803
+ textColor,
1607
1804
  onOpen
1608
1805
  }) {
1609
1806
  const copy = VARIANT_COPY[variant];
@@ -1612,20 +1809,50 @@ function AssistEdgeTab({
1612
1809
  "--tab-along": `${along}%`,
1613
1810
  "--tab-inset": `${inset}px`,
1614
1811
  ...brandColor ? { "--as-brand": brandColor } : {},
1615
- ...fontFamily ? { "--as-font-display": fontFamily } : {}
1812
+ ...brandForeground ? { "--as-visitor-text": brandForeground } : {},
1813
+ ...borderColor ? { "--as-border": borderColor } : {},
1814
+ ...fontFamily ? { "--as-font-display": fontFamily } : {},
1815
+ ...surfaceColor ? { "--as-surface": surfaceColor } : {},
1816
+ ...textColor ? { "--as-text": textColor } : {}
1616
1817
  };
1617
1818
  return /* @__PURE__ */ jsxs5(
1618
1819
  "button",
1619
1820
  {
1620
1821
  type: "button",
1621
- className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${visible ? " is-visible" : ""}`,
1822
+ className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${mobile ? " assist-edge-tab--mobile" : ""}${visible ? " is-visible" : ""}`,
1622
1823
  style,
1623
1824
  "aria-label": `Open ${visibleLabel}`,
1624
1825
  "aria-hidden": !visible,
1625
1826
  tabIndex: visible ? 0 : -1,
1626
1827
  onClick: onOpen,
1627
1828
  children: [
1628
- variant === "outline" ? /* @__PURE__ */ jsxs5(Fragment, { children: [
1829
+ mobile ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
1830
+ /* @__PURE__ */ jsxs5(
1831
+ "span",
1832
+ {
1833
+ className: "assist-edge-tab__mark assist-edge-tab__mark--mobile",
1834
+ "aria-hidden": "true",
1835
+ children: [
1836
+ visibleLabel.slice(0, 1).toUpperCase(),
1837
+ logoUrl ? /* @__PURE__ */ jsx6(
1838
+ "img",
1839
+ {
1840
+ className: "assist-edge-tab__logo",
1841
+ src: logoUrl,
1842
+ alt: "",
1843
+ onError: (event) => {
1844
+ event.currentTarget.hidden = true;
1845
+ }
1846
+ }
1847
+ ) : null
1848
+ ]
1849
+ }
1850
+ ),
1851
+ /* @__PURE__ */ jsxs5("span", { className: "assist-edge-tab__label", children: [
1852
+ "Ask ",
1853
+ visibleLabel
1854
+ ] })
1855
+ ] }) : variant === "outline" ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
1629
1856
  /* @__PURE__ */ jsxs5("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1630
1857
  /* @__PURE__ */ jsx6(SparklesIcon, {}),
1631
1858
  logoUrl ? /* @__PURE__ */ jsx6(
@@ -1643,12 +1870,12 @@ function AssistEdgeTab({
1643
1870
  /* @__PURE__ */ jsx6("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1644
1871
  /* @__PURE__ */ jsx6(ChevronDownIcon, {})
1645
1872
  ] }) : null,
1646
- variant === "ask" ? /* @__PURE__ */ jsxs5(Fragment, { children: [
1873
+ variant === "ask" ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
1647
1874
  /* @__PURE__ */ jsx6(ChevronLeftIcon, {}),
1648
1875
  /* @__PURE__ */ jsx6("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1649
1876
  /* @__PURE__ */ jsx6(DragDots, {})
1650
1877
  ] }) : null,
1651
- variant === "fill" ? /* @__PURE__ */ jsxs5(Fragment, { children: [
1878
+ variant === "fill" ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
1652
1879
  /* @__PURE__ */ jsxs5("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1653
1880
  /* @__PURE__ */ jsx6(SparklesIcon, {}),
1654
1881
  logoUrl ? /* @__PURE__ */ jsx6(
@@ -1791,6 +2018,7 @@ function AgentWidget({
1791
2018
  indexId,
1792
2019
  customerId,
1793
2020
  getUnpublishedPreviewGrant,
2021
+ previewBuildId,
1794
2022
  version,
1795
2023
  runtimeOrigin,
1796
2024
  placement: placementInput,
@@ -1814,10 +2042,11 @@ function AgentWidget({
1814
2042
  active: pageShiftActive,
1815
2043
  railSlotRef
1816
2044
  });
1817
- const { state, submit } = useAgentChat({
2045
+ const { state, reset, retry, submit } = useAgentChat({
1818
2046
  customerId,
1819
2047
  getUnpublishedPreviewGrant,
1820
2048
  indexId,
2049
+ previewBuildId,
1821
2050
  version,
1822
2051
  runtimeOrigin,
1823
2052
  greeting: branding?.greeting
@@ -1856,6 +2085,40 @@ function AgentWidget({
1856
2085
  if (isMobile) setRailCollapsed(false);
1857
2086
  await submit(message);
1858
2087
  }
2088
+ useEffect5(() => {
2089
+ if (railCollapsed) return;
2090
+ const handleKeyDown = (event) => {
2091
+ if (event.key === "Tab" && (isMobile || railExpanded)) {
2092
+ const focusable = railSlotRef.current?.querySelectorAll(
2093
+ 'button:not(:disabled), a[href], textarea:not(:disabled), input:not(:disabled), [tabindex]:not([tabindex="-1"])'
2094
+ );
2095
+ if (!focusable || focusable.length === 0) return;
2096
+ const first = focusable.item(0);
2097
+ const last = focusable.item(focusable.length - 1);
2098
+ const dialog = railSlotRef.current?.querySelector(".agent-rail");
2099
+ if (document.activeElement === dialog) {
2100
+ event.preventDefault();
2101
+ (event.shiftKey ? last : first).focus();
2102
+ } else if (event.shiftKey && document.activeElement === first) {
2103
+ event.preventDefault();
2104
+ last.focus();
2105
+ } else if (!event.shiftKey && document.activeElement === last) {
2106
+ event.preventDefault();
2107
+ first.focus();
2108
+ }
2109
+ return;
2110
+ }
2111
+ if (event.key === "Escape") {
2112
+ if (railExpanded) {
2113
+ setRailExpanded(false);
2114
+ return;
2115
+ }
2116
+ setRailCollapsed(true);
2117
+ }
2118
+ };
2119
+ window.addEventListener("keydown", handleKeyDown);
2120
+ return () => window.removeEventListener("keydown", handleKeyDown);
2121
+ }, [isMobile, railCollapsed, railExpanded]);
1859
2122
  return /* @__PURE__ */ jsxs6("div", { className: "webless-agent-root", children: [
1860
2123
  /* @__PURE__ */ jsxs6(
1861
2124
  "div",
@@ -1887,19 +2150,27 @@ function AgentWidget({
1887
2150
  onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1888
2151
  onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1889
2152
  onSubmit: handleSubmit,
2153
+ onReset: reset,
2154
+ onRetry: () => void retry(),
1890
2155
  onFollowUpSelect: (label) => void handleSubmit(label)
1891
2156
  }
1892
2157
  )
1893
2158
  }
1894
2159
  ),
1895
- !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ jsx7(
2160
+ !railCollapsed && isMobile || !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ jsx7(
1896
2161
  "button",
1897
2162
  {
1898
2163
  type: "button",
1899
- className: "webless-agent-root__backdrop",
2164
+ className: `webless-agent-root__backdrop${isMobile ? " webless-agent-root__backdrop--mobile" : ""}`,
1900
2165
  tabIndex: -1,
1901
- "aria-label": "Close expanded assist",
1902
- onClick: () => setRailExpanded(false)
2166
+ "aria-label": isMobile ? "Close agent" : "Exit focus view",
2167
+ onClick: () => {
2168
+ if (isMobile) {
2169
+ setRailCollapsed(true);
2170
+ } else {
2171
+ setRailExpanded(false);
2172
+ }
2173
+ }
1903
2174
  }
1904
2175
  ) : null
1905
2176
  ]
@@ -1916,7 +2187,12 @@ function AgentWidget({
1916
2187
  label: agentName,
1917
2188
  logoUrl: branding?.logoUrl,
1918
2189
  brandColor: branding?.colors?.primary,
2190
+ brandForeground: branding?.colors?.primaryForeground,
2191
+ borderColor: branding?.colors?.border,
1919
2192
  fontFamily: branding?.fontFamily,
2193
+ mobile: isMobile,
2194
+ surfaceColor: branding?.colors?.surface,
2195
+ textColor: branding?.colors?.text,
1920
2196
  onOpen: () => setRailCollapsed(false)
1921
2197
  }
1922
2198
  ) : null
@@ -1939,4 +2215,4 @@ export {
1939
2215
  AssistEdgeTab,
1940
2216
  AgentWidget
1941
2217
  };
1942
- //# sourceMappingURL=chunk-MMYSBSHG.js.map
2218
+ //# sourceMappingURL=chunk-SVWXFDV3.js.map