@webless/agent 0.2.13 → 0.2.15

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/dist/embed.cjs CHANGED
@@ -50,10 +50,90 @@ function closeAgentPanel(customerId) {
50
50
  }
51
51
 
52
52
  // src/react/components/AgentWidget/AgentWidget.tsx
53
- var import_react5 = require("react");
53
+ var import_react6 = require("react");
54
54
 
55
- // src/react/hooks/useAgentChat.ts
55
+ // src/react/page-shift.ts
56
56
  var import_react = require("react");
57
+ var PAGE_SHIFT_CLASS = "webless-agent-page-shift";
58
+ var DEFAULT_RAIL_WIDTH_PX = 450;
59
+ function shouldApplyPageShift(input) {
60
+ return input.pageShift && !input.isMobile && !input.railCollapsed && !input.railExpanded;
61
+ }
62
+ function resolvePageShiftWidth(railWidth) {
63
+ if (typeof railWidth === "number" && railWidth > 0) {
64
+ return railWidth;
65
+ }
66
+ if (typeof document !== "undefined") {
67
+ const token = getComputedStyle(document.documentElement).getPropertyValue("--as-rail-max-width").trim();
68
+ const parsed = Number.parseFloat(token);
69
+ if (Number.isFinite(parsed) && parsed > 0) {
70
+ return parsed;
71
+ }
72
+ }
73
+ return DEFAULT_RAIL_WIDTH_PX;
74
+ }
75
+ var savedPageMargin = null;
76
+ function readPageMarginSnapshot(style) {
77
+ return {
78
+ value: style.getPropertyValue("margin-right"),
79
+ priority: style.getPropertyPriority("margin-right")
80
+ };
81
+ }
82
+ function restorePageMargin(style, snapshot) {
83
+ if (snapshot.value) {
84
+ style.setProperty("margin-right", snapshot.value, snapshot.priority || void 0);
85
+ return;
86
+ }
87
+ style.removeProperty("margin-right");
88
+ }
89
+ function snapshotPageMarginIfNeeded() {
90
+ if (savedPageMargin !== null) {
91
+ return;
92
+ }
93
+ savedPageMargin = readPageMarginSnapshot(document.documentElement.style);
94
+ }
95
+ function setPageMargin(margin) {
96
+ snapshotPageMarginIfNeeded();
97
+ document.documentElement.style.setProperty("margin-right", margin, "important");
98
+ }
99
+ function clearPageMargin() {
100
+ if (savedPageMargin === null) {
101
+ return;
102
+ }
103
+ restorePageMargin(document.documentElement.style, savedPageMargin);
104
+ savedPageMargin = null;
105
+ }
106
+ function usePageShift(input) {
107
+ const { active, railSlotRef } = input;
108
+ (0, import_react.useEffect)(() => {
109
+ if (typeof document === "undefined") {
110
+ return;
111
+ }
112
+ if (!active) {
113
+ document.documentElement.classList.remove(PAGE_SHIFT_CLASS);
114
+ clearPageMargin();
115
+ return;
116
+ }
117
+ document.documentElement.classList.add(PAGE_SHIFT_CLASS);
118
+ function applyMargin() {
119
+ const rail = railSlotRef.current?.querySelector(".agent-rail");
120
+ const width = resolvePageShiftWidth(
121
+ rail instanceof HTMLElement ? rail.offsetWidth : null
122
+ );
123
+ setPageMargin(`${width}px`);
124
+ }
125
+ applyMargin();
126
+ const frame = requestAnimationFrame(applyMargin);
127
+ return () => {
128
+ cancelAnimationFrame(frame);
129
+ document.documentElement.classList.remove(PAGE_SHIFT_CLASS);
130
+ clearPageMargin();
131
+ };
132
+ }, [active, railSlotRef]);
133
+ }
134
+
135
+ // src/react/hooks/useAgentChat.ts
136
+ var import_react2 = require("react");
57
137
 
58
138
  // src/runtime/client.ts
59
139
  var import_client2 = require("eve/client");
