@atlaskit/editor-plugin-autocomplete 9.0.0 → 9.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @atlaskit/editor-plugin-autocomplete
2
2
 
3
+ ## 9.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`a164c6d8e7de6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a164c6d8e7de6) -
8
+ Offer the Confluence page the chat is open on to autocomplete as context, so words already written
9
+ on it carry an L1 session boost in the chat input. This reads the editor context the page editor
10
+ already publishes, so no host wiring is needed, and covers a page being edited; reaching a page
11
+ that is being viewed needs a host bridge that comes separately. The page text is held together
12
+ with the page it was read from, so navigating invalidates it in the same render that changes the
13
+ page rather than just after — the context store keeps the last published document until another
14
+ publisher replaces it, and that document does not say which page it came from.
15
+
16
+ Both the page and the chat transcript sit behind
17
+ `platform_editor_ai_autocomplete_rovo_chat_editor`, and the editor context subscription that reads
18
+ the page lives in a component the chat input only mounts once enrolled. An unenrolled session
19
+ therefore neither parses a page document for context it cannot use nor re-renders the input on a
20
+ publish, which the editor does on blur and on selection change.
21
+
22
+ Context text now waits for the vocabulary load to settle before it is applied. Session boosts were
23
+ previously spent against an empty trie whenever the page resolved first, which silently dropped
24
+ every word in it. What the session holds is readable from the console with
25
+ `__atlCtcDebug__.session()`.
26
+
27
+ ### Patch Changes
28
+
29
+ - Updated dependencies
30
+
3
31
  ## 9.0.0
4
32
 
5
33
  ### Major Changes
@@ -516,7 +516,72 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
516
516
  // Set when the plugin is torn down so in-flight getContext() resolutions don't
517
517
  // mutate the global text-predictor state after destruction.
518
518
  var destroyed = false;
519
- var ingestedContextTexts = new Set();
519
+ // L1 ingestion cannot run before the vocabulary has loaded: `incrementSessionFreq`
520
+ // only touches trie nodes that already exist, so an empty trie silently rejects
521
+ // every word. Text that arrives first — which a page usually does, since the
522
+ // chat resolves it on focus in the same tick as the load starts — is held here
523
+ // and applied once the load has settled.
524
+ var pendingSessionContextTexts = new Set();
525
+ var sessionIngestedContextTexts = new Set();
526
+ var isVocabularyReady = false;
527
+ var vocabularyLoadPromise;
528
+ var addBoundedContextText = function addBoundedContextText(texts, text) {
529
+ texts.add(text);
530
+ // Evict oldest entries (Set preserves insertion order) to bound memory.
531
+ while (texts.size > MAX_INGESTED_CONTEXT_TEXTS) {
532
+ var oldest = texts.values().next().value;
533
+ if (oldest === undefined) {
534
+ break;
535
+ }
536
+ texts.delete(oldest);
537
+ }
538
+ };
539
+ var flushPendingSessionContext = function flushPendingSessionContext() {
540
+ if (!isVocabularyReady || destroyed) {
541
+ return;
542
+ }
543
+ var _iterator = _createForOfIteratorHelper(pendingSessionContextTexts),
544
+ _step;
545
+ try {
546
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
547
+ var text = _step.value;
548
+ if (!sessionIngestedContextTexts.has(text)) {
549
+ (0, _textPredictor.ingestDocumentPage)(text);
550
+ addBoundedContextText(sessionIngestedContextTexts, text);
551
+ }
552
+ pendingSessionContextTexts.delete(text);
553
+ }
554
+ } catch (err) {
555
+ _iterator.e(err);
556
+ } finally {
557
+ _iterator.f();
558
+ }
559
+ };
560
+ var ensureVocabularyReady = function ensureVocabularyReady() {
561
+ var _options$useLocalMode;
562
+ if (isVocabularyReady) {
563
+ flushPendingSessionContext();
564
+ return Promise.resolve();
565
+ }
566
+ vocabularyLoadPromise !== null && vocabularyLoadPromise !== void 0 ? vocabularyLoadPromise : vocabularyLoadPromise = (0, _textPredictor.loadDefaultVocabulary)({
567
+ isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
568
+ surface: surface
569
+ }).then(function () {
570
+ if (destroyed) {
571
+ return;
572
+ }
573
+ isVocabularyReady = true;
574
+ flushPendingSessionContext();
575
+ }).catch(function (error) {
576
+ // Do not consume the pending text on failure. A later focus retries the
577
+ // load and can still apply the original context exactly once.
578
+ vocabularyLoadPromise = undefined;
579
+ (0, _monitoring.logException)(error, {
580
+ location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
581
+ });
582
+ });
583
+ return vocabularyLoadPromise;
584
+ };
520
585
  var logContextResolved = function logContextResolved(source, context) {
521
586
  var _context$parentCommen, _context$siblingComme4, _context$siblingComme5;
522
587
  if (!(0, _debugMode.isAutocompleteDebugEnabled)()) {
@@ -546,37 +611,29 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
546
611
  }));
547
612
  resolvedContext = _objectSpread(_objectSpread({}, resolvedContext), definedContext);
