@atlaskit/editor-plugin-autocomplete 9.0.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +82 -31
- package/dist/cjs/pm-plugins/debug-mode.js +17 -2
- package/dist/cjs/pm-plugins/text-predictor.js +290 -178
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +64 -22
- package/dist/es2019/pm-plugins/debug-mode.js +16 -1
- package/dist/es2019/pm-plugins/text-predictor.js +91 -3
- package/dist/esm/pm-plugins/autocomplete-plugin.js +82 -31
- package/dist/esm/pm-plugins/debug-mode.js +16 -1
- package/dist/esm/pm-plugins/text-predictor.js +290 -178
- package/dist/types/pm-plugins/debug-mode.d.ts +19 -0
- package/dist/types/pm-plugins/text-predictor.d.ts +36 -1
- package/package.json +2 -2
- package/src/pm-plugins/autocomplete-plugin.ts +67 -21
- package/src/pm-plugins/debug-mode.ts +26 -1
- package/src/pm-plugins/text-predictor.ts +116 -2
|
@@ -511,7 +511,63 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
511
511
|
// Set when the plugin is torn down so in-flight getContext() resolutions don't
|
|
512
512
|
// mutate the global text-predictor state after destruction.
|
|
513
513
|
let destroyed = false;
|
|
514
|
-
|
|
514
|
+
// L1 ingestion cannot run before the vocabulary has loaded: `incrementSessionFreq`
|
|
515
|
+
// only touches trie nodes that already exist, so an empty trie silently rejects
|
|
516
|
+
// every word. Text that arrives first — which a page usually does, since the
|
|
517
|
+
// chat resolves it on focus in the same tick as the load starts — is held here
|
|
518
|
+
// and applied once the load has settled.
|
|
519
|
+
const pendingSessionContextTexts = new Set();
|
|
520
|
+
const sessionIngestedContextTexts = new Set();
|
|
521
|
+
let isVocabularyReady = false;
|
|
522
|
+
let vocabularyLoadPromise;
|
|
523
|
+
const addBoundedContextText = (texts, text) => {
|
|
524
|
+
texts.add(text);
|
|
525
|
+
// Evict oldest entries (Set preserves insertion order) to bound memory.
|
|
526
|
+
while (texts.size > MAX_INGESTED_CONTEXT_TEXTS) {
|
|
527
|
+
const oldest = texts.values().next().value;
|
|
528
|
+
if (oldest === undefined) {
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
texts.delete(oldest);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
const flushPendingSessionContext = () => {
|
|
535
|
+
if (!isVocabularyReady || destroyed) {
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
for (const text of pendingSessionContextTexts) {
|
|
539
|
+
if (!sessionIngestedContextTexts.has(text)) {
|
|
540
|
+
ingestDocumentPage(text);
|
|
541
|
+
addBoundedContextText(sessionIngestedContextTexts, text);
|
|
542
|
+
}
|
|
543
|
+
pendingSessionContextTexts.delete(text);
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
const ensureVocabularyReady = () => {
|
|
547
|
+
var _options$useLocalMode;
|
|
548
|
+
if (isVocabularyReady) {
|
|
549
|
+
flushPendingSessionContext();
|
|
550
|
+
return Promise.resolve();
|
|
551
|
+
}
|
|
552
|
+
vocabularyLoadPromise ??= loadDefaultVocabulary({
|
|
553
|
+
isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
|
|
554
|
+
surface
|
|
555
|
+
}).then(() => {
|
|
556
|
+
if (destroyed) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
isVocabularyReady = true;
|
|
560
|
+
flushPendingSessionContext();
|
|
561
|
+
}).catch(error => {
|
|
562
|
+
// Do not consume the pending text on failure. A later focus retries the
|
|
563
|
+
// load and can still apply the original context exactly once.
|
|
564
|
+
vocabularyLoadPromise = undefined;
|
|
565
|
+
logException(error, {
|
|
566
|
+
location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
return vocabularyLoadPromise;
|
|
570
|
+
};
|
|
515
571
|
const logContextResolved = (source, context) => {
|
|
516
572
|
var _context$parentCommen, _context$siblingComme4, _context$siblingComme5;
|
|
517
573
|
if (!isAutocompleteDebugEnabled()) {
|
|
@@ -539,19 +595,10 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
539
595
|
...definedContext
|
|
540
596
|
};
|
|
541
597
|
const ingestContextText = text => {
|
|
542
|
-
if (!text ||
|
|
598
|
+
if (!text || sessionIngestedContextTexts.has(text)) {
|
|
543
599
|
return;
|
|
544
600
|
}
|
|
545
|
-
|
|
546
|
-
// Evict oldest entries (Set preserves insertion order) to bound memory.
|
|
547
|
-
while (ingestedContextTexts.size > MAX_INGESTED_CONTEXT_TEXTS) {
|
|
548
|
-
const oldest = ingestedContextTexts.values().next().value;
|
|
549
|
-
if (oldest === undefined) {
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
ingestedContextTexts.delete(oldest);
|
|
553
|
-
}
|
|
554
|
-
ingestDocumentPage(text);
|
|
601
|
+
addBoundedContextText(pendingSessionContextTexts, text);
|
|
555
602
|
};
|
|
556
603
|
ingestContextText(context.fullPageContent);
|
|
557
604
|
ingestContextText(context.parentCommentContent);
|
|
@@ -559,6 +606,7 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
559
606
|
var _context$siblingComme6;
|
|
560
607
|
ingestContextText(siblingCommentContent);
|
|
561
608
|
}
|
|
609
|
+
flushPendingSessionContext();
|
|
562
610
|
|
|
563
611
|
// Context arrived after word boundaries may already have fired. Re-send
|
|
564
612
|
// slow-lane context immediately so the next inference includes the thread.
|
|
@@ -962,18 +1010,11 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
962
1010
|
return accepted;
|
|
963
1011
|
},
|
|
964
1012
|
focus: () => {
|
|
965
|
-
var _options$
|
|
1013
|
+
var _options$useLocalMode2, _options$useLocalMode3;
|
|
966
1014
|
if (!isAutocompleteEnabled) {
|
|
967
1015
|
return false;
|
|
968
1016
|
}
|
|
969
|
-
|
|
970
|
-
isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
|
|
971
|
-
surface
|
|
972
|
-
}).catch(error => {
|
|
973
|
-
logException(error, {
|
|
974
|
-
location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
|
|
975
|
-
});
|
|
976
|
-
});
|
|
1017
|
+
void ensureVocabularyReady();
|
|
977
1018
|
loadVectorsAsync({
|
|
978
1019
|
isLocalLLM: (_options$useLocalMode2 = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode2 !== void 0 ? _options$useLocalMode2 : false,
|
|
979
1020
|
surface
|
|
@@ -1071,7 +1112,8 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
1071
1112
|
if (hasDestroy(slowLaneClient)) {
|
|
1072
1113
|
slowLaneClient.destroy();
|
|
1073
1114
|
}
|
|
1074
|
-
|
|
1115
|
+
pendingSessionContextTexts.clear();
|
|
1116
|
+
sessionIngestedContextTexts.clear();
|
|
1075
1117
|
}
|
|
1076
1118
|
};
|
|
1077
1119
|
}
|
|
@@ -89,7 +89,7 @@ const printLegend = verbose => {
|
|
|
89
89
|
// eslint-disable-next-line no-console
|
|
90
90
|
console.log('%cPlanes%c [CTC:init] loads · [CTC:signal] semantic/network · [CTC:model] primes/exact · [CTC:model-cost] prefill/decode · [CTC:readiness] deadline progress', CTC_STYLES.section, CTC_STYLES.body);
|
|
91
91
|
// eslint-disable-next-line no-console
|
|
92
|
-
console.log('%cInspect%c __atlCtcDebug__.enable("verbose") · .disable()', CTC_STYLES.section, CTC_STYLES.body);
|
|
92
|
+
console.log('%cInspect%c __atlCtcDebug__.enable("verbose") · .disable() · .session() (L1 boosts, narrow to a family with .session("poll"))', CTC_STYLES.section, CTC_STYLES.body);
|
|
93
93
|
// eslint-disable-next-line no-console
|
|
94
94
|
console.groupEnd();
|
|
95
95
|
};
|
|
@@ -133,5 +133,20 @@ export const isAutocompleteDebugVerbose = () => {
|
|
|
133
133
|
return (_getDebugApi$isVerbos = (_getDebugApi2 = getDebugApi()) === null || _getDebugApi2 === void 0 ? void 0 : _getDebugApi2.isVerbose()) !== null && _getDebugApi$isVerbos !== void 0 ? _getDebugApi$isVerbos : false;
|
|
134
134
|
};
|
|
135
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Hang the L1 session-boost snapshot off the console API.
|
|
138
|
+
*
|
|
139
|
+
* Unlike the log helpers this is available whether or not debug is enabled:
|
|
140
|
+
* inspecting state on demand is not logging, and asking someone to turn on
|
|
141
|
+
* logging and retype to find out what the session already holds defeats the
|
|
142
|
+
* point of being able to ask.
|
|
143
|
+
*/
|
|
144
|
+
export const registerCtcSessionInspector = inspect => {
|
|
145
|
+
const api = getDebugApi();
|
|
146
|
+
if (api) {
|
|
147
|
+
api.session = inspect;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
136
151
|
// Eagerly install so the console API is available on load, regardless of call order.
|
|
137
152
|
getDebugApi();
|
|
@@ -13,14 +13,17 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
13
13
|
* Falls back to cold mode (freq-only) when vectors not yet loaded.
|
|
14
14
|
*
|
|
15
15
|
* Session personalization (L1): words the user types are incrementally boosted
|
|
16
|
-
* via incrementSessionFreq(), called on word boundaries from the plugin
|
|
16
|
+
* via incrementSessionFreq(), called on word boundaries from the plugin, and
|
|
17
|
+
* words in ingested context text via ingestDocumentPage(). What the session has
|
|
18
|
+
* boosted is visible at any time from the console: `__atlCtcDebug__.session()`,
|
|
19
|
+
* or `__atlCtcDebug__.session('poll')` for one family — see inspectSessionBoosts.
|
|
17
20
|
*/
|
|
18
21
|
|
|
19
22
|
import { EXPERIENCE_NAME, failExp, startExp, succeedExp } from '../analytics/ufo';
|
|
20
23
|
import { fetchAutocompleteArtifactBinary, fetchAutocompleteArtifactJson } from './artifact-loader';
|
|
21
24
|
import { ARTIFACT_NAME } from './artifacts-manifest';
|
|
22
25
|
import { createCanonicalContextPositionCache, deriveCanonicalCandidateContext, deriveWhitespaceBoundaryContext, logSoftmaxAt, logSumExp, selectBoundaryPrimeRequests } from './canonical-lm-scoring';
|
|
23
|
-
import { CTC_STYLES, ctcSection, ctcTag, isAutocompleteDebugEnabled, isAutocompleteDebugVerbose } from './debug-mode';
|
|
26
|
+
import { CTC_STYLES, ctcSection, ctcTag, isAutocompleteDebugEnabled, isAutocompleteDebugVerbose, registerCtcSessionInspector } from './debug-mode';
|
|
24
27
|
import { loadGrammarDataAsync, rankCandidates, STAGE1_WEIGHT, STAGE2_WEIGHT, MIN_STAGE1_SCORE, MIN_WINNER_MARGIN } from './scoring-pipeline';
|
|
25
28
|
import { getBoundaryLmState, getCanonicalSurfaceCount, getCanonicalSurfaceTokenIds, getDefaultSlowLaneClientStatus, getProgressiveSurfaceEvidence, getStoredContextInput, getStoredContextVector, getStoredLmLogits, getSurfaceScore, isCanonicalSurfaceScoringSupported, primeBoundaryLm, requestProgressiveSurfaceScores } from './slow-lane-client';
|
|
26
29
|
|
|
@@ -298,6 +301,44 @@ class WeightedWordTrie {
|
|
|
298
301
|
node.sessionFreq += 1;
|
|
299
302
|
return true;
|
|
300
303
|
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Every word carrying a session boost, optionally limited to one prefix's
|
|
307
|
+
* subtree. Unlike `getCandidates` a word equal to the prefix is included,
|
|
308
|
+
* since the question here is what the session holds rather than what could
|
|
309
|
+
* still be typed.
|
|
310
|
+
*
|
|
311
|
+
* Walks the trie instead of reading an index, so nothing has to be kept in
|
|
312
|
+
* step on the write path for the sake of being able to ask.
|
|
313
|
+
*/
|
|
314
|
+
collectSessionBoosted(prefix = '') {
|
|
315
|
+
let node = this.root;
|
|
316
|
+
for (const char of prefix.toLowerCase()) {
|
|
317
|
+
const next = node.children.get(char);
|
|
318
|
+
if (!next) {
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
node = next;
|
|
322
|
+
}
|
|
323
|
+
const boosted = [];
|
|
324
|
+
const stack = [node];
|
|
325
|
+
while (stack.length > 0) {
|
|
326
|
+
const current = stack.pop();
|
|
327
|
+
if (!current) {
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (current.word !== null && current.sessionFreq > 0) {
|
|
331
|
+
boosted.push({
|
|
332
|
+
word: current.word,
|
|
333
|
+
node: current
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
for (const child of current.children.values()) {
|
|
337
|
+
stack.push(child);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return boosted;
|
|
341
|
+
}
|
|
301
342
|
}
|
|
302
343
|
|
|
303
344
|
// L1/L2 Trie (Session + Atlassian Domain)
|
|
@@ -672,7 +713,7 @@ export const ingestDocumentPage = pageContent => {
|
|
|
672
713
|
}
|
|
673
714
|
}
|
|
674
715
|
if (isAutocompleteDebugEnabled() && validBoostedWords.size > 0) {
|
|
675
|
-
ctcTag('init', `L1 session primed ${validBoostedWords.size} words from page`, CTC_STYLES.brand);
|
|
716
|
+
ctcTag('init', `L1 session primed ${validBoostedWords.size} words from page · __atlCtcDebug__.session() to inspect`, CTC_STYLES.brand);
|
|
676
717
|
if (isAutocompleteDebugVerbose()) {
|
|
677
718
|
// eslint-disable-next-line no-console
|
|
678
719
|
console.dir(Array.from(validBoostedWords).sort());
|
|
@@ -680,6 +721,53 @@ export const ingestDocumentPage = pageContent => {
|
|
|
680
721
|
}
|
|
681
722
|
};
|
|
682
723
|
|
|
724
|
+
/**
|
|
725
|
+
* How many boosted words `inspectSessionBoosts` lists.
|
|
726
|
+
*
|
|
727
|
+
* A page ingest can boost thousands, and a list that long is not read. The
|
|
728
|
+
* strongest boosts are the ones that change an ordering, and `boosted` still
|
|
729
|
+
* reports the full size, so the cap loses nothing but volume.
|
|
730
|
+
*/
|
|
731
|
+
const MAX_LISTED_SESSION_WORDS = 50;
|
|
732
|
+
/**
|
|
733
|
+
* Read the session's L1 boosts, optionally narrowed to a prefix.
|
|
734
|
+
*
|
|
735
|
+
* Installed as `__atlCtcDebug__.session()`, with `__atlCtcDebug__.session('poll')`
|
|
736
|
+
* to ask about one family. Returned rather than logged, so the console renders it
|
|
737
|
+
* as an inspectable object and a caller can assert on it.
|
|
738
|
+
*
|
|
739
|
+
* Only words the vocabulary already holds can carry a boost, because both writers
|
|
740
|
+
* go through `incrementSessionFreq` and it only finds existing nodes. An ingested
|
|
741
|
+
* word absent from the vocabulary is therefore missing from here and always will
|
|
742
|
+
* be.
|
|
743
|
+
*/
|
|
744
|
+
export const inspectSessionBoosts = prefix => {
|
|
745
|
+
const boosted = wordTrie.collectSessionBoosted(prefix !== null && prefix !== void 0 ? prefix : '');
|
|
746
|
+
return {
|
|
747
|
+
boosted: boosted.length,
|
|
748
|
+
limit: MAX_LISTED_SESSION_WORDS,
|
|
749
|
+
...(prefix === undefined ? {} : {
|
|
750
|
+
prefix
|
|
751
|
+
}),
|
|
752
|
+
words: boosted.sort((a, b) => b.node.sessionFreq - a.node.sessionFreq || a.word.localeCompare(b.word, 'en', {
|
|
753
|
+
numeric: true,
|
|
754
|
+
sensitivity: 'base'
|
|
755
|
+
})).slice(0, MAX_LISTED_SESSION_WORDS).map(({
|
|
756
|
+
node,
|
|
757
|
+
word
|
|
758
|
+
}) => ({
|
|
759
|
+
sessionFreq: node.sessionFreq,
|
|
760
|
+
sessionOnly: node.tenantFreq === 0,
|
|
761
|
+
surface: word,
|
|
762
|
+
tenantFreq: node.tenantFreq
|
|
763
|
+
}))
|
|
764
|
+
};
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
// At module scope so the console answers before the first keystroke, which is
|
|
768
|
+
// when someone reaching for it usually asks.
|
|
769
|
+
registerCtcSessionInspector(inspectSessionBoosts);
|
|
770
|
+
|
|
683
771
|
/**
|
|
684
772
|
* Result of a prediction: the ghost tail to insert plus an immutable record of
|
|
685
773
|
* the evidence that authorized the UI commitment.
|
|
@@ -509,7 +509,72 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
509
509
|
// Set when the plugin is torn down so in-flight getContext() resolutions don't
|
|
510
510
|
// mutate the global text-predictor state after destruction.
|
|
511
511
|
var destroyed = false;
|
|
512
|
-
|
|
512
|
+
// L1 ingestion cannot run before the vocabulary has loaded: `incrementSessionFreq`
|
|
513
|
+
// only touches trie nodes that already exist, so an empty trie silently rejects
|
|
514
|
+
// every word. Text that arrives first — which a page usually does, since the
|
|
515
|
+
// chat resolves it on focus in the same tick as the load starts — is held here
|
|
516
|
+
// and applied once the load has settled.
|
|
517
|
+
var pendingSessionContextTexts = new Set();
|
|
518
|
+
var sessionIngestedContextTexts = new Set();
|
|
519
|
+
var isVocabularyReady = false;
|
|
520
|
+
var vocabularyLoadPromise;
|
|
521
|
+
var addBoundedContextText = function addBoundedContextText(texts, text) {
|
|
522
|
+
texts.add(text);
|
|
523
|
+
// Evict oldest entries (Set preserves insertion order) to bound memory.
|
|
524
|
+
while (texts.size > MAX_INGESTED_CONTEXT_TEXTS) {
|
|
525
|
+
var oldest = texts.values().next().value;
|
|
526
|
+
if (oldest === undefined) {
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
texts.delete(oldest);
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
var flushPendingSessionContext = function flushPendingSessionContext() {
|
|
533
|
+
if (!isVocabularyReady || destroyed) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
var _iterator = _createForOfIteratorHelper(pendingSessionContextTexts),
|
|
537
|
+
_step;
|
|
538
|
+
try {
|
|
539
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
540
|
+
var text = _step.value;
|
|
541
|
+
if (!sessionIngestedContextTexts.has(text)) {
|
|
542
|
+
ingestDocumentPage(text);
|
|
543
|
+
addBoundedContextText(sessionIngestedContextTexts, text);
|
|
544
|
+
}
|
|
545
|
+
pendingSessionContextTexts.delete(text);
|
|
546
|
+
}
|
|
547
|
+
} catch (err) {
|
|
548
|
+
_iterator.e(err);
|
|
549
|
+
} finally {
|
|
550
|
+
_iterator.f();
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
var ensureVocabularyReady = function ensureVocabularyReady() {
|
|
554
|
+
var _options$useLocalMode;
|
|
555
|
+
if (isVocabularyReady) {
|
|
556
|
+
flushPendingSessionContext();
|
|
557
|
+
return Promise.resolve();
|
|
558
|
+
}
|
|
559
|
+
vocabularyLoadPromise !== null && vocabularyLoadPromise !== void 0 ? vocabularyLoadPromise : vocabularyLoadPromise = loadDefaultVocabulary({
|
|
560
|
+
isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
|
|
561
|
+
surface: surface
|
|
562
|
+
}).then(function () {
|
|
563
|
+
if (destroyed) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
isVocabularyReady = true;
|
|
567
|
+
flushPendingSessionContext();
|
|
568
|
+
}).catch(function (error) {
|
|
569
|
+
// Do not consume the pending text on failure. A later focus retries the
|
|
570
|
+
// load and can still apply the original context exactly once.
|
|
571
|
+
vocabularyLoadPromise = undefined;
|
|
572
|
+
logException(error, {
|
|
573
|
+
location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
return vocabularyLoadPromise;
|
|
577
|
+
};
|
|
513
578
|
var logContextResolved = function logContextResolved(source, context) {
|
|
514
579
|
var _context$parentCommen, _context$siblingComme4, _context$siblingComme5;
|
|
515
580
|
if (!isAutocompleteDebugEnabled()) {
|
|
@@ -539,37 +604,29 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
539
604
|
}));
|
|
540
605
|
resolvedContext = _objectSpread(_objectSpread({}, resolvedContext), definedContext);
|
|
541
606
|
var ingestContextText = function ingestContextText(text) {
|
|
542
|
-
if (!text ||
|
|
607
|
+
if (!text || sessionIngestedContextTexts.has(text)) {
|
|
543
608
|
return;
|
|
544
609
|
}
|
|
545
|
-
|
|
546
|
-
// Evict oldest entries (Set preserves insertion order) to bound memory.
|
|
547
|
-
while (ingestedContextTexts.size > MAX_INGESTED_CONTEXT_TEXTS) {
|
|
548
|
-
var oldest = ingestedContextTexts.values().next().value;
|
|
549
|
-
if (oldest === undefined) {
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
ingestedContextTexts.delete(oldest);
|
|
553
|
-
}
|
|
554
|
-
ingestDocumentPage(text);
|
|
610
|
+
addBoundedContextText(pendingSessionContextTexts, text);
|
|
555
611
|
};
|
|
556
612
|
ingestContextText(context.fullPageContent);
|
|
557
613
|
ingestContextText(context.parentCommentContent);
|
|
558
|
-
var
|
|
559
|
-
|
|
614
|
+
var _iterator2 = _createForOfIteratorHelper((_context$siblingComme6 = context.siblingCommentsContents) !== null && _context$siblingComme6 !== void 0 ? _context$siblingComme6 : []),
|
|
615
|
+
_step2;
|
|
560
616
|
try {
|
|
561
|
-
for (
|
|
562
|
-
var siblingCommentContent =
|
|
617
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
618
|
+
var siblingCommentContent = _step2.value;
|
|
563
619
|
ingestContextText(siblingCommentContent);
|
|
564
620
|
}
|
|
565
|
-
|
|
566
|
-
// Context arrived after word boundaries may already have fired. Re-send
|
|
567
|
-
// slow-lane context immediately so the next inference includes the thread.
|
|
568
621
|
} catch (err) {
|
|
569
|
-
|
|
622
|
+
_iterator2.e(err);
|
|
570
623
|
} finally {
|
|
571
|
-
|
|
624
|
+
_iterator2.f();
|
|
572
625
|
}
|
|
626
|
+
flushPendingSessionContext();
|
|
627
|
+
|
|
628
|
+
// Context arrived after word boundaries may already have fired. Re-send
|
|
629
|
+
// slow-lane context immediately so the next inference includes the thread.
|
|
573
630
|
if (currentView) {
|
|
574
631
|
slowLaneClient.updateContext(buildSlowLaneText(currentView.state.doc.textContent, resolvedContext));
|
|
575
632
|
}
|
|
@@ -960,18 +1017,11 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
960
1017
|
return accepted;
|
|
961
1018
|
},
|
|
962
1019
|
focus: function focus() {
|
|
963
|
-
var _options$
|
|
1020
|
+
var _options$useLocalMode2, _options$useLocalMode3;
|
|
964
1021
|
if (!isAutocompleteEnabled) {
|
|
965
1022
|
return false;
|
|
966
1023
|
}
|
|
967
|
-
|
|
968
|
-
isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
|
|
969
|
-
surface: surface
|
|
970
|
-
}).catch(function (error) {
|
|
971
|
-
logException(error, {
|
|
972
|
-
location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
|
|
973
|
-
});
|
|
974
|
-
});
|
|
1024
|
+
void ensureVocabularyReady();
|
|
975
1025
|
loadVectorsAsync({
|
|
976
1026
|
isLocalLLM: (_options$useLocalMode2 = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode2 !== void 0 ? _options$useLocalMode2 : false,
|
|
977
1027
|
surface: surface
|
|
@@ -1069,7 +1119,8 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
1069
1119
|
if (hasDestroy(slowLaneClient)) {
|
|
1070
1120
|
slowLaneClient.destroy();
|
|
1071
1121
|
}
|
|
1072
|
-
|
|
1122
|
+
pendingSessionContextTexts.clear();
|
|
1123
|
+
sessionIngestedContextTexts.clear();
|
|
1073
1124
|
}
|
|
1074
1125
|
};
|
|
1075
1126
|
}
|
|
@@ -90,7 +90,7 @@ var printLegend = function printLegend(verbose) {
|
|
|
90
90
|
// eslint-disable-next-line no-console
|
|
91
91
|
console.log('%cPlanes%c [CTC:init] loads · [CTC:signal] semantic/network · [CTC:model] primes/exact · [CTC:model-cost] prefill/decode · [CTC:readiness] deadline progress', CTC_STYLES.section, CTC_STYLES.body);
|
|
92
92
|
// eslint-disable-next-line no-console
|
|
93
|
-
console.log('%cInspect%c __atlCtcDebug__.enable("verbose") · .disable()', CTC_STYLES.section, CTC_STYLES.body);
|
|
93
|
+
console.log('%cInspect%c __atlCtcDebug__.enable("verbose") · .disable() · .session() (L1 boosts, narrow to a family with .session("poll"))', CTC_STYLES.section, CTC_STYLES.body);
|
|
94
94
|
// eslint-disable-next-line no-console
|
|
95
95
|
console.groupEnd();
|
|
96
96
|
};
|
|
@@ -138,5 +138,20 @@ export var isAutocompleteDebugVerbose = function isAutocompleteDebugVerbose() {
|
|
|
138
138
|
return (_getDebugApi$isVerbos = (_getDebugApi2 = getDebugApi()) === null || _getDebugApi2 === void 0 ? void 0 : _getDebugApi2.isVerbose()) !== null && _getDebugApi$isVerbos !== void 0 ? _getDebugApi$isVerbos : false;
|
|
139
139
|
};
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Hang the L1 session-boost snapshot off the console API.
|
|
143
|
+
*
|
|
144
|
+
* Unlike the log helpers this is available whether or not debug is enabled:
|
|
145
|
+
* inspecting state on demand is not logging, and asking someone to turn on
|
|
146
|
+
* logging and retype to find out what the session already holds defeats the
|
|
147
|
+
* point of being able to ask.
|
|
148
|
+
*/
|
|
149
|
+
export var registerCtcSessionInspector = function registerCtcSessionInspector(inspect) {
|
|
150
|
+
var api = getDebugApi();
|
|
151
|
+
if (api) {
|
|
152
|
+
api.session = inspect;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
141
156
|
// Eagerly install so the console API is available on load, regardless of call order.
|
|
142
157
|
getDebugApi();
|