@@ -94,6 +174,7 @@ function createAgentRuntimeCapability(options) {
94
174
  const fetchImplementation = options.fetchImplementation ?? fetch;
95
175
  const now = options.now ?? Date.now;
96
176
  let capability;
177
+ let generation = 0;
97
178
  let pendingBootstrap;
98
179
  const bootstrap = async () => {
99
180
  let previewGrant;
@@ -129,19 +210,32 @@ function createAgentRuntimeCapability(options) {
129
210
  }
130
211
  return parseBootstrapResponse(value, options.indexId, now());
131
212
  };
132
- return {
133
- getAccessToken: async () => {
134
- if (capability && capability.refreshAt > now()) {
135
- return capability.accessToken;
136
- }
137
- pendingBootstrap ??= bootstrap().finally(() => {
138
- pendingBootstrap = void 0;
139
- });
140
- capability = await pendingBootstrap;
213
+ const getAccessToken = async () => {
214
+ if (capability && capability.refreshAt > now()) {
141
215
  return capability.accessToken;
142
- },
216
+ }
217
+ const requestedGeneration = generation;
218
+ if (!pendingBootstrap) {
219
+ const trackedBootstrap = bootstrap().finally(() => {
220
+ if (pendingBootstrap === trackedBootstrap) {
221
+ pendingBootstrap = void 0;
222
+ }
223
+ });
224
+ pendingBootstrap = trackedBootstrap;
225
+ }
226
+ const nextCapability = await pendingBootstrap;
227
+ if (requestedGeneration !== generation) {
228
+ return getAccessToken();
229
+ }
230
+ capability = nextCapability;
231
+ return capability.accessToken;
232
+ };
233
+ return {
234
+ getAccessToken,
143
235
  invalidate: () => {
144
236
  capability = void 0;
237
+ generation += 1;
238
+ pendingBootstrap = void 0;
145
239
  }
146
240
  };
147
241
  }
@@ -348,6 +442,7 @@ var AgentSession = class {
348
442
  }
349
443
  this.activeResponse = void 0;
350
444
  this.session = void 0;
445
+ this.capability.invalidate();
351
446
  clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
352
447
  }
