@atlaskit/editor-plugin-autocomplete 6.0.0 → 8.0.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 +20 -0
- package/compass.yml +2 -2
- package/dist/cjs/analytics/ufo.js +3 -2
- package/dist/cjs/pm-plugins/artifacts-manifest.js +210 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +10 -2
- package/dist/cjs/pm-plugins/local-slow-lane-client.js +68 -153
- package/dist/cjs/pm-plugins/scoring-pipeline.js +130 -28
- package/dist/cjs/pm-plugins/text-predictor.js +45 -106
- package/dist/es2019/analytics/ufo.js +4 -2
- package/dist/es2019/pm-plugins/artifacts-manifest.js +126 -0
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +10 -2
- package/dist/es2019/pm-plugins/local-slow-lane-client.js +8 -78
- package/dist/es2019/pm-plugins/scoring-pipeline.js +97 -21
- package/dist/es2019/pm-plugins/text-predictor.js +17 -59
- package/dist/esm/analytics/ufo.js +3 -2
- package/dist/esm/pm-plugins/artifacts-manifest.js +204 -0
- package/dist/esm/pm-plugins/autocomplete-plugin.js +10 -2
- package/dist/esm/pm-plugins/local-slow-lane-client.js +67 -148
- package/dist/esm/pm-plugins/scoring-pipeline.js +128 -26
- package/dist/esm/pm-plugins/text-predictor.js +45 -98
- package/dist/types/analytics/ufo.d.ts +1 -0
- package/dist/types/pm-plugins/artifacts-manifest.d.ts +55 -0
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +5 -11
- package/dist/types/pm-plugins/scoring-pipeline.d.ts +14 -0
- package/dist/types/pm-plugins/text-predictor.d.ts +0 -1
- package/package.json +3 -6
- package/src/analytics/ufo.ts +5 -0
- package/src/pm-plugins/artifacts-manifest.ts +151 -0
- package/src/pm-plugins/autocomplete-plugin.ts +14 -12
- package/src/pm-plugins/local-slow-lane-client.ts +10 -92
- package/src/pm-plugins/scoring-pipeline.ts +115 -23
- package/src/pm-plugins/text-predictor.ts +28 -76
- package/dist/cjs/pm-plugins/data/combined_l2_l3_pos_tags.json +0 -73571
- package/dist/cjs/pm-plugins/data/first_token_to_words.json +0 -1
- package/dist/cjs/pm-plugins/data/ghost_pos_tags.json +0 -43
- package/dist/cjs/pm-plugins/data/grammar_transitions_10k.json +0 -46
- package/dist/cjs/pm-plugins/data/l3_vocabulary.json +0 -20002
- package/dist/cjs/pm-plugins/data/vocabulary_10k.json +0 -38794
- package/dist/cjs/pm-plugins/data/word_index_10k.json +0 -7762
- package/dist/es2019/pm-plugins/data/combined_l2_l3_pos_tags.json +0 -73571
- package/dist/es2019/pm-plugins/data/first_token_to_words.json +0 -1
- package/dist/es2019/pm-plugins/data/ghost_pos_tags.json +0 -43
- package/dist/es2019/pm-plugins/data/grammar_transitions_10k.json +0 -46
- package/dist/es2019/pm-plugins/data/l3_vocabulary.json +0 -20002
- package/dist/es2019/pm-plugins/data/vocabulary_10k.json +0 -38794
- package/dist/es2019/pm-plugins/data/word_index_10k.json +0 -7762
- package/dist/esm/pm-plugins/data/combined_l2_l3_pos_tags.json +0 -73571
- package/dist/esm/pm-plugins/data/first_token_to_words.json +0 -1
- package/dist/esm/pm-plugins/data/ghost_pos_tags.json +0 -43
- package/dist/esm/pm-plugins/data/grammar_transitions_10k.json +0 -46
- package/dist/esm/pm-plugins/data/l3_vocabulary.json +0 -20002
- package/dist/esm/pm-plugins/data/vocabulary_10k.json +0 -38794
- package/dist/esm/pm-plugins/data/word_index_10k.json +0 -7762
- package/src/pm-plugins/data/combined_l2_l3_pos_tags.json +0 -73571
- package/src/pm-plugins/data/first_token_to_words.json +0 -1
- package/src/pm-plugins/data/ghost_pos_tags.json +0 -43
- package/src/pm-plugins/data/grammar_transitions_10k.json +0 -46
- package/src/pm-plugins/data/l3_vocabulary.json +0 -20002
- package/src/pm-plugins/data/vocabulary_10k.json +0 -38794
- package/src/pm-plugins/data/word-vectors_10k.bin +0 -3
- package/src/pm-plugins/data/word_index_10k.json +0 -7762
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
var _typeof3 = require("@babel/runtime/helpers/typeof");
|
|
5
4
|
Object.defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
8
7
|
exports.predict = exports.loadVectorsAsync = exports.loadDefaultVocabulary = exports.initVocabulary = exports.initVectors = exports.initL3Vocabulary = exports.ingestDocumentPage = exports.incrementSessionFreq = exports.getPredictorStatus = exports.getLastPredictionDebug = void 0;
|
|
9
8
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
10
|
-
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
11
9
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
10
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
12
11
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
13
12
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
14
13
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
15
14
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
16
15
|
var _ufo = require("../analytics/ufo");
|
|
16
|
+
var _artifactsManifest = require("./artifacts-manifest");
|
|
17
17
|
var _debugMode = require("./debug-mode");
|
|
18
18
|
var _scoringPipeline = require("./scoring-pipeline");
|
|
19
19
|
var _slowLaneClient = require("./slow-lane-client");
|
|
20
|
-
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof3(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t4 in e) "default" !== _t4 && {}.hasOwnProperty.call(e, _t4) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t4)) && (i.get || i.set) ? o(f, _t4, i) : f[_t4] = e[_t4]); return f; })(e, t); }
|
|
21
20
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
22
21
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
23
22
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
@@ -37,9 +36,9 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
37
36
|
*
|
|
38
37
|
* Session personalization (L1): words the user types are incrementally boosted
|
|
39
38
|
* via incrementSessionFreq(), called on word boundaries from the plugin.
|
|
40
|
-
*/ // The vocabulary, L3 and word-index
|
|
41
|
-
// loadDefaultVocabulary / loadVectorsAsync so their (large) contents
|
|
42
|
-
// the editor's
|
|
39
|
+
*/ // The vocabulary, L3 and word-index payloads are fetched from the CDN in
|
|
40
|
+
// loadDefaultVocabulary / loadVectorsAsync so their (large) contents never enter
|
|
41
|
+
// the editor's bundle and only load when autocomplete is initialised.
|
|
43
42
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
44
43
|
|
|
45
44
|
// eslint-disable-next-line require-unicode-regexp
|
|
@@ -689,56 +688,10 @@ var predict = exports.predict = function predict(textBefore) {
|
|
|
689
688
|
|
|
690
689
|
// ─── Data Loading ────────────────────────────────────────────────────────────
|
|
691
690
|
|
|
692
|
-
/**
|
|
693
|
-
* Unwrap a dynamically imported JSON module to its parsed value, handling both
|
|
694
|
-
* interop modes AFM's bundler chain emits: a `.default`-wrapped namespace
|
|
695
|
-
* (classic webpack) and a named-exports namespace (webpack 5 / atlaspack JSON
|
|
696
|
-
* modules, where `default` can be a misleading scalar). Named exports are
|
|
697
|
-
* preferred when present. The caller declares the JSON `shape` because a dense
|
|
698
|
-
* array and a sparse numeric-keyed object are emitted identically as named
|
|
699
|
-
* exports. Kept in lock-step with the matching helper in local-slow-lane-client.ts.
|
|
700
|
-
*/
|
|
701
|
-
function unwrapJsonModule(mod, shape) {
|
|
702
|
-
if (mod == null || (0, _typeof2.default)(mod) !== 'object') {
|
|
703
|
-
return null;
|
|
704
|
-
}
|
|
705
|
-
var namespace = mod;
|
|
706
|
-
var ownKeys = Object.keys(namespace).filter(function (k) {
|
|
707
|
-
return k !== 'default' && k !== '__esModule';
|
|
708
|
-
});
|
|
709
|
-
if (ownKeys.length > 0) {
|
|
710
|
-
if (shape === 'array') {
|
|
711
|
-
var len = ownKeys.length;
|
|
712
|
-
var arr = new Array(len);
|
|
713
|
-
for (var i = 0; i < len; i++) {
|
|
714
|
-
arr[i] = namespace[String(i)];
|
|
715
|
-
}
|
|
716
|
-
return arr;
|
|
717
|
-
}
|
|
718
|
-
var obj = {};
|
|
719
|
-
var _iterator1 = _createForOfIteratorHelper(ownKeys),
|
|
720
|
-
_step1;
|
|
721
|
-
try {
|
|
722
|
-
for (_iterator1.s(); !(_step1 = _iterator1.n()).done;) {
|
|
723
|
-
var k = _step1.value;
|
|
724
|
-
obj[k] = namespace[k];
|
|
725
|
-
}
|
|
726
|
-
} catch (err) {
|
|
727
|
-
_iterator1.e(err);
|
|
728
|
-
} finally {
|
|
729
|
-
_iterator1.f();
|
|
730
|
-
}
|
|
731
|
-
return obj;
|
|
732
|
-
}
|
|
733
|
-
if ('default' in namespace && namespace.default != null) {
|
|
734
|
-
return namespace.default;
|
|
735
|
-
}
|
|
736
|
-
return null;
|
|
737
|
-
}
|
|
738
691
|
var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
739
692
|
var _ref6 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(options) {
|
|
740
693
|
var _options$isLocalLLM;
|
|
741
|
-
var isLocalLLM, surface, url,
|
|
694
|
+
var isLocalLLM, surface, url, res, buffer, float32, wordIndexPayload, wrappedIndex, wordIndex, nWords, dim, _t, _t2;
|
|
742
695
|
return _regenerator.default.wrap(function (_context) {
|
|
743
696
|
while (1) switch (_context.prev = _context.next) {
|
|
744
697
|
case 0:
|
|
@@ -748,14 +701,6 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
748
701
|
}
|
|
749
702
|
return _context.abrupt("return");
|
|
750
703
|
case 1:
|
|
751
|
-
if (options !== null && options !== void 0 && options.getBinaryUrl) {
|
|
752
|
-
_context.next = 2;
|
|
753
|
-
break;
|
|
754
|
-
}
|
|
755
|
-
// eslint-disable-next-line no-console
|
|
756
|
-
console.warn('[text-predictor] loadVectorsAsync called without a getBinaryUrl — vectors will not load. Pass getVectorsBinaryUrl via plugin options.');
|
|
757
|
-
return _context.abrupt("return");
|
|
758
|
-
case 2:
|
|
759
704
|
isLocalLLM = (_options$isLocalLLM = options === null || options === void 0 ? void 0 : options.isLocalLLM) !== null && _options$isLocalLLM !== void 0 ? _options$isLocalLLM : false;
|
|
760
705
|
surface = options === null || options === void 0 ? void 0 : options.surface;
|
|
761
706
|
vectorsLoadStarted = true;
|
|
@@ -764,16 +709,16 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
764
709
|
}, surface ? {
|
|
765
710
|
surface: surface
|
|
766
711
|
} : {}));
|
|
767
|
-
_context.prev =
|
|
768
|
-
_context.next =
|
|
769
|
-
return
|
|
770
|
-
case
|
|
712
|
+
_context.prev = 2;
|
|
713
|
+
_context.next = 3;
|
|
714
|
+
return (0, _artifactsManifest.getArtifactUrl)(_artifactsManifest.ARTIFACT_NAME.WORD_VECTORS);
|
|
715
|
+
case 3:
|
|
771
716
|
url = _context.sent;
|
|
772
|
-
_context.next =
|
|
717
|
+
_context.next = 5;
|
|
773
718
|
break;
|
|
774
|
-
case
|
|
775
|
-
_context.prev =
|
|
776
|
-
_t = _context["catch"](
|
|
719
|
+
case 4:
|
|
720
|
+
_context.prev = 4;
|
|
721
|
+
_t = _context["catch"](2);
|
|
777
722
|
vectorsLoadStarted = false;
|
|
778
723
|
(0, _ufo.failExp)(_ufo.EXPERIENCE_NAME.LOAD_VECTORS, 'singleton', _objectSpread({
|
|
779
724
|
isLocalLLM: isLocalLLM,
|
|
@@ -784,14 +729,14 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
784
729
|
// eslint-disable-next-line no-console
|
|
785
730
|
console.warn('[text-predictor] Failed to resolve vectors URL:', _t);
|
|
786
731
|
return _context.abrupt("return");
|
|
787
|
-
case
|
|
788
|
-
_context.prev =
|
|
789
|
-
_context.next =
|
|
732
|
+
case 5:
|
|
733
|
+
_context.prev = 5;
|
|
734
|
+
_context.next = 6;
|
|
790
735
|
return fetch(url);
|
|
791
|
-
case
|
|
736
|
+
case 6:
|
|
792
737
|
res = _context.sent;
|
|
793
738
|
if (res.ok) {
|
|
794
|
-
_context.next =
|
|
739
|
+
_context.next = 7;
|
|
795
740
|
break;
|
|
796
741
|
}
|
|
797
742
|
vectorsLoadStarted = false;
|
|
@@ -805,26 +750,26 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
805
750
|
// eslint-disable-next-line no-console
|
|
806
751
|
console.warn("[text-predictor] Failed to load vectors: ".concat(res.status));
|
|
807
752
|
return _context.abrupt("return");
|
|
753
|
+
case 7:
|
|
754
|
+
_context.next = 8;
|
|
755
|
+
return res.arrayBuffer();
|
|
808
756
|
case 8:
|
|
757
|
+
buffer = _context.sent;
|
|
758
|
+
float32 = new Float32Array(buffer); // The word index is published either bare or wrapped as `{ "index": {…} }`
|
|
759
|
+
// (the wrapper exists so no real entry, e.g. the word "default", can shadow
|
|
760
|
+
// a bundler-synthesised ESM export). Detect the wrapper by value type, not
|
|
761
|
+
// by key presence — "index" is itself a plausible vocabulary word, and in a
|
|
762
|
+
// bare index every value is a number.
|
|
809
763
|
_context.next = 9;
|
|
810
|
-
return
|
|
764
|
+
return (0, _artifactsManifest.fetchArtifactJson)(_artifactsManifest.ARTIFACT_NAME.WORD_INDEX);
|
|
811
765
|
case 9:
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
// the bundler creates for dynamically-imported JSON.
|
|
816
|
-
_context.next = 10;
|
|
817
|
-
return Promise.resolve().then(function () {
|
|
818
|
-
return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-word-index-10k" */'./data/word_index_10k.json'));
|
|
819
|
-
});
|
|
820
|
-
case 10:
|
|
821
|
-
wordIndexModule = _context.sent;
|
|
822
|
-
wordIndexOuter = unwrapJsonModule(wordIndexModule, 'object');
|
|
823
|
-
wordIndex = (_wordIndexOuter$index = wordIndexOuter === null || wordIndexOuter === void 0 ? void 0 : wordIndexOuter.index) !== null && _wordIndexOuter$index !== void 0 ? _wordIndexOuter$index : {};
|
|
766
|
+
wordIndexPayload = _context.sent;
|
|
767
|
+
wrappedIndex = wordIndexPayload === null || wordIndexPayload === void 0 ? void 0 : wordIndexPayload.index;
|
|
768
|
+
wordIndex = (0, _typeof2.default)(wrappedIndex) === 'object' && wrappedIndex !== null ? wrappedIndex : wordIndexPayload !== null && wordIndexPayload !== void 0 ? wordIndexPayload : {};
|
|
824
769
|
nWords = Object.keys(wordIndex).length;
|
|
825
770
|
if (nWords === 0) {
|
|
826
771
|
// eslint-disable-next-line no-console
|
|
827
|
-
console.warn(
|
|
772
|
+
console.warn("[text-predictor] ".concat(_artifactsManifest.ARTIFACT_NAME.WORD_INDEX, " was empty \u2014 semantic scoring will be a no-op."));
|
|
828
773
|
}
|
|
829
774
|
dim = float32.length / nWords;
|
|
830
775
|
vectorStore = {
|
|
@@ -848,11 +793,11 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
848
793
|
sizeBytes: float32.byteLength
|
|
849
794
|
});
|
|
850
795
|
}
|
|
851
|
-
_context.next =
|
|
796
|
+
_context.next = 11;
|
|
852
797
|
break;
|
|
853
|
-
case
|
|
854
|
-
_context.prev =
|
|
855
|
-
_t2 = _context["catch"](
|
|
798
|
+
case 10:
|
|
799
|
+
_context.prev = 10;
|
|
800
|
+
_t2 = _context["catch"](5);
|
|
856
801
|
vectorsLoadStarted = false;
|
|
857
802
|
(0, _ufo.failExp)(_ufo.EXPERIENCE_NAME.LOAD_VECTORS, 'singleton', _objectSpread({
|
|
858
803
|
isLocalLLM: isLocalLLM,
|
|
@@ -862,11 +807,11 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
862
807
|
} : {}));
|
|
863
808
|
// eslint-disable-next-line no-console
|
|
864
809
|
console.warn('[text-predictor] Failed to load vectors:', _t2);
|
|
865
|
-
case
|
|
810
|
+
case 11:
|
|
866
811
|
case "end":
|
|
867
812
|
return _context.stop();
|
|
868
813
|
}
|
|
869
|
-
}, _callee, null, [[
|
|
814
|
+
}, _callee, null, [[2, 4], [5, 10]]);
|
|
870
815
|
}));
|
|
871
816
|
return function loadVectorsAsync(_x) {
|
|
872
817
|
return _ref6.apply(this, arguments);
|
|
@@ -887,7 +832,7 @@ var loadDefaultVocabulary = exports.loadDefaultVocabulary = function loadDefault
|
|
|
887
832
|
var isLocalLLM = (_options$isLocalLLM2 = options === null || options === void 0 ? void 0 : options.isLocalLLM) !== null && _options$isLocalLLM2 !== void 0 ? _options$isLocalLLM2 : false;
|
|
888
833
|
var surface = options === null || options === void 0 ? void 0 : options.surface;
|
|
889
834
|
vocabularyLoadPromise = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
890
|
-
var _yield$Promise$all, _yield$Promise$all2,
|
|
835
|
+
var _yield$Promise$all, _yield$Promise$all2, vocabularyData, l3VocabularyData, terms, _t3;
|
|
891
836
|
return _regenerator.default.wrap(function (_context2) {
|
|
892
837
|
while (1) switch (_context2.prev = _context2.next) {
|
|
893
838
|
case 0:
|
|
@@ -898,23 +843,17 @@ var loadDefaultVocabulary = exports.loadDefaultVocabulary = function loadDefault
|
|
|
898
843
|
} : {}));
|
|
899
844
|
_context2.prev = 1;
|
|
900
845
|
_context2.next = 2;
|
|
901
|
-
return Promise.all([
|
|
902
|
-
return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-vocabulary-10k" */'./data/vocabulary_10k.json'));
|
|
903
|
-
}), Promise.resolve().then(function () {
|
|
904
|
-
return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-l3-vocabulary" */'./data/l3_vocabulary.json'));
|
|
905
|
-
})]);
|
|
846
|
+
return Promise.all([(0, _artifactsManifest.fetchArtifactJson)(_artifactsManifest.ARTIFACT_NAME.VOCABULARY), (0, _artifactsManifest.fetchArtifactJson)(_artifactsManifest.ARTIFACT_NAME.L3_VOCABULARY)]);
|
|
906
847
|
case 2:
|
|
907
848
|
_yield$Promise$all = _context2.sent;
|
|
908
849
|
_yield$Promise$all2 = (0, _slicedToArray2.default)(_yield$Promise$all, 2);
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
vocabularyData = unwrapJsonModule(vocabularyModule, 'object');
|
|
912
|
-
l3VocabularyData = unwrapJsonModule(l3VocabularyModule, 'array');
|
|
850
|
+
vocabularyData = _yield$Promise$all2[0];
|
|
851
|
+
l3VocabularyData = _yield$Promise$all2[1];
|
|
913
852
|
if (!((vocabularyData === null || vocabularyData === void 0 ? void 0 : vocabularyData.words) == null || !Array.isArray(l3VocabularyData))) {
|
|
914
853
|
_context2.next = 3;
|
|
915
854
|
break;
|
|
916
855
|
}
|
|
917
|
-
throw new Error(
|
|
856
|
+
throw new Error("[text-predictor] unexpected vocabulary payload \u2014 " + "".concat(_artifactsManifest.ARTIFACT_NAME.VOCABULARY, " ").concat((vocabularyData === null || vocabularyData === void 0 ? void 0 : vocabularyData.words) == null ? 'is missing its `words` wrapper' : 'is valid', ", ") + "".concat(_artifactsManifest.ARTIFACT_NAME.L3_VOCABULARY, " ").concat(Array.isArray(l3VocabularyData) ? 'is valid' : 'is not an array'));
|
|
918
857
|
case 3:
|
|
919
858
|
terms = Object.entries(vocabularyData.words).map(function (_ref8) {
|
|
920
859
|
var _ref9 = (0, _slicedToArray2.default)(_ref8, 2),
|
|
@@ -947,7 +886,7 @@ var loadDefaultVocabulary = exports.loadDefaultVocabulary = function loadDefault
|
|
|
947
886
|
_t3 = _context2["catch"](1);
|
|
948
887
|
(0, _ufo.failExp)(_ufo.EXPERIENCE_NAME.LOAD_VOCABULARY, 'singleton', _objectSpread({
|
|
949
888
|
isLocalLLM: isLocalLLM,
|
|
950
|
-
errorType: '
|
|
889
|
+
errorType: 'load_error'
|
|
951
890
|
}, surface ? {
|
|
952
891
|
surface: surface
|
|
953
892
|
} : {}));
|
|
@@ -31,7 +31,8 @@ import { ConcurrentExperience, ExperiencePerformanceTypes, ExperienceTypes } fro
|
|
|
31
31
|
export const EXPERIENCE_NAME = {
|
|
32
32
|
SLOW_LANE_FETCH: 'slow-lane-fetch',
|
|
33
33
|
LOAD_VOCABULARY: 'load-vocabulary',
|
|
34
|
-
LOAD_VECTORS: 'load-vectors'
|
|
34
|
+
LOAD_VECTORS: 'load-vectors',
|
|
35
|
+
LOAD_GRAMMAR: 'load-grammar'
|
|
35
36
|
};
|
|
36
37
|
const isUfoEnabled = () => {
|
|
37
38
|
var _process, _process$env;
|
|
@@ -54,7 +55,8 @@ const operationConfig = {
|
|
|
54
55
|
const experiences = {
|
|
55
56
|
[EXPERIENCE_NAME.SLOW_LANE_FETCH]: new ConcurrentExperience(EXPERIENCE_NAME.SLOW_LANE_FETCH, operationConfig),
|
|
56
57
|
[EXPERIENCE_NAME.LOAD_VOCABULARY]: new ConcurrentExperience(EXPERIENCE_NAME.LOAD_VOCABULARY, operationConfig),
|
|
57
|
-
[EXPERIENCE_NAME.LOAD_VECTORS]: new ConcurrentExperience(EXPERIENCE_NAME.LOAD_VECTORS, operationConfig)
|
|
58
|
+
[EXPERIENCE_NAME.LOAD_VECTORS]: new ConcurrentExperience(EXPERIENCE_NAME.LOAD_VECTORS, operationConfig),
|
|
59
|
+
[EXPERIENCE_NAME.LOAD_GRAMMAR]: new ConcurrentExperience(EXPERIENCE_NAME.LOAD_GRAMMAR, operationConfig)
|
|
58
60
|
};
|
|
59
61
|
export const startExp = (name, id, metadata) => {
|
|
60
62
|
if (!isUfoEnabled()) {
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifacts Manifest Client: resolves the autocomplete model artifacts hosted on
|
|
3
|
+
* the CDN.
|
|
4
|
+
*
|
|
5
|
+
* `GET /gateway/api/v1/autocomplete/artifacts` returns one presigned CDN URL per
|
|
6
|
+
* artifact for the tenant's active model version:
|
|
7
|
+
*
|
|
8
|
+
* { activeVersion, artifacts: [{ name, url, contentType, sizeBytes, checksum }] }
|
|
9
|
+
*
|
|
10
|
+
* Every loader in the plugin resolves its payload through here, so no model data
|
|
11
|
+
* is bundled with the package.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
15
|
+
|
|
16
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Manifest artifact names. These are the manifest's lookup keys and are
|
|
20
|
+
* hyphenated, unlike the underscored filenames the artifacts are generated from.
|
|
21
|
+
*/
|
|
22
|
+
export const ARTIFACT_NAME = {
|
|
23
|
+
FIRST_TOKEN_TO_WORDS: 'first-token-to-words.json',
|
|
24
|
+
GHOST_POS_TAGS: 'ghost-pos-tags.json',
|
|
25
|
+
GRAMMAR_TRANSITIONS: 'grammar-transitions-10k.json',
|
|
26
|
+
L3_VOCABULARY: 'l3-vocabulary.json',
|
|
27
|
+
POS_TAGS: 'combined-l2-l3-pos-tags.json',
|
|
28
|
+
VOCABULARY: 'vocabulary-10k.json',
|
|
29
|
+
WORD_INDEX: 'word-index-10k.json',
|
|
30
|
+
WORD_VECTORS: 'word-vectors-10k.bin'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** A single entry in the artifacts manifest. */
|
|
34
|
+
|
|
35
|
+
/** Response body of the artifacts endpoint. */
|
|
36
|
+
|
|
37
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
const MANIFEST_ENDPOINT = '/gateway/api/v1/autocomplete/artifacts';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Presigned artifact URLs expire ~10 minutes after the manifest is issued, so
|
|
43
|
+
* the manifest is re-requested well inside that window instead of being cached
|
|
44
|
+
* for the session and handing out dead URLs to a late loader.
|
|
45
|
+
*/
|
|
46
|
+
const MANIFEST_TTL_MS = 5 * 60 * 1000;
|
|
47
|
+
|
|
48
|
+
// ─── Manifest ────────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
let manifestPromise;
|
|
51
|
+
let manifestRequestedAt = 0;
|
|
52
|
+
|
|
53
|
+
/** Test-only: drops the memoised manifest so the next lookup re-requests it. */
|
|
54
|
+
export const resetArtifactsManifestCache = () => {
|
|
55
|
+
manifestPromise = undefined;
|
|
56
|
+
manifestRequestedAt = 0;
|
|
57
|
+
};
|
|
58
|
+
const requestManifest = async () => {
|
|
59
|
+
const res = await fetch(MANIFEST_ENDPOINT, {
|
|
60
|
+
method: 'GET',
|
|
61
|
+
headers: {
|
|
62
|
+
'x-experience-id': 'confluence-smart-typeahead-artifacts',
|
|
63
|
+
'x-product': 'confluence'
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
throw new Error(`[autocomplete-artifacts] Manifest request failed: ${res.status}`);
|
|
68
|
+
}
|
|
69
|
+
const body = await res.json();
|
|
70
|
+
if (!Array.isArray(body === null || body === void 0 ? void 0 : body.artifacts) || body.artifacts.length === 0) {
|
|
71
|
+
throw new Error('[autocomplete-artifacts] Manifest response contained no artifacts');
|
|
72
|
+
}
|
|
73
|
+
if (isAutocompleteDebugEnabled()) {
|
|
74
|
+
// eslint-disable-next-line no-console
|
|
75
|
+
console.log('[autocomplete-artifacts] Manifest loaded:', {
|
|
76
|
+
activeVersion: body.activeVersion,
|
|
77
|
+
names: body.artifacts.map(artifact => artifact.name)
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return new Map(body.artifacts.map(artifact => [artifact.name, artifact]));
|
|
81
|
+
};
|
|
82
|
+
const getManifest = () => {
|
|
83
|
+
if (manifestPromise && Date.now() - manifestRequestedAt < MANIFEST_TTL_MS) {
|
|
84
|
+
return manifestPromise;
|
|
85
|
+
}
|
|
86
|
+
manifestRequestedAt = Date.now();
|
|
87
|
+
manifestPromise = requestManifest().catch(e => {
|
|
88
|
+
// Never cache a rejection — a transient failure would otherwise stop every
|
|
89
|
+
// later loader in the session from retrying.
|
|
90
|
+
resetArtifactsManifestCache();
|
|
91
|
+
throw e;
|
|
92
|
+
});
|
|
93
|
+
return manifestPromise;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Resolve the CDN URL for an artifact.
|
|
100
|
+
*
|
|
101
|
+
* :raises Error: when the manifest cannot be fetched or omits the artifact.
|
|
102
|
+
*/
|
|
103
|
+
export const getArtifactUrl = async name => {
|
|
104
|
+
var _manifest$get;
|
|
105
|
+
const manifest = await getManifest();
|
|
106
|
+
const url = (_manifest$get = manifest.get(name)) === null || _manifest$get === void 0 ? void 0 : _manifest$get.url;
|
|
107
|
+
if (!url) {
|
|
108
|
+
throw new Error(`[autocomplete-artifacts] Manifest has no URL for "${name}"`);
|
|
109
|
+
}
|
|
110
|
+
return url;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Download and parse a JSON artifact. The presigned URL carries its own auth
|
|
115
|
+
* token, so the request is sent without Atlassian headers or credentials.
|
|
116
|
+
*
|
|
117
|
+
* :raises Error: when the manifest lookup or the download fails.
|
|
118
|
+
*/
|
|
119
|
+
export const fetchArtifactJson = async name => {
|
|
120
|
+
const url = await getArtifactUrl(name);
|
|
121
|
+
const res = await fetch(url);
|
|
122
|
+
if (!res.ok) {
|
|
123
|
+
throw new Error(`[autocomplete-artifacts] Failed to download "${name}": ${res.status}`);
|
|
124
|
+
}
|
|
125
|
+
return await res.json();
|
|
126
|
+
};
|
|
@@ -7,6 +7,7 @@ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
|
7
7
|
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
8
8
|
import { createGhostTextDecorationSet } from './ghost-text-decoration';
|
|
9
9
|
import { createLocalSlowLaneClient } from './local-slow-lane-client';
|
|
10
|
+
import { loadGrammarDataAsync } from './scoring-pipeline';
|
|
10
11
|
import { createSlowLaneClient, setDefaultSlowLaneClient, isWordBoundary } from './slow-lane-client';
|
|
11
12
|
import { predict, loadDefaultVocabulary, loadVectorsAsync, incrementSessionFreq, ingestDocumentPage } from './text-predictor';
|
|
12
13
|
export const autocompletePluginKey = new PluginKey('autocomplete');
|
|
@@ -665,7 +666,7 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
665
666
|
return accepted;
|
|
666
667
|
},
|
|
667
668
|
focus: () => {
|
|
668
|
-
var _options$useLocalMode, _options$useLocalMode2;
|
|
669
|
+
var _options$useLocalMode, _options$useLocalMode2, _options$useLocalMode3;
|
|
669
670
|
if (!isAutocompleteEnabled) {
|
|
670
671
|
return false;
|
|
671
672
|
}
|
|
@@ -678,7 +679,6 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
678
679
|
});
|
|
679
680
|
});
|
|
680
681
|
loadVectorsAsync({
|
|
681
|
-
getBinaryUrl: options === null || options === void 0 ? void 0 : options.getVectorsBinaryUrl,
|
|
682
682
|
isLocalLLM: (_options$useLocalMode2 = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode2 !== void 0 ? _options$useLocalMode2 : false,
|
|
683
683
|
surface
|
|
684
684
|
}).catch(error => {
|
|
@@ -686,6 +686,14 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
686
686
|
location: 'editor-plugin-autocomplete/loadVectorsAsync'
|
|
687
687
|
});
|
|
688
688
|
});
|
|
689
|
+
loadGrammarDataAsync({
|
|
690
|
+
isLocalLLM: (_options$useLocalMode3 = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode3 !== void 0 ? _options$useLocalMode3 : false,
|
|
691
|
+
surface
|
|
692
|
+
}).catch(error => {
|
|
693
|
+
logException(error, {
|
|
694
|
+
location: 'editor-plugin-autocomplete/loadGrammarDataAsync'
|
|
695
|
+
});
|
|
696
|
+
});
|
|
689
697
|
if (!hasIngestedPage) {
|
|
690
698
|
hasIngestedPage = true;
|
|
691
699
|
refreshContext({
|
|
@@ -37,6 +37,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
import { abortExp, EXPERIENCE_NAME, failExp, startExp, succeedExp } from '../analytics/ufo';
|
|
40
|
+
import { ARTIFACT_NAME, fetchArtifactJson } from './artifacts-manifest';
|
|
40
41
|
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
41
42
|
import { isWordBoundary } from './slow-lane-client';
|
|
42
43
|
|
|
@@ -225,77 +226,9 @@ let prefixMapTokenIds = [];
|
|
|
225
226
|
let bePayloadDataPromise;
|
|
226
227
|
|
|
227
228
|
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* 1. **`.default`-wrapped namespace** — classic webpack (and Jest) hang the
|
|
232
|
-
* JSON value under the `default` export.
|
|
233
|
-
* 2. **Named-exports namespace** — webpack 5 / atlaspack with JSON
|
|
234
|
-
* named-exports (or native ESM JSON modules) expose each top-level key as
|
|
235
|
-
* a named export and shadow `default`, so `mod.default` can be `undefined`
|
|
236
|
-
* (or some unrelated value) even though `mod` itself holds the data.
|
|
237
|
-
*
|
|
238
|
-
* The caller MUST declare the underlying JSON shape via `shape` because, in
|
|
239
|
-
* named-exports mode, a dense array `["a","b"]` and a sparse numeric-keyed
|
|
240
|
-
* object `{"5":"a","12":"b"}` are emitted identically (`{"0":..}` / `{"5":..}`);
|
|
241
|
-
* no runtime heuristic can tell them apart, so only the caller knows which:
|
|
242
|
-
*
|
|
243
|
-
* - `'object'` — the JSON is a `{...}` (including sparse maps keyed by integer
|
|
244
|
-
* IDs). The named exports are rebuilt into a plain object so `Object.entries`
|
|
245
|
-
* yields the real keys, not synthetic array indices.
|
|
246
|
-
* - `'array'` — the JSON is a `[...]`, reconstructed from the `0..n-1` indices.
|
|
247
|
-
*
|
|
248
|
-
* :param mod: The raw module object returned by `await import('./*.json')`.
|
|
249
|
-
* :param shape: `'object'` if the source JSON is `{...}`, `'array'` if `[...]`.
|
|
250
|
-
* :returns: The parsed JSON value, or `null` if neither interop mode applies.
|
|
251
|
-
*/
|
|
252
|
-
function unwrapJsonModule(mod, shape) {
|
|
253
|
-
if (mod == null || typeof mod !== 'object') {
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
const namespace = mod;
|
|
257
|
-
|
|
258
|
-
// Compute the named-export own-keys (strip synthetic markers).
|
|
259
|
-
const ownKeys = Object.keys(namespace).filter(k => k !== 'default' && k !== '__esModule');
|
|
260
|
-
|
|
261
|
-
// PREFER named exports when present — they always reflect the JSON's real
|
|
262
|
-
// top-level keys / indices, regardless of what `default` happens to be.
|
|
263
|
-
// Under JSON named-exports mode `default` is not necessarily the parsed
|
|
264
|
-
// value (e.g. for `{"service": 0, ...}` it can be the number `0`, with the
|
|
265
|
-
// real data in the named exports), so taking `default` first would corrupt it.
|
|
266
|
-
if (ownKeys.length > 0) {
|
|
267
|
-
if (shape === 'array') {
|
|
268
|
-
// JSON arrays are dense; reconstruct from `0..length-1` indices.
|
|
269
|
-
const len = ownKeys.length;
|
|
270
|
-
const arr = new Array(len);
|
|
271
|
-
for (let i = 0; i < len; i++) {
|
|
272
|
-
arr[i] = namespace[String(i)];
|
|
273
|
-
}
|
|
274
|
-
return arr;
|
|
275
|
-
}
|
|
276
|
-
// shape === 'object'. Rebuild a plain object from the (stripped) own
|
|
277
|
-
// keys so callers can `Object.entries()` it without iterating over
|
|
278
|
-
// `default` / `__esModule`, and to detach from the module-namespace
|
|
279
|
-
// object (which is sealed/non-extensible on some bundler outputs).
|
|
280
|
-
const obj = {};
|
|
281
|
-
for (const k of ownKeys) {
|
|
282
|
-
obj[k] = namespace[k];
|
|
283
|
-
}
|
|
284
|
-
return obj;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Fallback: no named exports — classic webpack JSON-module interop where
|
|
288
|
-
// the whole parsed JSON value is hung under `default`. Trust it.
|
|
289
|
-
if ('default' in namespace && namespace.default != null) {
|
|
290
|
-
return namespace.default;
|
|
291
|
-
}
|
|
292
|
-
return null;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Lazily load and build the BE-parity lookup tables from their JSON payloads.
|
|
297
|
-
* The dynamic imports are split into their own async chunks so neither file is
|
|
298
|
-
* bundled into the editor's main chunk unless local inference is initialised.
|
|
229
|
+
* Lazily load and build the BE-parity lookup tables from their CDN payloads.
|
|
230
|
+
* Both artifacts are fetched on demand so neither is downloaded unless local
|
|
231
|
+
* inference is initialised.
|
|
299
232
|
*
|
|
300
233
|
* :returns:
|
|
301
234
|
* A promise that resolves once `firstTokenToWords`, `l2Words` and
|
|
@@ -304,15 +237,12 @@ function unwrapJsonModule(mod, shape) {
|
|
|
304
237
|
const loadBePayloadData = () => {
|
|
305
238
|
if (!bePayloadDataPromise) {
|
|
306
239
|
bePayloadDataPromise = (async () => {
|
|
307
|
-
const [
|
|
308
|
-
const firstTokenToWordsData = unwrapJsonModule(firstTokenToWordsModule, 'object');
|
|
309
|
-
const vocabularyData = unwrapJsonModule(vocabularyModule, 'object');
|
|
240
|
+
const [firstTokenToWordsData, vocabularyData] = await Promise.all([fetchArtifactJson(ARTIFACT_NAME.FIRST_TOKEN_TO_WORDS), fetchArtifactJson(ARTIFACT_NAME.VOCABULARY)]);
|
|
310
241
|
if (firstTokenToWordsData == null || (vocabularyData === null || vocabularyData === void 0 ? void 0 : vocabularyData.words) == null) {
|
|
311
242
|
// Hard-fail with a precise message so the catch() in initEngine logs
|
|
312
|
-
// exactly which
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
throw new Error(`[LocalSlowLane] JSON module could not be unwrapped — ` + `firstTokenToWordsData=${firstTokenToWordsData == null ? 'null/undefined' : 'defined'}, ` + `vocabularyData=${vocabularyData == null ? 'null/undefined' : vocabularyData.words == null ? 'defined but missing .words' : 'defined'}`);
|
|
243
|
+
// exactly which payload was malformed, rather than the generic V8
|
|
244
|
+
// "Cannot convert undefined or null to object".
|
|
245
|
+
throw new Error(`[LocalSlowLane] unexpected artifact payload — ` + `firstTokenToWordsData=${firstTokenToWordsData == null ? 'null/undefined' : 'defined'}, ` + `vocabularyData=${vocabularyData == null ? 'null/undefined' : vocabularyData.words == null ? 'defined but missing .words' : 'defined'}`);
|
|
316
246
|
}
|
|
317
247
|
firstTokenToWords = new Map(Object.entries(firstTokenToWordsData).map(([tokenId, words]) => [Number(tokenId), words]));
|
|
318
248
|
l2Words = new Set(Object.keys(vocabularyData.words));
|