@atlaskit/editor-plugin-autocomplete 3.5.0 → 3.6.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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/editor-plugin-autocomplete
2
2
 
3
+ ## 3.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`9f6b6c9fffc50`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9f6b6c9fffc50) -
8
+ Add analytics for the on-device (local LLM) autocomplete slow lane: fire a `localModelLoaded`
9
+ track event when the engine initialises successfully (with load duration and GPU info) and a
10
+ `localModelLoadFailed` track event when it fails, categorising the reason and capturing WebGPU
11
+ capability diagnostics to surface user-machine limitations.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
3
17
  ## 3.5.0
4
18
 
5
19
  ### Minor Changes
@@ -247,12 +247,49 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
247
247
  }
248
248
  });
249
249
  };
250
- var fireSuggestionInsertedAnalytics = function fireSuggestionInsertedAnalytics(ghostText) {
250
+ var fireLocalModelLoadedAnalytics = function fireLocalModelLoadedAnalytics(info) {
251
251
  var _api$analytics2;
252
+ api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.fireAnalyticsEvent({
253
+ action: _analytics.ACTION.LOCAL_MODEL_LOADED,
254
+ actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
255
+ eventType: _analytics.EVENT_TYPE.TRACK,
256
+ attributes: {
257
+ modelId: info.modelId,
258
+ embeddingModelId: info.embeddingModelId,
259
+ loadDurationMs: info.loadDurationMs,
260
+ gpuVendor: info.capabilities.vendor,
261
+ gpuArchitecture: info.capabilities.architecture
262
+ }
263
+ });
264
+ };
265
+ var fireLocalModelLoadFailedAnalytics = function fireLocalModelLoadFailedAnalytics(error) {
266
+ var _api$analytics3;
267
+ var capabilities = error.capabilities;
268
+ api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.fireAnalyticsEvent({
269
+ action: _analytics.ACTION.LOCAL_MODEL_LOAD_FAILED,
270
+ actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
271
+ eventType: _analytics.EVENT_TYPE.TRACK,
272
+ attributes: {
273
+ reason: error.reason,
274
+ message: error.message,
275
+ modelId: error.modelId,
276
+ embeddingModelId: error.embeddingModelId,
277
+ webgpuAvailable: capabilities.available,
278
+ adapterAvailable: capabilities.adapterAvailable,
279
+ shaderF16Supported: capabilities.shaderF16Supported,
280
+ maxBufferSizeMB: capabilities.maxBufferSizeMB,
281
+ maxStorageBufferBindingSizeMB: capabilities.maxStorageBufferBindingSizeMB,
282
+ gpuVendor: capabilities.vendor,
283
+ gpuArchitecture: capabilities.architecture
284
+ }
285
+ });
286
+ };
287
+ var fireSuggestionInsertedAnalytics = function fireSuggestionInsertedAnalytics(ghostText) {
288
+ var _api$analytics4;
252
289
  var typedLength = lastSuggestionTypedLength;
253
290
  var suggestionLength = lastSuggestionLength || typedLength + ghostText.length;
254
291
  var kssDelta = suggestionLength - typedLength;
255
- api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.fireAnalyticsEvent({
292
+ api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || _api$analytics4.actions.fireAnalyticsEvent({
256
293
  action: _analytics.ACTION.SUGGESTION_INSERTED,
257
294
  actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
258
295
  eventType: _analytics.EVENT_TYPE.TRACK,
@@ -265,7 +302,9 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
265
302
  });
266
303
  };
267
304
  var slowLaneClient = options !== null && options !== void 0 && options.useLocalModel ? (0, _localSlowLaneClient.createLocalSlowLaneClient)({
268
- debounceMs: LOCAL_SLOW_LANE_DEBOUNCE_MS
305
+ debounceMs: LOCAL_SLOW_LANE_DEBOUNCE_MS,
306
+ onLoadSuccess: fireLocalModelLoadedAnalytics,
307
+ onLoadError: fireLocalModelLoadFailedAnalytics
269
308
  }) : (0, _slowLaneClient.createSlowLaneClient)({
270
309
  baseUrl: '',
271
310
  debounceMs: NETWORK_SLOW_LANE_DEBOUNCE_MS
@@ -419,9 +458,9 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
419
458
  lastSuggestionLength = typedLength + prediction.length;
420
459
  showGhostText(view, prediction, selection.from);
421
460
  if (prediction !== lastShownGhostText) {
422
- var _api$analytics3;
461
+ var _api$analytics5;
423
462
  lastShownGhostText = prediction;
424
- api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.fireAnalyticsEvent({
463
+ api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 || _api$analytics5.actions.fireAnalyticsEvent({
425
464
  action: _analytics.ACTION.SUGGESTION_VIEWED,
426
465
  actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
427
466
  eventType: _analytics.EVENT_TYPE.TRACK,
@@ -18,7 +18,7 @@ var _debugMode = require("./debug-mode");
18
18
  var _slowLaneClient = require("./slow-lane-client");
19
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
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" != _typeof3(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 _t3 in e) "default" !== _t3 && {}.hasOwnProperty.call(e, _t3) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t3)) && (i.get || i.set) ? o(f, _t3, i) : f[_t3] = e[_t3]); return f; })(e, t); }
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" != _typeof3(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 _t6 in e) "default" !== _t6 && {}.hasOwnProperty.call(e, _t6) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t6)) && (i.get || i.set) ? o(f, _t6, i) : f[_t6] = e[_t6]); return f; })(e, t); }
22
22
  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; } } }; }
23
23
  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; } }
24
24
  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; } /**
@@ -61,6 +61,19 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
61
61
 
62
62
  // Same return type as createSlowLaneClient for drop-in compatibility
63
63
 
64
+ /**
65
+ * Why the local engine failed to load/start.
66
+ *
67
+ * The first three are user-machine limitations (WebGPU missing, no compatible
68
+ * GPU adapter, GPU lacks the `shader-f16` feature the model needs);
69
+ * `insufficient_memory` is hit when weights don't fit in VRAM. The rest cover
70
+ * delivery/runtime failures unrelated to hardware.
71
+ */
72
+
73
+ /** Snapshot of the machine's WebGPU support, used to explain hardware limits. */
74
+
75
+ // Minimal WebGPU shape: lib.dom types aren't guaranteed in this build target.
76
+
64
77
  // ─── Constants ───────────────────────────────────────────────────────────────
65
78
 
66
79
  var DEFAULT_DEBOUNCE_MS = 300;
@@ -611,6 +624,8 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
611
624
  debounceMs = _config$debounceMs === void 0 ? DEFAULT_DEBOUNCE_MS : _config$debounceMs,
612
625
  onUpdate = config.onUpdate,
613
626
  onStatus = config.onStatus,
627
+ onLoadError = config.onLoadError,
628
+ onLoadSuccess = config.onLoadSuccess,
614
629
  _config$modelId = config.modelId,
615
630
  modelId = _config$modelId === void 0 ? LOCAL_MLC_CAUSAL_MODEL_ID : _config$modelId,
616
631
  customModelConfig = config.customModelConfig;
@@ -657,30 +672,191 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
657
672
  }
658
673
  onStatus === null || onStatus === void 0 || onStatus(message);
659
674
  };
660
- var initEngine = /*#__PURE__*/function () {
675
+ var bytesToMB = function bytesToMB(bytes) {
676
+ return typeof bytes === 'number' ? Math.round(bytes / (1024 * 1024)) : undefined;
677
+ };
678
+
679
+ /**
680
+ * Inspect the machine's WebGPU support so a load failure can be attributed
681
+ * to a concrete hardware/browser limitation rather than a generic error.
682
+ */
683
+ var probeWebGpuCapabilities = /*#__PURE__*/function () {
661
684
  var _ref8 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
662
- var _yield$Promise$all3, _yield$Promise$all4, _yield$Promise$all4$, MLCEngineCtor, prebuiltAppConfig, customModelRecord, appConfig, newEngine, errorMsg, _t;
685
+ var gpu, _adapter$limits, _adapter$limits2, adapter, vendor, architecture, _adapter$info, _adapter$requestAdapt, info, _t, _t2, _t3;
663
686
  return _regenerator.default.wrap(function (_context2) {
664
687
  while (1) switch (_context2.prev = _context2.next) {
665
688
  case 0:
666
- _context2.prev = 0;
667
- if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
668
- // eslint-disable-next-line no-console
669
- console.log("%c[LocalSlowLane] %c\uD83D\uDE80 Initialising MLC engine with models: ".concat(modelId, " (LM) + ").concat(LOCAL_MLC_EMBEDDING_MODEL_ID, " (embedder)"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
670
- }
671
- onStatus === null || onStatus === void 0 || onStatus("Initialising models: ".concat(modelId, " + ").concat(LOCAL_MLC_EMBEDDING_MODEL_ID, "\u2026"));
672
- if ('gpu' in navigator) {
689
+ gpu = navigator.gpu;
690
+ if (gpu) {
673
691
  _context2.next = 1;
674
692
  break;
675
693
  }
676
- throw new Error('WebGPU not supported');
694
+ return _context2.abrupt("return", {
695
+ available: false
696
+ });
677
697
  case 1:
698
+ _context2.prev = 1;
678
699
  _context2.next = 2;
700
+ return gpu.requestAdapter();
701
+ case 2:
702
+ adapter = _context2.sent;
703
+ if (adapter) {
704
+ _context2.next = 3;
705
+ break;
706
+ }
707
+ return _context2.abrupt("return", {
708
+ available: true,
709
+ adapterAvailable: false
710
+ });
711
+ case 3:
712
+ _context2.prev = 3;
713
+ if (!((_adapter$info = adapter.info) !== null && _adapter$info !== void 0)) {
714
+ _context2.next = 4;
715
+ break;
716
+ }
717
+ _t = _adapter$info;
718
+ _context2.next = 6;
719
+ break;
720
+ case 4:
721
+ _context2.next = 5;
722
+ return (_adapter$requestAdapt = adapter.requestAdapterInfo) === null || _adapter$requestAdapt === void 0 ? void 0 : _adapter$requestAdapt.call(adapter);
723
+ case 5:
724
+ _t = _context2.sent;
725
+ case 6:
726
+ info = _t;
727
+ vendor = (info === null || info === void 0 ? void 0 : info.vendor) || undefined;
728
+ architecture = (info === null || info === void 0 ? void 0 : info.architecture) || undefined;
729
+ _context2.next = 8;
730
+ break;
731
+ case 7:
732
+ _context2.prev = 7;
733
+ _t2 = _context2["catch"](3);
734
+ case 8:
735
+ return _context2.abrupt("return", {
736
+ available: true,
737
+ adapterAvailable: true,
738
+ shaderF16Supported: adapter.features.has('shader-f16'),
739
+ maxBufferSizeMB: bytesToMB((_adapter$limits = adapter.limits) === null || _adapter$limits === void 0 ? void 0 : _adapter$limits.maxBufferSize),
740
+ maxStorageBufferBindingSizeMB: bytesToMB((_adapter$limits2 = adapter.limits) === null || _adapter$limits2 === void 0 ? void 0 : _adapter$limits2.maxStorageBufferBindingSize),
741
+ vendor: vendor,
742
+ architecture: architecture
743
+ });
744
+ case 9:
745
+ _context2.prev = 9;
746
+ _t3 = _context2["catch"](1);
747
+ return _context2.abrupt("return", {
748
+ available: true,
749
+ adapterAvailable: false
750
+ });
751
+ case 10:
752
+ case "end":
753
+ return _context2.stop();
754
+ }
755
+ }, _callee2, null, [[1, 9], [3, 7]]);
756
+ }));
757
+ return function probeWebGpuCapabilities() {
758
+ return _ref8.apply(this, arguments);
759
+ };
760
+ }();
761
+
762
+ /** Map an MLC/WebLLM engine-creation error message to a coarse reason. */
763
+ var classifyEngineError = function classifyEngineError(message) {
764
+ var lower = message.toLowerCase();
765
+ if (lower.includes('loading chunk') || lower.includes('dynamically imported module') || lower.includes('dynamic import')) {
766
+ return 'module_load_failed';
767
+ }
768
+ if (lower.includes('out of memory') || /\boom\b/.test(lower) || lower.includes('allocation') || lower.includes('exceeds') || lower.includes('buffer size') || lower.includes('not enough memory')) {
769
+ return 'insufficient_memory';
770
+ }
771
+ // Pre-flight already returns missing_shader_f16 when the feature is absent,
772
+ // so only match the exact feature token here — not bare 'shader' (compile
773
+ // errors) or bare 'f16' (present in model ids like q0f16-MLC).
774
+ if (lower.includes('shader-f16') || lower.includes('shader_f16')) {
775
+ return 'missing_shader_f16';
776
+ }
777
+ if (lower.includes('fetch') || lower.includes('network') || lower.includes('download') || lower.includes('http') || lower.includes('cache')) {
778
+ return 'model_download_failed';
779
+ }
780
+ return 'init_failed';
781
+ };
782
+
783
+ // Canonical, controlled failure descriptions. We never emit the raw engine
784
+ // error into analytics — it can embed customer-context URLs/paths (HOT-120175)
785
+ // — so the analytics `message` is always one of these fixed strings.
786
+ var LOAD_FAILURE_MESSAGE = {
787
+ webgpu_unavailable: 'WebGPU is not available in this browser',
788
+ webgpu_no_adapter: 'No compatible WebGPU adapter found',
789
+ missing_shader_f16: 'GPU does not support the shader-f16 feature',
790
+ insufficient_memory: 'Insufficient GPU memory to load the model',
791
+ model_download_failed: 'Failed to download model assets',
792
+ module_load_failed: 'Failed to load the web-llm runtime module',
793
+ init_failed: 'Model engine failed to initialise'
794
+ };
795
+ var handleLoadFailure = function handleLoadFailure(reason, capabilities, debugDetail) {
796
+ ready = false;
797
+ var message = LOAD_FAILURE_MESSAGE[reason];
798
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
799
+ // eslint-disable-next-line no-console
800
+ console.log("[LocalSlowLane] Engine initialisation failed (".concat(reason, "): ").concat(debugDetail !== null && debugDetail !== void 0 ? debugDetail : message));
801
+ }
802
+ onStatus === null || onStatus === void 0 || onStatus("Engine initialisation failed: ".concat(message));
803
+ onLoadError === null || onLoadError === void 0 || onLoadError({
804
+ reason: reason,
805
+ message: message,
806
+ modelId: modelId,
807
+ embeddingModelId: LOCAL_MLC_EMBEDDING_MODEL_ID,
808
+ capabilities: capabilities
809
+ });
810
+ engineInitPromise = null;
811
+ initFailed = true;
812
+ };
813
+ var initEngine = /*#__PURE__*/function () {
814
+ var _ref9 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
815
+ var capabilities, startTime, _yield$Promise$all3, _yield$Promise$all4, _yield$Promise$all4$, MLCEngineCtor, prebuiltAppConfig, customModelRecord, appConfig, newEngine, loadDurationMs, errorMsg, _t4;
816
+ return _regenerator.default.wrap(function (_context3) {
817
+ while (1) switch (_context3.prev = _context3.next) {
818
+ case 0:
819
+ _context3.next = 1;
820
+ return probeWebGpuCapabilities();
821
+ case 1:
822
+ capabilities = _context3.sent;
823
+ if (capabilities.available) {
824
+ _context3.next = 2;
825
+ break;
826
+ }
827
+ handleLoadFailure('webgpu_unavailable', capabilities);
828
+ return _context3.abrupt("return");
829
+ case 2:
830
+ if (!(capabilities.adapterAvailable === false)) {
831
+ _context3.next = 3;
832
+ break;
833
+ }
834
+ handleLoadFailure('webgpu_no_adapter', capabilities);
835
+ return _context3.abrupt("return");
836
+ case 3:
837
+ if (!(capabilities.shaderF16Supported === false)) {
838
+ _context3.next = 4;
839
+ break;
840
+ }
841
+ handleLoadFailure('missing_shader_f16', capabilities);
842
+ return _context3.abrupt("return");
843
+ case 4:
844
+ startTime = performance.now();
845
+ _context3.prev = 5;
846
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
847
+ // eslint-disable-next-line no-console
848
+ console.log("%c[LocalSlowLane] %c\uD83D\uDE80 Initialising MLC engine with models: ".concat(modelId, " (LM) + ").concat(LOCAL_MLC_EMBEDDING_MODEL_ID, " (embedder)"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
849
+ }
850
+ onStatus === null || onStatus === void 0 || onStatus("Initialising models: ".concat(modelId, " + ").concat(LOCAL_MLC_EMBEDDING_MODEL_ID, "\u2026"));
851
+
852
+ // Fetch the web-llm runtime and the BE-parity lookup tables in parallel;
853
+ // both are dynamically imported so they stay out of the main editor chunk.
854
+ _context3.next = 6;
679
855
  return Promise.all([Promise.resolve().then(function () {
680
856
  return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-mlc-web-llm" */'@mlc-ai/web-llm'));
681
857
  }), loadBePayloadData()]);
682
- case 2:
683
- _yield$Promise$all3 = _context2.sent;
858
+ case 6:
859
+ _yield$Promise$all3 = _context3.sent;
684
860
  _yield$Promise$all4 = (0, _slicedToArray2.default)(_yield$Promise$all3, 1);
685
861
  _yield$Promise$all4$ = _yield$Promise$all4[0];
686
862
  MLCEngineCtor = _yield$Promise$all4$.MLCEngine;
@@ -708,19 +884,20 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
708
884
  initProgressCallback: initProgressCallback,
709
885
  logitProcessorRegistry: new Map([[modelId, lmLogitsCapture]])
710
886
  });
711
- _context2.next = 3;
887
+ _context3.next = 7;
712
888
  return newEngine.reload([modelId, LOCAL_MLC_EMBEDDING_MODEL_ID]);
713
- case 3:
889
+ case 7:
714
890
  if (!destroyed) {
715
- _context2.next = 4;
891
+ _context3.next = 8;
716
892
  break;
717
893
  }
718
894
  // destroy() was called while we were loading — clean up
719
895
  unloadEngine(newEngine);
720
- return _context2.abrupt("return");
721
- case 4:
896
+ return _context3.abrupt("return");
897
+ case 8:
722
898
  engine = newEngine;
723
899
  ready = true;
900
+ loadDurationMs = Math.round(performance.now() - startTime);
724
901
  if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
725
902
  // eslint-disable-next-line no-console
726
903
  console.log('%c[LocalSlowLane] %c✅ Both models loaded and ready', 'color: #9c27b0; font-weight: bold;', 'color: #4caf50;');
@@ -732,28 +909,27 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
732
909
  console.log('%c[LocalSlowLane] %c🔢 Embedder →', 'color: #9c27b0; font-weight: bold;', 'color: #009688; font-weight: bold;', LOCAL_MLC_EMBEDDING_MODEL_ID);
733
910
  }
734
911
  onStatus === null || onStatus === void 0 || onStatus('Model loaded and ready.');
735
- _context2.next = 6;
912
+ onLoadSuccess === null || onLoadSuccess === void 0 || onLoadSuccess({
913
+ modelId: modelId,
914
+ embeddingModelId: LOCAL_MLC_EMBEDDING_MODEL_ID,
915
+ loadDurationMs: loadDurationMs,
916
+ capabilities: capabilities
917
+ });
918
+ _context3.next = 10;
736
919
  break;
737
- case 5:
738
- _context2.prev = 5;
739
- _t = _context2["catch"](0);
740
- errorMsg = _t instanceof Error ? _t.message : String(_t);
741
- ready = false;
742
- if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
743
- // eslint-disable-next-line no-console
744
- console.log("[LocalSlowLane] Engine initialisation failed: ".concat(errorMsg));
745
- }
746
- onStatus === null || onStatus === void 0 || onStatus("Engine initialisation failed: ".concat(errorMsg));
747
- engineInitPromise = null;
748
- initFailed = true;
749
- case 6:
920
+ case 9:
921
+ _context3.prev = 9;
922
+ _t4 = _context3["catch"](5);
923
+ errorMsg = _t4 instanceof Error ? _t4.message : String(_t4);
924
+ handleLoadFailure(classifyEngineError(errorMsg), capabilities, errorMsg);
925
+ case 10:
750
926
  case "end":
751
- return _context2.stop();
927
+ return _context3.stop();
752
928
  }