353
448
  persistSessionCursor(session) {
@@ -718,7 +813,7 @@ function useAgentChat({
718
813
  visitorSessionId,
719
814
  storageKeyPrefix
720
815
  }) {
721
- const previewGrantProviderRef = (0, import_react.useRef)(getUnpublishedPreviewGrant);
816
+ const previewGrantProviderRef = (0, import_react2.useRef)(getUnpublishedPreviewGrant);
722
817
  previewGrantProviderRef.current = getUnpublishedPreviewGrant;
723
818
  const resolveUnpublishedPreviewGrant = () => {
724
819
  const provider = previewGrantProviderRef.current;
@@ -731,7 +826,7 @@ function useAgentChat({
731
826
  }
732
827
  return provider();
733
828
  };
734
- const resolvedStorageKeyPrefix = (0, import_react.useMemo)(
829
+ const resolvedStorageKeyPrefix = (0, import_react2.useMemo)(
735
830
  () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({
736
831
  customerId,
737
832
  indexId,
@@ -740,19 +835,19 @@ function useAgentChat({
740
835
  }),
741
836
  [customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
742
837
  );
743
- const visitorId = (0, import_react.useMemo)(
838
+ const visitorId = (0, import_react2.useMemo)(
744
839
  () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({
745
840
  storageKeyPrefix: resolvedStorageKeyPrefix
746
841
  }),
747
842
  [resolvedStorageKeyPrefix, visitorSessionId]
748
843
  );
749
- const [state, setState] = (0, import_react.useState)(
844
+ const [state, setState] = (0, import_react2.useState)(
750
845
  () => stateFromConversation(
751
846
  loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
752
847
  )
753
848
  );
754
- const runRef = (0, import_react.useRef)(null);
755
- const clientRef = (0, import_react.useRef)(
849
+ const runRef = (0, import_react2.useRef)(null);
850
+ const clientRef = (0, import_react2.useRef)(
756
851
  createAgentClient({
757
852
  customerId,
758
853
  getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
@@ -764,8 +859,8 @@ function useAgentChat({
764
859
  })
765
860
  );
766
861
  const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
767
- const identityRef = (0, import_react.useRef)(identityKey);
768
- (0, import_react.useEffect)(() => {
862
+ const identityRef = (0, import_react2.useRef)(identityKey);
863
+ (0, import_react2.useEffect)(() => {
769
864
  if (identityRef.current === identityKey) {
770
865
  return;
771
866
  }
@@ -795,7 +890,7 @@ function useAgentChat({
795
890
  version,
796
891
  visitorId
797
892
  ]);
798
- (0, import_react.useEffect)(() => {
893
+ (0, import_react2.useEffect)(() => {
799
894
  if (!hasVisitorMessages(state.messages)) return;
800
895
  savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
801
896
  messages: state.messages,
@@ -809,14 +904,14 @@ function useAgentChat({
809
904
  state.streamingText,
810
905
  visitorId
811
906
  ]);
812
- const reset = (0, import_react.useCallback)(() => {
907
+ const reset = (0, import_react2.useCallback)(() => {
813
908
  runRef.current?.abort();
814
909
  runRef.current = null;
815
910
  clientRef.current.reset();
816
911
  clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
817
912
  setState(INITIAL_STATE);
818
913
  }, [resolvedStorageKeyPrefix, visitorId]);
819
- const runTurn = (0, import_react.useCallback)(
914
+ const runTurn = (0, import_react2.useCallback)(
820
915
  async (input) => {
821
916
  const { controller, initialText = "", resume, visitorText } = input;
822
917
  const { signal } = controller;
@@ -917,7 +1012,7 @@ function useAgentChat({
917
1012
  },
918
1013
  []
919
1014
  );
920
- const submit = (0, import_react.useCallback)(
1015
+ const submit = (0, import_react2.useCallback)(
921
1016
  async (visitorText) => {
922
1017
  if (runRef.current) {
923
1018
  runRef.current.abort();
@@ -947,7 +1042,7 @@ function useAgentChat({
947
1042
  },
948
1043
  [runTurn]
949
1044
  );
950
- (0, import_react.useEffect)(() => {
1045
+ (0, import_react2.useEffect)(() => {
951
1046
  const conversation = loadPersistedAgentConversation(
952
1047
  resolvedStorageKeyPrefix,
953
1048
  visitorId
@@ -970,7 +1065,7 @@ function useAgentChat({
970
1065
  controller.abort();
971
1066
  };
972
1067
  }, [identityKey, resolvedStorageKeyPrefix, runTurn, visitorId]);
973
- (0, import_react.useEffect)(() => {
1068
+ (0, import_react2.useEffect)(() => {
974
1069
  return () => {
975
1070
  runRef.current?.abort();
976
1071
  runRef.current = null;
@@ -999,12 +1094,12 @@ function isAgentBusy(phase) {
999
1094
  }
1000
1095
 
1001
1096
  // src/react/hooks/useIsMobile.ts
1002
- var import_react2 = require("react");
1097
+ var import_react3 = require("react");
1003
1098
  function useIsMobile(breakpoint = 767) {
1004
- const [isMobile, setIsMobile] = (0, import_react2.useState)(
1099
+ const [isMobile, setIsMobile] = (0, import_react3.useState)(
1005
1100
  () => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
1006
1101
  );
1007
- (0, import_react2.useEffect)(() => {
1102
+ (0, import_react3.useEffect)(() => {
1008
1103
  const media = window.matchMedia(`(max-width: ${breakpoint}px)`);
1009
1104
  const onChange = () => setIsMobile(media.matches);
1010
1105
  onChange();
@@ -1032,7 +1127,7 @@ function normalizeAgentPlacement(placement) {
1032
1127
  }
1033
1128
 
1034
1129
  // src/react/components/AgentRail/AgentRail.tsx
1035
- var import_react4 = require("react");
1130
+ var import_react5 = require("react");
1036
1131
 
1037
1132
  // src/react/components/ToolTimeline/ToolTimeline.tsx
1038
1133
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -1103,7 +1198,7 @@ function AgentActivityBubble({
1103
1198
  }
1104
1199
 
1105
1200
  // src/react/components/Composer/Composer.tsx
1106
- var import_react3 = require("react");
1201
+ var import_react4 = require("react");
1107
1202
  var import_jsx_runtime3 = require("react/jsx-runtime");
1108
1203
  function SendIcon() {
1109
1204
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8 12V4M8 4l-3 3M8 4l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
@@ -1114,8 +1209,8 @@ function Composer({
1114
1209
  variant = "default",
1115
1210
  onSubmit
1116
1211
  }) {
1117
- const [value, setValue] = (0, import_react3.useState)("");
1118
- const inputRef = (0, import_react3.useRef)(null);
1212
+ const [value, setValue] = (0, import_react4.useState)("");
1213
+ const inputRef = (0, import_react4.useRef)(null);
1119
1214
  function submitCurrent() {
1120
1215
  const trimmed = value.trim();
1121
1216
  if (!trimmed || disabled) return;
@@ -1267,7 +1362,7 @@ function AgentRail({
1267
1362
  onSubmit,
1268
1363
  onFollowUpSelect
1269
1364
  }) {
1270
- const transcriptRef = (0, import_react4.useRef)(null);
1365
+ const transcriptRef = (0, import_react5.useRef)(null);
1271
1366
  const railStyle = theme?.railMaxWidth ? { ["--rail-width"]: theme.railMaxWidth, ["--as-rail-max-width"]: theme.railMaxWidth } : void 0;
1272
1367
  const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
1273
1368
  const showActivity = state.toolSteps.length > 0 && (state.phase === "thinking" || state.phase === "running-tools");
@@ -1281,7 +1376,7 @@ function AgentRail({
1281
1376
  streaming: true,
1282
1377
  text: state.streamingText
1283
1378
  } : null;
1284
- (0, import_react4.useEffect)(() => {
1379
+ (0, import_react5.useEffect)(() => {
1285
1380
  const node = transcriptRef.current;
1286
1381
  if (!node) return;
1287
1382
  node.scrollTop = node.scrollHeight;
@@ -1450,12 +1545,24 @@ function AgentWidget({
1450
1545
  runtimeOrigin,
1451
1546
  placement: placementInput,
1452
1547
  defaultCollapsed = true,
1548
+ pageShift = true,
1453
1549
  registerPanelController = false
1454
1550
  }) {
1455
1551
  const isMobile = useIsMobile();
1456
1552
  const placement = normalizeAgentPlacement(placementInput);
1457
- const [railCollapsed, setRailCollapsed] = (0, import_react5.useState)(defaultCollapsed);
1458
- const [railExpanded, setRailExpanded] = (0, import_react5.useState)(false);
1553
+ const railSlotRef = (0, import_react6.useRef)(null);
1554
+ const [railCollapsed, setRailCollapsed] = (0, import_react6.useState)(defaultCollapsed);
1555
+ const [railExpanded, setRailExpanded] = (0, import_react6.useState)(false);
1556
+ const pageShiftActive = shouldApplyPageShift({
1557
+ pageShift,
1558
+ isMobile,
1559
+ railCollapsed,
1560
+ railExpanded
1561
+ });
1562
+ usePageShift({
1563
+ active: pageShiftActive,
1564
+ railSlotRef
1565
+ });
1459
1566
  const { state, submit } = useAgentChat({
1460
1567
  customerId,
1461
1568
  getUnpublishedPreviewGrant,
@@ -1464,7 +1571,7 @@ function AgentWidget({
1464
1571
  runtimeOrigin
1465
1572
  });
1466
1573
  const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
1467
- (0, import_react5.useEffect)(() => {
1574
+ (0, import_react6.useEffect)(() => {
1468
1575
  if (!registerPanelController) return;
1469
1576
  registerAgentPanelController(customerId, {
1470
1577
  open: () => setRailCollapsed(false),
@@ -1487,6 +1594,7 @@ function AgentWidget({
1487
1594
  children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1488
1595
  "div",
1489
1596
  {
1597
+ ref: railSlotRef,
1490
1598
  className: "webless-agent-root__rail-slot",
1491
1599
  inert: railCollapsed || void 0,
1492
1600
  "aria-hidden": railCollapsed,
@@ -1544,6 +1652,7 @@ function AgentWidget2({ manifest }) {
1544
1652
  version: manifest.version,
1545
1653
  runtimeOrigin: manifest.runtimeOrigin,
1546
1654
  placement: manifest.placement,
1655
+ pageShift: manifest.pageShift,
1547
1656
  defaultCollapsed: true,
1548
1657
  registerPanelController: true
1549
1658
  }
@@ -1578,7 +1687,8 @@ function normalizeAgentTagManifest(manifest) {
1578
1687
  selector: manifest.mount?.selector?.trim(),
1579
1688
  strategy: manifest.mount?.strategy ?? "body"
1580
1689
  },
1581
- placement: normalizeAgentPlacement(manifest.placement)
1690
+ placement: normalizeAgentPlacement(manifest.placement),
1691
+ pageShift: manifest.pageShift ?? true
1582
1692
  };
1583
1693
  }
1584
1694