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