@atlaskit/editor-plugin-autocomplete 0.1.0 → 0.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/afm-cc/tsconfig.json +5 -1
  3. package/afm-jira/tsconfig.json +5 -1
  4. package/afm-products/tsconfig.json +5 -1
  5. package/build/tsconfig.json +24 -0
  6. package/dist/cjs/autocompletePlugin.js +18 -5
  7. package/dist/cjs/autocompletePluginType.js +5 -1
  8. package/dist/cjs/pm-plugins/autocomplete-plugin.js +361 -0
  9. package/dist/cjs/pm-plugins/ghost-text-decoration.js +39 -0
  10. package/dist/cjs/pm-plugins/scoring-pipeline.js +258 -0
  11. package/dist/cjs/pm-plugins/slow-lane-client.js +197 -0
  12. package/dist/cjs/pm-plugins/text-predictor.js +786 -0
  13. package/dist/es2019/autocompletePlugin.js +20 -6
  14. package/dist/es2019/autocompletePluginType.js +1 -0
  15. package/dist/es2019/pm-plugins/autocomplete-plugin.js +360 -0
  16. package/dist/es2019/pm-plugins/ghost-text-decoration.js +33 -0
  17. package/dist/es2019/pm-plugins/scoring-pipeline.js +224 -0
  18. package/dist/es2019/pm-plugins/slow-lane-client.js +154 -0
  19. package/dist/es2019/pm-plugins/text-predictor.js +624 -0
  20. package/dist/esm/autocompletePlugin.js +18 -5
  21. package/dist/esm/autocompletePluginType.js +1 -0
  22. package/dist/esm/pm-plugins/autocomplete-plugin.js +354 -0
  23. package/dist/esm/pm-plugins/ghost-text-decoration.js +33 -0
  24. package/dist/esm/pm-plugins/scoring-pipeline.js +255 -0
  25. package/dist/esm/pm-plugins/slow-lane-client.js +190 -0
  26. package/dist/esm/pm-plugins/text-predictor.js +783 -0
  27. package/dist/types/autocompletePluginType.d.ts +6 -3
  28. package/dist/types/pm-plugins/autocomplete-plugin.d.ts +36 -0
  29. package/dist/types/pm-plugins/ghost-text-decoration.d.ts +7 -0
  30. package/dist/types/pm-plugins/scoring-pipeline.d.ts +33 -0
  31. package/dist/types/pm-plugins/slow-lane-client.d.ts +46 -0
  32. package/dist/types/pm-plugins/text-predictor.d.ts +90 -0
  33. package/dist/types-ts4.5/autocompletePluginType.d.ts +6 -3
  34. package/dist/types-ts4.5/pm-plugins/autocomplete-plugin.d.ts +36 -0
  35. package/dist/types-ts4.5/pm-plugins/ghost-text-decoration.d.ts +7 -0
  36. package/dist/types-ts4.5/pm-plugins/scoring-pipeline.d.ts +33 -0
  37. package/dist/types-ts4.5/pm-plugins/slow-lane-client.d.ts +46 -0
  38. package/dist/types-ts4.5/pm-plugins/text-predictor.d.ts +90 -0
  39. package/package.json +2 -2
  40. package/src/autocompletePlugin.tsx +25 -5
  41. package/src/autocompletePluginType.ts +14 -3
  42. package/src/pm-plugins/autocomplete-plugin/package.json +15 -0
  43. package/src/pm-plugins/autocomplete-plugin.ts +429 -0
  44. package/src/pm-plugins/ghost-text-decoration.ts +44 -0
  45. package/src/pm-plugins/scoring-pipeline.ts +297 -0
  46. package/src/pm-plugins/slow-lane-client/package.json +15 -0
  47. package/src/pm-plugins/slow-lane-client.ts +220 -0
  48. package/src/pm-plugins/text-predictor/package.json +15 -0
  49. package/src/pm-plugins/text-predictor.ts +771 -0
  50. package/src/pm-plugins/typings.d.ts +12 -0
  51. package/tsconfig.app.json +10 -2
  52. package/tsconfig.json +3 -1
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Scoring Pipeline: Stage 1 (Semantic + Frequency), Grammar Filter, Stage 2 (LM Re-ranking).
3
+ *
4
+ * Operates synchronously on pre-loaded data. Each stage gracefully degrades
5
+ * when its required data isn't available (cold → warm → full warm).
6
+ */
7
+
8
+ // resolveJsonModule is disabled for this package (see tsconfig.json) to prevent
9
+ // TypeScript from parsing LFS pointer files during CI typecheck. JSON imports
10
+ // are typed via the '*.json' declaration in typings.d.ts.
11
+ import posTagsData from './data/combined_l2_l3_pos_tags.json';
12
+ import ghostPosTagsData from './data/ghost_pos_tags.json';
13
+ import grammarTransitionsData from './data/grammar_transitions_10k.json';
14
+
15
+ // ─── Types ──────────────────────────────────────────────────
16
+
17
+ export interface ScoringCandidate {
18
+ authorFreq: number;
19
+ docFreq: number;
20
+ sessionFreq: number;
21
+ tenantFreq: number;
22
+ word: string;
23
+ }
24
+
25
+ export interface ScoredCandidate {
26
+ finalScore: number;
27
+ freqScore: number;
28
+ lmScore: number;
29
+ semanticScore: number;
30
+ word: string;
31
+ }
32
+
33
+ /** Metadata returned by the grammar filter for debug logging in the caller. */
34
+ export interface GrammarFilterMeta {
35
+ after: number;
36
+ before: number;
37
+ dropped: string[];
38
+ prevTags: string[];
39
+ prevWord: string;
40
+ }
41
+
42
+ interface PosTransitionRule {
43
+ allowed: string[];
44
+ }
45
+
46
+ interface GrammarTransitions {
47
+ transitions: Record<string, PosTransitionRule>;
48
+ }
49
+
50
+ // ─── Scoring Constants ──────────────────────────────────────
51
+
52
+ const ALPHA = 0.5;
53
+ const BETA = 0.5;
54
+ const NEUTRAL_SCORE = 0.5;
55
+ const STAGE1_WEIGHT = 0.6;
56
+ const STAGE2_WEIGHT = 0.4;
57
+ const MIN_STAGE1_SCORE = 0.35;
58
+ const L1_SESSION_CAP = 1.2;
59
+
60
+ // ─── Grammar Data (loaded once on import) ───────────────────
61
+
62
+ const posTags: Map<string, string[]> = new Map(
63
+ Object.entries(posTagsData as Record<string, string[]>),
64
+ );
65
+
66
+ const grammarTransitions = grammarTransitionsData as GrammarTransitions;
67
+
68
+ /**
69
+ * Precomputed map from each POS tag to the set of allowed next POS tags.
70
+ * Built once at module load from grammarTransitions so applyGrammarFilter
71
+ * never re-iterates the transition rules per call.
72
+ */
73
+ const precomputedAllowedByPos: Map<string, Set<string>> = new Map(
74
+ Object.entries(grammarTransitions.transitions).map(([pos, rule]) => [
75
+ pos,
76
+ new Set(rule.allowed),
77
+ ]),
78
+ );
79
+
80
+ // ─── Math ───────────────────────────────────────────────────
81
+
82
+ function cosineSimilarity(a: Float32Array, b: Float32Array): number {
83
+ let dot = 0;
84
+ let normA = 0;
85
+ let normB = 0;
86
+ for (let i = 0; i < a.length; i++) {
87
+ dot += a[i] * b[i];
88
+ normA += a[i] * a[i];
89
+ normB += b[i] * b[i];
90
+ }
91
+ const dNormA = Math.sqrt(normA);
92
+ const dNormB = Math.sqrt(normB);
93
+ if (dNormA === 0 || dNormB === 0) {
94
+ return NEUTRAL_SCORE;
95
+ }
96
+ return (1 + dot / (dNormA * dNormB)) / 2;
97
+ }
98
+
99
+ // ─── Stage 1: Semantic + Frequency ──────────────────────────
100
+
101
+ function scoreStage1(
102
+ candidate: ScoringCandidate,
103
+ contextVector: Float32Array | null,
104
+ getWordVector: (word: string) => Float32Array | null,
105
+ maxTenantFreq: number,
106
+ ): { freqScore: number; semanticScore: number; stage1Score: number } {
107
+
108
+ // 1. Calculate Base Global Score (Normalized Log)
109
+ const maxPossibleLog = Math.log10(maxTenantFreq + 1);
110
+
111
+ // Diversity Adjustment
112
+ const diversityRaw = (
113
+ Math.log10(candidate.tenantFreq + 1) * 0.50 +
114
+ Math.log10(candidate.docFreq + 1) * 0.25 +
115
+ Math.log10(candidate.authorFreq + 1) * 0.25
116
+ ) / maxPossibleLog;
117
+
118
+ const sessionMultiplier = candidate.sessionFreq > 0
119
+ ? 1 + (Math.log10(candidate.sessionFreq + 1) * 2.5)
120
+ : 1;
121
+
122
+ // Apply multiplier; capped at L1_SESSION_CAP (default 1.2) to prevent excessive over-indexing
123
+ const freqScore = Math.min(diversityRaw * sessionMultiplier, L1_SESSION_CAP);
124
+
125
+ // 3. Semantic Scoring
126
+ let semanticScore = NEUTRAL_SCORE;
127
+ if (contextVector) {
128
+ const wordVec = getWordVector(candidate.word);
129
+ semanticScore = wordVec ? cosineSimilarity(contextVector, wordVec) : NEUTRAL_SCORE;
130
+ }
131
+
132
+ return {
133
+ semanticScore,
134
+ freqScore,
135
+ stage1Score: (ALPHA * semanticScore) + (BETA * freqScore),
136
+ };
137
+ }
138
+
139
+ // ─── Grammar Filter ─────────────────────────────────────────
140
+
141
+ /**
142
+ * GHOST POS DICTIONARY
143
+ * A hardcoded mapping of common structural English words that were stripped
144
+ * from the main domain vocabulary. This allows the grammar filter to understand
145
+ * context without suggesting these words to the user.
146
+ */
147
+ const ghostPosTags: Record<string, string[]> = ghostPosTagsData as Record<string, string[]>;
148
+
149
+ type FilterEntry = { candidate: ScoringCandidate; freqScore: number; semanticScore: number; stage1Score: number };
150
+
151
+ function applyGrammarFilter(
152
+ candidates: FilterEntry[],
153
+ previousWord: string,
154
+ ): { filtered: FilterEntry[]; grammarMeta: GrammarFilterMeta | null } {
155
+ if (!previousWord) return { filtered: candidates, grammarMeta: null };
156
+
157
+ const lowerPrev = previousWord.toLowerCase();
158
+ const prevTags = ghostPosTags[lowerPrev] || posTags.get(lowerPrev);
159
+
160
+ if (!prevTags || prevTags.length === 0) {
161
+ return { filtered: candidates, grammarMeta: null };
162
+ }
163
+
164
+ let allowedNextTags: Set<string>;
165
+ if (prevTags.length === 1) {
166
+ // Common case: single POS tag — reuse the precomputed Set directly (no allocation)
167
+ allowedNextTags = precomputedAllowedByPos.get(prevTags[0]) ?? new Set();
168
+ } else {
169
+ allowedNextTags = new Set<string>();
170
+ for (const pt of prevTags) {
171
+ const allowed = precomputedAllowedByPos.get(pt);
172
+ if (allowed) allowed.forEach(tag => allowedNextTags.add(tag));
173
+ }
174
+ }
175
+
176
+ const filtered: FilterEntry[] = [];
177
+ const dropped: string[] = [];
178
+
179
+ for (const entry of candidates) {
180
+ const candidateTags = posTags.get(entry.candidate.word.toLowerCase());
181
+
182
+ // If candidate has no tags (unknown word), let it pass to be safe
183
+ if (!candidateTags || candidateTags.length === 0) {
184
+ filtered.push(entry);
185
+ continue;
186
+ }
187
+
188
+ if (candidateTags.some((ct) => allowedNextTags.has(ct))) {
189
+ filtered.push(entry);
190
+ } else {
191
+ dropped.push(entry.candidate.word);
192
+ }
193
+ }
194
+
195
+ const finalFiltered = filtered.length > 0 ? filtered : candidates;
196
+
197
+ return {
198
+ filtered: finalFiltered,
199
+ grammarMeta: {
200
+ prevWord: lowerPrev,
201
+ prevTags,
202
+ before: candidates.length,
203
+ after: finalFiltered.length,
204
+ dropped: filtered.length > 0 ? dropped : [],
205
+ },
206
+ };
207
+ }
208
+
209
+ // ─── Stage 2: LM Re-ranking ────────────────────────────────
210
+ function getLmScore(
211
+ word: string,
212
+ lmLogits: Record<string, number> | null
213
+ ): number {
214
+ if (!lmLogits) return 0;
215
+
216
+ // Look up the word directly! No more tokens.
217
+ const val = lmLogits[word.toLowerCase()];
218
+ if (typeof val === 'number') {
219
+ return val;
220
+ }
221
+ return 0;
222
+ }
223
+
224
+ // ─── Public API ─────────────────────────────────────────────
225
+
226
+ export interface RankCandidatesResult {
227
+ candidates: ScoredCandidate[];
228
+ grammarMeta: GrammarFilterMeta | null;
229
+ }
230
+
231
+ export function rankCandidates(
232
+ candidates: ScoringCandidate[],
233
+ contextVector: Float32Array | null,
234
+ getWordVector: (word: string) => Float32Array | null,
235
+ lmLogits: Record<string, number> | null,
236
+ maxTenantFreq: number,
237
+ previousWord: string,
238
+ ): RankCandidatesResult {
239
+ // Stage 1
240
+ const stage1Results = candidates.map((candidate) => {
241
+ const { semanticScore, freqScore, stage1Score } = scoreStage1(
242
+ candidate,
243
+ contextVector,
244
+ getWordVector,
245
+ maxTenantFreq,
246
+ );
247
+ return { candidate, semanticScore, freqScore, stage1Score };
248
+ });
249
+
250
+ const stage1Survivors = stage1Results.filter(entry => entry.stage1Score >= MIN_STAGE1_SCORE);
251
+
252
+ // Grammar Filter
253
+ const { filtered, grammarMeta } = applyGrammarFilter(stage1Survivors, previousWord);
254
+
255
+ // Stage 2 + final assembly
256
+ let lmMax = 0;
257
+ if (lmLogits && Object.keys(lmLogits).length > 0) {
258
+ const values = Object.values(lmLogits);
259
+ lmMax = Math.max(...values);
260
+ }
261
+
262
+ const scored: ScoredCandidate[] = filtered.map((entry) => {
263
+ let lmScore = 0;
264
+ let finalScore = entry.stage1Score;
265
+
266
+ if (lmLogits && Object.keys(lmLogits).length > 0) {
267
+ const rawLm = getLmScore(entry.candidate.word, lmLogits);
268
+
269
+ if (rawLm !== 0) {
270
+ // The word was in the top_k! Score it normally.
271
+ const logitDiff = Math.log(rawLm) - Math.log(lmMax);
272
+ lmScore = Math.exp(logitDiff);
273
+ } else {
274
+ lmScore = 0.05;
275
+ }
276
+
277
+ finalScore = STAGE1_WEIGHT * entry.stage1Score + STAGE2_WEIGHT * lmScore;
278
+ }
279
+
280
+ return {
281
+ word: entry.candidate.word,
282
+ freqScore: entry.freqScore,
283
+ semanticScore: entry.semanticScore,
284
+ lmScore,
285
+ finalScore,
286
+ };
287
+ });
288
+
289
+ scored.sort((a, b) => {
290
+ if (b.finalScore !== a.finalScore) {
291
+ return b.finalScore - a.finalScore;
292
+ }
293
+ return a.word.length - b.word.length;
294
+ });
295
+
296
+ return { candidates: scored, grammarMeta };
297
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@atlaskit/editor-plugin-autocomplete/src/pm-plugins/slow-lane-client",
3
+ "main": "../../../dist/cjs/pm-plugins/slow-lane-client.js",
4
+ "module": "../../../dist/esm/pm-plugins/slow-lane-client.js",
5
+ "module:es2019": "../../../dist/es2019/pm-plugins/slow-lane-client.js",
6
+ "sideEffects": false,
7
+ "types": "../../../dist/types/pm-plugins/slow-lane-client.d.ts",
8
+ "typesVersions": {
9
+ ">=4.5 <5.9": {
10
+ "*": [
11
+ "../../../dist/types-ts4.5/pm-plugins/slow-lane-client.d.ts"
12
+ ]
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Slow Lane Client: Backend context encoding for autocomplete.
3
+ *
4
+ * Fires a BE request on word boundaries to encode document context.
5
+ * Expects the typeahead-encodings API format:
6
+ * Request: { text, session_id }
7
+ * Response: { semantic_vector: number[], lm_logits: Record<string, number> }
8
+ */
9
+
10
+ // ─── Types ───────────────────────────────────────────────────────────────────
11
+
12
+ /** Request payload for typeahead-encodings endpoint. */
13
+ export interface TypeaheadEncodingsRequest {
14
+ session_id: string;
15
+ text: string;
16
+ }
17
+
18
+ /** Response from typeahead-encodings endpoint. */
19
+ export interface TypeaheadEncodingsResponse {
20
+ lm_logits: Record<string, number>;
21
+ semantic_vector: number[];
22
+ }
23
+
24
+ // ─── Constants ───────────────────────────────────────────────────────────────
25
+
26
+ const WORD_BOUNDARY_CHARS = /[\s.,;:!?]/u;
27
+ const DEFAULT_DEBOUNCE_MS = 300;
28
+
29
+ /**
30
+ * Check if text ends with a word boundary character (space or punctuation).
31
+ */
32
+ export const isWordBoundary = (text: string): boolean => {
33
+ if (!text || text.length === 0) {
34
+ return false;
35
+ }
36
+ const lastChar = text[text.length - 1];
37
+ return WORD_BOUNDARY_CHARS.test(lastChar);
38
+ };
39
+
40
+ // ─── Slow Lane Client ────────────────────────────────────────────────────────
41
+
42
+ export interface SlowLaneClientConfig {
43
+ baseUrl: string;
44
+ debounceMs?: number;
45
+ endpoint?: string;
46
+ fetchFn?: typeof fetch;
47
+ onUpdate?: (opts: { hasLmLogits: boolean; hasVector: boolean; textLength: number }) => void;
48
+ productKey?: string;
49
+ sessionId?: string;
50
+ }
51
+
52
+ export const createSlowLaneClient = (
53
+ config: SlowLaneClientConfig,
54
+ ): {
55
+ getContextVector: () => Float32Array | null;
56
+ getLmLogits: () => Record<string, number> | null;
57
+ isWordBoundary: (text: string) => boolean;
58
+ setContextVector: (vector: Float32Array | null) => void;
59
+ setLmLogits: (logits: Record<string, number> | null) => void;
60
+ updateContext: (text: string) => void;
61
+ } => {
62
+ const {
63
+ baseUrl,
64
+ sessionId: configSessionId,
65
+ productKey = 'confluence',
66
+ endpoint = '/gateway/api/v1/autocomplete/typeahead-encodings',
67
+ debounceMs = DEFAULT_DEBOUNCE_MS,
68
+ fetchFn = fetch,
69
+ onUpdate,
70
+ } = config;
71
+
72
+ const sessionId = configSessionId ?? crypto.randomUUID();
73
+
74
+ const headers: Record<string, string> = {
75
+ 'Content-Type': 'application/json',
76
+ 'x-experience-id': 'confluence-smart-typeahead-encodings',
77
+ 'x-product': productKey,
78
+ };
79
+
80
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null;
81
+ let lastRequestedText = '';
82
+ let storedContextVector: Float32Array | null = null;
83
+ let storedLmLogits: Record<string, number> | null = null;
84
+
85
+ const doUpdateContext = async (text: string): Promise<void> => {
86
+ if (!text || text.trim().length === 0) {
87
+ return;
88
+ }
89
+
90
+ const url = `${baseUrl.replace(/\/$/u, '')}${endpoint}`;
91
+ const payload: TypeaheadEncodingsRequest = {
92
+ text,
93
+ session_id: sessionId,
94
+ };
95
+
96
+ // Log the exact payload being sent so the comment/reply structure is visible
97
+ // eslint-disable-next-line no-console
98
+ console.groupCollapsed(
99
+ `%c[SlowLane] %c📤 Sending context | ${text.length} chars`,
100
+ 'color: #9c27b0; font-weight: bold;',
101
+ 'color: inherit;',
102
+ );
103
+ text.split('\n').forEach((line, i, arr) => {
104
+ // eslint-disable-next-line no-console
105
+ console.log(` ${i === arr.length - 1 ? '▶' : ' '} ${line}`);
106
+ });
107
+ // eslint-disable-next-line no-console
108
+ console.groupEnd();
109
+
110
+ try {
111
+ const res = await fetchFn(url, {
112
+ method: 'POST',
113
+ headers,
114
+ body: JSON.stringify(payload),
115
+ });
116
+
117
+ if (!res.ok) {
118
+ storedContextVector = null;
119
+ storedLmLogits = null;
120
+ // eslint-disable-next-line no-console
121
+ console.log(
122
+ `%c[SlowLane] %c❌ Request failed (${res.status})`,
123
+ 'color: #9c27b0; font-weight: bold;',
124
+ 'color: #f44336;',
125
+ );
126
+ return;
127
+ }
128
+
129
+ const data = (await res.json()) as TypeaheadEncodingsResponse;
130
+
131
+ if (data.semantic_vector && Array.isArray(data.semantic_vector)) {
132
+ storedContextVector = new Float32Array(data.semantic_vector);
133
+ } else {
134
+ storedContextVector = null;
135
+ }
136
+
137
+ if (data.lm_logits && typeof data.lm_logits === 'object') {
138
+ storedLmLogits = data.lm_logits;
139
+ } else {
140
+ storedLmLogits = null;
141
+ }
142
+
143
+ // Log what came back so it can be correlated with the next prediction group
144
+ // eslint-disable-next-line no-console
145
+ console.groupCollapsed(
146
+ `%c[SlowLane] %c📥 Response received`,
147
+ 'color: #9c27b0; font-weight: bold;',
148
+ 'color: inherit;',
149
+ );
150
+ // eslint-disable-next-line no-console
151
+ console.log(
152
+ storedContextVector
153
+ ? `✅ semantic_vector: ${storedContextVector.length} dims`
154
+ : '❌ No semantic_vector',
155
+ );
156
+ // eslint-disable-next-line no-console
157
+ console.log(
158
+ storedLmLogits
159
+ ? `✅ lm_logits: ${Object.keys(storedLmLogits).length} tokens`
160
+ : '❌ No lm_logits',
161
+ );
162
+ // eslint-disable-next-line no-console
163
+ console.groupEnd();
164
+
165
+ onUpdate?.({
166
+ textLength: text.length,
167
+ hasVector: storedContextVector !== null,
168
+ hasLmLogits: storedLmLogits !== null,
169
+ });
170
+ // eslint-disable-next-line no-unused-vars
171
+ } catch (e) {
172
+ storedContextVector = null;
173
+ storedLmLogits = null;
174
+ // eslint-disable-next-line no-console
175
+ console.log(
176
+ '%c[SlowLane] %c❌ Network error — context cleared',
177
+ 'color: #9c27b0; font-weight: bold;',
178
+ 'color: #f44336;',
179
+ );
180
+ }
181
+ };
182
+
183
+ const updateContextDebounced = (text: string): void => {
184
+ if (debounceTimer) {
185
+ clearTimeout(debounceTimer);
186
+ }
187
+ lastRequestedText = text;
188
+ debounceTimer = setTimeout(() => {
189
+ debounceTimer = null;
190
+ doUpdateContext(lastRequestedText);
191
+ }, debounceMs);
192
+ };
193
+
194
+ return {
195
+ updateContext: updateContextDebounced,
196
+ getContextVector: () => storedContextVector,
197
+ getLmLogits: () => storedLmLogits,
198
+ setContextVector: (vector) => {
199
+ storedContextVector = vector;
200
+ },
201
+ setLmLogits: (logits) => {
202
+ storedLmLogits = logits;
203
+ },
204
+ isWordBoundary,
205
+ };
206
+ };
207
+
208
+ let defaultSlowLaneClient: ReturnType<typeof createSlowLaneClient> | null = null;
209
+
210
+ export const setDefaultSlowLaneClient = (
211
+ client: ReturnType<typeof createSlowLaneClient> | null,
212
+ ): void => {
213
+ defaultSlowLaneClient = client;
214
+ };
215
+
216
+ export const getStoredContextVector = (): Float32Array | null =>
217
+ defaultSlowLaneClient?.getContextVector() ?? null;
218
+
219
+ export const getStoredLmLogits = (): Record<string, number> | null =>
220
+ defaultSlowLaneClient?.getLmLogits() ?? null;
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@atlaskit/editor-plugin-autocomplete/src/pm-plugins/text-predictor",
3
+ "main": "../../../dist/cjs/pm-plugins/text-predictor.js",
4
+ "module": "../../../dist/esm/pm-plugins/text-predictor.js",
5
+ "module:es2019": "../../../dist/es2019/pm-plugins/text-predictor.js",
6
+ "sideEffects": false,
7
+ "types": "../../../dist/types/pm-plugins/text-predictor.d.ts",
8
+ "typesVersions": {
9
+ ">=4.5 <5.9": {
10
+ "*": [
11
+ "../../../dist/types-ts4.5/pm-plugins/text-predictor.d.ts"
12
+ ]
13
+ }
14
+ }
15
+ }