@atlaskit/editor-plugin-autocomplete 9.0.0 → 9.2.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 +133 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +564 -67
- package/dist/cjs/pm-plugins/debug-mode.js +28 -2
- package/dist/cjs/pm-plugins/inline-code-harvester.js +576 -0
- package/dist/cjs/pm-plugins/text-predictor.js +437 -178
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +515 -52
- package/dist/es2019/pm-plugins/debug-mode.js +27 -1
- package/dist/es2019/pm-plugins/inline-code-harvester.js +455 -0
- package/dist/es2019/pm-plugins/text-predictor.js +223 -3
- package/dist/esm/pm-plugins/autocomplete-plugin.js +562 -67
- package/dist/esm/pm-plugins/debug-mode.js +27 -1
- package/dist/esm/pm-plugins/inline-code-harvester.js +572 -0
- package/dist/esm/pm-plugins/text-predictor.js +437 -178
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +37 -0
- package/dist/types/pm-plugins/debug-mode.d.ts +34 -0
- package/dist/types/pm-plugins/inline-code-harvester.d.ts +146 -0
- package/dist/types/pm-plugins/text-predictor.d.ts +105 -3
- package/package.json +2 -2
- package/src/pm-plugins/autocomplete-plugin.ts +589 -48
- package/src/pm-plugins/debug-mode.ts +47 -1
- package/src/pm-plugins/inline-code-harvester.ts +561 -0
- package/src/pm-plugins/text-predictor.ts +274 -5
|
@@ -25,14 +25,17 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
25
25
|
* Falls back to cold mode (freq-only) when vectors not yet loaded.
|
|
26
26
|
*
|
|
27
27
|
* Session personalization (L1): words the user types are incrementally boosted
|
|
28
|
-
* via incrementSessionFreq(), called on word boundaries from the plugin
|
|
28
|
+
* via incrementSessionFreq(), called on word boundaries from the plugin, and
|
|
29
|
+
* words in ingested context text via ingestDocumentPage(). What the session has
|
|
30
|
+
* boosted is visible at any time from the console: `__atlCtcDebug__.session()`,
|
|
31
|
+
* or `__atlCtcDebug__.session('poll')` for one family — see inspectSessionBoosts.
|
|
29
32
|
*/
|
|
30
33
|
|
|
31
34
|
import { EXPERIENCE_NAME, failExp, startExp, succeedExp } from '../analytics/ufo';
|
|
32
35
|
import { fetchAutocompleteArtifactBinary, fetchAutocompleteArtifactJson } from './artifact-loader';
|
|
33
36
|
import { ARTIFACT_NAME } from './artifacts-manifest';
|
|
34
37
|
import { createCanonicalContextPositionCache, deriveCanonicalCandidateContext, deriveWhitespaceBoundaryContext, logSoftmaxAt, logSumExp, selectBoundaryPrimeRequests } from './canonical-lm-scoring';
|
|
35
|
-
import { CTC_STYLES, ctcSection, ctcTag, isAutocompleteDebugEnabled, isAutocompleteDebugVerbose } from './debug-mode';
|
|
38
|
+
import { CTC_STYLES, ctcSection, ctcTag, isAutocompleteDebugEnabled, isAutocompleteDebugVerbose, registerCtcSessionInspector } from './debug-mode';
|
|
36
39
|
import { loadGrammarDataAsync, rankCandidates, STAGE1_WEIGHT, STAGE2_WEIGHT, MIN_STAGE1_SCORE, MIN_WINNER_MARGIN } from './scoring-pipeline';
|
|
37
40
|
import { getBoundaryLmState, getCanonicalSurfaceCount, getCanonicalSurfaceTokenIds, getDefaultSlowLaneClientStatus, getProgressiveSurfaceEvidence, getStoredContextInput, getStoredContextVector, getStoredLmLogits, getSurfaceScore, isCanonicalSurfaceScoringSupported, primeBoundaryLm, requestProgressiveSurfaceScores } from './slow-lane-client';
|
|
38
41
|
|
|
@@ -184,6 +187,18 @@ var DEBUG_TEXT_TAIL_CHARS = 120;
|
|
|
184
187
|
* is vocabulary coverage.
|
|
185
188
|
*/
|
|
186
189
|
|
|
190
|
+
/**
|
|
191
|
+
* What the scored path concluded, recorded on every evaluation whether or not
|
|
192
|
+
* debug is on.
|
|
193
|
+
*
|
|
194
|
+
* This exists for the inline-code harvester, which may only offer a harvested
|
|
195
|
+
* surface once the scored path has finished and come away empty. The reason is
|
|
196
|
+
* the load-bearing part: `no-candidate` means no vocabulary reaches this prefix
|
|
197
|
+
* at all, while `winner-margin` means two known words the model cannot yet
|
|
198
|
+
* separate — the first is a gap worth filling and the second is a prefix
|
|
199
|
+
* ambiguous enough that filling it would be a guess.
|
|
200
|
+
*/
|
|
201
|
+
|
|
187
202
|
/**
|
|
188
203
|
* A candidate paired with the length of the already-typed prefix it completes.
|
|
189
204
|
* For a single word this is the current partial token length; for a phrase it
|
|
@@ -211,6 +226,17 @@ var WeightedWordTrie = /*#__PURE__*/function () {
|
|
|
211
226
|
function WeightedWordTrie() {
|
|
212
227
|
_classCallCheck(this, WeightedWordTrie);
|
|
213
228
|
_defineProperty(this, "root", new TrieNode());
|
|
229
|
+
/**
|
|
230
|
+
* Every node a session boost has been written to.
|
|
231
|
+
*
|
|
232
|
+
* Kept because dropping the boosts is no longer a rare event — it happens
|
|
233
|
+
* each time the reader changes page or conversation — and walking a vocabulary
|
|
234
|
+
* of tens of thousands of words to find the few hundred that were touched
|
|
235
|
+
* costs about 10ms of main thread every time. The two writers below are the
|
|
236
|
+
* only way a `sessionFreq` moves, so keeping this in step costs one Set
|
|
237
|
+
* insertion on a path that is already descending the trie.
|
|
238
|
+
*/
|
|
239
|
+
_defineProperty(this, "boostedNodes", new Set());
|
|
214
240
|
/** Highest tenantFreq seen — used to normalize freq scores at query time */
|
|
215
241
|
_defineProperty(this, "maxTenantFreq", 1);
|
|
216
242
|
}
|
|
@@ -327,6 +353,13 @@ var WeightedWordTrie = /*#__PURE__*/function () {
|
|
|
327
353
|
return node.word !== null ? node : null;
|
|
328
354
|
}
|
|
329
355
|
|
|
356
|
+
/** Whether this exact surface is stored as a terminal word. */
|
|
357
|
+
}, {
|
|
358
|
+
key: "hasWord",
|
|
359
|
+
value: function hasWord(word) {
|
|
360
|
+
return this.findNode(word) !== null;
|
|
361
|
+
}
|
|
362
|
+
|
|
330
363
|
/**
|
|
331
364
|
* Set the session frequency for a word.
|
|
332
365
|
* Returns true if the word exists in the trie.
|
|
@@ -339,6 +372,7 @@ var WeightedWordTrie = /*#__PURE__*/function () {
|
|
|
339
372
|
return false;
|
|
340
373
|
}
|
|
341
374
|
node.sessionFreq = count;
|
|
375
|
+
this.boostedNodes.add(node);
|
|
342
376
|
return true;
|
|
343
377
|
}
|
|
344
378
|
|
|
@@ -354,8 +388,90 @@ var WeightedWordTrie = /*#__PURE__*/function () {
|
|
|
354
388
|
return false;
|
|
355
389
|
}
|
|
356
390
|
node.sessionFreq += 1;
|
|
391
|
+
this.boostedNodes.add(node);
|
|
357
392
|
return true;
|
|
358
393
|
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Zero every session boost, in the number of words boosted rather than the
|
|
397
|
+
* number of words known.
|
|
398
|
+
*/
|
|
399
|
+
}, {
|
|
400
|
+
key: "clearSessionBoosts",
|
|
401
|
+
value: function clearSessionBoosts() {
|
|
402
|
+
var _iterator5 = _createForOfIteratorHelper(this.boostedNodes),
|
|
403
|
+
_step5;
|
|
404
|
+
try {
|
|
405
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
406
|
+
var node = _step5.value;
|
|
407
|
+
node.sessionFreq = 0;
|
|
408
|
+
}
|
|
409
|
+
} catch (err) {
|
|
410
|
+
_iterator5.e(err);
|
|
411
|
+
} finally {
|
|
412
|
+
_iterator5.f();
|
|
413
|
+
}
|
|
414
|
+
this.boostedNodes.clear();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Every word carrying a session boost, optionally limited to one prefix's
|
|
419
|
+
* subtree. Unlike `getCandidates` a word equal to the prefix is included,
|
|
420
|
+
* since the question here is what the session holds rather than what could
|
|
421
|
+
* still be typed.
|
|
422
|
+
*
|
|
423
|
+
* Walks the trie rather than reading `boostedNodes`, since a prefix answer is
|
|
424
|
+
* a subtree question and this only runs when a human asks it.
|
|
425
|
+
*/
|
|
426
|
+
}, {
|
|
427
|
+
key: "collectSessionBoosted",
|
|
428
|
+
value: function collectSessionBoosted() {
|
|
429
|
+
var prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
430
|
+
var node = this.root;
|
|
431
|
+
var _iterator6 = _createForOfIteratorHelper(prefix.toLowerCase()),
|
|
432
|
+
_step6;
|
|
433
|
+
try {
|
|
434
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
435
|
+
var char = _step6.value;
|
|
436
|
+
var next = node.children.get(char);
|
|
437
|
+
if (!next) {
|
|
438
|
+
return [];
|
|
439
|
+
}
|
|
440
|
+
node = next;
|
|
441
|
+
}
|
|
442
|
+
} catch (err) {
|
|
443
|
+
_iterator6.e(err);
|
|
444
|
+
} finally {
|
|
445
|
+
_iterator6.f();
|
|
446
|
+
}
|
|
447
|
+
var boosted = [];
|
|
448
|
+
var stack = [node];
|
|
449
|
+
while (stack.length > 0) {
|
|
450
|
+
var current = stack.pop();
|
|
451
|
+
if (!current) {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
if (current.word !== null && current.sessionFreq > 0) {
|
|
455
|
+
boosted.push({
|
|
456
|
+
word: current.word,
|
|
457
|
+
node: current
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
var _iterator7 = _createForOfIteratorHelper(current.children.values()),
|
|
461
|
+
_step7;
|
|
462
|
+
try {
|
|
463
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
464
|
+
var child = _step7.value;
|
|
465
|
+
stack.push(child);
|
|
466
|
+
}
|
|
467
|
+
} catch (err) {
|
|
468
|
+
_iterator7.e(err);
|
|
469
|
+
} finally {
|
|
470
|
+
_iterator7.f();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return boosted;
|
|
474
|
+
}
|
|
359
475
|
}]);
|
|
360
476
|
}(); // L1/L2 Trie (Session + Atlassian Domain)
|
|
361
477
|
var wordTrie = new WeightedWordTrie();
|
|
@@ -377,19 +493,19 @@ var phraseTrie = new WeightedWordTrie();
|
|
|
377
493
|
* expects a simple array of strings: ["about", "above", "actually", ...]
|
|
378
494
|
*/
|
|
379
495
|
export var initL3Vocabulary = function initL3Vocabulary(l3Words) {
|
|
380
|
-
var
|
|
381
|
-
|
|
496
|
+
var _iterator8 = _createForOfIteratorHelper(l3Words),
|
|
497
|
+
_step8;
|
|
382
498
|
try {
|
|
383
|
-
for (
|
|
384
|
-
var word =
|
|
499
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
500
|
+
var word = _step8.value;
|
|
385
501
|
// Insert with a tiny baseline frequency so it mathematically
|
|
386
502
|
// loses to any domain word in Stage 1, but still scores above 0.
|
|
387
503
|
l3Trie.insert(word, L3_BASELINE_FREQ, 0, 0);
|
|
388
504
|
}
|
|
389
505
|
} catch (err) {
|
|
390
|
-
|
|
506
|
+
_iterator8.e(err);
|
|
391
507
|
} finally {
|
|
392
|
-
|
|
508
|
+
_iterator8.f();
|
|
393
509
|
}
|
|
394
510
|
recallGeneration++;
|
|
395
511
|
ctcTag('init', "L3 general English loaded: ".concat(l3Words.length, " words"));
|
|
@@ -415,6 +531,15 @@ var phraseTermCount = 0;
|
|
|
415
531
|
var maxBigramFreq = 1;
|
|
416
532
|
var maxPhraseFreq = 1;
|
|
417
533
|
var lastPredictionDebug = null;
|
|
534
|
+
var lastPredictionOutcome = null;
|
|
535
|
+
var recordPredictionOutcome = function recordPredictionOutcome(outcome) {
|
|
536
|
+
lastPredictionOutcome = outcome;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
/** The verdict from the most recent `predict` call. Always populated. */
|
|
540
|
+
export var getLastPredictionOutcome = function getLastPredictionOutcome() {
|
|
541
|
+
return lastPredictionOutcome;
|
|
542
|
+
};
|
|
418
543
|
|
|
419
544
|
// ── Stabilization (QI-2): post-accept cooldown + whole-surface repetition ────
|
|
420
545
|
// Two guards that stop the accept→echo (`end to end` → `end to end to end`) and
|
|
@@ -446,6 +571,22 @@ export var noteSuggestionAccepted = function noteSuggestionAccepted(surface) {
|
|
|
446
571
|
}
|
|
447
572
|
};
|
|
448
573
|
|
|
574
|
+
/**
|
|
575
|
+
* Whether `surface` is the one the user just accepted and is still inside its
|
|
576
|
+
* cooldown window.
|
|
577
|
+
*
|
|
578
|
+
* Read-only, unlike the advance inside `predict`: the cooldown is measured in
|
|
579
|
+
* predictions, and a caller asking whether it is active must not consume one of
|
|
580
|
+
* them. Exported for the harvest path, which displays without going through
|
|
581
|
+
* arbitration and so would otherwise re-offer what was just accepted.
|
|
582
|
+
*/
|
|
583
|
+
export var isSurfaceInAcceptCooldown = function isSurfaceInAcceptCooldown(surface) {
|
|
584
|
+
if (!acceptCooldown || acceptCooldown.surface !== surface.trim().toLowerCase()) {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
return acceptCooldown.predictionsSince <= COOLDOWN_KEYSTROKES || performance.now() - acceptCooldown.ts < COOLDOWN_MS;
|
|
588
|
+
};
|
|
589
|
+
|
|
449
590
|
/** Get vector for a word from the store. */
|
|
450
591
|
var getWordVector = function getWordVector(word) {
|
|
451
592
|
if (!vectorStore) {
|
|
@@ -470,20 +611,20 @@ var computeContextVectorLocal = function computeContextVectorLocal(textBefore) {
|
|
|
470
611
|
var tokens = tokenize(textBefore);
|
|
471
612
|
var words = tokens.slice(-CONTEXT_WORDS);
|
|
472
613
|
var vectors = [];
|
|
473
|
-
var
|
|
474
|
-
|
|
614
|
+
var _iterator9 = _createForOfIteratorHelper(words),
|
|
615
|
+
_step9;
|
|
475
616
|
try {
|
|
476
|
-
for (
|
|
477
|
-
var word =
|
|
617
|
+
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
|
|
618
|
+
var word = _step9.value;
|
|
478
619
|
var _v = getWordVector(word);
|
|
479
620
|
if (_v) {
|
|
480
621
|
vectors.push(_v);
|
|
481
622
|
}
|
|
482
623
|
}
|
|
483
624
|
} catch (err) {
|
|
484
|
-
|
|
625
|
+
_iterator9.e(err);
|
|
485
626
|
} finally {
|
|
486
|
-
|
|
627
|
+
_iterator9.f();
|
|
487
628
|
}
|
|
488
629
|
if (vectors.length === 0) {
|
|
489
630
|
return null;
|
|
@@ -516,11 +657,11 @@ var getContextVectorForScoring = function getContextVectorForScoring(textBefore)
|
|
|
516
657
|
var tokenize = function tokenize(text) {
|
|
517
658
|
var tokens = [];
|
|
518
659
|
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
519
|
-
var
|
|
520
|
-
|
|
660
|
+
var _iterator0 = _createForOfIteratorHelper(text.toLowerCase().split(WHITESPACE_SPLIT_REGEX)),
|
|
661
|
+
_step0;
|
|
521
662
|
try {
|
|
522
|
-
for (
|
|
523
|
-
var raw =
|
|
663
|
+
for (_iterator0.s(); !(_step0 = _iterator0.n()).done;) {
|
|
664
|
+
var raw = _step0.value;
|
|
524
665
|
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
525
666
|
var clean = raw.replace(PUNCTUATION_BOUNDARY_REGEX, '');
|
|
526
667
|
if (clean.length >= 2) {
|
|
@@ -528,9 +669,9 @@ var tokenize = function tokenize(text) {
|
|
|
528
669
|
}
|
|
529
670
|
}
|
|
530
671
|
} catch (err) {
|
|
531
|
-
|
|
672
|
+
_iterator0.e(err);
|
|
532
673
|
} finally {
|
|
533
|
-
|
|
674
|
+
_iterator0.f();
|
|
534
675
|
}
|
|
535
676
|
return tokens;
|
|
536
677
|
};
|
|
@@ -634,11 +775,11 @@ var getPhraseCandidates = function getPhraseCandidates(trimmed) {
|
|
|
634
775
|
window: windowPrefix,
|
|
635
776
|
matches: matches.length
|
|
636
777
|
});
|
|
637
|
-
var
|
|
638
|
-
|
|
778
|
+
var _iterator1 = _createForOfIteratorHelper(matches),
|
|
779
|
+
_step1;
|
|
639
780
|
try {
|
|
640
|
-
for (
|
|
641
|
-
var _match =
|
|
781
|
+
for (_iterator1.s(); !(_step1 = _iterator1.n()).done;) {
|
|
782
|
+
var _match = _step1.value;
|
|
642
783
|
if (seen.has(_match.word)) {
|
|
643
784
|
continue;
|
|
644
785
|
}
|
|
@@ -651,9 +792,9 @@ var getPhraseCandidates = function getPhraseCandidates(trimmed) {
|
|
|
651
792
|
});
|
|
652
793
|
}
|
|
653
794
|
} catch (err) {
|
|
654
|
-
|
|
795
|
+
_iterator1.e(err);
|
|
655
796
|
} finally {
|
|
656
|
-
|
|
797
|
+
_iterator1.f();
|
|
657
798
|
}
|
|
658
799
|
}
|
|
659
800
|
logPhrasePath();
|
|
@@ -698,17 +839,17 @@ export var getLastPredictionDebug = function getLastPredictionDebug() {
|
|
|
698
839
|
return lastPredictionDebug;
|
|
699
840
|
};
|
|
700
841
|
export var initVocabulary = function initVocabulary(vocabulary) {
|
|
701
|
-
var
|
|
702
|
-
|
|
842
|
+
var _iterator10 = _createForOfIteratorHelper(vocabulary.terms),
|
|
843
|
+
_step10;
|
|
703
844
|
try {
|
|
704
|
-
for (
|
|
705
|
-
var term =
|
|
845
|
+
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
|
|
846
|
+
var term = _step10.value;
|
|
706
847
|
wordTrie.insert(term.word, term.freq, term.docFreq, term.authorFreq);
|
|
707
848
|
}
|
|
708
849
|
} catch (err) {
|
|
709
|
-
|
|
850
|
+
_iterator10.e(err);
|
|
710
851
|
} finally {
|
|
711
|
-
|
|
852
|
+
_iterator10.f();
|
|
712
853
|
}
|
|
713
854
|
isInitialized = true;
|
|
714
855
|
recallGeneration++;
|
|
@@ -759,6 +900,36 @@ export var incrementSessionFreq = function incrementSessionFreq(word) {
|
|
|
759
900
|
wordTrie.incrementSessionFreq(word);
|
|
760
901
|
};
|
|
761
902
|
|
|
903
|
+
/**
|
|
904
|
+
* Drop every L1 boost this session has accumulated.
|
|
905
|
+
*
|
|
906
|
+
* The vocabulary itself is left alone: only `sessionFreq` is cleared, so the
|
|
907
|
+
* tenant and generic frequencies a boost was sitting on top of survive. Called
|
|
908
|
+
* when the plugin decides the session it was learning for has ended — a new
|
|
909
|
+
* conversation, or a different page — since a boost is a claim about what is
|
|
910
|
+
* being discussed and that claim does not carry over.
|
|
911
|
+
*/
|
|
912
|
+
export var resetSessionBoosts = function resetSessionBoosts() {
|
|
913
|
+
wordTrie.clearSessionBoosts();
|
|
914
|
+
// Anything memoized against the old boosts is now describing a session that
|
|
915
|
+
// no longer exists.
|
|
916
|
+
recallGeneration++;
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Which vocabulary already holds this surface, if any.
|
|
921
|
+
*
|
|
922
|
+
* Used by the inline-code harvester to drop terms the scored path can already
|
|
923
|
+
* serve, so that harvesting stays limited to words with no route to a
|
|
924
|
+
* suggestion today.
|
|
925
|
+
*/
|
|
926
|
+
export var lookupVocabularySource = function lookupVocabularySource(word) {
|
|
927
|
+
if (wordTrie.hasWord(word)) {
|
|
928
|
+
return 'l2';
|
|
929
|
+
}
|
|
930
|
+
return l3Trie.hasWord(word) ? 'l3' : null;
|
|
931
|
+
};
|
|
932
|
+
|
|
762
933
|
/**
|
|
763
934
|
* Prime session frequencies from a document page string.
|
|
764
935
|
*
|
|
@@ -775,23 +946,23 @@ export var ingestDocumentPage = function ingestDocumentPage(pageContent) {
|
|
|
775
946
|
}
|
|
776
947
|
var words = tokenize(pageContent);
|
|
777
948
|
var validBoostedWords = new Set();
|
|
778
|
-
var
|
|
779
|
-
|
|
949
|
+
var _iterator11 = _createForOfIteratorHelper(words),
|
|
950
|
+
_step11;
|
|
780
951
|
try {
|
|
781
|
-
for (
|
|
782
|
-
var word =
|
|
952
|
+
for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
|
|
953
|
+
var word = _step11.value;
|
|
783
954
|
var didBoost = wordTrie.incrementSessionFreq(word);
|
|
784
955
|
if (didBoost) {
|
|
785
956
|
validBoostedWords.add(word);
|
|
786
957
|
}
|
|
787
958
|
}
|
|
788
959
|
} catch (err) {
|
|
789
|
-
|
|
960
|
+
_iterator11.e(err);
|
|
790
961
|
} finally {
|
|
791
|
-
|
|
962
|
+
_iterator11.f();
|
|
792
963
|
}
|
|
793
964
|
if (isAutocompleteDebugEnabled() && validBoostedWords.size > 0) {
|
|
794
|
-
ctcTag('init', "L1 session primed ".concat(validBoostedWords.size, " words from page"), CTC_STYLES.brand);
|
|
965
|
+
ctcTag('init', "L1 session primed ".concat(validBoostedWords.size, " words from page \xB7 __atlCtcDebug__.session() to inspect"), CTC_STYLES.brand);
|
|
795
966
|
if (isAutocompleteDebugVerbose()) {
|
|
796
967
|
// eslint-disable-next-line no-console
|
|
797
968
|
console.dir(Array.from(validBoostedWords).sort());
|
|
@@ -799,6 +970,57 @@ export var ingestDocumentPage = function ingestDocumentPage(pageContent) {
|
|
|
799
970
|
}
|
|
800
971
|
};
|
|
801
972
|
|
|
973
|
+
/**
|
|
974
|
+
* How many boosted words `inspectSessionBoosts` lists.
|
|
975
|
+
*
|
|
976
|
+
* A page ingest can boost thousands, and a list that long is not read. The
|
|
977
|
+
* strongest boosts are the ones that change an ordering, and `boosted` still
|
|
978
|
+
* reports the full size, so the cap loses nothing but volume.
|
|
979
|
+
*/
|
|
980
|
+
var MAX_LISTED_SESSION_WORDS = 100;
|
|
981
|
+
/**
|
|
982
|
+
* Read the session's L1 boosts, optionally narrowed to a prefix.
|
|
983
|
+
*
|
|
984
|
+
* Installed as `__atlCtcDebug__.session()`, with `__atlCtcDebug__.session('poll')`
|
|
985
|
+
* to ask about one family. Returned rather than logged, so the console renders it
|
|
986
|
+
* as an inspectable object and a caller can assert on it.
|
|
987
|
+
*
|
|
988
|
+
* Only words the vocabulary already holds can carry a boost, because both writers
|
|
989
|
+
* go through `incrementSessionFreq` and it only finds existing nodes. An ingested
|
|
990
|
+
* word absent from the vocabulary is therefore missing from here and always will
|
|
991
|
+
* be — that gap is what the inline-code harvester covers, and those surfaces show
|
|
992
|
+
* up under `__atlCtcDebug__.harvest()` instead.
|
|
993
|
+
*/
|
|
994
|
+
export var inspectSessionBoosts = function inspectSessionBoosts(prefix) {
|
|
995
|
+
var boosted = wordTrie.collectSessionBoosted(prefix !== null && prefix !== void 0 ? prefix : '');
|
|
996
|
+
return _objectSpread(_objectSpread({
|
|
997
|
+
boosted: boosted.length,
|
|
998
|
+
limit: MAX_LISTED_SESSION_WORDS
|
|
999
|
+
}, prefix === undefined ? {} : {
|
|
1000
|
+
prefix: prefix
|
|
1001
|
+
}), {}, {
|
|
1002
|
+
words: boosted.sort(function (a, b) {
|
|
1003
|
+
return b.node.sessionFreq - a.node.sessionFreq || a.word.localeCompare(b.word, 'en', {
|
|
1004
|
+
numeric: true,
|
|
1005
|
+
sensitivity: 'base'
|
|
1006
|
+
});
|
|
1007
|
+
}).slice(0, MAX_LISTED_SESSION_WORDS).map(function (_ref) {
|
|
1008
|
+
var node = _ref.node,
|
|
1009
|
+
word = _ref.word;
|
|
1010
|
+
return {
|
|
1011
|
+
sessionFreq: node.sessionFreq,
|
|
1012
|
+
sessionOnly: node.tenantFreq === 0,
|
|
1013
|
+
surface: word,
|
|
1014
|
+
tenantFreq: node.tenantFreq
|
|
1015
|
+
};
|
|
1016
|
+
})
|
|
1017
|
+
});
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
// At module scope so the console answers before the first keystroke, which is
|
|
1021
|
+
// when someone reaching for it usually asks.
|
|
1022
|
+
registerCtcSessionInspector(inspectSessionBoosts);
|
|
1023
|
+
|
|
802
1024
|
/**
|
|
803
1025
|
* Result of a prediction: the ghost tail to insert plus an immutable record of
|
|
804
1026
|
* the evidence that authorized the UI commitment.
|
|
@@ -830,20 +1052,20 @@ var computeCanonicalRecall = function computeCanonicalRecall(trimmed, currentWor
|
|
|
830
1052
|
var existingWords = new Set(wordCandidates.map(function (c) {
|
|
831
1053
|
return c.word;
|
|
832
1054
|
}));
|
|
833
|
-
var
|
|
834
|
-
|
|
1055
|
+
var _iterator12 = _createForOfIteratorHelper(l3Candidates),
|
|
1056
|
+
_step12;
|
|
835
1057
|
try {
|
|
836
|
-
for (
|
|
837
|
-
var l3c =
|
|
1058
|
+
for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
|
|
1059
|
+
var l3c = _step12.value;
|
|
838
1060
|
if (wordCandidates.length >= MAX_CANDIDATES) break;
|
|
839
1061
|
if (!existingWords.has(l3c.word)) {
|
|
840
1062
|
wordCandidates.push(l3c);
|
|
841
1063
|
}
|
|
842
1064
|
}
|
|
843
1065
|
} catch (err) {
|
|
844
|
-
|
|
1066
|
+
_iterator12.e(err);
|
|
845
1067
|
} finally {
|
|
846
|
-
|
|
1068
|
+
_iterator12.f();
|
|
847
1069
|
}
|
|
848
1070
|
}
|
|
849
1071
|
|
|
@@ -855,9 +1077,9 @@ var computeCanonicalRecall = function computeCanonicalRecall(trimmed, currentWor
|
|
|
855
1077
|
// Unify: a word completes the current partial token; a phrase completes its
|
|
856
1078
|
// matched multi-word window. Track the prefix length per term so the ghost
|
|
857
1079
|
// tail is sliced correctly regardless of term type.
|
|
858
|
-
var matched = [].concat(_toConsumableArray(wordCandidates.map(function (
|
|
859
|
-
var word =
|
|
860
|
-
node =
|
|
1080
|
+
var matched = [].concat(_toConsumableArray(wordCandidates.map(function (_ref2) {
|
|
1081
|
+
var word = _ref2.word,
|
|
1082
|
+
node = _ref2.node;
|
|
861
1083
|
return {
|
|
862
1084
|
word: word,
|
|
863
1085
|
node: node,
|
|
@@ -870,19 +1092,19 @@ var computeCanonicalRecall = function computeCanonicalRecall(trimmed, currentWor
|
|
|
870
1092
|
return _objectSpread(_objectSpread({}, candidate), deriveCanonicalCandidateContext(trimmed, candidate.matchedPrefixLen, candidate.word, getCanonicalSurfaceTokenIds, candidate.surfaceStart, positionCache));
|
|
871
1093
|
});
|
|
872
1094
|
var prefixLenByWord = new Map();
|
|
873
|
-
var
|
|
874
|
-
|
|
1095
|
+
var _iterator13 = _createForOfIteratorHelper(canonicalMatched),
|
|
1096
|
+
_step13;
|
|
875
1097
|
try {
|
|
876
|
-
for (
|
|
877
|
-
var m =
|
|
1098
|
+
for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
|
|
1099
|
+
var m = _step13.value;
|
|
878
1100
|
if (!prefixLenByWord.has(m.word)) {
|
|
879
1101
|
prefixLenByWord.set(m.word, m.matchedPrefixLen);
|
|
880
1102
|
}
|
|
881
1103
|
}
|
|
882
1104
|
} catch (err) {
|
|
883
|
-
|
|
1105
|
+
_iterator13.e(err);
|
|
884
1106
|
} finally {
|
|
885
|
-
|
|
1107
|
+
_iterator13.f();
|
|
886
1108
|
}
|
|
887
1109
|
return {
|
|
888
1110
|
canonicalMatched: canonicalMatched,
|
|
@@ -921,6 +1143,14 @@ export var predict = function predict(textBefore) {
|
|
|
921
1143
|
void loadDefaultVocabulary({
|
|
922
1144
|
source: 'predict'
|
|
923
1145
|
}).catch(function () {});
|
|
1146
|
+
// Awaiting, not empty-handed: with no vocabulary loaded the harvester's own
|
|
1147
|
+
// intake filter has not been applied to anything either.
|
|
1148
|
+
recordPredictionOutcome({
|
|
1149
|
+
abstainReason: 'not-initialized',
|
|
1150
|
+
awaitingAsyncEvidence: true,
|
|
1151
|
+
scoredCandidateCount: 0,
|
|
1152
|
+
textBefore: textBefore
|
|
1153
|
+
});
|
|
924
1154
|
return null;
|
|
925
1155
|
}
|
|
926
1156
|
var t0 = performance.now();
|
|
@@ -949,11 +1179,23 @@ export var predict = function predict(textBefore) {
|
|
|
949
1179
|
priority: 0
|
|
950
1180
|
}));
|
|
951
1181
|
}
|
|
1182
|
+
recordPredictionOutcome({
|
|
1183
|
+
abstainReason: 'prefetch',
|
|
1184
|
+
awaitingAsyncEvidence: true,
|
|
1185
|
+
scoredCandidateCount: 0,
|
|
1186
|
+
textBefore: textBefore
|
|
1187
|
+
});
|
|
952
1188
|
return null;
|
|
953
1189
|
}
|
|
954
1190
|
var trimmed = textBefore.trimEnd();
|
|
955
1191
|
var trailingSurfaceToken = (_trimmed$match$ = (_trimmed$match = trimmed.match(TRAILING_SURFACE_TOKEN_REGEX)) === null || _trimmed$match === void 0 ? void 0 : _trimmed$match[0]) !== null && _trimmed$match$ !== void 0 ? _trimmed$match$ : '';
|
|
956
1192
|
if (trailingSurfaceToken.length === 0) {
|
|
1193
|
+
recordPredictionOutcome({
|
|
1194
|
+
abstainReason: 'no-surface-token',
|
|
1195
|
+
awaitingAsyncEvidence: false,
|
|
1196
|
+
scoredCandidateCount: 0,
|
|
1197
|
+
textBefore: textBefore
|
|
1198
|
+
});
|
|
957
1199
|
return null;
|
|
958
1200
|
}
|
|
959
1201
|
var currentWord = trailingSurfaceToken;
|
|
@@ -964,6 +1206,14 @@ export var predict = function predict(textBefore) {
|
|
|
964
1206
|
|
|
965
1207
|
// If every trie was empty for this prefix
|
|
966
1208
|
if (canonicalMatched.length === 0) {
|
|
1209
|
+
// Terminal, and the only verdict that says the vocabulary has no claim on
|
|
1210
|
+
// this prefix at all — which is what makes it the harvester's cue.
|
|
1211
|
+
recordPredictionOutcome({
|
|
1212
|
+
abstainReason: 'no-candidate',
|
|
1213
|
+
awaitingAsyncEvidence: false,
|
|
1214
|
+
scoredCandidateCount: 0,
|
|
1215
|
+
textBefore: textBefore
|
|
1216
|
+
});
|
|
967
1217
|
if (isAutocompleteDebugEnabled()) {
|
|
968
1218
|
// eslint-disable-next-line no-console
|
|
969
1219
|
console.log("%c[CTC]%c \u2014 abstain: no matches for \"".concat(currentWord, "\""), CTC_STYLES.brand, CTC_STYLES.body);
|
|
@@ -976,9 +1226,9 @@ export var predict = function predict(textBefore) {
|
|
|
976
1226
|
var mode = contextVector ? 'warm' : 'cold';
|
|
977
1227
|
|
|
978
1228
|
// Build ScoringCandidate array from matched terms (words + phrases)
|
|
979
|
-
var scoringCandidates = canonicalMatched.map(function (
|
|
980
|
-
var word =
|
|
981
|
-
node =
|
|
1229
|
+
var scoringCandidates = canonicalMatched.map(function (_ref3) {
|
|
1230
|
+
var word = _ref3.word,
|
|
1231
|
+
node = _ref3.node;
|
|
982
1232
|
return {
|
|
983
1233
|
word: word,
|
|
984
1234
|
tenantFreq: node.tenantFreq,
|
|
@@ -998,9 +1248,9 @@ export var predict = function predict(textBefore) {
|
|
|
998
1248
|
var currentWordSeparator = (_canonicalMatched$fin = canonicalMatched.find(function (candidate) {
|
|
999
1249
|
return candidate.node.termType === 'word';
|
|
1000
1250
|
})) === null || _canonicalMatched$fin === void 0 ? void 0 : _canonicalMatched$fin.separatorKind;
|
|
1001
|
-
var prefixLmLogits = lmLogits && currentWordSeparator === 'whitespace' ? Object.fromEntries(Object.entries(lmLogits).filter(function (
|
|
1002
|
-
var
|
|
1003
|
-
word =
|
|
1251
|
+
var prefixLmLogits = lmLogits && currentWordSeparator === 'whitespace' ? Object.fromEntries(Object.entries(lmLogits).filter(function (_ref4) {
|
|
1252
|
+
var _ref5 = _slicedToArray(_ref4, 1),
|
|
1253
|
+
word = _ref5[0];
|
|
1004
1254
|
return word.startsWith(prefix);
|
|
1005
1255
|
})) : null;
|
|
1006
1256
|
var canonicalScoringSupported = isCanonicalSurfaceScoringSupported();
|
|
@@ -1011,29 +1261,29 @@ export var predict = function predict(textBefore) {
|
|
|
1011
1261
|
}))).sort();
|
|
1012
1262
|
var familyKey = eligibleContextKeys.join("\x01");
|
|
1013
1263
|
var primeRequests = selectBoundaryPrimeRequests(familyKey, canonicalMatched, PHRASE_MAX_WORDS);
|
|
1014
|
-
var
|
|
1015
|
-
|
|
1264
|
+
var _iterator14 = _createForOfIteratorHelper(primeRequests),
|
|
1265
|
+
_step14;
|
|
1016
1266
|
try {
|
|
1017
|
-
for (
|
|
1018
|
-
var request =
|
|
1267
|
+
for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
|
|
1268
|
+
var request = _step14.value;
|
|
1019
1269
|
primeBoundaryLm(request);
|
|
1020
1270
|
}
|
|
1021
1271
|
} catch (err) {
|
|
1022
|
-
|
|
1272
|
+
_iterator14.e(err);
|
|
1023
1273
|
} finally {
|
|
1024
|
-
|
|
1274
|
+
_iterator14.f();
|
|
1025
1275
|
}
|
|
1026
1276
|
var runtimeBySurface = new Map(canonicalMatched.map(function (candidate) {
|
|
1027
1277
|
return [candidate.word, candidate];
|
|
1028
1278
|
}));
|
|
1029
1279
|
var canonicalEvidence = new Map();
|
|
1030
1280
|
var firstTokenGroups = new Map();
|
|
1031
|
-
var
|
|
1032
|
-
|
|
1281
|
+
var _iterator15 = _createForOfIteratorHelper(canonicalMatched),
|
|
1282
|
+
_step15;
|
|
1033
1283
|
try {
|
|
1034
|
-
for (
|
|
1284
|
+
for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
|
|
1035
1285
|
var _firstTokenGroups$get;
|
|
1036
|
-
var _candidate =
|
|
1286
|
+
var _candidate = _step15.value;
|
|
1037
1287
|
if (_candidate.canonicalTokenIds === null) {
|
|
1038
1288
|
continue;
|
|
1039
1289
|
}
|
|
@@ -1061,28 +1311,28 @@ export var predict = function predict(textBefore) {
|
|
|
1061
1311
|
firstTokenGroups.set(_candidate.contextKey, _group2);
|
|
1062
1312
|
}
|
|
1063
1313
|
} catch (err) {
|
|
1064
|
-
|
|
1314
|
+
_iterator15.e(err);
|
|
1065
1315
|
} finally {
|
|
1066
|
-
|
|
1316
|
+
_iterator15.f();
|
|
1067
1317
|
}
|
|
1068
|
-
var
|
|
1069
|
-
|
|
1318
|
+
var _iterator16 = _createForOfIteratorHelper(firstTokenGroups),
|
|
1319
|
+
_step16;
|
|
1070
1320
|
try {
|
|
1071
|
-
for (
|
|
1072
|
-
var
|
|
1073
|
-
_contextKey =
|
|
1074
|
-
_group3 =
|
|
1321
|
+
for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) {
|
|
1322
|
+
var _step16$value = _slicedToArray(_step16.value, 2),
|
|
1323
|
+
_contextKey = _step16$value[0],
|
|
1324
|
+
_group3 = _step16$value[1];
|
|
1075
1325
|
var boundary = getBoundaryLmState(_contextKey);
|
|
1076
1326
|
if (!boundary) {
|
|
1077
1327
|
continue;
|
|
1078
1328
|
}
|
|
1079
1329
|
var maxLogit = -Infinity;
|
|
1080
|
-
var
|
|
1081
|
-
|
|
1330
|
+
var _iterator23 = _createForOfIteratorHelper(_group3),
|
|
1331
|
+
_step23;
|
|
1082
1332
|
try {
|
|
1083
|
-
for (
|
|
1333
|
+
for (_iterator23.s(); !(_step23 = _iterator23.n()).done;) {
|
|
1084
1334
|
var _candidate2$canonical;
|
|
1085
|
-
var _candidate2 =
|
|
1335
|
+
var _candidate2 = _step23.value;
|
|
1086
1336
|
var tokenId = (_candidate2$canonical = _candidate2.canonicalTokenIds) === null || _candidate2$canonical === void 0 ? void 0 : _candidate2$canonical[0];
|
|
1087
1337
|
var rawLogit = tokenId === undefined ? undefined : boundary.rawLogits[tokenId];
|
|
1088
1338
|
if (rawLogit !== undefined && Number.isFinite(rawLogit) && rawLogit > maxLogit) {
|
|
@@ -1090,19 +1340,19 @@ export var predict = function predict(textBefore) {
|
|
|
1090
1340
|
}
|
|
1091
1341
|
}
|
|
1092
1342
|
} catch (err) {
|
|
1093
|
-
|
|
1343
|
+
_iterator23.e(err);
|
|
1094
1344
|
} finally {
|
|
1095
|
-
|
|
1345
|
+
_iterator23.f();
|
|
1096
1346
|
}
|
|
1097
1347
|
if (!Number.isFinite(maxLogit)) {
|
|
1098
1348
|
continue;
|
|
1099
1349
|
}
|
|
1100
|
-
var
|
|
1101
|
-
|
|
1350
|
+
var _iterator24 = _createForOfIteratorHelper(_group3),
|
|
1351
|
+
_step24;
|
|
1102
1352
|
try {
|
|
1103
|
-
for (
|
|
1353
|
+
for (_iterator24.s(); !(_step24 = _iterator24.n()).done;) {
|
|
1104
1354
|
var _candidate3$canonical, _candidate3$canonical2, _candidate3$canonical3;
|
|
1105
|
-
var _candidate3 =
|
|
1355
|
+
var _candidate3 = _step24.value;
|
|
1106
1356
|
var _tokenId = (_candidate3$canonical = _candidate3.canonicalTokenIds) === null || _candidate3$canonical === void 0 ? void 0 : _candidate3$canonical[0];
|
|
1107
1357
|
var _rawLogit = _tokenId === undefined ? undefined : boundary.rawLogits[_tokenId];
|
|
1108
1358
|
if (_rawLogit === undefined || !Number.isFinite(_rawLogit)) {
|
|
@@ -1141,15 +1391,15 @@ export var predict = function predict(textBefore) {
|
|
|
1141
1391
|
});
|
|
1142
1392
|
}
|
|
1143
1393
|
} catch (err) {
|
|
1144
|
-
|
|
1394
|
+
_iterator24.e(err);
|
|
1145
1395
|
} finally {
|
|
1146
|
-
|
|
1396
|
+
_iterator24.f();
|
|
1147
1397
|
}
|
|
1148
1398
|
}
|
|
1149
1399
|
} catch (err) {
|
|
1150
|
-
|
|
1400
|
+
_iterator16.e(err);
|
|
1151
1401
|
} finally {
|
|
1152
|
-
|
|
1402
|
+
_iterator16.f();
|
|
1153
1403
|
}
|
|
1154
1404
|
var _rankCandidates = rankCandidates(scoringCandidates, contextVector, function (w) {
|
|
1155
1405
|
return getWordVector(w);
|
|
@@ -1170,12 +1420,12 @@ export var predict = function predict(textBefore) {
|
|
|
1170
1420
|
});
|
|
1171
1421
|
if (canonicalScoringSupported && progressiveEligible.length > 0) {
|
|
1172
1422
|
var byContext = new Map();
|
|
1173
|
-
var
|
|
1174
|
-
|
|
1423
|
+
var _iterator17 = _createForOfIteratorHelper(progressiveEligible),
|
|
1424
|
+
_step17;
|
|
1175
1425
|
try {
|
|
1176
|
-
for (
|
|
1426
|
+
for (_iterator17.s(); !(_step17 = _iterator17.n()).done;) {
|
|
1177
1427
|
var _byContext$get;
|
|
1178
|
-
var candidate =
|
|
1428
|
+
var candidate = _step17.value;
|
|
1179
1429
|
var runtime = runtimeBySurface.get(candidate.word);
|
|
1180
1430
|
if (!runtime || runtime.canonicalTokenIds === null) {
|
|
1181
1431
|
continue;
|
|
@@ -1188,25 +1438,25 @@ export var predict = function predict(textBefore) {
|
|
|
1188
1438
|
byContext.set(runtime.contextKey, group);
|
|
1189
1439
|
}
|
|
1190
1440
|
} catch (err) {
|
|
1191
|
-
|
|
1441
|
+
_iterator17.e(err);
|
|
1192
1442
|
} finally {
|
|
1193
|
-
|
|
1443
|
+
_iterator17.f();
|
|
1194
1444
|
}
|
|
1195
|
-
var
|
|
1196
|
-
|
|
1445
|
+
var _iterator18 = _createForOfIteratorHelper(byContext),
|
|
1446
|
+
_step18;
|
|
1197
1447
|
try {
|
|
1198
|
-
for (
|
|
1199
|
-
var
|
|
1200
|
-
contextKey =
|
|
1201
|
-
_group =
|
|
1448
|
+
for (_iterator18.s(); !(_step18 = _iterator18.n()).done;) {
|
|
1449
|
+
var _step18$value = _slicedToArray(_step18.value, 2),
|
|
1450
|
+
contextKey = _step18$value[0],
|
|
1451
|
+
_group = _step18$value[1];
|
|
1202
1452
|
requestProgressiveSurfaceScores({
|
|
1203
1453
|
familyKey: familyKey,
|
|
1204
1454
|
contextKey: contextKey,
|
|
1205
1455
|
prompt: _group[0].runtime.contextBeforeSurface,
|
|
1206
|
-
candidates: _group.map(function (
|
|
1456
|
+
candidates: _group.map(function (_ref6) {
|
|
1207
1457
|
var _runtime$canonicalTok;
|
|
1208
|
-
var runtime =
|
|
1209
|
-
rankHint =
|
|
1458
|
+
var runtime = _ref6.runtime,
|
|
1459
|
+
rankHint = _ref6.rankHint;
|
|
1210
1460
|
return {
|
|
1211
1461
|
surface: runtime.word,
|
|
1212
1462
|
tokenIds: (_runtime$canonicalTok = runtime.canonicalTokenIds) !== null && _runtime$canonicalTok !== void 0 ? _runtime$canonicalTok : [],
|
|
@@ -1216,9 +1466,9 @@ export var predict = function predict(textBefore) {
|
|
|
1216
1466
|
});
|
|
1217
1467
|
}
|
|
1218
1468
|
} catch (err) {
|
|
1219
|
-
|
|
1469
|
+
_iterator18.e(err);
|
|
1220
1470
|
} finally {
|
|
1221
|
-
|
|
1471
|
+
_iterator18.f();
|
|
1222
1472
|
}
|
|
1223
1473
|
}
|
|
1224
1474
|
|
|
@@ -1307,12 +1557,12 @@ export var predict = function predict(textBefore) {
|
|
|
1307
1557
|
var contextRequestedCount = new Map();
|
|
1308
1558
|
var bestTotalByContext = new Map();
|
|
1309
1559
|
var bestCandidateByContext = new Map();
|
|
1310
|
-
var
|
|
1311
|
-
|
|
1560
|
+
var _iterator19 = _createForOfIteratorHelper(ranked),
|
|
1561
|
+
_step19;
|
|
1312
1562
|
try {
|
|
1313
|
-
for (
|
|
1563
|
+
for (_iterator19.s(); !(_step19 = _iterator19.n()).done;) {
|
|
1314
1564
|
var _contextRequestedCoun2, _judged$total;
|
|
1315
|
-
var _candidate4 =
|
|
1565
|
+
var _candidate4 = _step19.value;
|
|
1316
1566
|
var _runtime = runtimeBySurface.get(_candidate4.word);
|
|
1317
1567
|
if (!_runtime || _runtime.canonicalTokenIds === null) {
|
|
1318
1568
|
continue;
|
|
@@ -1351,9 +1601,9 @@ export var predict = function predict(textBefore) {
|
|
|
1351
1601
|
* costs one lookup per space rather than a comparison against every member.
|
|
1352
1602
|
*/
|
|
1353
1603
|
} catch (err) {
|
|
1354
|
-
|
|
1604
|
+
_iterator19.e(err);
|
|
1355
1605
|
} finally {
|
|
1356
|
-
|
|
1606
|
+
_iterator19.f();
|
|
1357
1607
|
}
|
|
1358
1608
|
var extendsAPoolMember = function extendsAPoolMember(surface, pool) {
|
|
1359
1609
|
for (var space = surface.indexOf(' '); space !== -1; space = surface.indexOf(' ', space + 1)) {
|
|
@@ -1388,22 +1638,22 @@ export var predict = function predict(textBefore) {
|
|
|
1388
1638
|
// it continues, because the cap alone would leave it looking exactly as
|
|
1389
1639
|
// certain as its prefix while saying nothing about its own tail.
|
|
1390
1640
|
var underReadExtensions = new Set();
|
|
1391
|
-
var
|
|
1392
|
-
|
|
1641
|
+
var _iterator20 = _createForOfIteratorHelper(contextSurfaces),
|
|
1642
|
+
_step20;
|
|
1393
1643
|
try {
|
|
1394
|
-
for (
|
|
1395
|
-
var
|
|
1396
|
-
_contextKey2 =
|
|
1397
|
-
_surfaces =
|
|
1644
|
+
for (_iterator20.s(); !(_step20 = _iterator20.n()).done;) {
|
|
1645
|
+
var _step20$value = _slicedToArray(_step20.value, 2),
|
|
1646
|
+
_contextKey2 = _step20$value[0],
|
|
1647
|
+
_surfaces = _step20$value[1];
|
|
1398
1648
|
var pool = new Set(_surfaces);
|
|
1399
|
-
var
|
|
1649
|
+
var _iterator25 = _createForOfIteratorHelper(_toConsumableArray(_surfaces).sort(function (a, b) {
|
|
1400
1650
|
return a.length - b.length;
|
|
1401
1651
|
})),
|
|
1402
|
-
|
|
1652
|
+
_step25;
|
|
1403
1653
|
try {
|
|
1404
|
-
for (
|
|
1654
|
+
for (_iterator25.s(); !(_step25 = _iterator25.n()).done;) {
|
|
1405
1655
|
var _getProgressiveSurfac, _getProgressiveSurfac2, _runtimeBySurface$get8, _runtimeBySurface$get9;
|
|
1406
|
-
var surface =
|
|
1656
|
+
var surface = _step25.value;
|
|
1407
1657
|
var own = optimisticTotalByWord.get(surface);
|
|
1408
1658
|
if (own === undefined) {
|
|
1409
1659
|
continue;
|
|
@@ -1435,9 +1685,9 @@ export var predict = function predict(textBefore) {
|
|
|
1435
1685
|
}
|
|
1436
1686
|
}
|
|
1437
1687
|
} catch (err) {
|
|
1438
|
-
|
|
1688
|
+
_iterator25.e(err);
|
|
1439
1689
|
} finally {
|
|
1440
|
-
|
|
1690
|
+
_iterator25.f();
|
|
1441
1691
|
}
|
|
1442
1692
|
}
|
|
1443
1693
|
|
|
@@ -1450,9 +1700,9 @@ export var predict = function predict(textBefore) {
|
|
|
1450
1700
|
* depths.
|
|
1451
1701
|
*/
|
|
1452
1702
|
} catch (err) {
|
|
1453
|
-
|
|
1703
|
+
_iterator20.e(err);
|
|
1454
1704
|
} finally {
|
|
1455
|
-
|
|
1705
|
+
_iterator20.f();
|
|
1456
1706
|
}
|
|
1457
1707
|
var judgedEvidenceFor = function judgedEvidenceFor(candidate) {
|
|
1458
1708
|
return underReadExtensions.has(candidate.word) ? null : readJudgedEvidence(candidate);
|
|
@@ -1479,20 +1729,20 @@ export var predict = function predict(textBefore) {
|
|
|
1479
1729
|
// `contextTotals`, so how contested a context is still counts every scored
|
|
1480
1730
|
// candidate.
|
|
1481
1731
|
var logSumExpByContext = new Map();
|
|
1482
|
-
var
|
|
1483
|
-
|
|
1732
|
+
var _iterator21 = _createForOfIteratorHelper(contextSurfaces),
|
|
1733
|
+
_step21;
|
|
1484
1734
|
try {
|
|
1485
|
-
for (
|
|
1486
|
-
var
|
|
1487
|
-
_contextKey3 =
|
|
1488
|
-
_surfaces2 =
|
|
1735
|
+
for (_iterator21.s(); !(_step21 = _iterator21.n()).done;) {
|
|
1736
|
+
var _step21$value = _slicedToArray(_step21.value, 2),
|
|
1737
|
+
_contextKey3 = _step21$value[0],
|
|
1738
|
+
_surfaces2 = _step21$value[1];
|
|
1489
1739
|
var _pool = new Set(_surfaces2);
|
|
1490
1740
|
var minimalTotals = [];
|
|
1491
|
-
var
|
|
1492
|
-
|
|
1741
|
+
var _iterator26 = _createForOfIteratorHelper(_surfaces2),
|
|
1742
|
+
_step26;
|
|
1493
1743
|
try {
|
|
1494
|
-
for (
|
|
1495
|
-
var _surface =
|
|
1744
|
+
for (_iterator26.s(); !(_step26 = _iterator26.n()).done;) {
|
|
1745
|
+
var _surface = _step26.value;
|
|
1496
1746
|
var total = optimisticTotalByWord.get(_surface);
|
|
1497
1747
|
if (total !== undefined && !extendsAPoolMember(_surface, _pool)) {
|
|
1498
1748
|
minimalTotals.push(total);
|
|
@@ -1501,9 +1751,9 @@ export var predict = function predict(textBefore) {
|
|
|
1501
1751
|
// An extension is strictly longer than what it extends, so the shortest
|
|
1502
1752
|
// member of any non-empty pool is always minimal and this is never empty.
|
|
1503
1753
|
} catch (err) {
|
|
1504
|
-
|
|
1754
|
+
_iterator26.e(err);
|
|
1505
1755
|
} finally {
|
|
1506
|
-
|
|
1756
|
+
_iterator26.f();
|
|
1507
1757
|
}
|
|
1508
1758
|
logSumExpByContext.set(_contextKey3, logSumExp(minimalTotals));
|
|
1509
1759
|
}
|
|
@@ -1515,9 +1765,9 @@ export var predict = function predict(textBefore) {
|
|
|
1515
1765
|
* eventual posterior, or a verified total for the posterior itself.
|
|
1516
1766
|
*/
|
|
1517
1767
|
} catch (err) {
|
|
1518
|
-
|
|
1768
|
+
_iterator21.e(err);
|
|
1519
1769
|
} finally {
|
|
1520
|
-
|
|
1770
|
+
_iterator21.f();
|
|
1521
1771
|
}
|
|
1522
1772
|
var posteriorFor = function posteriorFor(candidate, total) {
|
|
1523
1773
|
var runtime = runtimeBySurface.get(candidate.word);
|
|
@@ -1647,9 +1897,9 @@ export var predict = function predict(textBefore) {
|
|
|
1647
1897
|
// The gate is the model's own confidence in the surface; the blended score
|
|
1648
1898
|
// only orders what has already cleared it, so a strong corpus prior can no
|
|
1649
1899
|
// longer carry a surface the model is unsure of onto the screen.
|
|
1650
|
-
.filter(function (
|
|
1651
|
-
var candidate =
|
|
1652
|
-
posterior =
|
|
1900
|
+
.filter(function (_ref7) {
|
|
1901
|
+
var candidate = _ref7.candidate,
|
|
1902
|
+
posterior = _ref7.posterior;
|
|
1653
1903
|
return posterior >= MIN_LM_POSTERIOR[candidate.termType];
|
|
1654
1904
|
});
|
|
1655
1905
|
/**
|
|
@@ -1677,15 +1927,15 @@ export var predict = function predict(textBefore) {
|
|
|
1677
1927
|
// cleared both. A candidate refused here stays in `ranked` and so still
|
|
1678
1928
|
// counts as competition below — promoting the runner-up in place of an
|
|
1679
1929
|
// implausible leader would show something worse, not something better.
|
|
1680
|
-
var plausible = gateCleared.filter(function (
|
|
1681
|
-
var candidate =
|
|
1930
|
+
var plausible = gateCleared.filter(function (_ref8) {
|
|
1931
|
+
var candidate = _ref8.candidate;
|
|
1682
1932
|
return isPlausibleSurface(candidate);
|
|
1683
1933
|
});
|
|
1684
1934
|
// Applied after the gate rather than folded into it, so the two populations
|
|
1685
1935
|
// stay separable: a surface refused here cleared its threshold and was
|
|
1686
1936
|
// refused for having had nothing to clear it against.
|
|
1687
|
-
var eligible = plausible.filter(function (
|
|
1688
|
-
var candidate =
|
|
1937
|
+
var eligible = plausible.filter(function (_ref9) {
|
|
1938
|
+
var candidate = _ref9.candidate;
|
|
1689
1939
|
return !canonicalLmSupported || scoredPoolSize(candidate) >= MIN_SCORED_POOL_SIZE || requestedPoolSize(candidate) <= 1;
|
|
1690
1940
|
}).sort(function (a, b) {
|
|
1691
1941
|
return b.score - a.score;
|
|
@@ -1807,6 +2057,12 @@ export var predict = function predict(textBefore) {
|
|
|
1807
2057
|
return ranked.some(hasJudgeableEvidence) ? 'below-posterior-gate' : 'no-evidence';
|
|
1808
2058
|
};
|
|
1809
2059
|
var abstainReason = resolveAbstainReason();
|
|
2060
|
+
recordPredictionOutcome({
|
|
2061
|
+
abstainReason: abstainReason,
|
|
2062
|
+
awaitingAsyncEvidence: hasUnresolvedPotential && !clearsWinnerMargin,
|
|
2063
|
+
scoredCandidateCount: ranked.length,
|
|
2064
|
+
textBefore: textBefore
|
|
2065
|
+
});
|
|
1810
2066
|
|
|
1811
2067
|
// The leader is the best-supported candidate, not the selected one: an
|
|
1812
2068
|
// evaluation that showed nothing is exactly the one whose posterior needs
|
|
@@ -1851,9 +2107,9 @@ export var predict = function predict(textBefore) {
|
|
|
1851
2107
|
'below-posterior-gate': "posterior below ".concat(MIN_LM_POSTERIOR[((_posteriorLeader$cand = posteriorLeader === null || posteriorLeader === void 0 ? void 0 : posteriorLeader.candidate) !== null && _posteriorLeader$cand !== void 0 ? _posteriorLeader$cand : ranked[0]).termType], " (best ").concat(((_posteriorLeader$post = posteriorLeader === null || posteriorLeader === void 0 ? void 0 : posteriorLeader.posterior) !== null && _posteriorLeader$post !== void 0 ? _posteriorLeader$post : 0).toFixed(2), ")"),
|
|
1852
2108
|
'cold-competitor': 'competitor has no LM evidence yet',
|
|
1853
2109
|
'empty-completion': 'empty completion',
|
|
1854
|
-
'implausible-surface': "mean per-token log-probability below ".concat(MIN_MEAN_TOKEN_LOG_PROBABILITY, " (best ").concat(gateCleared.map(function (
|
|
2110
|
+
'implausible-surface': "mean per-token log-probability below ".concat(MIN_MEAN_TOKEN_LOG_PROBABILITY, " (best ").concat(gateCleared.map(function (_ref0) {
|
|
1855
2111
|
var _judgedEvidenceFor$me, _judgedEvidenceFor4;
|
|
1856
|
-
var candidate =
|
|
2112
|
+
var candidate = _ref0.candidate;
|
|
1857
2113
|
return (_judgedEvidenceFor$me = (_judgedEvidenceFor4 = judgedEvidenceFor(candidate)) === null || _judgedEvidenceFor4 === void 0 ? void 0 : _judgedEvidenceFor4.mean) !== null && _judgedEvidenceFor$me !== void 0 ? _judgedEvidenceFor$me : -Infinity;
|
|
1858
2114
|
}).reduce(function (best, mean) {
|
|
1859
2115
|
return Math.max(best, mean);
|
|
@@ -1862,6 +2118,9 @@ export var predict = function predict(textBefore) {
|
|
|
1862
2118
|
'missing-artifact': 'canonical artifact coverage missing',
|
|
1863
2119
|
'no-candidate': 'nothing cleared scoring',
|
|
1864
2120
|
'no-evidence': 'full-surface evidence absent',
|
|
2121
|
+
// Recorded at the two exits above this block, so they never print here.
|
|
2122
|
+
'no-surface-token': 'no trailing surface token',
|
|
2123
|
+
'not-initialized': 'vocabulary not loaded',
|
|
1865
2124
|
prefetch: "prefetch: ".concat(currentWord.length, "/").concat(DISPLAY_MIN_PREFIX_LENGTH, " chars"),
|
|
1866
2125
|
'short-completion': "completion shorter than ".concat(MIN_SUGGESTION_LENGTH, " chars"),
|
|
1867
2126
|
'unresolved-rival': 'expanding plausible token-prefix groups',
|
|
@@ -1941,10 +2200,10 @@ export var predict = function predict(textBefore) {
|
|
|
1941
2200
|
if (verbose && logitCount > 0 && lmLogits) {
|
|
1942
2201
|
var rawLmTop = Object.entries(lmLogits).sort(function (a, b) {
|
|
1943
2202
|
return b[1] - a[1];
|
|
1944
|
-
}).slice(0, 5).map(function (
|
|
1945
|
-
var
|
|
1946
|
-
word =
|
|
1947
|
-
score =
|
|
2203
|
+
}).slice(0, 5).map(function (_ref1) {
|
|
2204
|
+
var _ref10 = _slicedToArray(_ref1, 2),
|
|
2205
|
+
word = _ref10[0],
|
|
2206
|
+
score = _ref10[1];
|
|
1948
2207
|
return "".concat(word, ":").concat(score.toFixed(3));
|
|
1949
2208
|
}).join(', ');
|
|
1950
2209
|
ctcSection(' rawLM', "\uD83E\uDDE0 ".concat(rawLmTop));
|
|
@@ -1956,17 +2215,17 @@ export var predict = function predict(textBefore) {
|
|
|
1956
2215
|
bigram: 0,
|
|
1957
2216
|
phrase: 0
|
|
1958
2217
|
};
|
|
1959
|
-
var
|
|
1960
|
-
|
|
2218
|
+
var _iterator22 = _createForOfIteratorHelper(canonicalMatched),
|
|
2219
|
+
_step22;
|
|
1961
2220
|
try {
|
|
1962
|
-
for (
|
|
1963
|
-
var m =
|
|
2221
|
+
for (_iterator22.s(); !(_step22 = _iterator22.n()).done;) {
|
|
2222
|
+
var m = _step22.value;
|
|
1964
2223
|
genByType[m.node.termType] += 1;
|
|
1965
2224
|
}
|
|
1966
2225
|
} catch (err) {
|
|
1967
|
-
|
|
2226
|
+
_iterator22.e(err);
|
|
1968
2227
|
} finally {
|
|
1969
|
-
|
|
2228
|
+
_iterator22.f();
|
|
1970
2229
|
}
|
|
1971
2230
|
ctcSection('GENERATE', "matched ".concat(canonicalMatched.length, " \u2192 word:").concat(genByType.word, " bigram:").concat(genByType.bigram, " phrase:").concat(genByType.phrase).concat(canonicalLmSupported ? ' · display needs exact surface evidence' : ''));
|
|
1972
2231
|
|
|
@@ -2025,8 +2284,8 @@ export var predict = function predict(textBefore) {
|
|
|
2025
2284
|
return judgedPosterior(candidate) >= MIN_LM_POSTERIOR[termType];
|
|
2026
2285
|
});
|
|
2027
2286
|
var plausiblePassed = floorPassed.filter(isPlausibleSurface);
|
|
2028
|
-
return "".concat(termType, " m:").concat(genByType[termType], " r:").concat(typeRanked.length, " exact:").concat(exact.length, " abs:").concat(absolute.length, " stable:").concat(stabilized.length, " suffix:").concat(longEnough.length, " floor:").concat(floorPassed.length, " plausible:").concat(plausiblePassed.length, " eligible:").concat(eligible.filter(function (
|
|
2029
|
-
var candidate =
|
|
2287
|
+
return "".concat(termType, " m:").concat(genByType[termType], " r:").concat(typeRanked.length, " exact:").concat(exact.length, " abs:").concat(absolute.length, " stable:").concat(stabilized.length, " suffix:").concat(longEnough.length, " floor:").concat(floorPassed.length, " plausible:").concat(plausiblePassed.length, " eligible:").concat(eligible.filter(function (_ref11) {
|
|
2288
|
+
var candidate = _ref11.candidate;
|
|
2030
2289
|
return candidate.termType === termType;
|
|
2031
2290
|
}).length);
|
|
2032
2291
|
};
|
|
@@ -2035,11 +2294,11 @@ export var predict = function predict(textBefore) {
|
|
|
2035
2294
|
// One line per context: how many candidates share the normaliser, and how
|
|
2036
2295
|
// much of the mass the leader holds. A leader well under its threshold
|
|
2037
2296
|
// means the context is contested, which is the abstention we want.
|
|
2038
|
-
var contextLeaders = Array.from(bestCandidateByContext.entries()).slice(0, PHRASE_MAX_WORDS).map(function (
|
|
2297
|
+
var contextLeaders = Array.from(bestCandidateByContext.entries()).slice(0, PHRASE_MAX_WORDS).map(function (_ref12) {
|
|
2039
2298
|
var _contextTotals$get$le2, _contextTotals$get2;
|
|
2040
|
-
var
|
|
2041
|
-
contextKey =
|
|
2042
|
-
leader =
|
|
2299
|
+
var _ref13 = _slicedToArray(_ref12, 2),
|
|
2300
|
+
contextKey = _ref13[0],
|
|
2301
|
+
leader = _ref13[1];
|
|
2043
2302
|
var shortlistSize = (_contextTotals$get$le2 = (_contextTotals$get2 = contextTotals.get(contextKey)) === null || _contextTotals$get2 === void 0 ? void 0 : _contextTotals$get2.length) !== null && _contextTotals$get$le2 !== void 0 ? _contextTotals$get$le2 : 0;
|
|
2044
2303
|
var evidenceKind = hasExactEvidence(leader) ? 'exact' : 'upper';
|
|
2045
2304
|
return "".concat(contextKey.slice(0, 32), " \u2192 n=").concat(shortlistSize, " ").concat(leader.termType, ":\"").concat(leader.word, "\" ").concat(evidenceKind, " p=").concat(optimisticPosterior(leader).toFixed(3), "/").concat(MIN_LM_POSTERIOR[leader.termType]);
|
|
@@ -2269,7 +2528,7 @@ var normalizePhraseArtifact = function normalizePhraseArtifact(payload) {
|
|
|
2269
2528
|
return null;
|
|
2270
2529
|
};
|
|
2271
2530
|
export var loadVectorsAsync = /*#__PURE__*/function () {
|
|
2272
|
-
var
|
|
2531
|
+
var _ref14 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(options) {
|
|
2273
2532
|
var _options$isLocalLLM;
|
|
2274
2533
|
var isLocalLLM, surface, buffer, float32, wordIndexPayload, wordIndex, nWords, dim, _t;
|
|
2275
2534
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
@@ -2344,7 +2603,7 @@ export var loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
2344
2603
|
}, _callee, null, [[2, 5]]);
|
|
2345
2604
|
}));
|
|
2346
2605
|
return function loadVectorsAsync(_x) {
|
|
2347
|
-
return
|
|
2606
|
+
return _ref14.apply(this, arguments);
|
|
2348
2607
|
};
|
|
2349
2608
|
}();
|
|
2350
2609
|
export var initVectors = function initVectors(store) {
|
|
@@ -2368,7 +2627,7 @@ export var initVectors = function initVectors(store) {
|
|
|
2368
2627
|
* A promise that resolves once both fetches have settled
|
|
2369
2628
|
*/
|
|
2370
2629
|
export var loadPhraseArtifacts = /*#__PURE__*/function () {
|
|
2371
|
-
var
|
|
2630
|
+
var _ref15 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(options) {
|
|
2372
2631
|
var _options$isLocalLLM2;
|
|
2373
2632
|
var isLocalLLM, loadOne, _yield$Promise$allSet, _yield$Promise$allSet2, bigramsResult, phrasesResult, bigramCount, phraseCount;
|
|
2374
2633
|
return _regeneratorRuntime.wrap(function (_context3) {
|
|
@@ -2386,7 +2645,7 @@ export var loadPhraseArtifacts = /*#__PURE__*/function () {
|
|
|
2386
2645
|
isLocalLLM: isLocalLLM
|
|
2387
2646
|
});
|
|
2388
2647
|
loadOne = /*#__PURE__*/function () {
|
|
2389
|
-
var
|
|
2648
|
+
var _ref16 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(artifactName, termType, label) {
|
|
2390
2649
|
var payload, normalized;
|
|
2391
2650
|
return _regeneratorRuntime.wrap(function (_context2) {
|
|
2392
2651
|
while (1) switch (_context2.prev = _context2.next) {
|
|
@@ -2415,7 +2674,7 @@ export var loadPhraseArtifacts = /*#__PURE__*/function () {
|
|
|
2415
2674
|
}, _callee2);
|
|
2416
2675
|
}));
|
|
2417
2676
|
return function loadOne(_x3, _x4, _x5) {
|
|
2418
|
-
return
|
|
2677
|
+
return _ref16.apply(this, arguments);
|
|
2419
2678
|
};
|
|
2420
2679
|
}();
|
|
2421
2680
|
_context3.next = 2;
|
|
@@ -2457,7 +2716,7 @@ export var loadPhraseArtifacts = /*#__PURE__*/function () {
|
|
|
2457
2716
|
}, _callee3);
|
|
2458
2717
|
}));
|
|
2459
2718
|
return function loadPhraseArtifacts(_x2) {
|
|
2460
|
-
return
|
|
2719
|
+
return _ref15.apply(this, arguments);
|
|
2461
2720
|
};
|
|
2462
2721
|
}();
|
|
2463
2722
|
var vocabularyLoadPromise;
|
|
@@ -2523,10 +2782,10 @@ export var loadDefaultVocabulary = function loadDefaultVocabulary(options) {
|
|
|
2523
2782
|
_yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 2);
|
|
2524
2783
|
vocabularyData = _yield$Promise$all2[0];
|
|
2525
2784
|
l3VocabularyData = _yield$Promise$all2[1];
|
|
2526
|
-
terms = Object.entries(vocabularyData.words).map(function (
|
|
2527
|
-
var
|
|
2528
|
-
word =
|
|
2529
|
-
stats =
|
|
2785
|
+
terms = Object.entries(vocabularyData.words).map(function (_ref18) {
|
|
2786
|
+
var _ref19 = _slicedToArray(_ref18, 2),
|
|
2787
|
+
word = _ref19[0],
|
|
2788
|
+
stats = _ref19[1];
|
|
2530
2789
|
return {
|
|
2531
2790
|
word: word,
|
|
2532
2791
|
freq: stats.freq,
|