753
- }, _callee2, null, [[0, 5]]);
929
+ }, _callee3, null, [[5, 9]]);
754
930
  }));
755
931
  return function initEngine() {
756
- return _ref8.apply(this, arguments);
932
+ return _ref9.apply(this, arguments);
757
933
  };
758
934
  }();
759
935
  var ensureEngineInitialized = function ensureEngineInitialized() {
@@ -780,16 +956,16 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
780
956
  * 384-d semantic vector (passage-encoded; see `wrapForArctic`).
781
957
  */
782
958
  var runInference = /*#__PURE__*/function () {
783
- var _ref9 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(text, requestId) {
784
- var lmText, semanticText, arcticInput, captureCompletionTime, _data, tStart, tLmDone, tEmbDone, _yield$Promise$all5, _yield$Promise$all6, embeddingResponse, rawLogits, payload, embedding, sumSq, i, topTokens, errorMsg, _t2;
785
- return _regenerator.default.wrap(function (_context3) {
786
- while (1) switch (_context3.prev = _context3.next) {
959
+ var _ref0 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(text, requestId) {
960
+ var lmText, semanticText, arcticInput, captureCompletionTime, _data, tStart, tLmDone, tEmbDone, _yield$Promise$all5, _yield$Promise$all6, embeddingResponse, rawLogits, payload, embedding, sumSq, i, topTokens, errorMsg, _t5;
961
+ return _regenerator.default.wrap(function (_context4) {
962
+ while (1) switch (_context4.prev = _context4.next) {
787
963
  case 0:
788
964
  if (!(!engine || destroyed)) {
789
- _context3.next = 1;
965
+ _context4.next = 1;
790
966
  break;
791
967
  }
792
- return _context3.abrupt("return");
968
+ return _context4.abrupt("return");
793
969
  case 1:
794
970
  // Clear the capture buffer so we read only this pass's logits. The engine
795
971
  // serialises per-model requests and updateContext is debounced, so the
@@ -816,11 +992,11 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
816
992
  // eslint-disable-next-line no-console
817
993
  console.log("%c[LocalSlowLane] %c\uD83E\uDDE0 LM input (".concat(lmText.length, " chars, ").concat(splitOnWhitespace(lmText).length, " words): \"").concat(lmText.length > 100 ? "".concat(lmText.slice(0, 100), "\u2026") : lmText, "\""), 'color: #9c27b0; font-weight: bold;', 'color: #2196f3;');
818
994
  }
819
- _context3.prev = 2;
995
+ _context4.prev = 2;
820
996
  tStart = performance.now();
821
997
  tLmDone = 0;
822
998
  tEmbDone = 0;
823
- _context3.next = 3;
999
+ _context4.next = 3;
824
1000
  return Promise.all([captureCompletionTime(engine.completions.create({
825
1001
  model: modelId,
826
1002
  prompt: lmText,
@@ -836,7 +1012,7 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
836
1012
  tEmbDone = resolvedAt;
837
1013
  })]);
838
1014
  case 3:
839
- _yield$Promise$all5 = _context3.sent;
1015
+ _yield$Promise$all5 = _context4.sent;
840
1016
  _yield$Promise$all6 = (0, _slicedToArray2.default)(_yield$Promise$all5, 2);
841
1017
  embeddingResponse = _yield$Promise$all6[1];
842
1018
  if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
@@ -846,10 +1022,10 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
846
1022
 
847
1023
  // Discard stale results
848
1024
  if (!(requestId < latestRequestId || destroyed)) {
849
- _context3.next = 4;
1025
+ _context4.next = 4;
850
1026
  break;
851
1027
  }
852
- return _context3.abrupt("return");
1028
+ return _context4.abrupt("return");
853
1029
  case 4:
854
1030
  // ── LM logits: whole-word BE-parity payload ──────────────────
855
1031
  rawLogits = lmLogitsCapture.captured;
@@ -883,17 +1059,17 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
883
1059
  // eslint-disable-next-line no-console
884
1060
  console.log(storedLmLogits ? "\u2705 lm_logits: ".concat(Object.keys(storedLmLogits).length, " words") : '❌ No lm_logits');
885
1061
  if (storedLmLogits) {
886
- topTokens = Object.entries(storedLmLogits).sort(function (_ref0, _ref1) {
887
- var _ref10 = (0, _slicedToArray2.default)(_ref0, 2),
888
- a = _ref10[1];
1062
+ topTokens = Object.entries(storedLmLogits).sort(function (_ref1, _ref10) {
889
1063
  var _ref11 = (0, _slicedToArray2.default)(_ref1, 2),
890
- b = _ref11[1];
1064
+ a = _ref11[1];
1065
+ var _ref12 = (0, _slicedToArray2.default)(_ref10, 2),
1066
+ b = _ref12[1];
891
1067
  return b - a;
892
1068
  }).slice(0, 10); // eslint-disable-next-line no-console
893
- console.log('Top 10 predictions:', topTokens.map(function (_ref12) {
894
- var _ref13 = (0, _slicedToArray2.default)(_ref12, 2),
895
- t = _ref13[0],
896
- p = _ref13[1];
1069
+ console.log('Top 10 predictions:', topTokens.map(function (_ref13) {
1070
+ var _ref14 = (0, _slicedToArray2.default)(_ref13, 2),
1071
+ t = _ref14[0],
1072
+ p = _ref14[1];
897
1073
  return "".concat(t, ": ").concat((p * 100).toFixed(1), "%");
898
1074
  }).join(', '));
899
1075
  }
@@ -905,16 +1081,16 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
905
1081
  hasVector: storedContextVector !== null,
906
1082
  hasLmLogits: storedLmLogits !== null
907
1083
  });
908
- _context3.next = 7;
1084
+ _context4.next = 7;
909
1085
  break;
910
1086
  case 5:
911
- _context3.prev = 5;
912
- _t2 = _context3["catch"](2);
1087
+ _context4.prev = 5;
1088
+ _t5 = _context4["catch"](2);
913
1089
  if (!(requestId < latestRequestId || destroyed)) {
914
- _context3.next = 6;
1090
+ _context4.next = 6;
915
1091
  break;
916
1092
  }
917
- return _context3.abrupt("return");
1093
+ return _context4.abrupt("return");
918
1094
  case 6:
919
1095
  storedContextVector = null;
920
1096
  storedLmLogits = null;
@@ -923,19 +1099,19 @@ var createLocalSlowLaneClient = exports.createLocalSlowLaneClient = function cre
923
1099
  hasVector: false,
924
1100
  hasLmLogits: false
925
1101
  });
926
- errorMsg = _t2 instanceof Error ? _t2.message : String(_t2);
1102
+ errorMsg = _t5 instanceof Error ? _t5.message : String(_t5);
927
1103
  if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
928
1104
  // eslint-disable-next-line no-console
929
1105
  console.log("%c[LocalSlowLane] %c\u274C Inference error (request #".concat(requestId, "): ").concat(errorMsg), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
930
1106
  }
931
1107
  case 7:
932
1108
  case "end":
933
- return _context3.stop();
1109
+ return _context4.stop();
934
1110
  }
935
- }, _callee3, null, [[2, 5]]);
1111
+ }, _callee4, null, [[2, 5]]);
936
1112
  }));
937
1113
  return function runInference(_x, _x2) {
938
- return _ref9.apply(this, arguments);
1114
+ return _ref0.apply(this, arguments);
939
1115
  };
940
1116
  }();
941
1117
 
@@ -235,12 +235,51 @@ export const createAutocompletePlugin = (options, api) => {
235
235
  }
236
236
  });