548
613
  var ingestContextText = function ingestContextText(text) {
549
- if (!text || ingestedContextTexts.has(text)) {
614
+ if (!text || sessionIngestedContextTexts.has(text)) {
550
615
  return;
551
616
  }
552
- ingestedContextTexts.add(text);
553
- // Evict oldest entries (Set preserves insertion order) to bound memory.
554
- while (ingestedContextTexts.size > MAX_INGESTED_CONTEXT_TEXTS) {
555
- var oldest = ingestedContextTexts.values().next().value;
556
- if (oldest === undefined) {
557
- break;
558
- }
559
- ingestedContextTexts.delete(oldest);
560
- }
561
- (0, _textPredictor.ingestDocumentPage)(text);
617
+ addBoundedContextText(pendingSessionContextTexts, text);
562
618
  };
563
619
  ingestContextText(context.fullPageContent);
564
620
  ingestContextText(context.parentCommentContent);
565
- var _iterator = _createForOfIteratorHelper((_context$siblingComme6 = context.siblingCommentsContents) !== null && _context$siblingComme6 !== void 0 ? _context$siblingComme6 : []),
566
- _step;
621
+ var _iterator2 = _createForOfIteratorHelper((_context$siblingComme6 = context.siblingCommentsContents) !== null && _context$siblingComme6 !== void 0 ? _context$siblingComme6 : []),
622
+ _step2;
567
623
  try {
568
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
569
- var siblingCommentContent = _step.value;
624
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
625
+ var siblingCommentContent = _step2.value;
570
626
  ingestContextText(siblingCommentContent);
571
627
  }
572
-
573
- // Context arrived after word boundaries may already have fired. Re-send
574
- // slow-lane context immediately so the next inference includes the thread.
575
628
  } catch (err) {
576
- _iterator.e(err);
629
+ _iterator2.e(err);
577
630
  } finally {
578
- _iterator.f();
631
+ _iterator2.f();
579
632
  }
633
+ flushPendingSessionContext();
634
+
635
+ // Context arrived after word boundaries may already have fired. Re-send
636
+ // slow-lane context immediately so the next inference includes the thread.
580
637
  if (currentView) {
581
638
  slowLaneClient.updateContext(buildSlowLaneText(currentView.state.doc.textContent, resolvedContext));
582
639
  }
@@ -967,18 +1024,11 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
967
1024
  return accepted;
968
1025
  },
969
1026
  focus: function focus() {
970
- var _options$useLocalMode, _options$useLocalMode2, _options$useLocalMode3;
1027
+ var _options$useLocalMode2, _options$useLocalMode3;
971
1028
  if (!isAutocompleteEnabled) {
972
1029
  return false;
973
1030
  }
974
- (0, _textPredictor.loadDefaultVocabulary)({
975
- isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
976
- surface: surface
977
- }).catch(function (error) {
978
- (0, _monitoring.logException)(error, {
979
- location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
980
- });
981
- });
1031
+ void ensureVocabularyReady();
982
1032
  (0, _textPredictor.loadVectorsAsync)({
983
1033
  isLocalLLM: (_options$useLocalMode2 = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode2 !== void 0 ? _options$useLocalMode2 : false,
984
1034
  surface: surface
@@ -1076,7 +1126,8 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
1076
1126
  if (hasDestroy(slowLaneClient)) {
1077
1127
  slowLaneClient.destroy();
1078
1128
  }
1079
- ingestedContextTexts.clear();
1129
+ pendingSessionContextTexts.clear();
1130
+ sessionIngestedContextTexts.clear();
1080
1131
  }
1081
1132
  };
1082
1133
  }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isAutocompleteDebugVerbose = exports.isAutocompleteDebugEnabled = exports.ctcTag = exports.ctcSection = exports.CTC_STYLES = void 0;
6
+ exports.registerCtcSessionInspector = exports.isAutocompleteDebugVerbose = exports.isAutocompleteDebugEnabled = exports.ctcTag = exports.ctcSection = exports.CTC_STYLES = void 0;
7
7
  /**
8
8
  * Contextual Typeahead Completions (CTC) debug logging utility.
9
9
  *
@@ -96,7 +96,7 @@ var printLegend = function printLegend(verbose) {
96
96
  // eslint-disable-next-line no-console
97
97
  console.log('%cPlanes%c [CTC:init] loads · [CTC:signal] semantic/network · [CTC:model] primes/exact · [CTC:model-cost] prefill/decode · [CTC:readiness] deadline progress', CTC_STYLES.section, CTC_STYLES.body);
98
98
  // eslint-disable-next-line no-console
99
- console.log('%cInspect%c __atlCtcDebug__.enable("verbose") · .disable()', CTC_STYLES.section, CTC_STYLES.body);
99
+ console.log('%cInspect%c __atlCtcDebug__.enable("verbose") · .disable() · .session() (L1 boosts, narrow to a family with .session("poll"))', CTC_STYLES.section, CTC_STYLES.body);
100
100
  // eslint-disable-next-line no-console
101
101
  console.groupEnd();
102
102
  };
@@ -144,5 +144,20 @@ var isAutocompleteDebugVerbose = exports.isAutocompleteDebugVerbose = function i
144
144
  return (_getDebugApi$isVerbos = (_getDebugApi2 = getDebugApi()) === null || _getDebugApi2 === void 0 ? void 0 : _getDebugApi2.isVerbose()) !== null && _getDebugApi$isVerbos !== void 0 ? _getDebugApi$isVerbos : false;
145
145
  };
146
146
 
147
+ /**
148
+ * Hang the L1 session-boost snapshot off the console API.
149
+ *
150
+ * Unlike the log helpers this is available whether or not debug is enabled:
151
+ * inspecting state on demand is not logging, and asking someone to turn on
152
+ * logging and retype to find out what the session already holds defeats the
153
+ * point of being able to ask.
154
+ */
155
+ var registerCtcSessionInspector = exports.registerCtcSessionInspector = function registerCtcSessionInspector(inspect) {
156
+ var api = getDebugApi();
157
+ if (api) {
158
+ api.session = inspect;
159
+ }
160
+ };
161
+
147
162
  // Eagerly install so the console API is available on load, regardless of call order.
148
163
  getDebugApi();