@atlaskit/editor-plugin-autocomplete 8.0.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/dist/cjs/analytics/ufo.js +2 -1
- package/dist/cjs/pm-plugins/artifact-loader.js +135 -0
- package/dist/cjs/pm-plugins/artifacts-manifest.js +3 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +416 -129
- package/dist/cjs/pm-plugins/canonical-lm-scoring.js +371 -0
- package/dist/cjs/pm-plugins/debug-mode.js +90 -7
- package/dist/cjs/pm-plugins/ghost-text-decoration.js +12 -3
- package/dist/cjs/pm-plugins/local-slow-lane-client.js +1202 -453
- package/dist/cjs/pm-plugins/scoring-pipeline.js +164 -19
- package/dist/cjs/pm-plugins/slow-lane-client.js +100 -37
- package/dist/cjs/pm-plugins/text-predictor.js +1951 -273
- package/dist/es2019/analytics/ufo.js +2 -0
- package/dist/es2019/pm-plugins/artifact-loader.js +70 -0
- package/dist/es2019/pm-plugins/artifacts-manifest.js +3 -0
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +425 -130
- package/dist/es2019/pm-plugins/canonical-lm-scoring.js +270 -0
- package/dist/es2019/pm-plugins/debug-mode.js +87 -7
- package/dist/es2019/pm-plugins/ghost-text-decoration.js +12 -3
- package/dist/es2019/pm-plugins/local-slow-lane-client.js +940 -326
- package/dist/es2019/pm-plugins/scoring-pipeline.js +137 -13
- package/dist/es2019/pm-plugins/slow-lane-client.js +94 -37
- package/dist/es2019/pm-plugins/text-predictor.js +1603 -199
- package/dist/esm/analytics/ufo.js +2 -1
- package/dist/esm/pm-plugins/artifact-loader.js +128 -0
- package/dist/esm/pm-plugins/artifacts-manifest.js +3 -0
- package/dist/esm/pm-plugins/autocomplete-plugin.js +419 -132
- package/dist/esm/pm-plugins/canonical-lm-scoring.js +364 -0
- package/dist/esm/pm-plugins/debug-mode.js +89 -6
- package/dist/esm/pm-plugins/ghost-text-decoration.js +12 -3
- package/dist/esm/pm-plugins/local-slow-lane-client.js +1200 -451
- package/dist/esm/pm-plugins/scoring-pipeline.js +163 -18
- package/dist/esm/pm-plugins/slow-lane-client.js +100 -37
- package/dist/esm/pm-plugins/text-predictor.js +1953 -277
- package/dist/types/analytics/ufo.d.ts +1 -0
- package/dist/types/pm-plugins/artifact-loader.d.ts +44 -0
- package/dist/types/pm-plugins/artifacts-manifest.d.ts +3 -0
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +39 -0
- package/dist/types/pm-plugins/canonical-lm-scoring.d.ts +158 -0
- package/dist/types/pm-plugins/debug-mode.d.ts +36 -1
- package/dist/types/pm-plugins/ghost-text-decoration.d.ts +5 -2
- package/dist/types/pm-plugins/local-slow-lane-client.d.ts +87 -54
- package/dist/types/pm-plugins/scoring-pipeline.d.ts +33 -1
- package/dist/types/pm-plugins/slow-lane-client.d.ts +51 -3
- package/dist/types/pm-plugins/text-predictor.d.ts +120 -2
- package/package.json +2 -2
- package/src/analytics/ufo.ts +5 -0
- package/src/pm-plugins/artifact-loader.ts +92 -0
- package/src/pm-plugins/artifacts-manifest.ts +3 -0
- package/src/pm-plugins/autocomplete-plugin.ts +517 -133
- package/src/pm-plugins/canonical-lm-scoring.ts +412 -0
- package/src/pm-plugins/debug-mode.ts +109 -7
- package/src/pm-plugins/ghost-text-decoration.ts +13 -4
- package/src/pm-plugins/local-slow-lane-client.ts +1302 -386
- package/src/pm-plugins/scoring-pipeline.ts +167 -17
- package/src/pm-plugins/slow-lane-client.ts +147 -62
- package/src/pm-plugins/text-predictor.ts +2006 -255
- package/CANONICAL_FIX__DO_NOT_USE_ME_A/package.json +0 -8
- package/CANONICAL_FIX__DO_NOT_USE_ME_B/package.json +0 -8
- package/CANONICAL_FIX__DO_NOT_USE_ME_C/package.json +0 -8
- package/dist/cjs/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -18
- package/dist/cjs/entry-points/src-pm-plugins-slow-lane-client.js +0 -36
- package/dist/cjs/entry-points/src-pm-plugins-text-predictor.js +0 -66
- package/dist/es2019/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
- package/dist/es2019/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
- package/dist/es2019/entry-points/src-pm-plugins-text-predictor.js +0 -2
- package/dist/esm/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
- package/dist/esm/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
- package/dist/esm/entry-points/src-pm-plugins-text-predictor.js +0 -2
- package/dist/types/entry-points/src-pm-plugins-autocomplete-plugin.d.ts +0 -2
- package/dist/types/entry-points/src-pm-plugins-slow-lane-client.d.ts +0 -2
- package/dist/types/entry-points/src-pm-plugins-text-predictor.d.ts +0 -2
- package/scripts/gen_first_token_to_words.py +0 -170
- package/src/entry-points/src-pm-plugins-autocomplete-plugin.ts +0 -7
- package/src/entry-points/src-pm-plugins-slow-lane-client.ts +0 -13
- package/src/entry-points/src-pm-plugins-text-predictor.ts +0 -14
- package/src/pm-plugins/autocomplete-plugin/package.json +0 -8
- package/src/pm-plugins/slow-lane-client/package.json +0 -8
- package/src/pm-plugins/text-predictor/package.json +0 -8
|
@@ -14,6 +14,11 @@ import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
|
14
14
|
|
|
15
15
|
// ─── Types ──────────────────────────────────────────────────
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* A completion term is `(term, termType)`. `word` is the v1 default; `bigram`
|
|
19
|
+
* (2 tokens) and `phrase` (3 tokens) are multi-word units mined by the producer.
|
|
20
|
+
*/
|
|
21
|
+
|
|
17
22
|
/** Metadata returned by the grammar filter for debug logging in the caller. */
|
|
18
23
|
|
|
19
24
|
// ─── Scoring Constants ──────────────────────────────────────
|
|
@@ -21,9 +26,25 @@ import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
|
21
26
|
const ALPHA = 0.5;
|
|
22
27
|
const BETA = 0.5;
|
|
23
28
|
const NEUTRAL_SCORE = 0.5;
|
|
29
|
+
// Multiplicative Stage-1 boost applied to a multi-word term proportional to its
|
|
30
|
+
// (clamped [0,1]) NPMI association, so a strongly-collocated phrase outranks a
|
|
31
|
+
// coincidental word sequence of comparable freq/semantics. Tunable.
|
|
32
|
+
const ASSOCIATION_BOOST = 0.5;
|
|
24
33
|
export const STAGE1_WEIGHT = 0.35;
|
|
25
34
|
export const STAGE2_WEIGHT = 0.65;
|
|
26
35
|
export const MIN_STAGE1_SCORE = 0.35;
|
|
36
|
+
/**
|
|
37
|
+
* How far the leading candidate must sit above the runner-up on the blended
|
|
38
|
+
* score before a ghost is committed.
|
|
39
|
+
*
|
|
40
|
+
* Lives beside the weights it is measured in, because it is only meaningful on
|
|
41
|
+
* that scale — and because both the arbitration that applies it and the
|
|
42
|
+
* scheduler that decides when reading more tokens can no longer change the
|
|
43
|
+
* outcome have to use the same number. When those two drifted apart, the
|
|
44
|
+
* scheduler stopped early on a margin the arbitration did not recognise and the
|
|
45
|
+
* abstention that followed was invisible from either side.
|
|
46
|
+
*/
|
|
47
|
+
export const MIN_WINNER_MARGIN = 0.08;
|
|
27
48
|
const L1_SESSION_CAP = 1.2;
|
|
28
49
|
// Minimum prefix-payload max LM probability before Stage 2 activates.
|
|
29
50
|
// Below this threshold the LM signal is too weak to suppress Stage 1 — finalScore
|
|
@@ -42,13 +63,32 @@ let posTags = new Map();
|
|
|
42
63
|
* without suggesting these words to the user.
|
|
43
64
|
*/
|
|
44
65
|
let ghostPosTags = {};
|
|
66
|
+
let grammarDataPromise;
|
|
45
67
|
|
|
46
68
|
/**
|
|
47
69
|
* Precomputed map from each POS tag to the set of allowed next POS tags, so
|
|
48
70
|
* applyGrammarFilter never re-iterates the transition rules per call.
|
|
49
71
|
*/
|
|
50
72
|
let precomputedAllowedByPos = new Map();
|
|
51
|
-
|
|
73
|
+
const isPosTagsRecord = payload => {
|
|
74
|
+
if (payload == null || typeof payload !== 'object') {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return Object.values(payload).every(value => Array.isArray(value) && value.every(entry => typeof entry === 'string'));
|
|
78
|
+
};
|
|
79
|
+
const isGrammarTransitions = payload => {
|
|
80
|
+
if (payload == null || typeof payload !== 'object') {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const transitions = payload.transitions;
|
|
84
|
+
if (transitions == null || typeof transitions !== 'object') {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return Object.values(transitions).every(value => {
|
|
88
|
+
const allowed = value === null || value === void 0 ? void 0 : value.allowed;
|
|
89
|
+
return Array.isArray(allowed) && allowed.every(entry => typeof entry === 'string');
|
|
90
|
+
});
|
|
91
|
+
};
|
|
52
92
|
const setGrammarData = data => {
|
|
53
93
|
var _data$grammarTransiti;
|
|
54
94
|
posTags = new Map(Object.entries(data.posTags));
|
|
@@ -79,12 +119,24 @@ export const loadGrammarDataAsync = options => {
|
|
|
79
119
|
});
|
|
80
120
|
try {
|
|
81
121
|
const [posTagsData, ghostPosTagsData, grammarTransitionsData] = await Promise.all([fetchArtifactJson(ARTIFACT_NAME.POS_TAGS), fetchArtifactJson(ARTIFACT_NAME.GHOST_POS_TAGS), fetchArtifactJson(ARTIFACT_NAME.GRAMMAR_TRANSITIONS)]);
|
|
122
|
+
|
|
123
|
+
// A missing wrapper and a malformed ruleset are reported separately: the
|
|
124
|
+
// first points at the publishing step, the second at the payload itself.
|
|
82
125
|
if ((grammarTransitionsData === null || grammarTransitionsData === void 0 ? void 0 : grammarTransitionsData.transitions) == null) {
|
|
83
126
|
throw new Error(`[scoring-pipeline] ${ARTIFACT_NAME.GRAMMAR_TRANSITIONS} is missing its \`transitions\` wrapper`);
|
|
84
127
|
}
|
|
128
|
+
if (!isGrammarTransitions(grammarTransitionsData)) {
|
|
129
|
+
throw new Error(`[scoring-pipeline] ${ARTIFACT_NAME.GRAMMAR_TRANSITIONS} payload shape was invalid`);
|
|
130
|
+
}
|
|
131
|
+
if (!isPosTagsRecord(posTagsData)) {
|
|
132
|
+
throw new Error(`[scoring-pipeline] ${ARTIFACT_NAME.POS_TAGS} payload shape was invalid`);
|
|
133
|
+
}
|
|
134
|
+
if (!isPosTagsRecord(ghostPosTagsData)) {
|
|
135
|
+
throw new Error(`[scoring-pipeline] ${ARTIFACT_NAME.GHOST_POS_TAGS} payload shape was invalid`);
|
|
136
|
+
}
|
|
85
137
|
setGrammarData({
|
|
86
|
-
posTags: posTagsData
|
|
87
|
-
ghostPosTags: ghostPosTagsData
|
|
138
|
+
posTags: posTagsData,
|
|
139
|
+
ghostPosTags: ghostPosTagsData,
|
|
88
140
|
grammarTransitions: grammarTransitionsData
|
|
89
141
|
});
|
|
90
142
|
succeedExp(EXPERIENCE_NAME.LOAD_GRAMMAR, 'singleton', {
|
|
@@ -198,7 +250,16 @@ function applyGrammarFilter(candidates, previousWord) {
|
|
|
198
250
|
const filtered = [];
|
|
199
251
|
const dropped = [];
|
|
200
252
|
for (const entry of candidates) {
|
|
201
|
-
|
|
253
|
+
// The producer validates a multi-word term's *internal* grammar offline
|
|
254
|
+
// (boundary-clean, noun-headed, AUP-passed — spec §9), but nothing judges
|
|
255
|
+
// the transition into it. Exempting multi-word terms therefore let a noun
|
|
256
|
+
// this filter had just rejected re-enter wrapped in a bigram — "be" [AUX]
|
|
257
|
+
// dropped "quality" and then displayed "quality assurance". Only the term's
|
|
258
|
+
// first word takes part in the transition, so gate every term on that.
|
|
259
|
+
const surface = entry.candidate.word;
|
|
260
|
+
const firstSpace = surface.indexOf(' ');
|
|
261
|
+
const transitionWord = firstSpace === -1 ? surface : surface.slice(0, firstSpace);
|
|
262
|
+
const candidateTags = posTags.get(transitionWord.toLowerCase());
|
|
202
263
|
|
|
203
264
|
// If candidate has no tags (unknown word), let it pass to be safe
|
|
204
265
|
if (!candidateTags || candidateTags.length === 0) {
|
|
@@ -239,20 +300,35 @@ function getLmScore(word, lmLogits) {
|
|
|
239
300
|
|
|
240
301
|
// ─── Public API ─────────────────────────────────────────────
|
|
241
302
|
|
|
242
|
-
|
|
303
|
+
/**
|
|
304
|
+
* Apply Stage 1, grammar, and nullable context-local LM evidence to candidates.
|
|
305
|
+
*/
|
|
306
|
+
export function rankCandidates(candidates, contextVector, getWordVector, lmLogits, maxFreqByType, previousWord, getCanonicalLmEvidence) {
|
|
243
307
|
var _grammarMeta$dropped;
|
|
244
308
|
// Stage 1
|
|
245
309
|
const stage1Results = candidates.map(candidate => {
|
|
310
|
+
var _candidate$termType;
|
|
311
|
+
const termType = (_candidate$termType = candidate.termType) !== null && _candidate$termType !== void 0 ? _candidate$termType : 'word';
|
|
312
|
+
// Normalize freq within the candidate's own term-type population so a
|
|
313
|
+
// phrase (whose absolute counts are far below top unigrams) isn't crushed
|
|
314
|
+
// by the unigram max.
|
|
315
|
+
const maxFreq = maxFreqByType[termType] || 1;
|
|
246
316
|
const {
|
|
247
317
|
semanticScore,
|
|
248
318
|
freqScore,
|
|
249
319
|
stage1Score
|
|
250
|
-
} = scoreStage1(candidate, contextVector, getWordVector,
|
|
320
|
+
} = scoreStage1(candidate, contextVector, getWordVector, maxFreq);
|
|
321
|
+
// Multi-word units get an NPMI association boost (Stage-1 only).
|
|
322
|
+
let adjustedStage1 = stage1Score;
|
|
323
|
+
if (termType !== 'word' && typeof candidate.association === 'number') {
|
|
324
|
+
const assoc = Math.max(0, Math.min(1, candidate.association));
|
|
325
|
+
adjustedStage1 = stage1Score * (1 + ASSOCIATION_BOOST * assoc);
|
|
326
|
+
}
|
|
251
327
|
return {
|
|
252
328
|
candidate,
|
|
253
329
|
semanticScore,
|
|
254
330
|
freqScore,
|
|
255
|
-
stage1Score
|
|
331
|
+
stage1Score: adjustedStage1
|
|
256
332
|
};
|
|
257
333
|
});
|
|
258
334
|
const stage1Survivors = [];
|
|
@@ -277,26 +353,74 @@ export function rankCandidates(candidates, contextVector, getWordVector, lmLogit
|
|
|
277
353
|
const values = Object.values(lmLogits);
|
|
278
354
|
if (values.length > 0) lmMax = Math.max(...values);
|
|
279
355
|
}
|
|
356
|
+
const canonicalEvidenceBySurface = new Map();
|
|
357
|
+
const maxLmRankingValueByTierAndContext = new Map();
|
|
358
|
+
for (const entry of filtered) {
|
|
359
|
+
var _getCanonicalLmEviden;
|
|
360
|
+
const evidence = (_getCanonicalLmEviden = getCanonicalLmEvidence === null || getCanonicalLmEvidence === void 0 ? void 0 : getCanonicalLmEvidence(entry.candidate.word)) !== null && _getCanonicalLmEviden !== void 0 ? _getCanonicalLmEviden : null;
|
|
361
|
+
if (!evidence) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
canonicalEvidenceBySurface.set(entry.candidate.word, evidence);
|
|
365
|
+
const rankingValue = evidence.source === 'canonical-full-surface' ? evidence.meanTokenLogProbability : evidence.rawLogit;
|
|
366
|
+
if (rankingValue !== undefined && Number.isFinite(rankingValue)) {
|
|
367
|
+
var _maxLmRankingValueByT;
|
|
368
|
+
const key = `${evidence.source}\u0000${evidence.contextKey}`;
|
|
369
|
+
const current = (_maxLmRankingValueByT = maxLmRankingValueByTierAndContext.get(key)) !== null && _maxLmRankingValueByT !== void 0 ? _maxLmRankingValueByT : -Infinity;
|
|
370
|
+
if (rankingValue > current) {
|
|
371
|
+
maxLmRankingValueByTierAndContext.set(key, rankingValue);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
280
375
|
const scored = filtered.map(entry => {
|
|
376
|
+
var _entry$candidate$term, _canonicalEvidenceByS;
|
|
377
|
+
const termType = (_entry$candidate$term = entry.candidate.termType) !== null && _entry$candidate$term !== void 0 ? _entry$candidate$term : 'word';
|
|
378
|
+
const isMultiWord = termType !== 'word';
|
|
281
379
|
let lmScore = 0;
|
|
282
380
|
let finalScore = entry.stage1Score;
|
|
283
|
-
|
|
381
|
+
let lmEvidence = (_canonicalEvidenceByS = canonicalEvidenceBySurface.get(entry.candidate.word)) !== null && _canonicalEvidenceByS !== void 0 ? _canonicalEvidenceByS : null;
|
|
382
|
+
if (lmEvidence) {
|
|
383
|
+
const rankingValue = lmEvidence.source === 'canonical-full-surface' ? lmEvidence.meanTokenLogProbability : lmEvidence.rawLogit;
|
|
384
|
+
const maxRankingValue = maxLmRankingValueByTierAndContext.get(`${lmEvidence.source}\u0000${lmEvidence.contextKey}`);
|
|
385
|
+
if (rankingValue !== undefined && maxRankingValue !== undefined) {
|
|
386
|
+
lmEvidence = {
|
|
387
|
+
...lmEvidence,
|
|
388
|
+
score: Math.exp(rankingValue - maxRankingValue)
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (lmEvidence) {
|
|
393
|
+
lmScore = lmEvidence.score;
|
|
394
|
+
finalScore = STAGE1_WEIGHT * entry.stage1Score + STAGE2_WEIGHT * lmScore;
|
|
395
|
+
} else if (!isMultiWord && lmLogits && lmMax >= LM_GATE_THRESHOLD) {
|
|
396
|
+
// Backward-compatible network slow-lane path.
|
|
284
397
|
const rawLm = getLmScore(entry.candidate.word, lmLogits);
|
|
285
398
|
if (rawLm !== 0) {
|
|
286
399
|
const logitDiff = Math.log(rawLm) - Math.log(lmMax);
|
|
287
400
|
lmScore = Math.exp(logitDiff);
|
|
401
|
+
lmEvidence = {
|
|
402
|
+
contextKey: 'network',
|
|
403
|
+
score: lmScore,
|
|
404
|
+
separatorKind: 'whitespace',
|
|
405
|
+
source: 'network-logit',
|
|
406
|
+
totalSurfaceCharCount: entry.candidate.word.length,
|
|
407
|
+
// The legacy BE word map does not report canonical token depth.
|
|
408
|
+
totalTokenCount: 0,
|
|
409
|
+
verifiedCharCount: 0,
|
|
410
|
+
verifiedTokenCount: 0
|
|
411
|
+
};
|
|
412
|
+
finalScore = STAGE1_WEIGHT * entry.stage1Score + STAGE2_WEIGHT * lmScore;
|
|
288
413
|
}
|
|
289
|
-
// Words absent from the prefix-filtered payload get lmScore = 0,
|
|
290
|
-
// not 0.05, so they don't outrank genuine LM predictions.
|
|
291
|
-
|
|
292
|
-
finalScore = STAGE1_WEIGHT * entry.stage1Score + STAGE2_WEIGHT * lmScore;
|
|
293
414
|
}
|
|
294
415
|
return {
|
|
295
416
|
word: entry.candidate.word,
|
|
296
417
|
freqScore: entry.freqScore,
|
|
297
418
|
semanticScore: entry.semanticScore,
|
|
298
419
|
lmScore,
|
|
299
|
-
|
|
420
|
+
lmEvidence,
|
|
421
|
+
finalScore,
|
|
422
|
+
stage1Score: entry.stage1Score,
|
|
423
|
+
termType
|
|
300
424
|
};
|
|
301
425
|
});
|
|
302
426
|
scored.sort((a, b) => {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { abortExp, EXPERIENCE_NAME, failExp, startExp, succeedExp } from '../analytics/ufo';
|
|
11
|
-
import {
|
|
11
|
+
import { buildAutocompleteGatewayUrl } from './artifact-loader';
|
|
12
|
+
import { CTC_STYLES, ctcTag } from './debug-mode';
|
|
12
13
|
|
|
13
14
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
14
15
|
|
|
@@ -20,8 +21,6 @@ import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
|
20
21
|
|
|
21
22
|
// eslint-disable-next-line require-unicode-regexp
|
|
22
23
|
const WORD_BOUNDARY_CHARS = /[\s.,;:!?]/;
|
|
23
|
-
// eslint-disable-next-line require-unicode-regexp
|
|
24
|
-
const TRAILING_SLASH_REGEX = /\/$/;
|
|
25
24
|
const DEFAULT_DEBOUNCE_MS = 300;
|
|
26
25
|
|
|
27
26
|
/**
|
|
@@ -56,6 +55,7 @@ export const createSlowLaneClient = config => {
|
|
|
56
55
|
};
|
|
57
56
|
let debounceTimer = null;
|
|
58
57
|
let lastRequestedText = '';
|
|
58
|
+
let storedContextInput = null;
|
|
59
59
|
let storedContextVector = null;
|
|
60
60
|
let storedLmLogits = null;
|
|
61
61
|
let requestSeq = 0;
|
|
@@ -64,7 +64,7 @@ export const createSlowLaneClient = config => {
|
|
|
64
64
|
if (!text || text.trim().length === 0) {
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
|
-
const url =
|
|
67
|
+
const url = buildAutocompleteGatewayUrl(endpoint, baseUrl);
|
|
68
68
|
const payload = {
|
|
69
69
|
text,
|
|
70
70
|
session_id: sessionId
|
|
@@ -76,16 +76,7 @@ export const createSlowLaneClient = config => {
|
|
|
76
76
|
surface
|
|
77
77
|
} : {})
|
|
78
78
|
});
|
|
79
|
-
|
|
80
|
-
// eslint-disable-next-line no-console
|
|
81
|
-
console.groupCollapsed(`%c[SlowLane] %c📤 Sending context | ${text.length} chars`, 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
82
|
-
text.split('\n').forEach((line, i, arr) => {
|
|
83
|
-
// eslint-disable-next-line no-console
|
|
84
|
-
console.log(` ${i === arr.length - 1 ? '▶' : ' '} ${line}`);
|
|
85
|
-
});
|
|
86
|
-
// eslint-disable-next-line no-console
|
|
87
|
-
console.groupEnd();
|
|
88
|
-
}
|
|
79
|
+
ctcTag('signal', `📤 network context sent · ${text.length} chars`, CTC_STYLES.section);
|
|
89
80
|
try {
|
|
90
81
|
const res = await fetchFn(url, {
|
|
91
82
|
method: 'POST',
|
|
@@ -93,6 +84,7 @@ export const createSlowLaneClient = config => {
|
|
|
93
84
|
body: JSON.stringify(payload)
|
|
94
85
|
});
|
|
95
86
|
if (!res.ok) {
|
|
87
|
+
storedContextInput = null;
|
|
96
88
|
storedContextVector = null;
|
|
97
89
|
storedLmLogits = null;
|
|
98
90
|
failExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
@@ -103,33 +95,23 @@ export const createSlowLaneClient = config => {
|
|
|
103
95
|
surface
|
|
104
96
|
} : {})
|
|
105
97
|
});
|
|
106
|
-
|
|
107
|
-
// eslint-disable-next-line no-console
|
|
108
|
-
console.log(`%c[SlowLane] %c❌ Request failed (${res.status})`, 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
109
|
-
}
|
|
98
|
+
ctcTag('signal', `❌ network request failed (${res.status})`, CTC_STYLES.bad);
|
|
110
99
|
return;
|
|
111
100
|
}
|
|
112
101
|
const data = await res.json();
|
|
113
102
|
if (data.semantic_vector && Array.isArray(data.semantic_vector)) {
|
|
114
103
|
storedContextVector = new Float32Array(data.semantic_vector);
|
|
104
|
+
storedContextInput = text;
|
|
115
105
|
} else {
|
|
116
106
|
storedContextVector = null;
|
|
107
|
+
storedContextInput = null;
|
|
117
108
|
}
|
|
118
109
|
if (data.lm_logits && typeof data.lm_logits === 'object') {
|
|
119
110
|
storedLmLogits = data.lm_logits;
|
|
120
111
|
} else {
|
|
121
112
|
storedLmLogits = null;
|
|
122
113
|
}
|
|
123
|
-
|
|
124
|
-
// eslint-disable-next-line no-console
|
|
125
|
-
console.groupCollapsed(`%c[SlowLane] %c📥 Response received`, 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
126
|
-
// eslint-disable-next-line no-console
|
|
127
|
-
console.log(storedContextVector ? `✅ semantic_vector: ${storedContextVector.length} dims` : '❌ No semantic_vector');
|
|
128
|
-
// eslint-disable-next-line no-console
|
|
129
|
-
console.log(storedLmLogits ? `✅ lm_logits: ${Object.keys(storedLmLogits).length} tokens` : '❌ No lm_logits');
|
|
130
|
-
// eslint-disable-next-line no-console
|
|
131
|
-
console.groupEnd();
|
|
132
|
-
}
|
|
114
|
+
ctcTag('signal', `📥 network response · ${storedContextVector ? `semantic ✅ ${storedContextVector.length}d` : 'semantic ❌'} · ${storedLmLogits ? `logits ✅ ${Object.keys(storedLmLogits).length}tok` : 'logits ❌'}`, CTC_STYLES.section);
|
|
133
115
|
succeedExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
134
116
|
textLength: text.length,
|
|
135
117
|
hasVector: storedContextVector !== null,
|
|
@@ -146,6 +128,7 @@ export const createSlowLaneClient = config => {
|
|
|
146
128
|
});
|
|
147
129
|
// eslint-disable-next-line no-unused-vars
|
|
148
130
|
} catch (e) {
|
|
131
|
+
storedContextInput = null;
|
|
149
132
|
storedContextVector = null;
|
|
150
133
|
storedLmLogits = null;
|
|
151
134
|
failExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
@@ -155,10 +138,7 @@ export const createSlowLaneClient = config => {
|
|
|
155
138
|
surface
|
|
156
139
|
} : {})
|
|
157
140
|
});
|
|
158
|
-
|
|
159
|
-
// eslint-disable-next-line no-console
|
|
160
|
-
console.log('%c[SlowLane] %c❌ Network error — context cleared', 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
161
|
-
}
|
|
141
|
+
ctcTag('signal', '❌ network error — context cleared', CTC_STYLES.bad);
|
|
162
142
|
} finally {
|
|
163
143
|
if (inflightRequestId === requestId) {
|
|
164
144
|
inflightRequestId = null;
|
|
@@ -187,9 +167,11 @@ export const createSlowLaneClient = config => {
|
|
|
187
167
|
};
|
|
188
168
|
return {
|
|
189
169
|
updateContext: updateContextDebounced,
|
|
170
|
+
getContextInput: () => storedContextInput,
|
|
190
171
|
getContextVector: () => storedContextVector,
|
|
191
172
|
getLmLogits: () => storedLmLogits,
|
|
192
173
|
setContextVector: vector => {
|
|
174
|
+
storedContextInput = null;
|
|
193
175
|
storedContextVector = vector;
|
|
194
176
|
},
|
|
195
177
|
setLmLogits: logits => {
|
|
@@ -199,14 +181,89 @@ export const createSlowLaneClient = config => {
|
|
|
199
181
|
};
|
|
200
182
|
};
|
|
201
183
|
let defaultSlowLaneClient = null;
|
|
202
|
-
|
|
184
|
+
let defaultSlowLaneClientRegistration = null;
|
|
185
|
+
const supportsCanonicalSurfaceScoring = client => typeof (client === null || client === void 0 ? void 0 : client.primeBoundaryLm) === 'function' && typeof (client === null || client === void 0 ? void 0 : client.requestProgressiveSurfaceScores) === 'function';
|
|
186
|
+
export const setDefaultSlowLaneClient = (client, registration) => {
|
|
203
187
|
defaultSlowLaneClient = client;
|
|
188
|
+
defaultSlowLaneClientRegistration = client ? registration !== null && registration !== void 0 ? registration : {
|
|
189
|
+
clientId: 'untracked',
|
|
190
|
+
kind: supportsCanonicalSurfaceScoring(client) ? 'localLlm' : 'server'
|
|
191
|
+
} : null;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Clear the shared client only when the caller still owns the registration.
|
|
196
|
+
*
|
|
197
|
+
* Multiple editor instances can briefly overlap during a React/editor remount.
|
|
198
|
+
* An older instance must not disconnect the newer instance when its delayed
|
|
199
|
+
* teardown runs after the newer client has registered.
|
|
200
|
+
*/
|
|
201
|
+
export const clearDefaultSlowLaneClient = client => {
|
|
202
|
+
if (defaultSlowLaneClient !== client) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
defaultSlowLaneClient = null;
|
|
206
|
+
defaultSlowLaneClientRegistration = null;
|
|
207
|
+
return true;
|
|
208
|
+
};
|
|
209
|
+
export const getDefaultSlowLaneClientStatus = () => {
|
|
210
|
+
var _defaultSlowLaneClien, _defaultSlowLaneClien2, _defaultSlowLaneClien3, _defaultSlowLaneClien4, _defaultSlowLaneClien5, _defaultSlowLaneClien6, _defaultSlowLaneClien7;
|
|
211
|
+
const canonicalScoringSupported = supportsCanonicalSurfaceScoring(defaultSlowLaneClient);
|
|
212
|
+
const isLocalClient = ((_defaultSlowLaneClien = defaultSlowLaneClientRegistration) === null || _defaultSlowLaneClien === void 0 ? void 0 : _defaultSlowLaneClien.kind) === 'localLlm';
|
|
213
|
+
return {
|
|
214
|
+
registered: defaultSlowLaneClient !== null,
|
|
215
|
+
clientId: (_defaultSlowLaneClien2 = (_defaultSlowLaneClien3 = defaultSlowLaneClientRegistration) === null || _defaultSlowLaneClien3 === void 0 ? void 0 : _defaultSlowLaneClien3.clientId) !== null && _defaultSlowLaneClien2 !== void 0 ? _defaultSlowLaneClien2 : null,
|
|
216
|
+
clientKind: (_defaultSlowLaneClien4 = (_defaultSlowLaneClien5 = defaultSlowLaneClientRegistration) === null || _defaultSlowLaneClien5 === void 0 ? void 0 : _defaultSlowLaneClien5.kind) !== null && _defaultSlowLaneClien4 !== void 0 ? _defaultSlowLaneClien4 : null,
|
|
217
|
+
canonicalScoringSupported,
|
|
218
|
+
localModelReady: isLocalClient && typeof ((_defaultSlowLaneClien6 = defaultSlowLaneClient) === null || _defaultSlowLaneClien6 === void 0 ? void 0 : _defaultSlowLaneClien6.isReady) === 'function' ? defaultSlowLaneClient.isReady() : null,
|
|
219
|
+
canonicalSurfaceCount: canonicalScoringSupported && typeof ((_defaultSlowLaneClien7 = defaultSlowLaneClient) === null || _defaultSlowLaneClien7 === void 0 ? void 0 : _defaultSlowLaneClien7.getCanonicalSurfaceCount) === 'function' ? defaultSlowLaneClient.getCanonicalSurfaceCount() : null
|
|
220
|
+
};
|
|
204
221
|
};
|
|
205
222
|
export const getStoredContextVector = () => {
|
|
206
|
-
var
|
|
207
|
-
return (
|
|
223
|
+
var _defaultSlowLaneClien8, _defaultSlowLaneClien9;
|
|
224
|
+
return (_defaultSlowLaneClien8 = (_defaultSlowLaneClien9 = defaultSlowLaneClient) === null || _defaultSlowLaneClien9 === void 0 ? void 0 : _defaultSlowLaneClien9.getContextVector()) !== null && _defaultSlowLaneClien8 !== void 0 ? _defaultSlowLaneClien8 : null;
|
|
225
|
+
};
|
|
226
|
+
export const getStoredContextInput = () => {
|
|
227
|
+
var _defaultSlowLaneClien0, _defaultSlowLaneClien1, _defaultSlowLaneClien10;
|
|
228
|
+
return (_defaultSlowLaneClien0 = (_defaultSlowLaneClien1 = defaultSlowLaneClient) === null || _defaultSlowLaneClien1 === void 0 ? void 0 : (_defaultSlowLaneClien10 = _defaultSlowLaneClien1.getContextInput) === null || _defaultSlowLaneClien10 === void 0 ? void 0 : _defaultSlowLaneClien10.call(_defaultSlowLaneClien1)) !== null && _defaultSlowLaneClien0 !== void 0 ? _defaultSlowLaneClien0 : null;
|
|
208
229
|
};
|
|
209
230
|
export const getStoredLmLogits = () => {
|
|
210
|
-
var
|
|
211
|
-
return (
|
|
231
|
+
var _defaultSlowLaneClien11, _defaultSlowLaneClien12;
|
|
232
|
+
return (_defaultSlowLaneClien11 = (_defaultSlowLaneClien12 = defaultSlowLaneClient) === null || _defaultSlowLaneClien12 === void 0 ? void 0 : _defaultSlowLaneClien12.getLmLogits()) !== null && _defaultSlowLaneClien11 !== void 0 ? _defaultSlowLaneClien11 : null;
|
|
233
|
+
};
|
|
234
|
+
export const getBoundaryLmState = contextKey => {
|
|
235
|
+
var _defaultSlowLaneClien13, _defaultSlowLaneClien14, _defaultSlowLaneClien15;
|
|
236
|
+
return (_defaultSlowLaneClien13 = (_defaultSlowLaneClien14 = defaultSlowLaneClient) === null || _defaultSlowLaneClien14 === void 0 ? void 0 : (_defaultSlowLaneClien15 = _defaultSlowLaneClien14.getBoundaryLmState) === null || _defaultSlowLaneClien15 === void 0 ? void 0 : _defaultSlowLaneClien15.call(_defaultSlowLaneClien14, contextKey)) !== null && _defaultSlowLaneClien13 !== void 0 ? _defaultSlowLaneClien13 : null;
|
|
237
|
+
};
|
|
238
|
+
export const getCanonicalSurfaceTokenIds = surface => {
|
|
239
|
+
var _defaultSlowLaneClien16, _defaultSlowLaneClien17, _defaultSlowLaneClien18;
|
|
240
|
+
return (_defaultSlowLaneClien16 = (_defaultSlowLaneClien17 = defaultSlowLaneClient) === null || _defaultSlowLaneClien17 === void 0 ? void 0 : (_defaultSlowLaneClien18 = _defaultSlowLaneClien17.getCanonicalSurfaceTokenIds) === null || _defaultSlowLaneClien18 === void 0 ? void 0 : _defaultSlowLaneClien18.call(_defaultSlowLaneClien17, surface)) !== null && _defaultSlowLaneClien16 !== void 0 ? _defaultSlowLaneClien16 : null;
|
|
241
|
+
};
|
|
242
|
+
export const getSurfaceScore = (contextKey, surface) => {
|
|
243
|
+
var _defaultSlowLaneClien19, _defaultSlowLaneClien20, _defaultSlowLaneClien21;
|
|
244
|
+
return (_defaultSlowLaneClien19 = (_defaultSlowLaneClien20 = defaultSlowLaneClient) === null || _defaultSlowLaneClien20 === void 0 ? void 0 : (_defaultSlowLaneClien21 = _defaultSlowLaneClien20.getSurfaceScore) === null || _defaultSlowLaneClien21 === void 0 ? void 0 : _defaultSlowLaneClien21.call(_defaultSlowLaneClien20, contextKey, surface)) !== null && _defaultSlowLaneClien19 !== void 0 ? _defaultSlowLaneClien19 : null;
|
|
245
|
+
};
|
|
246
|
+
export const getProgressiveSurfaceEvidence = (contextKey, surface) => {
|
|
247
|
+
var _defaultSlowLaneClien22, _defaultSlowLaneClien23, _defaultSlowLaneClien24;
|
|
248
|
+
return (_defaultSlowLaneClien22 = (_defaultSlowLaneClien23 = defaultSlowLaneClient) === null || _defaultSlowLaneClien23 === void 0 ? void 0 : (_defaultSlowLaneClien24 = _defaultSlowLaneClien23.getProgressiveSurfaceEvidence) === null || _defaultSlowLaneClien24 === void 0 ? void 0 : _defaultSlowLaneClien24.call(_defaultSlowLaneClien23, contextKey, surface)) !== null && _defaultSlowLaneClien22 !== void 0 ? _defaultSlowLaneClien22 : null;
|
|
249
|
+
};
|
|
250
|
+
export const primeBoundaryLm = input => {
|
|
251
|
+
var _defaultSlowLaneClien25, _defaultSlowLaneClien26;
|
|
252
|
+
(_defaultSlowLaneClien25 = defaultSlowLaneClient) === null || _defaultSlowLaneClien25 === void 0 ? void 0 : (_defaultSlowLaneClien26 = _defaultSlowLaneClien25.primeBoundaryLm) === null || _defaultSlowLaneClien26 === void 0 ? void 0 : _defaultSlowLaneClien26.call(_defaultSlowLaneClien25, input);
|
|
253
|
+
};
|
|
254
|
+
export const requestProgressiveSurfaceScores = input => {
|
|
255
|
+
var _defaultSlowLaneClien27, _defaultSlowLaneClien28;
|
|
256
|
+
(_defaultSlowLaneClien27 = defaultSlowLaneClient) === null || _defaultSlowLaneClien27 === void 0 ? void 0 : (_defaultSlowLaneClien28 = _defaultSlowLaneClien27.requestProgressiveSurfaceScores) === null || _defaultSlowLaneClien28 === void 0 ? void 0 : _defaultSlowLaneClien28.call(_defaultSlowLaneClien27, input);
|
|
257
|
+
};
|
|
258
|
+
export const isCanonicalSurfaceScoringSupported = () => supportsCanonicalSurfaceScoring(defaultSlowLaneClient);
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* How many surfaces the canonical token map currently holds. Goes from zero to
|
|
262
|
+
* its final size once the artifact lands, which is the only point at which
|
|
263
|
+
* `getCanonicalSurfaceTokenIds` starts answering — so callers memoising over
|
|
264
|
+
* that lookup can use this to detect the transition.
|
|
265
|
+
*/
|
|
266
|
+
export const getCanonicalSurfaceCount = () => {
|
|
267
|
+
var _defaultSlowLaneClien29, _defaultSlowLaneClien30, _defaultSlowLaneClien31;
|
|
268
|
+
return (_defaultSlowLaneClien29 = (_defaultSlowLaneClien30 = defaultSlowLaneClient) === null || _defaultSlowLaneClien30 === void 0 ? void 0 : (_defaultSlowLaneClien31 = _defaultSlowLaneClien30.getCanonicalSurfaceCount) === null || _defaultSlowLaneClien31 === void 0 ? void 0 : _defaultSlowLaneClien31.call(_defaultSlowLaneClien30)) !== null && _defaultSlowLaneClien29 !== void 0 ? _defaultSlowLaneClien29 : 0;
|
|
212
269
|
};
|