@atlaskit/editor-plugin-autocomplete 2.4.0 → 2.5.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 +31 -0
- package/afm-cc/tsconfig.json +3 -0
- package/afm-products/tsconfig.json +3 -0
- package/dist/cjs/analytics/ufo.js +111 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +126 -64
- package/dist/cjs/pm-plugins/local-slow-lane-client.js +447 -0
- package/dist/cjs/pm-plugins/slow-lane-client.js +45 -16
- package/dist/cjs/pm-plugins/text-predictor.js +72 -40
- package/dist/es2019/analytics/ufo.js +110 -0
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +132 -72
- package/dist/es2019/pm-plugins/local-slow-lane-client.js +355 -0
- package/dist/es2019/pm-plugins/slow-lane-client.js +29 -2
- package/dist/es2019/pm-plugins/text-predictor.js +48 -15
- package/dist/esm/analytics/ufo.js +105 -0
- package/dist/esm/pm-plugins/autocomplete-plugin.js +126 -64
- package/dist/esm/pm-plugins/local-slow-lane-client.js +439 -0
- package/dist/esm/pm-plugins/slow-lane-client.js +45 -16
- package/dist/esm/pm-plugins/text-predictor.js +73 -40
- package/dist/types/analytics/ufo.d.ts +38 -0
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +5 -0
- package/dist/types/pm-plugins/local-slow-lane-client.d.ts +102 -0
- package/dist/types-ts4.5/analytics/ufo.d.ts +38 -0
- package/dist/types-ts4.5/pm-plugins/autocomplete-plugin.d.ts +5 -0
- package/dist/types-ts4.5/pm-plugins/local-slow-lane-client.d.ts +102 -0
- package/package.json +7 -2
- package/src/analytics/ufo.ts +139 -0
- package/src/pm-plugins/autocomplete-plugin.ts +126 -64
- package/src/pm-plugins/local-slow-lane-client.ts +480 -0
- package/src/pm-plugins/slow-lane-client.ts +28 -2
- package/src/pm-plugins/text-predictor.ts +42 -12
- package/tsconfig.app.json +3 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
5
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
6
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
7
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
8
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
9
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
10
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
11
|
+
/**
|
|
12
|
+
* Local Slow Lane Client: On-device inference via @mlc-ai/web-llm.
|
|
13
|
+
*
|
|
14
|
+
* Drop-in replacement for the network-based slow-lane-client. Instead of
|
|
15
|
+
* calling a backend API, this client uses MLC WebLLM to run a small language
|
|
16
|
+
* model (SmolLM 135M) directly in the browser via WebGPU.
|
|
17
|
+
*
|
|
18
|
+
* ── Why main thread (no Web Worker)? ─────────────────────────────────────
|
|
19
|
+
* SmolLM 135M is small enough (~270 MB weights, 350-400 MB VRAM) that
|
|
20
|
+
* WebGPU inference on the main thread is production-viable:
|
|
21
|
+
*
|
|
22
|
+
* - WebGPU GPU compute is inherently async (doesn't block the main thread)
|
|
23
|
+
* - CPU overhead (tokenization + post-processing) is only 5-10 ms
|
|
24
|
+
* - Single forward pass latency is 50-150 ms — well within autocomplete
|
|
25
|
+
* expectations (~250 ms between word boundaries)
|
|
26
|
+
*
|
|
27
|
+
* This avoids all the complexity of Web Workers:
|
|
28
|
+
* - No CSP workarounds (blob URLs, inline scripts)
|
|
29
|
+
* - No bundler configuration (worker-plugin, import.meta.url)
|
|
30
|
+
* - No message passing protocol
|
|
31
|
+
* - Standard npm import — just works
|
|
32
|
+
*
|
|
33
|
+
* ── Interface ────────────────────────────────────────────────────────────
|
|
34
|
+
* Same shape as createSlowLaneClient so text-predictor.ts needs zero changes.
|
|
35
|
+
* The client exposes getContextVector() and getLmLogits() which are populated
|
|
36
|
+
* asynchronously after each updateContext() call.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
40
|
+
import { isWordBoundary } from './slow-lane-client';
|
|
41
|
+
|
|
42
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
// Same return type as createSlowLaneClient for drop-in compatibility
|
|
45
|
+
|
|
46
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
var DEFAULT_DEBOUNCE_MS = 300;
|
|
49
|
+
export var LOCAL_MLC_MODEL_ID = 'SmolLM2-135M-Instruct-q0f16-MLC';
|
|
50
|
+
|
|
51
|
+
/** HF root for the default weights (includes `tensor-cache.json` for WebLLM 0.2+). */
|
|
52
|
+
export var LOCAL_MLC_HF_MODEL_REPO = 'https://huggingface.co/mlc-ai/SmolLM2-135M-Instruct-q0f16-MLC';
|
|
53
|
+
export var LOCAL_MLC_MODEL_LIB_WASM_NAME = 'SmolLM2-135M-Instruct-q0f16-ctx4k_cs1k-webgpu.wasm';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Original target repo (add-basics fine-tune). **Not compatible with WebLLM 0.2.x** (no `tensor-cache.json`).
|
|
57
|
+
* @see module doc above
|
|
58
|
+
*/
|
|
59
|
+
export var HUGGINGFACE_TB_SMOLLM_ADD_BASICS_REPO = 'https://huggingface.co/HuggingFaceTB/smollm-135M-instruct-add-basics-q0f16-MLC';
|
|
60
|
+
|
|
61
|
+
// ─── Factory ─────────────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create a local slow-lane client powered by MLC WebLLM.
|
|
65
|
+
*
|
|
66
|
+
* The engine is initialised lazily — model weights are downloaded (and cached
|
|
67
|
+
* in IndexedDB) on first use. Subsequent page loads skip the download.
|
|
68
|
+
*
|
|
69
|
+
* Usage:
|
|
70
|
+
* ```ts
|
|
71
|
+
* const client = createLocalSlowLaneClient({ debounceMs: 300 });
|
|
72
|
+
* // On word boundaries:
|
|
73
|
+
* client.updateContext(docText);
|
|
74
|
+
* // In scoring pipeline:
|
|
75
|
+
* const vec = client.getContextVector();
|
|
76
|
+
* const logits = client.getLmLogits();
|
|
77
|
+
* // On plugin teardown:
|
|
78
|
+
* client.destroy();
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
82
|
+
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
83
|
+
var _config$debounceMs = config.debounceMs,
|
|
84
|
+
debounceMs = _config$debounceMs === void 0 ? DEFAULT_DEBOUNCE_MS : _config$debounceMs,
|
|
85
|
+
onUpdate = config.onUpdate,
|
|
86
|
+
onStatus = config.onStatus,
|
|
87
|
+
_config$modelId = config.modelId,
|
|
88
|
+
modelId = _config$modelId === void 0 ? LOCAL_MLC_MODEL_ID : _config$modelId,
|
|
89
|
+
customModelConfig = config.customModelConfig;
|
|
90
|
+
|
|
91
|
+
// ── State ──────────────────────────────────────────────────────────────
|
|
92
|
+
var storedContextVector = null;
|
|
93
|
+
var storedLmLogits = null;
|
|
94
|
+
var debounceTimer = null;
|
|
95
|
+
var lastRequestedText = '';
|
|
96
|
+
var requestCounter = 0;
|
|
97
|
+
var latestRequestId = -1;
|
|
98
|
+
var ready = false;
|
|
99
|
+
var destroyed = false;
|
|
100
|
+
var initFailed = false;
|
|
101
|
+
var engine = null;
|
|
102
|
+
var engineInitPromise = null;
|
|
103
|
+
var unloadEngine = function unloadEngine(engineToUnload) {
|
|
104
|
+
engineToUnload.unload().catch(function (error) {
|
|
105
|
+
if (isAutocompleteDebugEnabled()) {
|
|
106
|
+
// eslint-disable-next-line no-console
|
|
107
|
+
console.log('%c[LocalSlowLane] %cFailed to unload engine', 'color: #9c27b0; font-weight: bold;', 'color: inherit;', error);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// ── Engine initialisation ──────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
var initProgressCallback = function initProgressCallback(progress) {
|
|
115
|
+
var message = "[".concat((progress.progress * 100).toFixed(0), "%] ").concat(progress.text);
|
|
116
|
+
if (isAutocompleteDebugEnabled()) {
|
|
117
|
+
// eslint-disable-next-line no-console
|
|
118
|
+
console.log("%c[LocalSlowLane] %c\uD83D\uDD04 ".concat(message), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
119
|
+
}
|
|
120
|
+
onStatus === null || onStatus === void 0 || onStatus(message);
|
|
121
|
+
};
|
|
122
|
+
var initEngine = /*#__PURE__*/function () {
|
|
123
|
+
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
124
|
+
var _yield$import, CreateMLCEngine, prebuiltAppConfig, customModelRecord, appConfig, errorMsg;
|
|
125
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
126
|
+
while (1) switch (_context.prev = _context.next) {
|
|
127
|
+
case 0:
|
|
128
|
+
_context.prev = 0;
|
|
129
|
+
if (isAutocompleteDebugEnabled()) {
|
|
130
|
+
// eslint-disable-next-line no-console
|
|
131
|
+
console.log("%c[LocalSlowLane] %c\uD83D\uDE80 Initialising MLC engine with model: ".concat(modelId), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
132
|
+
}
|
|
133
|
+
onStatus === null || onStatus === void 0 || onStatus("Initialising model: ".concat(modelId, "\u2026"));
|
|
134
|
+
if ('gpu' in navigator) {
|
|
135
|
+
_context.next = 5;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
throw new Error('WebGPU not supported');
|
|
139
|
+
case 5:
|
|
140
|
+
_context.next = 7;
|
|
141
|
+
return import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-mlc-web-llm" */'@mlc-ai/web-llm');
|
|
142
|
+
case 7:
|
|
143
|
+
_yield$import = _context.sent;
|
|
144
|
+
CreateMLCEngine = _yield$import.CreateMLCEngine;
|
|
145
|
+
prebuiltAppConfig = _yield$import.prebuiltAppConfig;
|
|
146
|
+
customModelRecord = customModelConfig ? _objectSpread(_objectSpread({
|
|
147
|
+
model: customModelConfig.model,
|
|
148
|
+
model_id: modelId,
|
|
149
|
+
model_lib: customModelConfig.modelLib,
|
|
150
|
+
low_resource_required: true,
|
|
151
|
+
required_features: ['shader-f16']
|
|
152
|
+
}, customModelConfig.vramRequiredMB !== undefined ? {
|
|
153
|
+
vram_required_MB: customModelConfig.vramRequiredMB
|
|
154
|
+
} : {}), customModelConfig.contextWindowSize !== undefined ? {
|
|
155
|
+
overrides: {
|
|
156
|
+
context_window_size: customModelConfig.contextWindowSize
|
|
157
|
+
}
|
|
158
|
+
} : {}) : undefined;
|
|
159
|
+
appConfig = {
|
|
160
|
+
model_list: [].concat(_toConsumableArray(prebuiltAppConfig.model_list), _toConsumableArray(customModelRecord ? [customModelRecord] : []))
|
|
161
|
+
};
|
|
162
|
+
_context.next = 14;
|
|
163
|
+
return CreateMLCEngine(modelId, {
|
|
164
|
+
appConfig: appConfig,
|
|
165
|
+
initProgressCallback: initProgressCallback
|
|
166
|
+
});
|
|
167
|
+
case 14:
|
|
168
|
+
engine = _context.sent;
|
|
169
|
+
if (!destroyed) {
|
|
170
|
+
_context.next = 19;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
// destroy() was called while we were loading — clean up
|
|
174
|
+
unloadEngine(engine);
|
|
175
|
+
engine = null;
|
|
176
|
+
return _context.abrupt("return");
|
|
177
|
+
case 19:
|
|
178
|
+
ready = true;
|
|
179
|
+
if (isAutocompleteDebugEnabled()) {
|
|
180
|
+
// eslint-disable-next-line no-console
|
|
181
|
+
console.log('%c[LocalSlowLane] %c✅ MLC engine loaded and ready', 'color: #9c27b0; font-weight: bold;', 'color: #4caf50;');
|
|
182
|
+
}
|
|
183
|
+
onStatus === null || onStatus === void 0 || onStatus('Model loaded and ready.');
|
|
184
|
+
_context.next = 32;
|
|
185
|
+
break;
|
|
186
|
+
case 24:
|
|
187
|
+
_context.prev = 24;
|
|
188
|
+
_context.t0 = _context["catch"](0);
|
|
189
|
+
errorMsg = _context.t0 instanceof Error ? _context.t0.message : String(_context.t0);
|
|
190
|
+
ready = false;
|
|
191
|
+
if (isAutocompleteDebugEnabled()) {
|
|
192
|
+
// eslint-disable-next-line no-console
|
|
193
|
+
console.log("[LocalSlowLane] Engine initialisation failed: ".concat(errorMsg));
|
|
194
|
+
}
|
|
195
|
+
onStatus === null || onStatus === void 0 || onStatus("Engine initialisation failed: ".concat(errorMsg));
|
|
196
|
+
engineInitPromise = null;
|
|
197
|
+
initFailed = true;
|
|
198
|
+
case 32:
|
|
199
|
+
case "end":
|
|
200
|
+
return _context.stop();
|
|
201
|
+
}
|
|
202
|
+
}, _callee, null, [[0, 24]]);
|
|
203
|
+
}));
|
|
204
|
+
return function initEngine() {
|
|
205
|
+
return _ref.apply(this, arguments);
|
|
206
|
+
};
|
|
207
|
+
}();
|
|
208
|
+
var ensureEngineInitialized = function ensureEngineInitialized() {
|
|
209
|
+
if (initFailed) {
|
|
210
|
+
return Promise.resolve();
|
|
211
|
+
}
|
|
212
|
+
if (!engineInitPromise) {
|
|
213
|
+
engineInitPromise = initEngine();
|
|
214
|
+
}
|
|
215
|
+
return engineInitPromise;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// ── Inference ──────────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Run a single forward pass to extract next-token logit probabilities.
|
|
222
|
+
*
|
|
223
|
+
* We use the chat completions API with `max_tokens: 1` and `logprobs: true`
|
|
224
|
+
* to get the model's next-token distribution without generating text.
|
|
225
|
+
* This is the cheapest possible inference call — a single forward pass.
|
|
226
|
+
*/
|
|
227
|
+
var runInference = /*#__PURE__*/function () {
|
|
228
|
+
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(text, requestId) {
|
|
229
|
+
var _response$choices, response, lmLogits, logprobsContent, tokenLogprobs, token, _iterator, _step, alt, _token, logitValues, topTokens, errorMsg;
|
|
230
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
231
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
232
|
+
case 0:
|
|
233
|
+
if (!(!engine || destroyed)) {
|
|
234
|
+
_context2.next = 2;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
return _context2.abrupt("return");
|
|
238
|
+
case 2:
|
|
239
|
+
_context2.prev = 2;
|
|
240
|
+
_context2.next = 5;
|
|
241
|
+
return engine.chat.completions.create({
|
|
242
|
+
messages: [{
|
|
243
|
+
role: 'user',
|
|
244
|
+
content: text
|
|
245
|
+
}],
|
|
246
|
+
max_tokens: 1,
|
|
247
|
+
logprobs: true,
|
|
248
|
+
top_logprobs: 5,
|
|
249
|
+
temperature: 0
|
|
250
|
+
});
|
|
251
|
+
case 5:
|
|
252
|
+
response = _context2.sent;
|
|
253
|
+
if (!(requestId < latestRequestId || destroyed)) {
|
|
254
|
+
_context2.next = 8;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
return _context2.abrupt("return");
|
|
258
|
+
case 8:
|
|
259
|
+
// ── Extract LM logits ───────────────────────────────────────
|
|
260
|
+
lmLogits = {};
|
|
261
|
+
logprobsContent = (_response$choices = response.choices) === null || _response$choices === void 0 || (_response$choices = _response$choices[0]) === null || _response$choices === void 0 || (_response$choices = _response$choices.logprobs) === null || _response$choices === void 0 ? void 0 : _response$choices.content;
|
|
262
|
+
if (logprobsContent && logprobsContent.length > 0) {
|
|
263
|
+
tokenLogprobs = logprobsContent[0]; // Add the top token
|
|
264
|
+
if (tokenLogprobs.token) {
|
|
265
|
+
token = tokenLogprobs.token.trim().toLowerCase();
|
|
266
|
+
if (token.length > 0 && /^[a-z\u017F\u212A]/i.test(token)) {
|
|
267
|
+
lmLogits[token] = Math.exp(tokenLogprobs.logprob);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Add alternative tokens from top_logprobs
|
|
272
|
+
if (tokenLogprobs.top_logprobs) {
|
|
273
|
+
_iterator = _createForOfIteratorHelper(tokenLogprobs.top_logprobs);
|
|
274
|
+
try {
|
|
275
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
276
|
+
alt = _step.value;
|
|
277
|
+
_token = alt.token.trim().toLowerCase();
|
|
278
|
+
if (_token.length > 0 && /^[a-z\u017F\u212A]/i.test(_token)) {
|
|
279
|
+
lmLogits[_token] = Math.exp(alt.logprob);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
} catch (err) {
|
|
283
|
+
_iterator.e(err);
|
|
284
|
+
} finally {
|
|
285
|
+
_iterator.f();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
storedLmLogits = Object.keys(lmLogits).length > 0 ? lmLogits : null;
|
|
290
|
+
|
|
291
|
+
// ── Semantic vector ─────────────────────────────────────────
|
|
292
|
+
// SmolLM is a generative model, not an embedding model, so we
|
|
293
|
+
// don't get a true semantic vector. We generate a lightweight
|
|
294
|
+
// pseudo-embedding from the logit distribution for compatibility
|
|
295
|
+
// with the existing scoring pipeline.
|
|
296
|
+
//
|
|
297
|
+
// For a production implementation, you would use a dedicated
|
|
298
|
+
// embedding model (e.g. via web-llm's embeddings API with an
|
|
299
|
+
// embedding-specific model).
|
|
300
|
+
if (storedLmLogits) {
|
|
301
|
+
logitValues = Object.values(storedLmLogits);
|
|
302
|
+
storedContextVector = new Float32Array(logitValues);
|
|
303
|
+
} else {
|
|
304
|
+
storedContextVector = null;
|
|
305
|
+
}
|
|
306
|
+
if (isAutocompleteDebugEnabled()) {
|
|
307
|
+
// eslint-disable-next-line no-console
|
|
308
|
+
console.groupCollapsed("%c[LocalSlowLane] %c\uD83D\uDCE5 Inference result (request #".concat(requestId, ")"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
309
|
+
// eslint-disable-next-line no-console
|
|
310
|
+
console.log(storedContextVector ? "\u2705 pseudo-vector: ".concat(storedContextVector.length, " dims") : '❌ No vector');
|
|
311
|
+
// eslint-disable-next-line no-console
|
|
312
|
+
console.log(storedLmLogits ? "\u2705 lm_logits: ".concat(Object.keys(storedLmLogits).length, " tokens") : '❌ No lm_logits');
|
|
313
|
+
if (storedLmLogits) {
|
|
314
|
+
topTokens = Object.entries(storedLmLogits).sort(function (_ref3, _ref4) {
|
|
315
|
+
var _ref5 = _slicedToArray(_ref3, 2),
|
|
316
|
+
a = _ref5[1];
|
|
317
|
+
var _ref6 = _slicedToArray(_ref4, 2),
|
|
318
|
+
b = _ref6[1];
|
|
319
|
+
return b - a;
|
|
320
|
+
}).slice(0, 10); // eslint-disable-next-line no-console
|
|
321
|
+
console.log('Top 10 predictions:', topTokens.map(function (_ref7) {
|
|
322
|
+
var _ref8 = _slicedToArray(_ref7, 2),
|
|
323
|
+
t = _ref8[0],
|
|
324
|
+
p = _ref8[1];
|
|
325
|
+
return "".concat(t, ": ").concat((p * 100).toFixed(1), "%");
|
|
326
|
+
}).join(', '));
|
|
327
|
+
}
|
|
328
|
+
// eslint-disable-next-line no-console
|
|
329
|
+
console.groupEnd();
|
|
330
|
+
}
|
|
331
|
+
onUpdate === null || onUpdate === void 0 || onUpdate({
|
|
332
|
+
textLength: text.length,
|
|
333
|
+
hasVector: storedContextVector !== null,
|
|
334
|
+
hasLmLogits: storedLmLogits !== null
|
|
335
|
+
});
|
|
336
|
+
_context2.next = 26;
|
|
337
|
+
break;
|
|
338
|
+
case 17:
|
|
339
|
+
_context2.prev = 17;
|
|
340
|
+
_context2.t0 = _context2["catch"](2);
|
|
341
|
+
if (!(requestId < latestRequestId)) {
|
|
342
|
+
_context2.next = 21;
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
return _context2.abrupt("return");
|
|
346
|
+
case 21:
|
|
347
|
+
storedContextVector = null;
|
|
348
|
+
storedLmLogits = null;
|
|
349
|
+
onUpdate === null || onUpdate === void 0 || onUpdate({
|
|
350
|
+
textLength: text.length,
|
|
351
|
+
hasVector: false,
|
|
352
|
+
hasLmLogits: false
|
|
353
|
+
});
|
|
354
|
+
errorMsg = _context2.t0 instanceof Error ? _context2.t0.message : String(_context2.t0);
|
|
355
|
+
if (isAutocompleteDebugEnabled()) {
|
|
356
|
+
// eslint-disable-next-line no-console
|
|
357
|
+
console.log("%c[LocalSlowLane] %c\u274C Inference error (request #".concat(requestId, "): ").concat(errorMsg), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
358
|
+
}
|
|
359
|
+
case 26:
|
|
360
|
+
case "end":
|
|
361
|
+
return _context2.stop();
|
|
362
|
+
}
|
|
363
|
+
}, _callee2, null, [[2, 17]]);
|
|
364
|
+
}));
|
|
365
|
+
return function runInference(_x, _x2) {
|
|
366
|
+
return _ref2.apply(this, arguments);
|
|
367
|
+
};
|
|
368
|
+
}();
|
|
369
|
+
|
|
370
|
+
// ── Context update (debounced) ─────────────────────────────────────────
|
|
371
|
+
|
|
372
|
+
var doUpdateContext = function doUpdateContext(text) {
|
|
373
|
+
if (destroyed || !text || text.trim().length === 0) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
var requestId = ++requestCounter;
|
|
377
|
+
latestRequestId = requestId;
|
|
378
|
+
if (isAutocompleteDebugEnabled()) {
|
|
379
|
+
// eslint-disable-next-line no-console
|
|
380
|
+
console.groupCollapsed("%c[LocalSlowLane] %c\uD83D\uDCE4 Context update (request #".concat(requestId, ") | ").concat(text.length, " chars"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
381
|
+
var lines = text.split('\n');
|
|
382
|
+
lines.forEach(function (line, i) {
|
|
383
|
+
// eslint-disable-next-line no-console
|
|
384
|
+
console.log(" ".concat(i === lines.length - 1 ? '▶' : ' ', " ").concat(line));
|
|
385
|
+
});
|
|
386
|
+
// eslint-disable-next-line no-console
|
|
387
|
+
console.groupEnd();
|
|
388
|
+
}
|
|
389
|
+
void ensureEngineInitialized().then(function () {
|
|
390
|
+
return runInference(text, requestId);
|
|
391
|
+
}).catch(function () {});
|
|
392
|
+
};
|
|
393
|
+
var updateContextDebounced = function updateContextDebounced(text) {
|
|
394
|
+
if (debounceTimer) {
|
|
395
|
+
clearTimeout(debounceTimer);
|
|
396
|
+
}
|
|
397
|
+
lastRequestedText = text;
|
|
398
|
+
debounceTimer = setTimeout(function () {
|
|
399
|
+
debounceTimer = null;
|
|
400
|
+
doUpdateContext(lastRequestedText);
|
|
401
|
+
}, debounceMs);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// ── Public API (same shape as createSlowLaneClient) ────────────────────
|
|
405
|
+
return {
|
|
406
|
+
updateContext: updateContextDebounced,
|
|
407
|
+
getContextVector: function getContextVector() {
|
|
408
|
+
return storedContextVector;
|
|
409
|
+
},
|
|
410
|
+
getLmLogits: function getLmLogits() {
|
|
411
|
+
return storedLmLogits;
|
|
412
|
+
},
|
|
413
|
+
setContextVector: function setContextVector(vector) {
|
|
414
|
+
storedContextVector = vector;
|
|
415
|
+
},
|
|
416
|
+
setLmLogits: function setLmLogits(logits) {
|
|
417
|
+
storedLmLogits = logits;
|
|
418
|
+
},
|
|
419
|
+
isWordBoundary: isWordBoundary,
|
|
420
|
+
isReady: function isReady() {
|
|
421
|
+
return ready;
|
|
422
|
+
},
|
|
423
|
+
destroy: function destroy() {
|
|
424
|
+
destroyed = true;
|
|
425
|
+
ready = false;
|
|
426
|
+
if (debounceTimer) {
|
|
427
|
+
clearTimeout(debounceTimer);
|
|
428
|
+
}
|
|
429
|
+
if (engine) {
|
|
430
|
+
var engineToUnload = engine;
|
|
431
|
+
engine = null;
|
|
432
|
+
unloadEngine(engineToUnload);
|
|
433
|
+
}
|
|
434
|
+
engineInitPromise = null;
|
|
435
|
+
storedContextVector = null;
|
|
436
|
+
storedLmLogits = null;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
};
|
|
@@ -10,6 +10,7 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
10
10
|
* Response: { semantic_vector: number[], lm_logits: Record<string, number> }
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { abortExp, EXPERIENCE_NAME, failExp, startExp, succeedExp } from '../analytics/ufo';
|
|
13
14
|
import { isAutocompleteDebugEnabled } from './debug-mode';
|
|
14
15
|
|
|
15
16
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
@@ -59,8 +60,10 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
59
60
|
var lastRequestedText = '';
|
|
60
61
|
var storedContextVector = null;
|
|
61
62
|
var storedLmLogits = null;
|
|
63
|
+
var requestSeq = 0;
|
|
64
|
+
var inflightRequestId = null;
|
|
62
65
|
var doUpdateContext = /*#__PURE__*/function () {
|
|
63
|
-
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(text) {
|
|
66
|
+
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(text, requestId) {
|
|
64
67
|
var url, payload, res, data;
|
|
65
68
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
66
69
|
while (1) switch (_context.prev = _context.next) {
|
|
@@ -77,6 +80,9 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
77
80
|
text: text,
|
|
78
81
|
session_id: sessionId
|
|
79
82
|
};
|
|
83
|
+
startExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
84
|
+
textLength: text.length
|
|
85
|
+
});
|
|
80
86
|
if (isAutocompleteDebugEnabled()) {
|
|
81
87
|
// eslint-disable-next-line no-console
|
|
82
88
|
console.groupCollapsed("%c[SlowLane] %c\uD83D\uDCE4 Sending context | ".concat(text.length, " chars"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
@@ -87,30 +93,34 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
87
93
|
// eslint-disable-next-line no-console
|
|
88
94
|
console.groupEnd();
|
|
89
95
|
}
|
|
90
|
-
_context.prev =
|
|
91
|
-
_context.next =
|
|
96
|
+
_context.prev = 6;
|
|
97
|
+
_context.next = 9;
|
|
92
98
|
return fetchFn(url, {
|
|
93
99
|
method: 'POST',
|
|
94
100
|
headers: headers,
|
|
95
101
|
body: JSON.stringify(payload)
|
|
96
102
|
});
|
|
97
|
-
case
|
|
103
|
+
case 9:
|
|
98
104
|
res = _context.sent;
|
|
99
105
|
if (res.ok) {
|
|
100
|
-
_context.next =
|
|
106
|
+
_context.next = 16;
|
|
101
107
|
break;
|
|
102
108
|
}
|
|
103
109
|
storedContextVector = null;
|
|
104
110
|
storedLmLogits = null;
|
|
111
|
+
failExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
112
|
+
status: res.status,
|
|
113
|
+
errorType: 'http_error'
|
|
114
|
+
});
|
|
105
115
|
if (isAutocompleteDebugEnabled()) {
|
|
106
116
|
// eslint-disable-next-line no-console
|
|
107
117
|
console.log("%c[SlowLane] %c\u274C Request failed (".concat(res.status, ")"), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
108
118
|
}
|
|
109
119
|
return _context.abrupt("return");
|
|
110
|
-
case 14:
|
|
111
|
-
_context.next = 16;
|
|
112
|
-
return res.json();
|
|
113
120
|
case 16:
|
|
121
|
+
_context.next = 18;
|
|
122
|
+
return res.json();
|
|
123
|
+
case 18:
|
|
114
124
|
data = _context.sent;
|
|
115
125
|
if (data.semantic_vector && Array.isArray(data.semantic_vector)) {
|
|
116
126
|
storedContextVector = new Float32Array(data.semantic_vector);
|
|
@@ -132,30 +142,44 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
132
142
|
// eslint-disable-next-line no-console
|
|
133
143
|
console.groupEnd();
|
|
134
144
|
}
|
|
145
|
+
succeedExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
146
|
+
textLength: text.length,
|
|
147
|
+
hasVector: storedContextVector !== null,
|
|
148
|
+
hasLmLogits: storedLmLogits !== null
|
|
149
|
+
});
|
|
135
150
|
onUpdate === null || onUpdate === void 0 || onUpdate({
|
|
136
151
|
textLength: text.length,
|
|
137
152
|
hasVector: storedContextVector !== null,
|
|
138
153
|
hasLmLogits: storedLmLogits !== null
|
|
139
154
|
});
|
|
140
155
|
// eslint-disable-next-line no-unused-vars
|
|
141
|
-
_context.next =
|
|
156
|
+
_context.next = 32;
|
|
142
157
|
break;
|
|
143
|
-
case
|
|
144
|
-
_context.prev =
|
|
145
|
-
_context.t0 = _context["catch"](
|
|
158
|
+
case 26:
|
|
159
|
+
_context.prev = 26;
|
|
160
|
+
_context.t0 = _context["catch"](6);
|
|
146
161
|
storedContextVector = null;
|
|
147
162
|
storedLmLogits = null;
|
|
163
|
+
failExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, requestId, {
|
|
164
|
+
errorType: 'network'
|
|
165
|
+
});
|
|
148
166
|
if (isAutocompleteDebugEnabled()) {
|
|
149
167
|
// eslint-disable-next-line no-console
|
|
150
168
|
console.log('%c[SlowLane] %c❌ Network error — context cleared', 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
151
169
|
}
|
|
152
|
-
case
|
|
170
|
+
case 32:
|
|
171
|
+
_context.prev = 32;
|
|
172
|
+
if (inflightRequestId === requestId) {
|
|
173
|
+
inflightRequestId = null;
|
|
174
|
+
}
|
|
175
|
+
return _context.finish(32);
|
|
176
|
+
case 35:
|
|
153
177
|
case "end":
|
|
154
178
|
return _context.stop();
|
|
155
179
|
}
|
|
156
|
-
}, _callee, null, [[
|
|
180
|
+
}, _callee, null, [[6, 26, 32, 35]]);
|
|
157
181
|
}));
|
|
158
|
-
return function doUpdateContext(_x) {
|
|
182
|
+
return function doUpdateContext(_x, _x2) {
|
|
159
183
|
return _ref.apply(this, arguments);
|
|
160
184
|
};
|
|
161
185
|
}();
|
|
@@ -166,7 +190,12 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
166
190
|
lastRequestedText = text;
|
|
167
191
|
debounceTimer = setTimeout(function () {
|
|
168
192
|
debounceTimer = null;
|
|
169
|
-
|
|
193
|
+
if (inflightRequestId !== null) {
|
|
194
|
+
abortExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, inflightRequestId, 'superseded');
|
|
195
|
+
}
|
|
196
|
+
var requestId = String(++requestSeq);
|
|
197
|
+
inflightRequestId = requestId;
|
|
198
|
+
doUpdateContext(lastRequestedText, requestId);
|
|
170
199
|
}, debounceMs);
|
|
171
200
|
};
|
|
172
201
|
return {
|