@webless/agent 0.2.12 → 0.2.14

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
@@ -72,7 +72,10 @@ function parseBootstrapResponse(value, indexId, now) {
72
72
  if (!Number.isFinite(expiresAt) || expiresAt <= now) {
73
73
  throw new Error("Agent Runtime returned an expired access response.");
74
74
  }
75
- const refreshSkew = Math.min(MAX_REFRESH_SKEW_MS, Math.floor((expiresAt - now) / 10));
75
+ const refreshSkew = Math.min(
76
+ MAX_REFRESH_SKEW_MS,
77
+ Math.floor((expiresAt - now) / 10)
78
+ );
76
79
  return {
77
80
  accessToken: value.accessToken,
78
81
  refreshAt: expiresAt - refreshSkew
@@ -91,17 +94,31 @@ function createAgentRuntimeCapability(options) {
91
94
  const fetchImplementation = options.fetchImplementation ?? fetch;
92
95
  const now = options.now ?? Date.now;
93
96
  let capability;
97
+ let generation = 0;
94
98
  let pendingBootstrap;
95
99
  const bootstrap = async () => {
96
- const response = await fetchImplementation(`${options.runtimeOrigin}/webless/v1/bootstrap`, {
97
- body: JSON.stringify({
98
- clientSessionId: options.visitorSessionId,
99
- indexId: options.indexId,
100
- version: options.version
101
- }),
102
- headers: { "content-type": "application/json" },
103
- method: "POST"
104
- });
100
+ let previewGrant;
101
+ if (options.version === "unpublished") {
102
+ previewGrant = (await options.getUnpublishedPreviewGrant?.())?.trim();
103
+ if (!previewGrant) {
104
+ throw new Error(
105
+ "An unpublished preview grant is required to use the Agent Runtime preview."
106
+ );
107
+ }
108
+ }
109
+ const response = await fetchImplementation(
110
+ `${options.runtimeOrigin}/webless/v1/bootstrap`,
111
+ {
112
+ body: JSON.stringify({
113
+ clientSessionId: options.visitorSessionId,
114
+ indexId: options.indexId,
115
+ ...previewGrant ? { previewGrant } : {},
116
+ version: options.version
117
+ }),
118
+ headers: { "content-type": "application/json" },
119
+ method: "POST"
120
+ }
121
+ );
105
122
  if (!response.ok) {
106
123
  throw new Error(await readBootstrapError(response));
107
124
  }
@@ -113,19 +130,32 @@ function createAgentRuntimeCapability(options) {
113
130
  }
114
131
  return parseBootstrapResponse(value, options.indexId, now());
115
132
  };
116
- return {
117
- getAccessToken: async () => {
118
- if (capability && capability.refreshAt > now()) {
119
- return capability.accessToken;
120
- }
121
- pendingBootstrap ??= bootstrap().finally(() => {
122
- pendingBootstrap = void 0;
123
- });
124
- capability = await pendingBootstrap;
133
+ const getAccessToken = async () => {
134
+ if (capability && capability.refreshAt > now()) {
125
135
  return capability.accessToken;
126
- },
136
+ }
137
+ const requestedGeneration = generation;
138
+ if (!pendingBootstrap) {
139
+ const trackedBootstrap = bootstrap().finally(() => {
140
+ if (pendingBootstrap === trackedBootstrap) {
141
+ pendingBootstrap = void 0;
142
+ }
143
+ });
144
+ pendingBootstrap = trackedBootstrap;
145
+ }
146
+ const nextCapability = await pendingBootstrap;
147
+ if (requestedGeneration !== generation) {
148
+ return getAccessToken();
149
+ }
150
+ capability = nextCapability;
151
+ return capability.accessToken;
152
+ };
153
+ return {
154
+ getAccessToken,
127
155
  invalidate: () => {
128
156
  capability = void 0;
157
+ generation += 1;
158
+ pendingBootstrap = void 0;
129
159
  }
130
160
  };
131
161
  }
@@ -295,13 +325,14 @@ function mapStepLabel(event) {
295
325
  };
296
326
  }
297
327
  var AgentSession = class {
298
- constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions) {
328
+ constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, getUnpublishedPreviewGrant) {
299
329
  this.indexId = indexId;
300
330
  this.version = version;
301
331
  this.runtimeOrigin = runtimeOrigin;
302
332
  this.visitorSessionId = visitorSessionId;
303
333
  this.storeOptions = storeOptions;
304
334
  this.capability = createAgentRuntimeCapability({
335
+ getUnpublishedPreviewGrant,
305
336
  indexId,
306
337
  runtimeOrigin,
307
338
  version,
@@ -331,6 +362,7 @@ var AgentSession = class {
331
362
  }
332
363
  this.activeResponse = void 0;
333
364
  this.session = void 0;
365
+ this.capability.invalidate();
334
366
  clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
335
367
  }
336
368
  persistSessionCursor(session) {
@@ -364,7 +396,10 @@ var AgentSession = class {
364
396
  return this.client;
365
397
  }
366
398
  attachPersistedSession(client) {
367
- const persisted = loadPersistedAgentSession(this.visitorSessionId, this.storeOptions);
399
+ const persisted = loadPersistedAgentSession(
400
+ this.visitorSessionId,
401
+ this.storeOptions
402
+ );
368
403
  if (!persisted?.sessionId) return void 0;
369
404
  return client.sessions.attach(persisted.sessionId, {
370
405
  streamIndex: persisted.streamIndex
@@ -431,7 +466,10 @@ var AgentSession = class {
431
466
  return rendered.trim();
432
467
  }
433
468
  async resumeTurn(message, signal, handlers, initialText = "") {
434
- const persisted = loadPersistedAgentSession(this.visitorSessionId, this.storeOptions);
469
+ const persisted = loadPersistedAgentSession(
470
+ this.visitorSessionId,
471
+ this.storeOptions
472
+ );
435
473
  if (!persisted) return null;
436
474
  const client = this.ensureClient();
437
475
  const attached = client.sessions.attach(persisted.sessionId, {
@@ -470,7 +508,9 @@ var AgentSession = class {
470
508
  }
471
509
  if (snapshotBoundary) {
472
510
  if (snapshotBoundary.type === "session.failed") {
473
- throw new Error(snapshotBoundary.data.message || snapshotBoundary.data.code);
511
+ throw new Error(
512
+ snapshotBoundary.data.message || snapshotBoundary.data.code
513
+ );
474
514
  }
475
515
  handlers.onComplete?.();
476
516
  if (!rendered.trim()) throw new Error("Empty response from runtime");
@@ -527,7 +567,14 @@ function createAgentClient(options) {
527
567
  })
528
568
  };
529
569
  const visitorSessionId = options.visitorSessionId?.trim() || getOrCreateVisitorSessionId(storeOptions);
530
- const session = new AgentSession(indexId, version, runtimeOrigin, visitorSessionId, storeOptions);
570
+ const session = new AgentSession(
571
+ indexId,
572
+ version,
573
+ runtimeOrigin,
574
+ visitorSessionId,
575
+ storeOptions,
576
+ options.getUnpublishedPreviewGrant
577
+ );
531
578
  return {
532
579
  indexId,
533
580
  version,
@@ -668,24 +715,50 @@ function delay(ms, signal) {
668
715
  }
669
716
  async function runStatusSequence(signal, onStep) {
670
717
  for (const item of STATUS_SEQUENCE) {
671
- onStep({ id: item.id, label: item.label, detail: item.detail, state: "active" });
718
+ onStep({
719
+ id: item.id,
720
+ label: item.label,
721
+ detail: item.detail,
722
+ state: "active"
723
+ });
672
724
  await delay(item.ms, signal);
673
725
  }
674
726
  }
675
727
  function useAgentChat({
676
728
  customerId,
729
+ getUnpublishedPreviewGrant,
677
730
  indexId,
678
731
  version,
679
732
  runtimeOrigin,
680
733
  visitorSessionId,
681
734
  storageKeyPrefix
682
735
  }) {
736
+ const previewGrantProviderRef = (0, import_react.useRef)(getUnpublishedPreviewGrant);
737
+ previewGrantProviderRef.current = getUnpublishedPreviewGrant;
738
+ const resolveUnpublishedPreviewGrant = () => {
739
+ const provider = previewGrantProviderRef.current;
740
+ if (!provider) {
741
+ return Promise.reject(
742
+ new Error(
743
+ "An unpublished preview grant is required to use the Agent Runtime preview."
744
+ )
745
+ );
746
+ }
747
+ return provider();
748
+ };
683
749
  const resolvedStorageKeyPrefix = (0, import_react.useMemo)(
684
- () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({ customerId, indexId, version, runtimeOrigin }),
750
+ () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({
751
+ customerId,
752
+ indexId,
753
+ version,
754
+ runtimeOrigin
755
+ }),
685
756
  [customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
686
757
  );
687
758
  const visitorId = (0, import_react.useMemo)(
688
- () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({ storageKeyPrefix: resolvedStorageKeyPrefix }),
759
+ () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({
760
+ storageKeyPrefix: resolvedStorageKeyPrefix
761
+ }),
689
762
  [resolvedStorageKeyPrefix, visitorSessionId]
690
763
  );
691
764
  const [state, setState] = (0, import_react.useState)(
@@ -697,6 +770,7 @@ function useAgentChat({
697
770
  const clientRef = (0, import_react.useRef)(
698
771
  createAgentClient({
699
772
  customerId,
773
+ getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
700
774
  indexId,
701
775
  version,
702
776
  runtimeOrigin,
@@ -715,6 +789,7 @@ function useAgentChat({
715
789
  runRef.current = null;
716
790
  clientRef.current = createAgentClient({
717
791
  customerId,
792
+ getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
718
793
  indexId,
719
794
  version,
720
795
  runtimeOrigin,
@@ -726,7 +801,15 @@ function useAgentChat({
726
801
  loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
727
802
  )
728
803
  );
729
- }, [customerId, identityKey, indexId, runtimeOrigin, resolvedStorageKeyPrefix, version, visitorId]);
804
+ }, [
805
+ customerId,
806
+ identityKey,
807
+ indexId,
808
+ runtimeOrigin,
809
+ resolvedStorageKeyPrefix,
810
+ version,
811
+ visitorId
812
+ ]);
730
813
  (0, import_react.useEffect)(() => {
731
814
  if (!hasVisitorMessages(state.messages)) return;
732
815
  savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
@@ -734,7 +817,13 @@ function useAgentChat({
734
817
  pending: isAgentBusy(state.phase),
735
818
  streamingText: state.streamingText
736
819
  });
737
- }, [resolvedStorageKeyPrefix, state.messages, state.phase, state.streamingText, visitorId]);
820
+ }, [
821
+ resolvedStorageKeyPrefix,
822
+ state.messages,
823
+ state.phase,
824
+ state.streamingText,
825
+ visitorId
826
+ ]);
738
827
  const reset = (0, import_react.useCallback)(() => {
739
828
  runRef.current?.abort();
740
829
  runRef.current = null;
@@ -752,7 +841,11 @@ function useAgentChat({
752
841
  let streamed = initialText;
753
842
  const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
754
843
  if (streamStarted || !isActiveRun()) return;
755
- setState((prev) => ({ ...prev, phase: "running-tools", toolSteps: [step] }));
844
+ setState((prev) => ({
845
+ ...prev,
846
+ phase: "running-tools",
847
+ toolSteps: [step]
848
+ }));
756
849
  });
757
850
  const handlers = {
758
851
  onStep: (label, detail) => {
@@ -760,7 +853,9 @@ function useAgentChat({
760
853
  setState((prev) => ({
761
854
  ...prev,
762
855
  phase: "running-tools",
763
- toolSteps: [{ id: `step-${label}`, label, detail, state: "active" }]
856
+ toolSteps: [
857
+ { id: `step-${label}`, label, detail, state: "active" }
858
+ ]
764
859
  }));
765
860
  },
766
861
  onDelta: (delta) => {
@@ -777,7 +872,11 @@ function useAgentChat({
777
872
  }));
778
873
  }
779
874
  streamed += delta;
780
- setState((prev) => ({ ...prev, phase: "streaming", streamingText: streamed }));
875
+ setState((prev) => ({
876
+ ...prev,
877
+ phase: "streaming",
878
+ streamingText: streamed
879
+ }));
781
880
  },
782
881
  onComplete: () => {
783
882
  if (!isActiveRun()) return;
@@ -791,7 +890,10 @@ function useAgentChat({
791
890
  signal
792
891
  }) : await clientRef.current.sendTurn(visitorText, { handlers, signal });
793
892
  if (resume && finalText === null) {
794
- finalText = await clientRef.current.sendTurn(visitorText, { handlers, signal });
893
+ finalText = await clientRef.current.sendTurn(visitorText, {
894
+ handlers,
895
+ signal
896
+ });
795
897
  }
796
898
  await planningPromise.catch(() => {
797
899
  });
@@ -813,7 +915,8 @@ function useAgentChat({
813
915
  }));
814
916
  runRef.current = null;
815
917
  } catch (error) {
816
- if (error instanceof DOMException && error.name === "AbortError") return;
918
+ if (error instanceof DOMException && error.name === "AbortError")
919
+ return;
817
920
  if (!isActiveRun()) return;
818
921
  const message = formatAgentError(error);
819
922
  if (!message) return;
@@ -847,7 +950,9 @@ function useAgentChat({
847
950
  ...prev,
848
951
  phase: "thinking",
849
952
  messages: [...prev.messages, visitorMessage],
850
- toolSteps: [{ id: "s1", label: "Starting Eve session", state: "active" }],
953
+ toolSteps: [
954
+ { id: "s1", label: "Starting Eve session", state: "active" }
955
+ ],
851
956
  journey: null,
852
957
  followUps: [],
853
958
  streamingText: "",
@@ -1355,6 +1460,7 @@ var import_jsx_runtime8 = require("react/jsx-runtime");
1355
1460
  function AgentWidget({
1356
1461
  indexId,
1357
1462
  customerId,
1463
+ getUnpublishedPreviewGrant,
1358
1464
  version,
1359
1465
  runtimeOrigin,
1360
1466
  placement: placementInput,
@@ -1367,6 +1473,7 @@ function AgentWidget({
1367
1473
  const [railExpanded, setRailExpanded] = (0, import_react5.useState)(false);
1368
1474
  const { state, submit } = useAgentChat({
1369
1475
  customerId,
1476
+ getUnpublishedPreviewGrant,
1370
1477
  indexId,
1371
1478
  version,
1372
1479
  runtimeOrigin