@atlaskit/editor-plugin-autocomplete 2.5.2 → 3.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/CANONICAL_FIX__DO_NOT_USE_ME_A/package.json +15 -0
- package/CANONICAL_FIX__DO_NOT_USE_ME_B/package.json +15 -0
- package/CANONICAL_FIX__DO_NOT_USE_ME_C/package.json +15 -0
- package/CHANGELOG.md +14 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +6 -22
- package/dist/cjs/pm-plugins/local-slow-lane-client.js +36 -36
- package/dist/cjs/pm-plugins/scoring-pipeline.js +5 -4
- package/dist/cjs/pm-plugins/slow-lane-client.js +20 -20
- package/dist/cjs/pm-plugins/text-predictor.js +175 -83
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +6 -22
- package/dist/es2019/pm-plugins/scoring-pipeline.js +5 -4
- package/dist/es2019/pm-plugins/text-predictor.js +105 -50
- package/dist/esm/pm-plugins/autocomplete-plugin.js +6 -22
- package/dist/esm/pm-plugins/local-slow-lane-client.js +35 -35
- package/dist/esm/pm-plugins/scoring-pipeline.js +5 -4
- package/dist/esm/pm-plugins/slow-lane-client.js +20 -20
- package/dist/esm/pm-plugins/text-predictor.js +167 -83
- package/dist/types/pm-plugins/text-predictor.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/text-predictor.d.ts +1 -1
- package/package.json +3 -3
- package/src/pm-plugins/autocomplete-plugin.ts +6 -16
- package/src/pm-plugins/data/word_index_10k.json +7761 -7759
- package/src/pm-plugins/scoring-pipeline.ts +4 -5
- package/src/pm-plugins/text-predictor.ts +124 -45
|
@@ -18,11 +18,9 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
18
18
|
|
|
19
19
|
import { EXPERIENCE_NAME, failExp, startExp, succeedExp } from '../analytics/ufo';
|
|
20
20
|
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
import wordIndexData from './data/word_index_10k.json';
|
|
25
|
-
// import { rankCandidates, isGrammarAllowed } from './scoring-pipeline';
|
|
21
|
+
// The vocabulary, L3 and word-index JSON payloads are dynamically imported in
|
|
22
|
+
// loadDefaultVocabulary / loadVectorsAsync so their (large) contents stay out of
|
|
23
|
+
// the editor's main chunk and only load when autocomplete is initialised.
|
|
26
24
|
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
27
25
|
import { rankCandidates, STAGE1_WEIGHT, STAGE2_WEIGHT, MIN_STAGE1_SCORE } from './scoring-pipeline';
|
|
28
26
|
import { getStoredContextVector, getStoredLmLogits } from './slow-lane-client';
|
|
@@ -34,7 +32,7 @@ const PUNCTUATION_BOUNDARY_REGEX = /^[.,;:!?()\[\]{}"'`]+|[.,;:!?()\[\]{}"'`]+$/
|
|
|
34
32
|
const MIN_PREFIX_LENGTH = 3;
|
|
35
33
|
const MAX_CANDIDATES = 200;
|
|
36
34
|
const CONTEXT_WORDS = 10;
|
|
37
|
-
const MIN_SCORE_THRESHOLD = 0.
|
|
35
|
+
const MIN_SCORE_THRESHOLD = 0.35;
|
|
38
36
|
const L3_BASELINE_FREQ = 0.001;
|
|
39
37
|
|
|
40
38
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
@@ -153,7 +151,6 @@ const wordTrie = new WeightedWordTrie();
|
|
|
153
151
|
// L3 Trie (General English Fallback)
|
|
154
152
|
const l3Trie = new WeightedWordTrie();
|
|
155
153
|
|
|
156
|
-
// --- Initialization Function ---
|
|
157
154
|
/**
|
|
158
155
|
* Loads the General English vocabulary.
|
|
159
156
|
* expects a simple array of strings: ["about", "above", "actually", ...]
|
|
@@ -249,14 +246,11 @@ const tokenize = text => {
|
|
|
249
246
|
return tokens;
|
|
250
247
|
};
|
|
251
248
|
const extractPreviousWord = text => {
|
|
252
|
-
//
|
|
249
|
+
// Only consider the current sentence/line the user is typing in.
|
|
253
250
|
// eslint-disable-next-line require-unicode-regexp
|
|
254
251
|
const sentences = text.split(/[\n.?!]+/);
|
|
255
|
-
|
|
256
|
-
// 2. Only look at the current sentence/line the user is typing in
|
|
257
252
|
const currentSentence = sentences[sentences.length - 1];
|
|
258
253
|
|
|
259
|
-
// 3. Extract the previous word as normal
|
|
260
254
|
// eslint-disable-next-line require-unicode-regexp
|
|
261
255
|
const words = currentSentence.trimEnd().split(/\s+/);
|
|
262
256
|
return words.length >= 2 ? words[words.length - 2] : '';
|
|
@@ -310,7 +304,6 @@ export const incrementSessionFreq = word => {
|
|
|
310
304
|
* Pass `undefined` (or omit the argument) to skip priming — useful when the
|
|
311
305
|
* calling context does not yet have a page value available.
|
|
312
306
|
*/
|
|
313
|
-
// NOTE: We ingest full page context here
|
|
314
307
|
export const ingestDocumentPage = pageContent => {
|
|
315
308
|
if (!pageContent) {
|
|
316
309
|
return;
|
|
@@ -334,7 +327,11 @@ export const ingestDocumentPage = pageContent => {
|
|
|
334
327
|
};
|
|
335
328
|
export const predict = textBefore => {
|
|
336
329
|
if (!isInitialized) {
|
|
337
|
-
|
|
330
|
+
// Vocabulary JSON is code-split and loads asynchronously. Kick off the load
|
|
331
|
+
// and skip this keystroke; the plugin also primes it on focus, so the tries
|
|
332
|
+
// are usually ready before the user types.
|
|
333
|
+
void loadDefaultVocabulary().catch(() => {});
|
|
334
|
+
return null;
|
|
338
335
|
}
|
|
339
336
|
const t0 = performance.now();
|
|
340
337
|
|
|
@@ -386,19 +383,15 @@ export const predict = textBefore => {
|
|
|
386
383
|
if (currentWord.length < MIN_PREFIX_LENGTH) {
|
|
387
384
|
return null;
|
|
388
385
|
}
|
|
389
|
-
|
|
390
|
-
// 1. Primary Query: Ask the L2 Domain Trie
|
|
391
386
|
const candidates = wordTrie.getCandidates(currentWord, MAX_CANDIDATES);
|
|
392
387
|
|
|
393
|
-
//
|
|
388
|
+
// Gap-fill from the L3 general-English trie, requesting a full buffer so
|
|
389
|
+
// enough survive de-duplication against the L2 results.
|
|
394
390
|
if (candidates.length < MAX_CANDIDATES) {
|
|
395
|
-
// Ask L3 for MAX_CANDIDATES to guarantee we have enough buffer
|
|
396
|
-
// to survive the deduplication process.
|
|
397
391
|
const l3Candidates = l3Trie.getCandidates(currentWord, MAX_CANDIDATES);
|
|
398
392
|
const existingWords = new Set(candidates.map(c => c.word));
|
|
399
393
|
for (const l3c of l3Candidates) {
|
|
400
|
-
if (candidates.length >= MAX_CANDIDATES) break;
|
|
401
|
-
|
|
394
|
+
if (candidates.length >= MAX_CANDIDATES) break;
|
|
402
395
|
if (!existingWords.has(l3c.word)) {
|
|
403
396
|
candidates.push(l3c);
|
|
404
397
|
}
|
|
@@ -558,6 +551,41 @@ export const predict = textBefore => {
|
|
|
558
551
|
|
|
559
552
|
// ─── Data Loading ────────────────────────────────────────────────────────────
|
|
560
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Unwrap a dynamically imported JSON module to its parsed value, handling both
|
|
556
|
+
* interop modes AFM's bundler chain emits: a `.default`-wrapped namespace
|
|
557
|
+
* (classic webpack) and a named-exports namespace (webpack 5 / atlaspack JSON
|
|
558
|
+
* modules, where `default` can be a misleading scalar). Named exports are
|
|
559
|
+
* preferred when present. The caller declares the JSON `shape` because a dense
|
|
560
|
+
* array and a sparse numeric-keyed object are emitted identically as named
|
|
561
|
+
* exports. Kept in lock-step with the matching helper in local-slow-lane-client.ts.
|
|
562
|
+
*/
|
|
563
|
+
const unwrapJsonModule = (mod, shape) => {
|
|
564
|
+
if (mod == null || typeof mod !== 'object') {
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
const namespace = mod;
|
|
568
|
+
const ownKeys = Object.keys(namespace).filter(k => k !== 'default' && k !== '__esModule');
|
|
569
|
+
if (ownKeys.length > 0) {
|
|
570
|
+
if (shape === 'array') {
|
|
571
|
+
const len = ownKeys.length;
|
|
572
|
+
const arr = new Array(len);
|
|
573
|
+
for (let i = 0; i < len; i++) {
|
|
574
|
+
arr[i] = namespace[String(i)];
|
|
575
|
+
}
|
|
576
|
+
return arr;
|
|
577
|
+
}
|
|
578
|
+
const obj = {};
|
|
579
|
+
for (const k of ownKeys) {
|
|
580
|
+
obj[k] = namespace[k];
|
|
581
|
+
}
|
|
582
|
+
return obj;
|
|
583
|
+
}
|
|
584
|
+
if ('default' in namespace && namespace.default != null) {
|
|
585
|
+
return namespace.default;
|
|
586
|
+
}
|
|
587
|
+
return null;
|
|
588
|
+
};
|
|
561
589
|
export const loadVectorsAsync = async options => {
|
|
562
590
|
if (vectorStore || vectorsLoadStarted) {
|
|
563
591
|
return;
|
|
@@ -582,6 +610,7 @@ export const loadVectorsAsync = async options => {
|
|
|
582
610
|
return;
|
|
583
611
|
}
|
|
584
612
|
try {
|
|
613
|
+
var _wordIndexOuter$index;
|
|
585
614
|
const res = await fetch(url);
|
|
586
615
|
if (!res.ok) {
|
|
587
616
|
vectorsLoadStarted = false;
|
|
@@ -595,8 +624,18 @@ export const loadVectorsAsync = async options => {
|
|
|
595
624
|
}
|
|
596
625
|
const buffer = await res.arrayBuffer();
|
|
597
626
|
const float32 = new Float32Array(buffer);
|
|
598
|
-
|
|
627
|
+
|
|
628
|
+
// word_index_10k.json is wrapped as `{ "index": {…} }` so no real entry
|
|
629
|
+
// (e.g. the word "default") can shadow the synthetic ESM `default` export
|
|
630
|
+
// the bundler creates for dynamically-imported JSON.
|
|
631
|
+
const wordIndexModule = await import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-word-index-10k" */'./data/word_index_10k.json');
|
|
632
|
+
const wordIndexOuter = unwrapJsonModule(wordIndexModule, 'object');
|
|
633
|
+
const wordIndex = (_wordIndexOuter$index = wordIndexOuter === null || wordIndexOuter === void 0 ? void 0 : wordIndexOuter.index) !== null && _wordIndexOuter$index !== void 0 ? _wordIndexOuter$index : {};
|
|
599
634
|
const nWords = Object.keys(wordIndex).length;
|
|
635
|
+
if (nWords === 0) {
|
|
636
|
+
// eslint-disable-next-line no-console
|
|
637
|
+
console.warn('[text-predictor] word_index_10k.json missing its `index` wrapper — wordIndex is empty, semantic scoring will be a no-op.');
|
|
638
|
+
}
|
|
600
639
|
const dim = float32.length / nWords;
|
|
601
640
|
vectorStore = {
|
|
602
641
|
float32,
|
|
@@ -628,35 +667,51 @@ export const loadVectorsAsync = async options => {
|
|
|
628
667
|
export const initVectors = store => {
|
|
629
668
|
vectorStore = store;
|
|
630
669
|
};
|
|
670
|
+
let vocabularyLoadPromise;
|
|
631
671
|
export const loadDefaultVocabulary = () => {
|
|
632
672
|
if (isInitialized) {
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
673
|
+
return Promise.resolve();
|
|
674
|
+
}
|
|
675
|
+
if (vocabularyLoadPromise) {
|
|
676
|
+
return vocabularyLoadPromise;
|
|
677
|
+
}
|
|
678
|
+
vocabularyLoadPromise = (async () => {
|
|
679
|
+
startExp(EXPERIENCE_NAME.LOAD_VOCABULARY, 'singleton');
|
|
680
|
+
try {
|
|
681
|
+
// The L2 vocabulary and L3 word list are code-split into their own async
|
|
682
|
+
// chunks so they stay out of the editor's main bundle.
|
|
683
|
+
const [vocabularyModule, l3VocabularyModule] = await Promise.all([import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-vocabulary-10k" */'./data/vocabulary_10k.json'), import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-l3-vocabulary" */'./data/l3_vocabulary.json')]);
|
|
684
|
+
const vocabularyData = unwrapJsonModule(vocabularyModule, 'object');
|
|
685
|
+
const l3VocabularyData = unwrapJsonModule(l3VocabularyModule, 'array');
|
|
686
|
+
if ((vocabularyData === null || vocabularyData === void 0 ? void 0 : vocabularyData.words) == null || !Array.isArray(l3VocabularyData)) {
|
|
687
|
+
throw new Error('[text-predictor] vocabulary JSON modules could not be unwrapped');
|
|
688
|
+
}
|
|
689
|
+
const terms = Object.entries(vocabularyData.words).map(([word, stats]) => ({
|
|
690
|
+
word,
|
|
691
|
+
freq: stats.freq,
|
|
692
|
+
docFreq: stats.doc_freq,
|
|
693
|
+
authorFreq: stats.author_freq
|
|
694
|
+
}));
|
|
695
|
+
|
|
696
|
+
// Load L3 before L2: initVocabulary flips `isInitialized = true`, so it
|
|
697
|
+
// must run last — otherwise a throw in initL3Vocabulary would strand
|
|
698
|
+
// `isInitialized` true and the retry path could never reload L3.
|
|
699
|
+
initL3Vocabulary(l3VocabularyData);
|
|
700
|
+
initVocabulary({
|
|
701
|
+
terms
|
|
702
|
+
});
|
|
703
|
+
succeedExp(EXPERIENCE_NAME.LOAD_VOCABULARY, 'singleton', {
|
|
704
|
+
l2WordCount: terms.length,
|
|
705
|
+
l3WordCount: l3VocabularyData.length
|
|
706
|
+
});
|
|
707
|
+
} catch (e) {
|
|
708
|
+
failExp(EXPERIENCE_NAME.LOAD_VOCABULARY, 'singleton', {
|
|
709
|
+
errorType: 'parse_error'
|
|
710
|
+
});
|
|
711
|
+
// Allow a later call to retry the load rather than caching the failure.
|
|
712
|
+
vocabularyLoadPromise = undefined;
|
|
713
|
+
throw e;
|
|
714
|
+
}
|
|
715
|
+
})();
|
|
716
|
+
return vocabularyLoadPromise;
|
|
662
717
|
};
|
|
@@ -31,8 +31,6 @@ var createInitialState = function createInitialState() {
|
|
|
31
31
|
var getTextBeforeCursor = function getTextBeforeCursor(state) {
|
|
32
32
|
var $from = state.selection.$from;
|
|
33
33
|
var maxChars = 200;
|
|
34
|
-
|
|
35
|
-
// 1. Get the perfectly flattened text of the current block up to the cursor
|
|
36
34
|
var blockNode = $from.parent;
|
|
37
35
|
var offsetInBlock = $from.parentOffset;
|
|
38
36
|
var blockText = blockNode.textContent.slice(0, offsetInBlock);
|
|
@@ -41,7 +39,7 @@ var getTextBeforeCursor = function getTextBeforeCursor(state) {
|
|
|
41
39
|
}
|
|
42
40
|
var fullText = blockText;
|
|
43
41
|
|
|
44
|
-
//
|
|
42
|
+
// Walk backwards through previous blocks until we have enough context.
|
|
45
43
|
var depth = $from.depth - 1;
|
|
46
44
|
while (fullText.length < maxChars && depth >= 0) {
|
|
47
45
|
var parentNode = $from.node(depth);
|
|
@@ -242,8 +240,6 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
242
240
|
try {
|
|
243
241
|
var state = view.state;
|
|
244
242
|
var selection = state.selection;
|
|
245
|
-
|
|
246
|
-
// Only predict for cursor selections (not range selections)
|
|
247
243
|
if (!selection.empty) {
|
|
248
244
|
return;
|
|
249
245
|
}
|
|
@@ -255,13 +251,9 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
255
251
|
return;
|
|
256
252
|
}
|
|
257
253
|
dismissedContext = null;
|
|
258
|
-
|
|
259
|
-
// Don't predict if there's not enough context
|
|
260
254
|
if (textBefore.trim().length < 3) {
|
|
261
255
|
return;
|
|
262
256
|
}
|
|
263
|
-
|
|
264
|
-
// Tier 1 prediction is synchronous -- no async needed
|
|
265
257
|
var prediction = predict(textBefore);
|
|
266
258
|
if (prediction && prediction.length > 0) {
|
|
267
259
|
var typedLength = getTypedLengthForPrediction(textBefore);
|
|
@@ -323,8 +315,7 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
323
315
|
return _objectSpread(_objectSpread({}, pluginState), meta);
|
|
324
316
|
}
|
|
325
317
|
|
|
326
|
-
//
|
|
327
|
-
// (new prediction will be scheduled from view.update)
|
|
318
|
+
// A new prediction is scheduled from view.update.
|
|
328
319
|
if (tr.docChanged) {
|
|
329
320
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
330
321
|
ghostText: '',
|
|
@@ -332,8 +323,6 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
332
323
|
decorationSet: DecorationSet.empty
|
|
333
324
|
});
|
|
334
325
|
}
|
|
335
|
-
|
|
336
|
-
// If selection changed without doc change, clear ghost text
|
|
337
326
|
if (tr.selectionSet && pluginState.ghostText) {
|
|
338
327
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
339
328
|
ghostText: '',
|
|
@@ -394,13 +383,11 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
394
383
|
return false;
|
|
395
384
|
},
|
|
396
385
|
focus: function focus() {
|
|
397
|
-
|
|
398
|
-
loadDefaultVocabulary();
|
|
399
|
-
} catch (error) {
|
|
386
|
+
loadDefaultVocabulary().catch(function (error) {
|
|
400
387
|
logException(error, {
|
|
401
388
|
location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
|
|
402
389
|
});
|
|
403
|
-
}
|
|
390
|
+
});
|
|
404
391
|
loadVectorsAsync({
|
|
405
392
|
getBinaryUrl: options === null || options === void 0 ? void 0 : options.getVectorsBinaryUrl
|
|
406
393
|
}).catch(function (error) {
|
|
@@ -442,12 +429,9 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
442
429
|
if (justAccepted) {
|
|
443
430
|
justAccepted = false;
|
|
444
431
|
|
|
445
|
-
//
|
|
446
|
-
//
|
|
447
|
-
// block and abort until the user actually types a new character!
|
|
432
|
+
// Snapshot the post-acceptance text so follow-up transactions hit
|
|
433
|
+
// the dismissedContext guard and abort until the user types again.
|
|
448
434
|
dismissedContext = getTextBeforeCursor(view.state);
|
|
449
|
-
|
|
450
|
-
// Also clear any pending debounce timers from before the acceptance
|
|
451
435
|
if (debounceTimer) {
|
|
452
436
|
clearTimeout(debounceTimer);
|
|
453
437
|
}
|
|
@@ -121,8 +121,8 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
121
121
|
};
|
|
122
122
|
var initEngine = /*#__PURE__*/function () {
|
|
123
123
|
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
124
|
-
var _yield$import, CreateMLCEngine, prebuiltAppConfig, customModelRecord, appConfig, errorMsg;
|
|
125
|
-
return _regeneratorRuntime.wrap(function
|
|
124
|
+
var _yield$import, CreateMLCEngine, prebuiltAppConfig, customModelRecord, appConfig, errorMsg, _t;
|
|
125
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
126
126
|
while (1) switch (_context.prev = _context.next) {
|
|
127
127
|
case 0:
|
|
128
128
|
_context.prev = 0;
|
|
@@ -132,14 +132,14 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
132
132
|
}
|
|
133
133
|
onStatus === null || onStatus === void 0 || onStatus("Initialising model: ".concat(modelId, "\u2026"));
|
|
134
134
|
if ('gpu' in navigator) {
|
|
135
|
-
_context.next =
|
|
135
|
+
_context.next = 1;
|
|
136
136
|
break;
|
|
137
137
|
}
|
|
138
138
|
throw new Error('WebGPU not supported');
|
|
139
|
-
case
|
|
140
|
-
_context.next =
|
|
139
|
+
case 1:
|
|
140
|
+
_context.next = 2;
|
|
141
141
|
return import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-mlc-web-llm" */'@mlc-ai/web-llm');
|
|
142
|
-
case
|
|
142
|
+
case 2:
|
|
143
143
|
_yield$import = _context.sent;
|
|
144
144
|
CreateMLCEngine = _yield$import.CreateMLCEngine;
|
|
145
145
|
prebuiltAppConfig = _yield$import.prebuiltAppConfig;
|
|
@@ -159,34 +159,34 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
159
159
|
appConfig = {
|
|
160
160
|
model_list: [].concat(_toConsumableArray(prebuiltAppConfig.model_list), _toConsumableArray(customModelRecord ? [customModelRecord] : []))
|
|
161
161
|
};
|
|
162
|
-
_context.next =
|
|
162
|
+
_context.next = 3;
|
|
163
163
|
return CreateMLCEngine(modelId, {
|
|
164
164
|
appConfig: appConfig,
|
|
165
165
|
initProgressCallback: initProgressCallback
|
|
166
166
|
});
|
|
167
|
-
case
|
|
167
|
+
case 3:
|
|
168
168
|
engine = _context.sent;
|
|
169
169
|
if (!destroyed) {
|
|
170
|
-
_context.next =
|
|
170
|
+
_context.next = 4;
|
|
171
171
|
break;
|
|
172
172
|
}
|
|
173
173
|
// destroy() was called while we were loading — clean up
|
|
174
174
|
unloadEngine(engine);
|
|
175
175
|
engine = null;
|
|
176
176
|
return _context.abrupt("return");
|
|
177
|
-
case
|
|
177
|
+
case 4:
|
|
178
178
|
ready = true;
|
|
179
179
|
if (isAutocompleteDebugEnabled()) {
|
|
180
180
|
// eslint-disable-next-line no-console
|
|
181
181
|
console.log('%c[LocalSlowLane] %c✅ MLC engine loaded and ready', 'color: #9c27b0; font-weight: bold;', 'color: #4caf50;');
|
|
182
182
|
}
|
|
183
183
|
onStatus === null || onStatus === void 0 || onStatus('Model loaded and ready.');
|
|
184
|
-
_context.next =
|
|
184
|
+
_context.next = 6;
|
|
185
185
|
break;
|
|
186
|
-
case
|
|
187
|
-
_context.prev =
|
|
188
|
-
|
|
189
|
-
errorMsg =
|
|
186
|
+
case 5:
|
|
187
|
+
_context.prev = 5;
|
|
188
|
+
_t = _context["catch"](0);
|
|
189
|
+
errorMsg = _t instanceof Error ? _t.message : String(_t);
|
|
190
190
|
ready = false;
|
|
191
191
|
if (isAutocompleteDebugEnabled()) {
|
|
192
192
|
// eslint-disable-next-line no-console
|
|
@@ -195,11 +195,11 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
195
195
|
onStatus === null || onStatus === void 0 || onStatus("Engine initialisation failed: ".concat(errorMsg));
|
|
196
196
|
engineInitPromise = null;
|
|
197
197
|
initFailed = true;
|
|
198
|
-
case
|
|
198
|
+
case 6:
|
|
199
199
|
case "end":
|
|
200
200
|
return _context.stop();
|
|
201
201
|
}
|
|
202
|
-
}, _callee, null, [[0,
|
|
202
|
+
}, _callee, null, [[0, 5]]);
|
|
203
203
|
}));
|
|
204
204
|
return function initEngine() {
|
|
205
205
|
return _ref.apply(this, arguments);
|
|
@@ -226,18 +226,18 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
226
226
|
*/
|
|
227
227
|
var runInference = /*#__PURE__*/function () {
|
|
228
228
|
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(text, requestId) {
|
|
229
|
-
var _response$choices, response, lmLogits, logprobsContent, tokenLogprobs, token, _iterator, _step, alt, _token, logitValues, topTokens, errorMsg;
|
|
230
|
-
return _regeneratorRuntime.wrap(function
|
|
229
|
+
var _response$choices, response, lmLogits, logprobsContent, tokenLogprobs, token, _iterator, _step, alt, _token, logitValues, topTokens, errorMsg, _t2;
|
|
230
|
+
return _regeneratorRuntime.wrap(function (_context2) {
|
|
231
231
|
while (1) switch (_context2.prev = _context2.next) {
|
|
232
232
|
case 0:
|
|
233
233
|
if (!(!engine || destroyed)) {
|
|
234
|
-
_context2.next =
|
|
234
|
+
_context2.next = 1;
|
|
235
235
|
break;
|
|
236
236
|
}
|
|
237
237
|
return _context2.abrupt("return");
|
|
238
|
-
case
|
|
239
|
-
_context2.prev =
|
|
240
|
-
_context2.next =
|
|
238
|
+
case 1:
|
|
239
|
+
_context2.prev = 1;
|
|
240
|
+
_context2.next = 2;
|
|
241
241
|
return engine.chat.completions.create({
|
|
242
242
|
messages: [{
|
|
243
243
|
role: 'user',
|
|
@@ -248,14 +248,14 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
248
248
|
top_logprobs: 5,
|
|
249
249
|
temperature: 0
|
|
250
250
|
});
|
|
251
|
-
case
|
|
251
|
+
case 2:
|
|
252
252
|
response = _context2.sent;
|
|
253
253
|
if (!(requestId < latestRequestId || destroyed)) {
|
|
254
|
-
_context2.next =
|
|
254
|
+
_context2.next = 3;
|
|
255
255
|
break;
|
|
256
256
|
}
|
|
257
257
|
return _context2.abrupt("return");
|
|
258
|
-
case
|
|
258
|
+
case 3:
|
|
259
259
|
// ── Extract LM logits ───────────────────────────────────────
|
|
260
260
|
lmLogits = {};
|
|
261
261
|
logprobsContent = (_response$choices = response.choices) === null || _response$choices === void 0 || (_response$choices = _response$choices[0]) === null || _response$choices === void 0 || (_response$choices = _response$choices.logprobs) === null || _response$choices === void 0 ? void 0 : _response$choices.content;
|
|
@@ -333,17 +333,17 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
333
333
|
hasVector: storedContextVector !== null,
|
|
334
334
|
hasLmLogits: storedLmLogits !== null
|
|
335
335
|
});
|
|
336
|
-
_context2.next =
|
|
336
|
+
_context2.next = 6;
|
|
337
337
|
break;
|
|
338
|
-
case
|
|
339
|
-
_context2.prev =
|
|
340
|
-
|
|
338
|
+
case 4:
|
|
339
|
+
_context2.prev = 4;
|
|
340
|
+
_t2 = _context2["catch"](1);
|
|
341
341
|
if (!(requestId < latestRequestId)) {
|
|
342
|
-
_context2.next =
|
|
342
|
+
_context2.next = 5;
|
|
343
343
|
break;
|
|
344
344
|
}
|
|
345
345
|
return _context2.abrupt("return");
|
|
346
|
-
case
|
|
346
|
+
case 5:
|
|
347
347
|
storedContextVector = null;
|
|
348
348
|
storedLmLogits = null;
|
|
349
349
|
onUpdate === null || onUpdate === void 0 || onUpdate({
|
|
@@ -351,16 +351,16 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
351
351
|
hasVector: false,
|
|
352
352
|
hasLmLogits: false
|
|
353
353
|
});
|
|
354
|
-
errorMsg =
|
|
354
|
+
errorMsg = _t2 instanceof Error ? _t2.message : String(_t2);
|
|
355
355
|
if (isAutocompleteDebugEnabled()) {
|
|
356
356
|
// eslint-disable-next-line no-console
|
|
357
357
|
console.log("%c[LocalSlowLane] %c\u274C Inference error (request #".concat(requestId, "): ").concat(errorMsg), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
358
358
|
}
|
|
359
|
-
case
|
|
359
|
+
case 6:
|
|
360
360
|
case "end":
|
|
361
361
|
return _context2.stop();
|
|
362
362
|
}
|
|
363
|
-
}, _callee2, null, [[
|
|
363
|
+
}, _callee2, null, [[1, 4]]);
|
|
364
364
|
}));
|
|
365
365
|
return function runInference(_x, _x2) {
|
|
366
366
|
return _ref2.apply(this, arguments);
|
|
@@ -161,20 +161,21 @@ function applyGrammarFilter(candidates, previousWord) {
|
|
|
161
161
|
dropped.push(entry.candidate.word);
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
+
|
|
165
|
+
// Grammar is authoritative.
|
|
164
166
|
} catch (err) {
|
|
165
167
|
_iterator2.e(err);
|
|
166
168
|
} finally {
|
|
167
169
|
_iterator2.f();
|
|
168
170
|
}
|
|
169
|
-
var finalFiltered = filtered.length > 0 ? filtered : candidates;
|
|
170
171
|
return {
|
|
171
|
-
filtered:
|
|
172
|
+
filtered: filtered,
|
|
172
173
|
grammarMeta: {
|
|
173
174
|
prevWord: lowerPrev,
|
|
174
175
|
prevTags: prevTags,
|
|
175
176
|
before: candidates.length,
|
|
176
|
-
after:
|
|
177
|
-
dropped:
|
|
177
|
+
after: filtered.length,
|
|
178
|
+
dropped: dropped
|
|
178
179
|
}
|
|
179
180
|
};
|
|
180
181
|
}
|
|
@@ -64,16 +64,16 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
64
64
|
var inflightRequestId = null;
|
|
65
65
|
var doUpdateContext = /*#__PURE__*/function () {
|
|
66
66
|
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(text, requestId) {
|
|
67
|
-
var url, payload, res, data;
|
|
68
|
-
return _regeneratorRuntime.wrap(function
|
|
67
|
+
var url, payload, res, data, _t;
|
|
68
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
69
69
|
while (1) switch (_context.prev = _context.next) {
|
|
70
70
|
case 0:
|
|
71
71
|
if (!(!text || text.trim().length === 0)) {
|
|
72
|
-
_context.next =
|
|
72
|
+
_context.next = 1;
|
|
73
73
|
break;
|
|
74
74
|
}
|
|
75
75
|
return _context.abrupt("return");
|
|
76
|
-
case
|
|
76
|
+
case 1:
|
|
77
77
|
// eslint-disable-next-line require-unicode-regexp
|
|
78
78
|
url = "".concat(baseUrl.replace(/\/$/, '')).concat(endpoint);
|
|
79
79
|
payload = {
|
|
@@ -93,17 +93,17 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
93
93
|
// eslint-disable-next-line no-console
|
|
94
94
|
console.groupEnd();
|
|
95
95
|
}
|
|
96
|
-
_context.prev =
|
|
97
|
-
_context.next =
|
|
96
|
+
_context.prev = 2;
|
|
97
|
+
_context.next = 3;
|
|
98
98
|
return fetchFn(url, {
|
|
99
99
|
method: 'POST',
|
|
100
100
|
headers: headers,
|
|
101
101
|
body: JSON.stringify(payload)
|
|
102
102
|
});
|
|
103
|
-
case
|
|
103
|
+
case 3:
|
|
104
104
|
res = _context.sent;
|
|
105
105
|
if (res.ok) {
|
|
106
|
-
_context.next =
|
|
106
|
+
_context.next = 4;
|
|
107
107
|
break;
|
|
108
108
|
}
|
|
109
109
|
storedContextVector = null;
|
|
@@ -117,10 +117,10 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
117
117
|
console.log("%c[SlowLane] %c\u274C Request failed (".concat(res.status, ")"), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
118
118
|
}
|
|
119
119
|
return _context.abrupt("return");
|
|
120
|
-
case
|
|
121
|
-
_context.next =
|
|
120
|
+
case 4:
|
|
121
|
+
_context.next = 5;
|
|
122
122
|
return res.json();
|
|
123
|
-
case
|
|
123
|
+
case 5:
|
|
124
124
|
data = _context.sent;
|
|
125
125
|
if (data.semantic_vector && Array.isArray(data.semantic_vector)) {
|
|
126
126
|
storedContextVector = new Float32Array(data.semantic_vector);
|
|
@@ -153,11 +153,11 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
153
153
|
hasLmLogits: storedLmLogits !== null
|
|
154
154
|
});
|
|
155
155
|
// eslint-disable-next-line no-unused-vars
|
|
156
|
-
_context.next =
|
|
156
|
+
_context.next = 7;
|
|
157
157
|
break;
|
|
158
|
-
case
|
|
159
|
-
_context.prev =
|
|
160
|
-
|
|
158
|
+
case 6:
|
|
159
|
+
_context.prev = 6;
|
|
160
|
+
_t = _context["catch"](2);
|
|
161
161
|
storedContextVector = null;
|
|
162
162
|
storedLmLogits = null;
|
|
163
163
|
failExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
@@ -167,17 +167,17 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
167
167
|
// eslint-disable-next-line no-console
|
|
168
168
|
console.log('%c[SlowLane] %c❌ Network error — context cleared', 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
169
169
|
}
|
|
170
|
-
case
|
|
171
|
-
_context.prev =
|
|
170
|
+
case 7:
|
|
171
|
+
_context.prev = 7;
|
|
172
172
|
if (inflightRequestId === requestId) {
|
|
173
173
|
inflightRequestId = null;
|
|
174
174
|
}
|
|
175
|
-
return _context.finish(
|
|
176
|
-
case
|
|
175
|
+
return _context.finish(7);
|
|
176
|
+
case 8:
|
|
177
177
|
case "end":
|
|
178
178
|
return _context.stop();
|
|
179
179
|
}
|
|
180
|
-
}, _callee, null, [[
|
|
180
|
+
}, _callee, null, [[2, 6, 7, 8]]);
|
|
181
181
|
}));
|
|
182
182
|
return function doUpdateContext(_x, _x2) {
|
|
183
183
|
return _ref.apply(this, arguments);
|