@atlaskit/editor-plugin-autocomplete 2.2.0 → 2.4.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 +22 -0
- package/afm-cc/tsconfig.json +0 -1
- package/afm-products/tsconfig.json +0 -1
- package/autocompletePlugin/package.json +15 -0
- package/autocompletePluginType/package.json +15 -0
- package/build/tsconfig.json +0 -1
- package/dist/cjs/entry-points/autocompletePlugin.js +12 -0
- package/dist/cjs/entry-points/autocompletePluginType.js +1 -0
- package/dist/cjs/entry-points/src-pm-plugins-autocomplete-plugin.js +18 -0
- package/dist/cjs/entry-points/src-pm-plugins-slow-lane-client.js +36 -0
- package/dist/cjs/entry-points/src-pm-plugins-text-predictor.js +66 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +41 -14
- package/dist/cjs/pm-plugins/debug-mode.js +24 -0
- package/dist/cjs/pm-plugins/slow-lane-client.js +42 -35
- package/dist/cjs/pm-plugins/text-predictor.js +12 -32
- package/dist/es2019/entry-points/autocompletePlugin.js +2 -0
- package/dist/es2019/entry-points/autocompletePluginType.js +0 -0
- package/dist/es2019/entry-points/src-pm-plugins-autocomplete-plugin.js +2 -0
- package/dist/es2019/entry-points/src-pm-plugins-slow-lane-client.js +2 -0
- package/dist/es2019/entry-points/src-pm-plugins-text-predictor.js +2 -0
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +41 -14
- package/dist/es2019/pm-plugins/debug-mode.js +18 -0
- package/dist/es2019/pm-plugins/slow-lane-client.js +29 -23
- package/dist/es2019/pm-plugins/text-predictor.js +6 -26
- package/dist/esm/entry-points/autocompletePlugin.js +2 -0
- package/dist/esm/entry-points/autocompletePluginType.js +0 -0
- package/dist/esm/entry-points/src-pm-plugins-autocomplete-plugin.js +2 -0
- package/dist/esm/entry-points/src-pm-plugins-slow-lane-client.js +2 -0
- package/dist/esm/entry-points/src-pm-plugins-text-predictor.js +2 -0
- package/dist/esm/pm-plugins/autocomplete-plugin.js +41 -14
- package/dist/esm/pm-plugins/debug-mode.js +18 -0
- package/dist/esm/pm-plugins/slow-lane-client.js +43 -35
- package/dist/esm/pm-plugins/text-predictor.js +11 -31
- package/dist/types/entry-points/autocompletePlugin.d.ts +1 -0
- package/dist/types/entry-points/autocompletePluginType.d.ts +1 -0
- package/dist/types/entry-points/src-pm-plugins-autocomplete-plugin.d.ts +2 -0
- package/dist/types/entry-points/src-pm-plugins-slow-lane-client.d.ts +2 -0
- package/dist/types/entry-points/src-pm-plugins-text-predictor.d.ts +2 -0
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +1 -1
- package/dist/types/pm-plugins/debug-mode.d.ts +12 -0
- package/dist/types/pm-plugins/text-predictor.d.ts +0 -2
- package/dist/types-ts4.5/entry-points/autocompletePlugin.d.ts +1 -0
- package/dist/types-ts4.5/entry-points/autocompletePluginType.d.ts +1 -0
- package/dist/types-ts4.5/entry-points/src-pm-plugins-autocomplete-plugin.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/src-pm-plugins-slow-lane-client.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/src-pm-plugins-text-predictor.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/autocomplete-plugin.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/debug-mode.d.ts +12 -0
- package/dist/types-ts4.5/pm-plugins/text-predictor.d.ts +0 -2
- package/package.json +3 -3
- package/src/entry-points/autocompletePlugin.tsx +2 -0
- package/src/entry-points/autocompletePluginType.ts +2 -0
- package/src/entry-points/src-pm-plugins-autocomplete-plugin.ts +7 -0
- package/src/entry-points/src-pm-plugins-slow-lane-client.ts +13 -0
- package/src/entry-points/src-pm-plugins-text-predictor.ts +14 -0
- package/src/pm-plugins/autocomplete-plugin/package.json +5 -5
- package/src/pm-plugins/autocomplete-plugin.ts +48 -12
- package/src/pm-plugins/debug-mode.ts +18 -0
- package/src/pm-plugins/slow-lane-client/package.json +5 -5
- package/src/pm-plugins/slow-lane-client.ts +53 -45
- package/src/pm-plugins/text-predictor/package.json +5 -5
- package/src/pm-plugins/text-predictor.ts +6 -30
- package/tsconfig.app.json +3 -1
- package/tsconfig.dev.json +2 -1
- package/afm-jira/tsconfig.json +0 -30
|
@@ -142,6 +142,16 @@ const buildSlowLaneText = (docText, context) => {
|
|
|
142
142
|
lines.push(`reply ${nextReplyNumber}: ${docText}`);
|
|
143
143
|
return lines.join('\n');
|
|
144
144
|
};
|
|
145
|
+
const getTypedLengthForPrediction = textBefore => {
|
|
146
|
+
var _textBefore$match$, _textBefore$match;
|
|
147
|
+
if (isWordBoundary(textBefore)) {
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
152
|
+
const trailingToken = (_textBefore$match$ = (_textBefore$match = textBefore.match(/([^\s.,;:!?]*)$/)) === null || _textBefore$match === void 0 ? void 0 : _textBefore$match[1]) !== null && _textBefore$match$ !== void 0 ? _textBefore$match$ : '';
|
|
153
|
+
return trailingToken.length;
|
|
154
|
+
};
|
|
145
155
|
export const createAutocompletePlugin = (options, api) => {
|
|
146
156
|
let debounceTimer = null;
|
|
147
157
|
let hasIngestedPage = false;
|
|
@@ -159,6 +169,24 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
159
169
|
* re-showing the same suggestion. Resets to null as soon as the text changes.
|
|
160
170
|
*/
|
|
161
171
|
let dismissedContext = null;
|
|
172
|
+
let lastSuggestionTypedLength = 0;
|
|
173
|
+
let lastSuggestionLength = 0;
|
|
174
|
+
const fireSuggestionInsertedAnalytics = ghostText => {
|
|
175
|
+
var _api$analytics;
|
|
176
|
+
const typedLength = lastSuggestionTypedLength;
|
|
177
|
+
const suggestionLength = lastSuggestionLength || typedLength + ghostText.length;
|
|
178
|
+
const kssDelta = suggestionLength - typedLength;
|
|
179
|
+
api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent({
|
|
180
|
+
action: ACTION.SUGGESTION_INSERTED,
|
|
181
|
+
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
182
|
+
eventType: EVENT_TYPE.TRACK,
|
|
183
|
+
attributes: {
|
|
184
|
+
suggestionLength,
|
|
185
|
+
typedLength,
|
|
186
|
+
kssDelta
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
};
|
|
162
190
|
const slowLaneClient = createSlowLaneClient({
|
|
163
191
|
baseUrl: '',
|
|
164
192
|
endpoint: SLOW_LANE_ENDPOINT
|
|
@@ -203,11 +231,14 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
203
231
|
// Tier 1 prediction is synchronous -- no async needed
|
|
204
232
|
const prediction = predict(textBefore);
|
|
205
233
|
if (prediction && prediction.length > 0) {
|
|
234
|
+
const typedLength = getTypedLengthForPrediction(textBefore);
|
|
235
|
+
lastSuggestionTypedLength = typedLength;
|
|
236
|
+
lastSuggestionLength = typedLength + prediction.length;
|
|
206
237
|
showGhostText(view, prediction, selection.from);
|
|
207
238
|
if (prediction !== lastShownGhostText) {
|
|
208
|
-
var _api$
|
|
239
|
+
var _api$analytics2;
|
|
209
240
|
lastShownGhostText = prediction;
|
|
210
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
241
|
+
api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent({
|
|
211
242
|
action: ACTION.SUGGESTION_VIEWED,
|
|
212
243
|
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
213
244
|
eventType: EVENT_TYPE.TRACK
|
|
@@ -286,30 +317,26 @@ export const createAutocompletePlugin = (options, api) => {
|
|
|
286
317
|
},
|
|
287
318
|
handleKeyDown: keydownHandler({
|
|
288
319
|
Tab: (state, dispatch) => {
|
|
320
|
+
var _pluginState$ghostTex;
|
|
321
|
+
const pluginState = autocompletePluginKey.getState(state);
|
|
322
|
+
const ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
289
323
|
const accepted = acceptGhostText(state, dispatch);
|
|
290
324
|
if (accepted) {
|
|
291
|
-
var _api$analytics2;
|
|
292
325
|
justAccepted = true;
|
|
293
326
|
lastShownGhostText = '';
|
|
294
|
-
|
|
295
|
-
action: ACTION.SUGGESTION_INSERTED,
|
|
296
|
-
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
297
|
-
eventType: EVENT_TYPE.TRACK
|
|
298
|
-
});
|
|
327
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
299
328
|
}
|
|
300
329
|
return accepted;
|
|
301
330
|
},
|
|
302
331
|
ArrowRight: (state, dispatch) => {
|
|
332
|
+
var _pluginState$ghostTex2;
|
|
333
|
+
const pluginState = autocompletePluginKey.getState(state);
|
|
334
|
+
const ghostText = (_pluginState$ghostTex2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex2 !== void 0 ? _pluginState$ghostTex2 : '';
|
|
303
335
|
const accepted = acceptGhostText(state, dispatch);
|
|
304
336
|
if (accepted) {
|
|
305
|
-
var _api$analytics3;
|
|
306
337
|
justAccepted = true;
|
|
307
338
|
lastShownGhostText = '';
|
|
308
|
-
|
|
309
|
-
action: ACTION.SUGGESTION_INSERTED,
|
|
310
|
-
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
311
|
-
eventType: EVENT_TYPE.TRACK
|
|
312
|
-
});
|
|
339
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
313
340
|
}
|
|
314
341
|
return accepted;
|
|
315
342
|
},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contextual Typeahead Completions (CTC) debug logging utility.
|
|
3
|
+
*
|
|
4
|
+
* Logs are silent by default. To enable in any environment (dev, staging, prod):
|
|
5
|
+
*
|
|
6
|
+
* localStorage.setItem('atl-ctc-dbg', '1')
|
|
7
|
+
*
|
|
8
|
+
* Then reload the page. To disable:
|
|
9
|
+
*
|
|
10
|
+
* localStorage.removeItem('atl-ctc-dbg')
|
|
11
|
+
*/
|
|
12
|
+
export const isAutocompleteDebugEnabled = () => {
|
|
13
|
+
try {
|
|
14
|
+
return typeof localStorage !== 'undefined' && localStorage.getItem('atl-ctc-dbg') === '1';
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* Response: { semantic_vector: number[], lm_logits: Record<string, number> }
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
11
|
+
|
|
10
12
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
11
13
|
|
|
12
14
|
/** Request payload for typeahead-encodings endpoint. */
|
|
@@ -63,16 +65,16 @@ export const createSlowLaneClient = config => {
|
|
|
63
65
|
text,
|
|
64
66
|
session_id: sessionId
|
|
65
67
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
if (isAutocompleteDebugEnabled()) {
|
|
69
|
+
// eslint-disable-next-line no-console
|
|
70
|
+
console.groupCollapsed(`%c[SlowLane] %c📤 Sending context | ${text.length} chars`, 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
71
|
+
text.split('\n').forEach((line, i, arr) => {
|
|
72
|
+
// eslint-disable-next-line no-console
|
|
73
|
+
console.log(` ${i === arr.length - 1 ? '▶' : ' '} ${line}`);
|
|
74
|
+
});
|
|
71
75
|
// eslint-disable-next-line no-console
|
|
72
|
-
console.
|
|
73
|
-
}
|
|
74
|
-
// eslint-disable-next-line no-console
|
|
75
|
-
console.groupEnd();
|
|
76
|
+
console.groupEnd();
|
|
77
|
+
}
|
|
76
78
|
try {
|
|
77
79
|
const res = await fetchFn(url, {
|
|
78
80
|
method: 'POST',
|
|
@@ -82,8 +84,10 @@ export const createSlowLaneClient = config => {
|
|
|
82
84
|
if (!res.ok) {
|
|
83
85
|
storedContextVector = null;
|
|
84
86
|
storedLmLogits = null;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
if (isAutocompleteDebugEnabled()) {
|
|
88
|
+
// eslint-disable-next-line no-console
|
|
89
|
+
console.log(`%c[SlowLane] %c❌ Request failed (${res.status})`, 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
90
|
+
}
|
|
87
91
|
return;
|
|
88
92
|
}
|
|
89
93
|
const data = await res.json();
|
|
@@ -97,16 +101,16 @@ export const createSlowLaneClient = config => {
|
|
|
97
101
|
} else {
|
|
98
102
|
storedLmLogits = null;
|
|
99
103
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
if (isAutocompleteDebugEnabled()) {
|
|
105
|
+
// eslint-disable-next-line no-console
|
|
106
|
+
console.groupCollapsed(`%c[SlowLane] %c📥 Response received`, 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
107
|
+
// eslint-disable-next-line no-console
|
|
108
|
+
console.log(storedContextVector ? `✅ semantic_vector: ${storedContextVector.length} dims` : '❌ No semantic_vector');
|
|
109
|
+
// eslint-disable-next-line no-console
|
|
110
|
+
console.log(storedLmLogits ? `✅ lm_logits: ${Object.keys(storedLmLogits).length} tokens` : '❌ No lm_logits');
|
|
111
|
+
// eslint-disable-next-line no-console
|
|
112
|
+
console.groupEnd();
|
|
113
|
+
}
|
|
110
114
|
onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate({
|
|
111
115
|
textLength: text.length,
|
|
112
116
|
hasVector: storedContextVector !== null,
|
|
@@ -116,8 +120,10 @@ export const createSlowLaneClient = config => {
|
|
|
116
120
|
} catch (e) {
|
|
117
121
|
storedContextVector = null;
|
|
118
122
|
storedLmLogits = null;
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
if (isAutocompleteDebugEnabled()) {
|
|
124
|
+
// eslint-disable-next-line no-console
|
|
125
|
+
console.log('%c[SlowLane] %c❌ Network error — context cleared', 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
126
|
+
}
|
|
121
127
|
}
|
|
122
128
|
};
|
|
123
129
|
const updateContextDebounced = text => {
|
|
@@ -21,6 +21,7 @@ import l3VocabularyData from './data/l3_vocabulary.json';
|
|
|
21
21
|
import vocabularyData from './data/vocabulary_10k.json';
|
|
22
22
|
import wordIndexData from './data/word_index_10k.json';
|
|
23
23
|
// import { rankCandidates, isGrammarAllowed } from './scoring-pipeline';
|
|
24
|
+
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
24
25
|
import { rankCandidates, STAGE1_WEIGHT, STAGE2_WEIGHT, MIN_STAGE1_SCORE } from './scoring-pipeline';
|
|
25
26
|
import { getStoredContextVector, getStoredLmLogits } from './slow-lane-client';
|
|
26
27
|
|
|
@@ -161,7 +162,7 @@ export const initL3Vocabulary = l3Words => {
|
|
|
161
162
|
// loses to any domain word in Stage 1, but still scores above 0.
|
|
162
163
|
l3Trie.insert(word, L3_BASELINE_FREQ, 0, 0);
|
|
163
164
|
}
|
|
164
|
-
if (
|
|
165
|
+
if (isAutocompleteDebugEnabled()) {
|
|
165
166
|
// eslint-disable-next-line no-console
|
|
166
167
|
console.log(`[text-predictor] L3 General English loaded: ${l3Words.length} words`);
|
|
167
168
|
}
|
|
@@ -174,9 +175,7 @@ export const initL3Vocabulary = l3Words => {
|
|
|
174
175
|
let isInitialized = false;
|
|
175
176
|
let vectorStore = null;
|
|
176
177
|
let vectorsLoadStarted = false;
|
|
177
|
-
let debugMode = true;
|
|
178
178
|
let lastPredictionDebug = null;
|
|
179
|
-
let hasLoggedSemanticActive = false;
|
|
180
179
|
|
|
181
180
|
/** Get vector for a word from the store. */
|
|
182
181
|
const getWordVector = word => {
|
|
@@ -263,25 +262,12 @@ const extractPreviousWord = text => {
|
|
|
263
262
|
|
|
264
263
|
// ─── Debug Helpers ───────────────────────────────────────────────────────────
|
|
265
264
|
|
|
266
|
-
/** Enable or disable debug logging. Also checks localStorage key `autocomplete-debug`. */
|
|
267
|
-
export const setDebugMode = enabled => {
|
|
268
|
-
debugMode = enabled;
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
/** Check localStorage for autocomplete-debug on first access. */
|
|
272
|
-
const ensureDebugModeFromStorage = () => {
|
|
273
|
-
if (typeof localStorage !== 'undefined' && localStorage.getItem('autocomplete-debug') === '1') {
|
|
274
|
-
debugMode = true;
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
|
|
278
265
|
/**
|
|
279
266
|
* Get predictor status for debugging.
|
|
280
267
|
* vectorsLoaded: true when semantic scoring is active
|
|
281
268
|
* wordCount: number of words in vector store (0 if not loaded)
|
|
282
269
|
*/
|
|
283
270
|
export const getPredictorStatus = () => {
|
|
284
|
-
ensureDebugModeFromStorage();
|
|
285
271
|
return {
|
|
286
272
|
vectorsLoaded: vectorStore !== null,
|
|
287
273
|
wordCount: vectorStore ? Object.keys(vectorStore.wordIndex).length : 0,
|
|
@@ -295,7 +281,6 @@ export const getPredictorStatus = () => {
|
|
|
295
281
|
* Returns null if no prediction has run yet or debug was off.
|
|
296
282
|
*/
|
|
297
283
|
export const getLastPredictionDebug = () => {
|
|
298
|
-
ensureDebugModeFromStorage();
|
|
299
284
|
return lastPredictionDebug;
|
|
300
285
|
};
|
|
301
286
|
export const initVocabulary = vocabulary => {
|
|
@@ -336,7 +321,7 @@ export const ingestDocumentPage = pageContent => {
|
|
|
336
321
|
validBoostedWords.add(word);
|
|
337
322
|
}
|
|
338
323
|
}
|
|
339
|
-
if (
|
|
324
|
+
if (isAutocompleteDebugEnabled() && validBoostedWords.size > 0) {
|
|
340
325
|
// eslint-disable-next-line no-console
|
|
341
326
|
console.groupCollapsed(`%c[L1 Session] %cPrimed ${validBoostedWords.size} valid dictionary words from page`, 'color: #00b8d9; font-weight: bold;', 'color: inherit; font-style: italic;');
|
|
342
327
|
// eslint-disable-next-line no-console
|
|
@@ -346,7 +331,6 @@ export const ingestDocumentPage = pageContent => {
|
|
|
346
331
|
}
|
|
347
332
|
};
|
|
348
333
|
export const predict = textBefore => {
|
|
349
|
-
ensureDebugModeFromStorage();
|
|
350
334
|
if (!isInitialized) {
|
|
351
335
|
loadDefaultVocabulary();
|
|
352
336
|
}
|
|
@@ -428,7 +412,7 @@ export const predict = textBefore => {
|
|
|
428
412
|
const lmLogits = getStoredLmLogits();
|
|
429
413
|
|
|
430
414
|
// Raw LM Output Logger
|
|
431
|
-
if (
|
|
415
|
+
if (isAutocompleteDebugEnabled() && lmLogits && Object.keys(lmLogits).length > 0) {
|
|
432
416
|
const rawLmTop = Object.entries(lmLogits).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([word, score]) => ({
|
|
433
417
|
Word: word,
|
|
434
418
|
Prob: Number(score.toFixed(5))
|
|
@@ -437,9 +421,6 @@ export const predict = textBefore => {
|
|
|
437
421
|
console.log('%c[Raw LM Prediction]🧠', 'color: #e83e8c; font-weight: bold;', rawLmTop);
|
|
438
422
|
}
|
|
439
423
|
const mode = contextVector ? 'warm' : 'cold';
|
|
440
|
-
if (debugMode && contextVector && !hasLoggedSemanticActive) {
|
|
441
|
-
hasLoggedSemanticActive = true;
|
|
442
|
-
}
|
|
443
424
|
|
|
444
425
|
// Build ScoringCandidate array from TrieNodes
|
|
445
426
|
const scoringCandidates = candidates.map(({
|
|
@@ -464,7 +445,7 @@ export const predict = textBefore => {
|
|
|
464
445
|
} = rankCandidates(scoringCandidates, contextVector, w => getWordVector(w), prefixLmLogits, wordTrie.maxTenantFreq, previousWord);
|
|
465
446
|
const best = ranked[0];
|
|
466
447
|
const suggestion = best && best.finalScore >= MIN_SCORE_THRESHOLD ? best.word.slice(currentWord.length) : null;
|
|
467
|
-
if (
|
|
448
|
+
if (isAutocompleteDebugEnabled()) {
|
|
468
449
|
const latencyMs = performance.now() - t0;
|
|
469
450
|
const tokens = tokenize(trimmed);
|
|
470
451
|
const contextWords = tokens.slice(-CONTEXT_WORDS);
|
|
@@ -612,8 +593,7 @@ export const loadVectorsAsync = async options => {
|
|
|
612
593
|
wordIndex,
|
|
613
594
|
dim
|
|
614
595
|
};
|
|
615
|
-
|
|
616
|
-
if (debugMode) {
|
|
596
|
+
if (isAutocompleteDebugEnabled()) {
|
|
617
597
|
// eslint-disable-next-line no-console
|
|
618
598
|
console.log('[text-predictor] Vectors loaded:', {
|
|
619
599
|
wordCount: nWords,
|
|
File without changes
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
|
+
export { getLastPredictionDebug, getPredictorStatus, incrementSessionFreq, ingestDocumentPage, initL3Vocabulary, initVectors, initVocabulary, loadDefaultVocabulary, loadVectorsAsync, predict } from '../pm-plugins/text-predictor';
|
|
@@ -141,6 +141,16 @@ var buildSlowLaneText = function buildSlowLaneText(docText, context) {
|
|
|
141
141
|
lines.push("reply ".concat(nextReplyNumber, ": ").concat(docText));
|
|
142
142
|
return lines.join('\n');
|
|
143
143
|
};
|
|
144
|
+
var getTypedLengthForPrediction = function getTypedLengthForPrediction(textBefore) {
|
|
145
|
+
var _textBefore$match$, _textBefore$match;
|
|
146
|
+
if (isWordBoundary(textBefore)) {
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
151
|
+
var trailingToken = (_textBefore$match$ = (_textBefore$match = textBefore.match(/([^\s.,;:!?]*)$/)) === null || _textBefore$match === void 0 ? void 0 : _textBefore$match[1]) !== null && _textBefore$match$ !== void 0 ? _textBefore$match$ : '';
|
|
152
|
+
return trailingToken.length;
|
|
153
|
+
};
|
|
144
154
|
export var createAutocompletePlugin = function createAutocompletePlugin(options, api) {
|
|
145
155
|
var debounceTimer = null;
|
|
146
156
|
var hasIngestedPage = false;
|
|
@@ -158,6 +168,24 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
158
168
|
* re-showing the same suggestion. Resets to null as soon as the text changes.
|
|
159
169
|
*/
|
|
160
170
|
var dismissedContext = null;
|
|
171
|
+
var lastSuggestionTypedLength = 0;
|
|
172
|
+
var lastSuggestionLength = 0;
|
|
173
|
+
var fireSuggestionInsertedAnalytics = function fireSuggestionInsertedAnalytics(ghostText) {
|
|
174
|
+
var _api$analytics;
|
|
175
|
+
var typedLength = lastSuggestionTypedLength;
|
|
176
|
+
var suggestionLength = lastSuggestionLength || typedLength + ghostText.length;
|
|
177
|
+
var kssDelta = suggestionLength - typedLength;
|
|
178
|
+
api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
|
|
179
|
+
action: ACTION.SUGGESTION_INSERTED,
|
|
180
|
+
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
181
|
+
eventType: EVENT_TYPE.TRACK,
|
|
182
|
+
attributes: {
|
|
183
|
+
suggestionLength: suggestionLength,
|
|
184
|
+
typedLength: typedLength,
|
|
185
|
+
kssDelta: kssDelta
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
};
|
|
161
189
|
var slowLaneClient = createSlowLaneClient({
|
|
162
190
|
baseUrl: '',
|
|
163
191
|
endpoint: SLOW_LANE_ENDPOINT
|
|
@@ -198,11 +226,14 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
198
226
|
// Tier 1 prediction is synchronous -- no async needed
|
|
199
227
|
var prediction = predict(textBefore);
|
|
200
228
|
if (prediction && prediction.length > 0) {
|
|
229
|
+
var typedLength = getTypedLengthForPrediction(textBefore);
|
|
230
|
+
lastSuggestionTypedLength = typedLength;
|
|
231
|
+
lastSuggestionLength = typedLength + prediction.length;
|
|
201
232
|
showGhostText(view, prediction, selection.from);
|
|
202
233
|
if (prediction !== lastShownGhostText) {
|
|
203
|
-
var _api$
|
|
234
|
+
var _api$analytics2;
|
|
204
235
|
lastShownGhostText = prediction;
|
|
205
|
-
api === null || api === void 0 || (_api$
|
|
236
|
+
api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.fireAnalyticsEvent({
|
|
206
237
|
action: ACTION.SUGGESTION_VIEWED,
|
|
207
238
|
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
208
239
|
eventType: EVENT_TYPE.TRACK
|
|
@@ -278,30 +309,26 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options,
|
|
|
278
309
|
},
|
|
279
310
|
handleKeyDown: keydownHandler({
|
|
280
311
|
Tab: function Tab(state, dispatch) {
|
|
312
|
+
var _pluginState$ghostTex;
|
|
313
|
+
var pluginState = autocompletePluginKey.getState(state);
|
|
314
|
+
var ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
|
|
281
315
|
var accepted = acceptGhostText(state, dispatch);
|
|
282
316
|
if (accepted) {
|
|
283
|
-
var _api$analytics2;
|
|
284
317
|
justAccepted = true;
|
|
285
318
|
lastShownGhostText = '';
|
|
286
|
-
|
|
287
|
-
action: ACTION.SUGGESTION_INSERTED,
|
|
288
|
-
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
289
|
-
eventType: EVENT_TYPE.TRACK
|
|
290
|
-
});
|
|
319
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
291
320
|
}
|
|
292
321
|
return accepted;
|
|
293
322
|
},
|
|
294
323
|
ArrowRight: function ArrowRight(state, dispatch) {
|
|
324
|
+
var _pluginState$ghostTex2;
|
|
325
|
+
var pluginState = autocompletePluginKey.getState(state);
|
|
326
|
+
var ghostText = (_pluginState$ghostTex2 = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex2 !== void 0 ? _pluginState$ghostTex2 : '';
|
|
295
327
|
var accepted = acceptGhostText(state, dispatch);
|
|
296
328
|
if (accepted) {
|
|
297
|
-
var _api$analytics3;
|
|
298
329
|
justAccepted = true;
|
|
299
330
|
lastShownGhostText = '';
|
|
300
|
-
|
|
301
|
-
action: ACTION.SUGGESTION_INSERTED,
|
|
302
|
-
actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
|
|
303
|
-
eventType: EVENT_TYPE.TRACK
|
|
304
|
-
});
|
|
331
|
+
fireSuggestionInsertedAnalytics(ghostText);
|
|
305
332
|
}
|
|
306
333
|
return accepted;
|
|
307
334
|
},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contextual Typeahead Completions (CTC) debug logging utility.
|
|
3
|
+
*
|
|
4
|
+
* Logs are silent by default. To enable in any environment (dev, staging, prod):
|
|
5
|
+
*
|
|
6
|
+
* localStorage.setItem('atl-ctc-dbg', '1')
|
|
7
|
+
*
|
|
8
|
+
* Then reload the page. To disable:
|
|
9
|
+
*
|
|
10
|
+
* localStorage.removeItem('atl-ctc-dbg')
|
|
11
|
+
*/
|
|
12
|
+
export var isAutocompleteDebugEnabled = function isAutocompleteDebugEnabled() {
|
|
13
|
+
try {
|
|
14
|
+
return typeof localStorage !== 'undefined' && localStorage.getItem('atl-ctc-dbg') === '1';
|
|
15
|
+
} catch (_unused) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -10,6 +10,8 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
10
10
|
* Response: { semantic_vector: number[], lm_logits: Record<string, number> }
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
14
|
+
|
|
13
15
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
14
16
|
|
|
15
17
|
/** Request payload for typeahead-encodings endpoint. */
|
|
@@ -74,37 +76,41 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
74
76
|
payload = {
|
|
75
77
|
text: text,
|
|
76
78
|
session_id: sessionId
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
console.groupCollapsed("%c[SlowLane] %c\uD83D\uDCE4 Sending context | ".concat(text.length, " chars"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
80
|
-
text.split('\n').forEach(function (line, i, arr) {
|
|
79
|
+
};
|
|
80
|
+
if (isAutocompleteDebugEnabled()) {
|
|
81
81
|
// eslint-disable-next-line no-console
|
|
82
|
-
console.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
console.groupCollapsed("%c[SlowLane] %c\uD83D\uDCE4 Sending context | ".concat(text.length, " chars"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
83
|
+
text.split('\n').forEach(function (line, i, arr) {
|
|
84
|
+
// eslint-disable-next-line no-console
|
|
85
|
+
console.log(" ".concat(i === arr.length - 1 ? '▶' : ' ', " ").concat(line));
|
|
86
|
+
});
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.groupEnd();
|
|
89
|
+
}
|
|
90
|
+
_context.prev = 5;
|
|
91
|
+
_context.next = 8;
|
|
88
92
|
return fetchFn(url, {
|
|
89
93
|
method: 'POST',
|
|
90
94
|
headers: headers,
|
|
91
95
|
body: JSON.stringify(payload)
|
|
92
96
|
});
|
|
93
|
-
case
|
|
97
|
+
case 8:
|
|
94
98
|
res = _context.sent;
|
|
95
99
|
if (res.ok) {
|
|
96
|
-
_context.next =
|
|
100
|
+
_context.next = 14;
|
|
97
101
|
break;
|
|
98
102
|
}
|
|
99
103
|
storedContextVector = null;
|
|
100
104
|
storedLmLogits = null;
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
if (isAutocompleteDebugEnabled()) {
|
|
106
|
+
// eslint-disable-next-line no-console
|
|
107
|
+
console.log("%c[SlowLane] %c\u274C Request failed (".concat(res.status, ")"), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
108
|
+
}
|
|
103
109
|
return _context.abrupt("return");
|
|
104
|
-
case
|
|
105
|
-
_context.next =
|
|
110
|
+
case 14:
|
|
111
|
+
_context.next = 16;
|
|
106
112
|
return res.json();
|
|
107
|
-
case
|
|
113
|
+
case 16:
|
|
108
114
|
data = _context.sent;
|
|
109
115
|
if (data.semantic_vector && Array.isArray(data.semantic_vector)) {
|
|
110
116
|
storedContextVector = new Float32Array(data.semantic_vector);
|
|
@@ -116,36 +122,38 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
116
122
|
} else {
|
|
117
123
|
storedLmLogits = null;
|
|
118
124
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
if (isAutocompleteDebugEnabled()) {
|
|
126
|
+
// eslint-disable-next-line no-console
|
|
127
|
+
console.groupCollapsed("%c[SlowLane] %c\uD83D\uDCE5 Response received", 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
128
|
+
// eslint-disable-next-line no-console
|
|
129
|
+
console.log(storedContextVector ? "\u2705 semantic_vector: ".concat(storedContextVector.length, " dims") : '❌ No semantic_vector');
|
|
130
|
+
// eslint-disable-next-line no-console
|
|
131
|
+
console.log(storedLmLogits ? "\u2705 lm_logits: ".concat(Object.keys(storedLmLogits).length, " tokens") : '❌ No lm_logits');
|
|
132
|
+
// eslint-disable-next-line no-console
|
|
133
|
+
console.groupEnd();
|
|
134
|
+
}
|
|
129
135
|
onUpdate === null || onUpdate === void 0 || onUpdate({
|
|
130
136
|
textLength: text.length,
|
|
131
137
|
hasVector: storedContextVector !== null,
|
|
132
138
|
hasLmLogits: storedLmLogits !== null
|
|
133
139
|
});
|
|
134
140
|
// eslint-disable-next-line no-unused-vars
|
|
135
|
-
_context.next =
|
|
141
|
+
_context.next = 28;
|
|
136
142
|
break;
|
|
137
|
-
case
|
|
138
|
-
_context.prev =
|
|
139
|
-
_context.t0 = _context["catch"](
|
|
143
|
+
case 23:
|
|
144
|
+
_context.prev = 23;
|
|
145
|
+
_context.t0 = _context["catch"](5);
|
|
140
146
|
storedContextVector = null;
|
|
141
147
|
storedLmLogits = null;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
148
|
+
if (isAutocompleteDebugEnabled()) {
|
|
149
|
+
// eslint-disable-next-line no-console
|
|
150
|
+
console.log('%c[SlowLane] %c❌ Network error — context cleared', 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
151
|
+
}
|
|
152
|
+
case 28:
|
|
145
153
|
case "end":
|
|
146
154
|
return _context.stop();
|
|
147
155
|
}
|
|
148
|
-
}, _callee, null, [[
|
|
156
|
+
}, _callee, null, [[5, 23]]);
|
|
149
157
|
}));
|
|
150
158
|
return function doUpdateContext(_x) {
|
|
151
159
|
return _ref.apply(this, arguments);
|