237
237
  };
238
- const fireSuggestionInsertedAnalytics = ghostText => {
238
+ const fireLocalModelLoadedAnalytics = info => {
239
239
  var _api$analytics2;
240
+ api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent({
241
+ action: ACTION.LOCAL_MODEL_LOADED,
242
+ actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
243
+ eventType: EVENT_TYPE.TRACK,
244
+ attributes: {
245
+ modelId: info.modelId,
246
+ embeddingModelId: info.embeddingModelId,
247
+ loadDurationMs: info.loadDurationMs,
248
+ gpuVendor: info.capabilities.vendor,
249
+ gpuArchitecture: info.capabilities.architecture
250
+ }
251
+ });
252
+ };
253
+ const fireLocalModelLoadFailedAnalytics = error => {
254
+ var _api$analytics3;
255
+ const {
256
+ capabilities
257
+ } = error;
258
+ api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent({
259
+ action: ACTION.LOCAL_MODEL_LOAD_FAILED,
260
+ actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
261
+ eventType: EVENT_TYPE.TRACK,
262
+ attributes: {
263
+ reason: error.reason,
264
+ message: error.message,
265
+ modelId: error.modelId,
266
+ embeddingModelId: error.embeddingModelId,
267
+ webgpuAvailable: capabilities.available,
268
+ adapterAvailable: capabilities.adapterAvailable,
269
+ shaderF16Supported: capabilities.shaderF16Supported,
270
+ maxBufferSizeMB: capabilities.maxBufferSizeMB,
271
+ maxStorageBufferBindingSizeMB: capabilities.maxStorageBufferBindingSizeMB,
272
+ gpuVendor: capabilities.vendor,
273
+ gpuArchitecture: capabilities.architecture
274
+ }
275
+ });
276
+ };
277
+ const fireSuggestionInsertedAnalytics = ghostText => {
278
+ var _api$analytics4;
240
279
  const typedLength = lastSuggestionTypedLength;
241
280
  const suggestionLength = lastSuggestionLength || typedLength + ghostText.length;
242
281
  const kssDelta = suggestionLength - typedLength;
243
- api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent({
282
+ api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions.fireAnalyticsEvent({
244
283
  action: ACTION.SUGGESTION_INSERTED,
245
284
  actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
246
285
  eventType: EVENT_TYPE.TRACK,
@@ -253,7 +292,9 @@ export const createAutocompletePlugin = (options, api) => {
253
292
  });
254
293
  };
255
294
  const slowLaneClient = options !== null && options !== void 0 && options.useLocalModel ? createLocalSlowLaneClient({
256
- debounceMs: LOCAL_SLOW_LANE_DEBOUNCE_MS
295
+ debounceMs: LOCAL_SLOW_LANE_DEBOUNCE_MS,
296
+ onLoadSuccess: fireLocalModelLoadedAnalytics,
297
+ onLoadError: fireLocalModelLoadFailedAnalytics
257
298
  }) : createSlowLaneClient({
258
299
  baseUrl: '',
259
300
  debounceMs: NETWORK_SLOW_LANE_DEBOUNCE_MS
@@ -401,9 +442,9 @@ export const createAutocompletePlugin = (options, api) => {
401
442
  lastSuggestionLength = typedLength + prediction.length;
402
443
  showGhostText(view, prediction, selection.from);
403
444
  if (prediction !== lastShownGhostText) {
404
- var _api$analytics3;
445
+ var _api$analytics5;
405
446
  lastShownGhostText = prediction;
406
- api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent({
447
+ api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions.fireAnalyticsEvent({
407
448
  action: ACTION.SUGGESTION_VIEWED,
408
449
  actionSubject: ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
409
450
  eventType: EVENT_TYPE.TRACK,