@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
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Request: { text, session_id }
|
|
7
7
|
* Response: { semantic_vector: number[], lm_logits: Record<string, number> }
|
|
8
8
|
*/
|
|
9
|
+
import type { BoundaryLmState, BoundaryPrimeRequest, ProgressiveSurfaceEvidence, SurfaceScore, SurfaceScoreRequest } from './canonical-lm-scoring';
|
|
9
10
|
/** Request payload for typeahead-encodings endpoint. */
|
|
10
11
|
export interface TypeaheadEncodingsRequest {
|
|
11
12
|
session_id: string;
|
|
@@ -34,14 +35,61 @@ export interface SlowLaneClientConfig {
|
|
|
34
35
|
sessionId?: string;
|
|
35
36
|
surface?: string;
|
|
36
37
|
}
|
|
37
|
-
export
|
|
38
|
+
export interface SlowLaneClient {
|
|
39
|
+
getBoundaryLmState?: (contextKey: string) => BoundaryLmState | null;
|
|
40
|
+
getCanonicalSurfaceCount?: () => number;
|
|
41
|
+
getCanonicalSurfaceTokenIds?: (surface: string) => number[] | null;
|
|
42
|
+
getContextInput?: () => string | null;
|
|
38
43
|
getContextVector: () => Float32Array | null;
|
|
39
44
|
getLmLogits: () => Record<string, number> | null;
|
|
45
|
+
getProgressiveSurfaceEvidence?: (contextKey: string, surface: string) => ProgressiveSurfaceEvidence | null;
|
|
46
|
+
getSurfaceScore?: (contextKey: string, surface: string) => SurfaceScore | null;
|
|
47
|
+
isReady?: () => boolean;
|
|
40
48
|
isWordBoundary: (text: string) => boolean;
|
|
49
|
+
primeBoundaryLm?: (input: BoundaryPrimeRequest) => void;
|
|
50
|
+
requestProgressiveSurfaceScores?: (input: SurfaceScoreRequest) => void;
|
|
41
51
|
setContextVector: (vector: Float32Array | null) => void;
|
|
42
52
|
setLmLogits: (logits: Record<string, number> | null) => void;
|
|
43
53
|
updateContext: (text: string) => void;
|
|
44
|
-
}
|
|
45
|
-
export declare const
|
|
54
|
+
}
|
|
55
|
+
export declare const createSlowLaneClient: (config: SlowLaneClientConfig) => SlowLaneClient;
|
|
56
|
+
export type SlowLaneClientKind = 'localLlm' | 'server';
|
|
57
|
+
export interface SlowLaneClientRegistration {
|
|
58
|
+
clientId: string;
|
|
59
|
+
kind: SlowLaneClientKind;
|
|
60
|
+
}
|
|
61
|
+
export interface SlowLaneClientStatus {
|
|
62
|
+
canonicalScoringSupported: boolean;
|
|
63
|
+
canonicalSurfaceCount: number | null;
|
|
64
|
+
clientId: string | null;
|
|
65
|
+
clientKind: SlowLaneClientKind | null;
|
|
66
|
+
localModelReady: boolean | null;
|
|
67
|
+
registered: boolean;
|
|
68
|
+
}
|
|
69
|
+
export declare const setDefaultSlowLaneClient: (client: SlowLaneClient | null, registration?: SlowLaneClientRegistration) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Clear the shared client only when the caller still owns the registration.
|
|
72
|
+
*
|
|
73
|
+
* Multiple editor instances can briefly overlap during a React/editor remount.
|
|
74
|
+
* An older instance must not disconnect the newer instance when its delayed
|
|
75
|
+
* teardown runs after the newer client has registered.
|
|
76
|
+
*/
|
|
77
|
+
export declare const clearDefaultSlowLaneClient: (client: SlowLaneClient) => boolean;
|
|
78
|
+
export declare const getDefaultSlowLaneClientStatus: () => SlowLaneClientStatus;
|
|
46
79
|
export declare const getStoredContextVector: () => Float32Array | null;
|
|
80
|
+
export declare const getStoredContextInput: () => string | null;
|
|
47
81
|
export declare const getStoredLmLogits: () => Record<string, number> | null;
|
|
82
|
+
export declare const getBoundaryLmState: (contextKey: string) => BoundaryLmState | null;
|
|
83
|
+
export declare const getCanonicalSurfaceTokenIds: (surface: string) => number[] | null;
|
|
84
|
+
export declare const getSurfaceScore: (contextKey: string, surface: string) => SurfaceScore | null;
|
|
85
|
+
export declare const getProgressiveSurfaceEvidence: (contextKey: string, surface: string) => ProgressiveSurfaceEvidence | null;
|
|
86
|
+
export declare const primeBoundaryLm: (input: BoundaryPrimeRequest) => void;
|
|
87
|
+
export declare const requestProgressiveSurfaceScores: (input: SurfaceScoreRequest) => void;
|
|
88
|
+
export declare const isCanonicalSurfaceScoringSupported: () => boolean;
|
|
89
|
+
/**
|
|
90
|
+
* How many surfaces the canonical token map currently holds. Goes from zero to
|
|
91
|
+
* its final size once the artifact lands, which is the only point at which
|
|
92
|
+
* `getCanonicalSurfaceTokenIds` starts answering — so callers memoising over
|
|
93
|
+
* that lookup can use this to detect the transition.
|
|
94
|
+
*/
|
|
95
|
+
export declare const getCanonicalSurfaceCount: () => number;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Two prediction modes:
|
|
5
5
|
* 1. Word boundary → bigram-based next-word suggestion (grammar-filtered)
|
|
6
|
-
* 2. Mid-word (≥
|
|
6
|
+
* 2. Mid-word (≥1 char) → grouped prefetch; ≥3 chars + exact evidence → ghost result
|
|
7
7
|
*
|
|
8
8
|
* Scoring is delegated to scoring-pipeline.ts which handles:
|
|
9
9
|
* Stage 1 (semantic + frequency), grammar filter, Stage 2 (optional LM re-ranking).
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* Session personalization (L1): words the user types are incrementally boosted
|
|
15
15
|
* via incrementSessionFreq(), called on word boundaries from the plugin.
|
|
16
16
|
*/
|
|
17
|
+
import type { TermType } from './scoring-pipeline';
|
|
17
18
|
export interface WeightedTerm {
|
|
18
19
|
authorFreq: number;
|
|
19
20
|
docFreq: number;
|
|
@@ -33,13 +34,32 @@ interface VectorStore {
|
|
|
33
34
|
* expects a simple array of strings: ["about", "above", "actually", ...]
|
|
34
35
|
*/
|
|
35
36
|
export declare const initL3Vocabulary: (l3Words: string[]) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Start a short cooldown for the exact surface the editor inserted. The caller
|
|
39
|
+
* passes the committed snapshot's surface so background re-ranking can never
|
|
40
|
+
* move cooldown bookkeeping away from what the user actually accepted.
|
|
41
|
+
*/
|
|
42
|
+
export declare const noteSuggestionAccepted: (surface: string) => void;
|
|
36
43
|
/**
|
|
37
44
|
* Get predictor status for debugging.
|
|
38
45
|
* vectorsLoaded: true when semantic scoring is active
|
|
39
46
|
* wordCount: number of words in vector store (0 if not loaded)
|
|
40
47
|
*/
|
|
41
48
|
export declare const getPredictorStatus: () => {
|
|
49
|
+
canonicalScoringSupported: boolean;
|
|
50
|
+
canonicalSurfaceCount: number | null;
|
|
51
|
+
clientId: string | null;
|
|
52
|
+
clientKind: 'localLlm' | 'server' | null;
|
|
42
53
|
isInitialized: boolean;
|
|
54
|
+
localModelReady: boolean | null;
|
|
55
|
+
maxFreqByType: {
|
|
56
|
+
bigram: number;
|
|
57
|
+
phrase: number;
|
|
58
|
+
word: number;
|
|
59
|
+
};
|
|
60
|
+
phraseCount: number;
|
|
61
|
+
phrasesLoaded: boolean;
|
|
62
|
+
slowLaneRegistered: boolean;
|
|
43
63
|
vectorsLoaded: boolean;
|
|
44
64
|
vectorsLoadStarted: boolean;
|
|
45
65
|
wordCount: number;
|
|
@@ -49,8 +69,10 @@ export declare const getPredictorStatus: () => {
|
|
|
49
69
|
* Returns null if no prediction has run yet or debug was off.
|
|
50
70
|
*/
|
|
51
71
|
export declare const getLastPredictionDebug: () => {
|
|
72
|
+
awaitingAsyncEvidence: boolean;
|
|
52
73
|
contextWords: string[];
|
|
53
74
|
currentWord: string;
|
|
75
|
+
decision: string;
|
|
54
76
|
mode: 'cold' | 'warm';
|
|
55
77
|
suggestion: string | null;
|
|
56
78
|
textBefore: string;
|
|
@@ -63,6 +85,16 @@ export declare const getLastPredictionDebug: () => {
|
|
|
63
85
|
}>;
|
|
64
86
|
} | null;
|
|
65
87
|
export declare const initVocabulary: (vocabulary: TenantVocabulary) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Insert a producer-shipped bigram/phrase artifact into the phrase trie.
|
|
90
|
+
*
|
|
91
|
+
* :params:
|
|
92
|
+
* artifact: Normalized `{term: {freq, doc_freq, author_freq, pos_seq, head_pos, association}}` map
|
|
93
|
+
* termType: Whether these terms are `bigram` (2 tokens) or `phrase` (3 tokens)
|
|
94
|
+
* :returns:
|
|
95
|
+
* The number of terms inserted
|
|
96
|
+
*/
|
|
97
|
+
export declare const initPhrases: (artifact: PhraseArtifactJson, termType: TermType) => number;
|
|
66
98
|
/**
|
|
67
99
|
* Increment L1 session frequency for a single word.
|
|
68
100
|
* Called from the plugin on word boundaries for efficient incremental boosting.
|
|
@@ -79,14 +111,100 @@ export declare const incrementSessionFreq: (word: string) => void;
|
|
|
79
111
|
* calling context does not yet have a page value available.
|
|
80
112
|
*/
|
|
81
113
|
export declare const ingestDocumentPage: (pageContent: string | undefined) => void;
|
|
82
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Result of a prediction: the ghost tail to insert plus an immutable record of
|
|
116
|
+
* the evidence that authorized the UI commitment.
|
|
117
|
+
*/
|
|
118
|
+
export interface PredictionResult {
|
|
119
|
+
/** Canonical evidence depth for the selected full surface. */
|
|
120
|
+
evidenceDepth: {
|
|
121
|
+
totalChars: number;
|
|
122
|
+
totalTokens: number;
|
|
123
|
+
verifiedChars: number;
|
|
124
|
+
verifiedTokens: number;
|
|
125
|
+
};
|
|
126
|
+
/** Evidence tier that authorized display. Tier A is never display-eligible. */
|
|
127
|
+
evidenceTier: 'canonical-full-surface' | 'network-logit';
|
|
128
|
+
/**
|
|
129
|
+
* Mean per-token log-probability of the verified prefix.
|
|
130
|
+
*
|
|
131
|
+
* Carried alongside the posterior because the two answer different
|
|
132
|
+
* questions and a plausibility floor is placed on this one. A surface alone
|
|
133
|
+
* in its normaliser holds the whole pool whatever the model thinks of it,
|
|
134
|
+
* so its posterior cannot say whether it was worth showing and this can.
|
|
135
|
+
*/
|
|
136
|
+
meanTokenLogProbability: number;
|
|
137
|
+
/**
|
|
138
|
+
* Whether a longer candidate in the same pool extends the selected surface.
|
|
139
|
+
*
|
|
140
|
+
* The chain rule leaves such a surface holding its pool's mass undivided, so
|
|
141
|
+
* its posterior is high for a structural reason rather than a modelled one —
|
|
142
|
+
* whichever continuation was meant, the prefix was right. Carried so the top
|
|
143
|
+
* posterior bucket can be split on it, since a lifted nested leader and a
|
|
144
|
+
* genuinely preferred surface are otherwise the same number.
|
|
145
|
+
*/
|
|
146
|
+
poolHeldExtension: boolean;
|
|
147
|
+
/** Share of its shortlist's mass the model put on the selected surface. */
|
|
148
|
+
posterior: number;
|
|
149
|
+
/** Final Stage-1 + LM ranking score. */
|
|
150
|
+
rankScore: number;
|
|
151
|
+
/** How many scored candidates the selected surface's normaliser divided between. */
|
|
152
|
+
shortlistSize: number;
|
|
153
|
+
/** Full surface of the selected candidate (identity for keep-vs-swap checks). */
|
|
154
|
+
surface: string;
|
|
155
|
+
/** Whether the selected surface is a single word, a bigram, or a phrase. */
|
|
156
|
+
termType: TermType;
|
|
157
|
+
/** Ghost tail actually shown/inserted (surface minus the already-typed prefix). */
|
|
158
|
+
text: string;
|
|
159
|
+
/** Final-score lead over the strongest evidence-backed runner-up. */
|
|
160
|
+
winnerMargin: number;
|
|
161
|
+
}
|
|
162
|
+
export declare const predict: (textBefore: string) => PredictionResult | null;
|
|
163
|
+
/**
|
|
164
|
+
* Per-term stats shape for `bigrams.json` / `phrases.json`. Field names/types
|
|
165
|
+
* confirmed against the producer (`l2_vocabulary_creation._build_ngram_stat_payload`
|
|
166
|
+
* + `artifact_release._validate_ngram_payload`): `freq`/`doc_freq`/`author_freq`
|
|
167
|
+
* are ints, `pos_seq` a string array, `head_pos` a string or null, `association`
|
|
168
|
+
* a number.
|
|
169
|
+
*/
|
|
170
|
+
interface PhraseStatsJson {
|
|
171
|
+
association?: number;
|
|
172
|
+
author_freq: number;
|
|
173
|
+
doc_freq: number;
|
|
174
|
+
freq: number;
|
|
175
|
+
head_pos?: string | null;
|
|
176
|
+
pos_seq?: string[];
|
|
177
|
+
}
|
|
178
|
+
/** Normalized `{term: stats}` map after unwrapping any producer wrapper key. */
|
|
179
|
+
type PhraseArtifactJson = Record<string, PhraseStatsJson>;
|
|
83
180
|
export declare const loadVectorsAsync: (options?: {
|
|
84
181
|
isLocalLLM?: boolean;
|
|
85
182
|
surface?: string;
|
|
86
183
|
}) => Promise<void>;
|
|
87
184
|
export declare const initVectors: (store: VectorStore) => void;
|
|
185
|
+
/**
|
|
186
|
+
* Load the producer's `bigrams.json` + `phrases.json` completion-term artifacts
|
|
187
|
+
* over the TDP-OS gateway and insert them into the phrase trie.
|
|
188
|
+
*
|
|
189
|
+
* Each file is fetched independently (`Promise.allSettled`) so a missing or
|
|
190
|
+
* late-published artifact only skips that term type — word completion and the
|
|
191
|
+
* other term type are unaffected. Phrase VECTORS are not fetched here: per the
|
|
192
|
+
* producer's `extend` decision they are appended into the existing
|
|
193
|
+
* `word-index-10k.json` / `word-vectors-10k.bin`, so `loadVectorsAsync` already
|
|
194
|
+
* covers them.
|
|
195
|
+
*
|
|
196
|
+
* :params:
|
|
197
|
+
* options.isLocalLLM: Tags the UFO experience so latency/success feeds the same SLO
|
|
198
|
+
* :returns:
|
|
199
|
+
* A promise that resolves once both fetches have settled
|
|
200
|
+
*/
|
|
201
|
+
export declare const loadPhraseArtifacts: (options?: {
|
|
202
|
+
isLocalLLM?: boolean;
|
|
203
|
+
}) => Promise<void>;
|
|
204
|
+
type VocabularyLoadSource = 'focus' | 'predict';
|
|
88
205
|
export declare const loadDefaultVocabulary: (options?: {
|
|
89
206
|
isLocalLLM?: boolean;
|
|
207
|
+
source?: VocabularyLoadSource;
|
|
90
208
|
surface?: string;
|
|
91
209
|
}) => Promise<void>;
|
|
92
210
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-autocomplete",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "Client-side text autocomplete plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"wink-nlp": "^2.4.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@atlaskit/editor-common": "^119.
|
|
30
|
+
"@atlaskit/editor-common": "^119.4.0",
|
|
31
31
|
"@atlaskit/editor-plugin-analytics": "^15.0.0",
|
|
32
32
|
"react": "^18.2.0 || ^19.2.0"
|
|
33
33
|
},
|
package/src/analytics/ufo.ts
CHANGED
|
@@ -37,6 +37,7 @@ export const EXPERIENCE_NAME = {
|
|
|
37
37
|
SLOW_LANE_FETCH: 'slow-lane-fetch',
|
|
38
38
|
LOAD_VOCABULARY: 'load-vocabulary',
|
|
39
39
|
LOAD_VECTORS: 'load-vectors',
|
|
40
|
+
LOAD_PHRASES: 'load-phrases',
|
|
40
41
|
LOAD_GRAMMAR: 'load-grammar',
|
|
41
42
|
} as const;
|
|
42
43
|
|
|
@@ -70,6 +71,10 @@ const experiences: Record<AutocompleteExperienceName, ConcurrentExperience> = {
|
|
|
70
71
|
EXPERIENCE_NAME.LOAD_VECTORS,
|
|
71
72
|
operationConfig,
|
|
72
73
|
),
|
|
74
|
+
[EXPERIENCE_NAME.LOAD_PHRASES]: new ConcurrentExperience(
|
|
75
|
+
EXPERIENCE_NAME.LOAD_PHRASES,
|
|
76
|
+
operationConfig,
|
|
77
|
+
),
|
|
73
78
|
[EXPERIENCE_NAME.LOAD_GRAMMAR]: new ConcurrentExperience(
|
|
74
79
|
EXPERIENCE_NAME.LOAD_GRAMMAR,
|
|
75
80
|
operationConfig,
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation and diagnostics layer over the artifacts manifest.
|
|
3
|
+
*
|
|
4
|
+
* `artifacts-manifest` owns *where* a payload comes from (one manifest request,
|
|
5
|
+
* then a presigned CDN download). This module owns *whether the payload is
|
|
6
|
+
* usable*: every loader declares the shape it expects, so a mis-published
|
|
7
|
+
* artifact fails at the boundary with the artifact's name rather than surfacing
|
|
8
|
+
* later as an empty trie or a silent no-op in scoring.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { type ArtifactName, fetchArtifactJson, getArtifactUrl } from './artifacts-manifest';
|
|
12
|
+
import { ctcTag } from './debug-mode';
|
|
13
|
+
|
|
14
|
+
const TRAILING_SLASH_REGEX = /\/$/u;
|
|
15
|
+
const DEFAULT_BASE_URL = '';
|
|
16
|
+
const AUTOCOMPLETE_GATEWAY_BASE = '/gateway/api/v1/autocomplete';
|
|
17
|
+
|
|
18
|
+
type ArtifactLoaderOptions<T> = {
|
|
19
|
+
label?: string;
|
|
20
|
+
summarize?: (payload: T) => string;
|
|
21
|
+
validate?: (payload: unknown) => payload is T;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build a URL for one of the autocomplete gateway's own endpoints (e.g. the
|
|
26
|
+
* network slow lane). Model artifacts do NOT go through here — they are served
|
|
27
|
+
* from the CDN via the manifest.
|
|
28
|
+
*/
|
|
29
|
+
export const buildAutocompleteGatewayUrl = (
|
|
30
|
+
path: string,
|
|
31
|
+
baseUrl: string = DEFAULT_BASE_URL,
|
|
32
|
+
): string => {
|
|
33
|
+
const normalizedBase = baseUrl.replace(TRAILING_SLASH_REGEX, '');
|
|
34
|
+
return `${normalizedBase}${AUTOCOMPLETE_GATEWAY_BASE}${path}`;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Download a JSON artifact and assert its shape before handing it to a loader.
|
|
39
|
+
*
|
|
40
|
+
* :params:
|
|
41
|
+
* artifactName: Manifest key for the artifact
|
|
42
|
+
* options.label: Name used in diagnostics; defaults to the manifest key
|
|
43
|
+
* options.summarize: Renders a short size/count summary for the debug log
|
|
44
|
+
* options.validate: Type guard the payload must satisfy
|
|
45
|
+
* :returns:
|
|
46
|
+
* The parsed, validated payload
|
|
47
|
+
*/
|
|
48
|
+
export const fetchAutocompleteArtifactJson = async <T>(
|
|
49
|
+
artifactName: ArtifactName,
|
|
50
|
+
options: ArtifactLoaderOptions<T> = {},
|
|
51
|
+
): Promise<T> => {
|
|
52
|
+
const label = options.label ?? artifactName;
|
|
53
|
+
// Presigned CDN URLs carry an auth token, so only the artifact name is logged.
|
|
54
|
+
ctcTag('init', `↓ loading ${label}`);
|
|
55
|
+
|
|
56
|
+
const payload = await fetchArtifactJson<unknown>(artifactName);
|
|
57
|
+
if (options.validate && !options.validate(payload)) {
|
|
58
|
+
throw new Error(`[autocomplete-artifacts] ${label} payload shape was invalid`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const summary = options.summarize?.(payload as T);
|
|
62
|
+
ctcTag('init', `✓ loaded ${label}${summary ? ` (${summary})` : ''}`);
|
|
63
|
+
|
|
64
|
+
return payload as T;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Download a binary artifact (the word-vectors blob) as an ArrayBuffer.
|
|
69
|
+
*
|
|
70
|
+
* :params:
|
|
71
|
+
* artifactName: Manifest key for the artifact
|
|
72
|
+
* label: Name used in diagnostics; defaults to the manifest key
|
|
73
|
+
* :returns:
|
|
74
|
+
* The raw bytes of the artifact
|
|
75
|
+
*/
|
|
76
|
+
export const fetchAutocompleteArtifactBinary = async (
|
|
77
|
+
artifactName: ArtifactName,
|
|
78
|
+
label: string = artifactName,
|
|
79
|
+
): Promise<ArrayBuffer> => {
|
|
80
|
+
ctcTag('init', `↓ loading ${label}`);
|
|
81
|
+
|
|
82
|
+
const url = await getArtifactUrl(artifactName);
|
|
83
|
+
const response = await fetch(url);
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
throw new Error(`[autocomplete-artifacts] Failed to fetch ${label}: ${response.status}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const payload = await response.arrayBuffer();
|
|
89
|
+
ctcTag('init', `✓ loaded ${label} (${payload.byteLength} bytes)`);
|
|
90
|
+
|
|
91
|
+
return payload;
|
|
92
|
+
};
|
|
@@ -20,10 +20,13 @@ import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
|
20
20
|
* hyphenated, unlike the underscored filenames the artifacts are generated from.
|
|
21
21
|
*/
|
|
22
22
|
export const ARTIFACT_NAME = {
|
|
23
|
+
BIGRAMS: 'bigrams.json',
|
|
23
24
|
FIRST_TOKEN_TO_WORDS: 'first-token-to-words.json',
|
|
24
25
|
GHOST_POS_TAGS: 'ghost-pos-tags.json',
|
|
25
26
|
GRAMMAR_TRANSITIONS: 'grammar-transitions-10k.json',
|
|
26
27
|
L3_VOCABULARY: 'l3-vocabulary.json',
|
|
28
|
+
PHRASE_CONTINUATION_TOKENS: 'phrase-continuation-tokens.json',
|
|
29
|
+
PHRASES: 'phrases.json',
|
|
27
30
|
POS_TAGS: 'combined-l2-l3-pos-tags.json',
|
|
28
31
|
VOCABULARY: 'vocabulary-10k.json',
|
|
29
32
|
WORD_INDEX: 'word-index-10k.json',
|