@atlaskit/editor-plugin-autocomplete 8.0.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/dist/cjs/analytics/ufo.js +2 -1
  3. package/dist/cjs/pm-plugins/artifact-loader.js +135 -0
  4. package/dist/cjs/pm-plugins/artifacts-manifest.js +3 -0
  5. package/dist/cjs/pm-plugins/autocomplete-plugin.js +498 -160
  6. package/dist/cjs/pm-plugins/canonical-lm-scoring.js +371 -0
  7. package/dist/cjs/pm-plugins/debug-mode.js +105 -7
  8. package/dist/cjs/pm-plugins/ghost-text-decoration.js +12 -3
  9. package/dist/cjs/pm-plugins/local-slow-lane-client.js +1202 -453
  10. package/dist/cjs/pm-plugins/scoring-pipeline.js +164 -19
  11. package/dist/cjs/pm-plugins/slow-lane-client.js +100 -37
  12. package/dist/cjs/pm-plugins/text-predictor.js +2099 -309
  13. package/dist/es2019/analytics/ufo.js +2 -0
  14. package/dist/es2019/pm-plugins/artifact-loader.js +70 -0
  15. package/dist/es2019/pm-plugins/artifacts-manifest.js +3 -0
  16. package/dist/es2019/pm-plugins/autocomplete-plugin.js +489 -152
  17. package/dist/es2019/pm-plugins/canonical-lm-scoring.js +270 -0
  18. package/dist/es2019/pm-plugins/debug-mode.js +102 -7
  19. package/dist/es2019/pm-plugins/ghost-text-decoration.js +12 -3
  20. package/dist/es2019/pm-plugins/local-slow-lane-client.js +940 -326
  21. package/dist/es2019/pm-plugins/scoring-pipeline.js +137 -13
  22. package/dist/es2019/pm-plugins/slow-lane-client.js +94 -37
  23. package/dist/es2019/pm-plugins/text-predictor.js +1692 -200
  24. package/dist/esm/analytics/ufo.js +2 -1
  25. package/dist/esm/pm-plugins/artifact-loader.js +128 -0
  26. package/dist/esm/pm-plugins/artifacts-manifest.js +3 -0
  27. package/dist/esm/pm-plugins/autocomplete-plugin.js +501 -163
  28. package/dist/esm/pm-plugins/canonical-lm-scoring.js +364 -0
  29. package/dist/esm/pm-plugins/debug-mode.js +104 -6
  30. package/dist/esm/pm-plugins/ghost-text-decoration.js +12 -3
  31. package/dist/esm/pm-plugins/local-slow-lane-client.js +1200 -451
  32. package/dist/esm/pm-plugins/scoring-pipeline.js +163 -18
  33. package/dist/esm/pm-plugins/slow-lane-client.js +100 -37
  34. package/dist/esm/pm-plugins/text-predictor.js +2101 -313
  35. package/dist/types/analytics/ufo.d.ts +1 -0
  36. package/dist/types/pm-plugins/artifact-loader.d.ts +44 -0
  37. package/dist/types/pm-plugins/artifacts-manifest.d.ts +3 -0
  38. package/dist/types/pm-plugins/autocomplete-plugin.d.ts +39 -0
  39. package/dist/types/pm-plugins/canonical-lm-scoring.d.ts +158 -0
  40. package/dist/types/pm-plugins/debug-mode.d.ts +55 -1
  41. package/dist/types/pm-plugins/ghost-text-decoration.d.ts +5 -2
  42. package/dist/types/pm-plugins/local-slow-lane-client.d.ts +87 -54
  43. package/dist/types/pm-plugins/scoring-pipeline.d.ts +33 -1
  44. package/dist/types/pm-plugins/slow-lane-client.d.ts +51 -3
  45. package/dist/types/pm-plugins/text-predictor.d.ts +156 -3
  46. package/package.json +2 -2
  47. package/src/analytics/ufo.ts +5 -0
  48. package/src/pm-plugins/artifact-loader.ts +92 -0
  49. package/src/pm-plugins/artifacts-manifest.ts +3 -0
  50. package/src/pm-plugins/autocomplete-plugin.ts +584 -154
  51. package/src/pm-plugins/canonical-lm-scoring.ts +412 -0
  52. package/src/pm-plugins/debug-mode.ts +134 -7
  53. package/src/pm-plugins/ghost-text-decoration.ts +13 -4
  54. package/src/pm-plugins/local-slow-lane-client.ts +1302 -386
  55. package/src/pm-plugins/scoring-pipeline.ts +167 -17
  56. package/src/pm-plugins/slow-lane-client.ts +147 -62
  57. package/src/pm-plugins/text-predictor.ts +2119 -254
  58. package/CANONICAL_FIX__DO_NOT_USE_ME_A/package.json +0 -8
  59. package/CANONICAL_FIX__DO_NOT_USE_ME_B/package.json +0 -8
  60. package/CANONICAL_FIX__DO_NOT_USE_ME_C/package.json +0 -8
  61. package/dist/cjs/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -18
  62. package/dist/cjs/entry-points/src-pm-plugins-slow-lane-client.js +0 -36
  63. package/dist/cjs/entry-points/src-pm-plugins-text-predictor.js +0 -66
  64. package/dist/es2019/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
  65. package/dist/es2019/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
  66. package/dist/es2019/entry-points/src-pm-plugins-text-predictor.js +0 -2
  67. package/dist/esm/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
  68. package/dist/esm/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
  69. package/dist/esm/entry-points/src-pm-plugins-text-predictor.js +0 -2
  70. package/dist/types/entry-points/src-pm-plugins-autocomplete-plugin.d.ts +0 -2
  71. package/dist/types/entry-points/src-pm-plugins-slow-lane-client.d.ts +0 -2
  72. package/dist/types/entry-points/src-pm-plugins-text-predictor.d.ts +0 -2
  73. package/scripts/gen_first_token_to_words.py +0 -170
  74. package/src/entry-points/src-pm-plugins-autocomplete-plugin.ts +0 -7
  75. package/src/entry-points/src-pm-plugins-slow-lane-client.ts +0 -13
  76. package/src/entry-points/src-pm-plugins-text-predictor.ts +0 -14
  77. package/src/pm-plugins/autocomplete-plugin/package.json +0 -8
  78. package/src/pm-plugins/slow-lane-client/package.json +0 -8
  79. package/src/pm-plugins/text-predictor/package.json +0 -8
@@ -5,8 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.createAutocompletePlugin = exports.autocompletePluginKey = void 0;
8
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
10
  var _analytics = require("@atlaskit/editor-common/analytics");
11
11
  var _monitoring = require("@atlaskit/editor-common/monitoring");
12
12
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
@@ -25,7 +25,8 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
25
25
  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; }
26
26
  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; }
27
27
  var autocompletePluginKey = exports.autocompletePluginKey = new _state.PluginKey('autocomplete');
28
- var DEBOUNCE_MS = 150;
28
+ var PREDICTION_COALESCE_MS = 0;
29
+ var GHOST_DECISION_BUDGET_MS = 100;
29
30
  var NETWORK_SLOW_LANE_DEBOUNCE_MS = 300;
30
31
  var LOCAL_SLOW_LANE_DEBOUNCE_MS = 100;
31
32
  var CONTEXT_REFRESH_THROTTLE_MS = 1000;
@@ -40,11 +41,11 @@ var MAX_INGESTED_CONTEXT_TEXTS = 50;
40
41
  // on every word boundary for the plugin's lifetime.
41
42
  var MAX_CONTEXT_REFRESH_ATTEMPTS = 5;
42
43
  var INLINE_LEAF_TEXT = ' ';
44
+ var slowLaneClientInstanceSequence = 0;
43
45
 
44
- // eslint-disable-next-line require-unicode-regexp
45
- var TRAILING_NON_BOUNDARY_TOKEN_REGEX = /([^\s.,;:!?]*)$/;
46
46
  // eslint-disable-next-line require-unicode-regexp
47
47
  var WORD_BOUNDARY_CHARS_REGEX = /[\s.,;:!?]/;
48
+ var TRAILING_SURFACE_PREFIX_REGEX = /(?:['\x2D0-9A-Z_a-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u0870-\u0887\u0889-\u088F\u08A0-\u08C9\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C5C\u0C5D\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDC-\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u1711\u171F-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4C\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C8A\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7DC\uA7F1-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDDC0-\uDDF3\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD40-\uDD59\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDD40-\uDD65\uDD6F-\uDD85\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDEC2-\uDEC7\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDF70-\uDF81\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE3F\uDE40\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61\uDF80-\uDF89\uDF8B\uDF8E\uDF90-\uDFB5\uDFB7\uDFD1\uDFD3]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDED0-\uDEE3\uDF00-\uDF1A\uDF30-\uDF3B\uDF40-\uDF46]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEB0-\uDEF8\uDFC0-\uDFE0\uDFF0-\uDFF9]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDDB0-\uDDDB\uDDE0-\uDDE9\uDEE0-\uDEF2\uDF02\uDF04-\uDF10\uDF12-\uDF33\uDF50-\uDF59\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD80E\uD80F\uD81C-\uD822\uD840-\uD868\uD86A-\uD86D\uD86F-\uD872\uD874-\uD879\uD880-\uD883\uD885-\uD88C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F\uDC41-\uDC46\uDC60-\uDFFF]|\uD810[\uDC00-\uDFFA]|\uD811[\uDC00-\uDE46]|\uD818[\uDD00-\uDD1D\uDD30-\uDD39]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDE70-\uDEBE\uDEC0-\uDEC9\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDD40-\uDD6C\uDD70-\uDD79\uDE40-\uDE96\uDEA0-\uDEB8\uDEBB-\uDED3\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3\uDFF2-\uDFF6]|\uD823[\uDC00-\uDCD5\uDCFF-\uDD1E\uDD80-\uDDF2]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD32\uDD50-\uDD52\uDD55\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD833[\uDCF0-\uDCF9]|\uD834[\uDEC0-\uDED3\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD837[\uDF00-\uDF1E\uDF25-\uDF2A]|\uD838[\uDC30-\uDC6D\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD839[\uDCD0-\uDCEB\uDCF0-\uDCF9\uDDD0-\uDDED\uDDF0-\uDDFA\uDEC0-\uDEDE\uDEE0-\uDEE2\uDEE4\uDEE5\uDEE7-\uDEED\uDEF0-\uDEF4\uDEFE\uDEFF\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDF\uDF00-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEAD\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0\uDFF0-\uDFFF]|\uD87B[\uDC00-\uDE5D]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A\uDF50-\uDFFF]|\uD88D[\uDC00-\uDC79])+$/;
48
49
  var hasDestroy = function hasDestroy(client) {
49
50
  return 'destroy' in client && typeof client.destroy === 'function';
50
51
  };
@@ -52,9 +53,70 @@ var createInitialState = function createInitialState() {
52
53
  return {
53
54
  ghostText: '',
54
55
  ghostPosition: -1,
55
- decorationSet: _view.DecorationSet.empty
56
+ decorationSet: _view.DecorationSet.empty,
57
+ suggestion: null
56
58
  };
57
59
  };
60
+ var clearGhostState = function clearGhostState(pluginState) {
61
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
62
+ ghostText: '',
63
+ ghostPosition: -1,
64
+ decorationSet: _view.DecorationSet.empty,
65
+ suggestion: null
66
+ });
67
+ };
68
+
69
+ /**
70
+ * Keep a displayed ghost alive when the user types the character it already
71
+ * predicted.
72
+ *
73
+ * Clearing on every document change throws away a suggestion the keystroke just
74
+ * confirmed, and the replacement decision has to re-earn it from an empty state
75
+ * inside the budget — which it often misses, so the ghost blinks out mid-word.
76
+ * It is worse for multi-word surfaces: typing the space in `machine learning`
77
+ * empties the current word, and the display gate refuses to show anything again
78
+ * until three characters of `learning` exist.
79
+ *
80
+ * A confirming keystroke is not new information about the prediction, so the
81
+ * ghost simply advances by one character and the still-running decision is free
82
+ * to replace it with something better. Anything else — a different character,
83
+ * a paste, a deletion, an edit elsewhere — clears as before.
84
+ */
85
+ var advanceGhostThroughTypedCharacter = function advanceGhostThroughTypedCharacter(tr, pluginState) {
86
+ var ghostPosition = pluginState.ghostPosition,
87
+ ghostText = pluginState.ghostText,
88
+ suggestion = pluginState.suggestion;
89
+ if (ghostText.length < 2 || ghostPosition < 0 || !suggestion) {
90
+ // A one-character tail leaves nothing to show after advancing.
91
+ return null;
92
+ }
93
+
94
+ // Exactly one character longer, with the cursor sitting just past the ghost
95
+ // anchor: together these identify a single insertion made at the anchor
96
+ // rather than a paste or an edit elsewhere in the document.
97
+ if (tr.doc.content.size - tr.before.content.size !== 1) {
98
+ return null;
99
+ }
100
+ if (!tr.selection.empty || tr.selection.from !== ghostPosition + 1) {
101
+ return null;
102
+ }
103
+ if (tr.doc.textBetween(ghostPosition, ghostPosition + 1) !== ghostText[0]) {
104
+ return null;
105
+ }
106
+ var remaining = ghostText.slice(1);
107
+ var nextPosition = ghostPosition + 1;
108
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
109
+ ghostText: remaining,
110
+ ghostPosition: nextPosition,
111
+ decorationSet: (0, _ghostTextDecoration.createGhostTextDecorationSet)(tr.doc, nextPosition, remaining),
112
+ // `surface` stays the full candidate so cooldown and analytics still
113
+ // describe the suggestion that was originally committed.
114
+ suggestion: _objectSpread(_objectSpread({}, suggestion), {}, {
115
+ ghostText: remaining,
116
+ position: nextPosition
117
+ })
118
+ });
119
+ };
58
120
 
59
121
  /**
60
122
  * Extract text content before the cursor from the current document.
@@ -86,6 +148,10 @@ var getTextBeforeCursor = function getTextBeforeCursor(state) {
86
148
  }
87
149
  return fullText.slice(-maxChars);
88
150
  };
151
+ var getTrailingSurfacePrefixLength = function getTrailingSurfacePrefixLength(text) {
152
+ var _text$trimEnd$match$, _text$trimEnd$match;
153
+ return (_text$trimEnd$match$ = (_text$trimEnd$match = text.trimEnd().match(TRAILING_SURFACE_PREFIX_REGEX)) === null || _text$trimEnd$match === void 0 ? void 0 : _text$trimEnd$match[0].length) !== null && _text$trimEnd$match$ !== void 0 ? _text$trimEnd$match$ : 0;
154
+ };
89
155
 
90
156
  /**
91
157
  * Set the autocomplete state via a transaction metadata.
@@ -98,21 +164,39 @@ var setAutocompleteMeta = function setAutocompleteMeta(tr, meta) {
98
164
  * Apply a ghost text suggestion to the editor state.
99
165
  */
100
166
  var lastShownGhostText = '';
101
- var showGhostText = function showGhostText(view, text, position) {
167
+ var showGhostText = function showGhostText(view, prediction, position, revision, decisionStartedAt) {
102
168
  try {
103
169
  var state = view.state,
104
170
  dispatch = view.dispatch;
105
- var decorationSet = (0, _ghostTextDecoration.createGhostTextDecorationSet)(state, position, text);
171
+ var suggestion = {
172
+ decisionLatencyMs: performance.now() - decisionStartedAt,
173
+ evidenceTier: prediction.evidenceTier,
174
+ ghostText: prediction.text,
175
+ meanTokenLogProbability: prediction.meanTokenLogProbability,
176
+ poolHeldExtension: prediction.poolHeldExtension,
177
+ position: position,
178
+ posterior: prediction.posterior,
179
+ rankScore: prediction.rankScore,
180
+ revision: revision,
181
+ shortlistSize: prediction.shortlistSize,
182
+ surface: prediction.surface,
183
+ termType: prediction.termType,
184
+ winnerMargin: prediction.winnerMargin
185
+ };
186
+ var decorationSet = (0, _ghostTextDecoration.createGhostTextDecorationSet)(state.doc, position, prediction.text);
106
187
  var tr = setAutocompleteMeta(state.tr, {
107
- ghostText: text,
188
+ ghostText: prediction.text,
108
189
  ghostPosition: position,
109
- decorationSet: decorationSet
190
+ decorationSet: decorationSet,
191
+ suggestion: suggestion
110
192
  });
111
193
  dispatch(tr);
194
+ return suggestion;
112
195
  } catch (error) {
113
196
  (0, _monitoring.logException)(error, {
114
197
  location: 'editor-plugin-autocomplete/showGhostText'
115
198
  });
199
+ return null;
116
200
  }
117
201
  };
118
202
 
@@ -129,7 +213,8 @@ var clearGhostText = function clearGhostText(state, dispatch) {
129
213
  var tr = setAutocompleteMeta(state.tr, {
130
214
  ghostText: '',
131
215
  ghostPosition: -1,
132
- decorationSet: _view.DecorationSet.empty
216
+ decorationSet: _view.DecorationSet.empty,
217
+ suggestion: null
133
218
  });
134
219
  dispatch(tr);
135
220
  } catch (error) {
@@ -147,38 +232,41 @@ var clearGhostText = function clearGhostText(state, dispatch) {
147
232
  */
148
233
  var acceptGhostText = function acceptGhostText(state, dispatch) {
149
234
  var pluginState = autocompletePluginKey.getState(state);
150
- if (!pluginState || !pluginState.ghostText) {
151
- return false;
235
+ if (!(pluginState !== null && pluginState !== void 0 && pluginState.suggestion) || !pluginState.ghostText) {
236
+ return null;
152
237
  }
153
238
  if (dispatch) {
154
239
  try {
155
240
  var ghostText = pluginState.ghostText,
156
- ghostPosition = pluginState.ghostPosition;
241
+ ghostPosition = pluginState.ghostPosition,
242
+ suggestion = pluginState.suggestion;
157
243
  var tr = state.tr.insertText(ghostText, ghostPosition);
158
244
  tr = setAutocompleteMeta(tr, {
159
245
  ghostText: '',
160
246
  ghostPosition: -1,
161
- decorationSet: _view.DecorationSet.empty
247
+ decorationSet: _view.DecorationSet.empty,
248
+ suggestion: null
162
249
  });
163
250
  dispatch(tr);
251
+ return suggestion;
164
252
  } catch (error) {
165
253
  (0, _monitoring.logException)(error, {
166
254
  location: 'editor-plugin-autocomplete/acceptGhostText'
167
255
  });
168
- return false;
256
+ return null;
169
257
  }
170
258
  }
171
- return true;
259
+ return pluginState.suggestion;
172
260
  };
173
261
  var acceptGhostTextWithAnalytics = function acceptGhostTextWithAnalytics(state, dispatch, onAccepted) {
174
- var _pluginState$ghostTex;
175
- var pluginState = autocompletePluginKey.getState(state);
176
- var ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
177
- var accepted = acceptGhostText(state, dispatch);
178
- if (accepted) {
179
- onAccepted(ghostText);
262
+ var acceptedSuggestion = acceptGhostText(state, dispatch);
263
+ if (acceptedSuggestion) {
264
+ // Start the post-accept cooldown so the just-accepted unit isn't immediately
265
+ // re-offered (QI-2 echo, e.g. `end to end` → `end to end to end`).
266
+ (0, _textPredictor.noteSuggestionAccepted)(acceptedSuggestion.surface);
267
+ onAccepted(acceptedSuggestion);
180
268
  }
181
- return accepted;
269
+ return acceptedSuggestion !== null;
182
270
  };
183
271
 
184
272
  /**
@@ -240,14 +328,6 @@ var getLeadingTextCharacter = function getLeadingTextCharacter(text) {
240
328
  }
241
329
  return String.fromCodePoint(firstCodePoint);
242
330
  };
243
- var getTypedLengthForPrediction = function getTypedLengthForPrediction(textBefore) {
244
- var _textBefore$match$, _textBefore$match;
245
- if ((0, _slowLaneClient.isWordBoundary)(textBefore)) {
246
- return 0;
247
- }
248
- var trailingToken = (_textBefore$match$ = (_textBefore$match = textBefore.match(TRAILING_NON_BOUNDARY_TOKEN_REGEX)) === null || _textBefore$match === void 0 ? void 0 : _textBefore$match[1]) !== null && _textBefore$match$ !== void 0 ? _textBefore$match$ : '';
249
- return trailingToken.length;
250
- };
251
331
  var isEnglishLocale = function isEnglishLocale(locale) {
252
332
  if (!locale) {
253
333
  return false;
@@ -255,11 +335,12 @@ var isEnglishLocale = function isEnglishLocale(locale) {
255
335
  return locale.toLowerCase().startsWith('en');
256
336
  };
257
337
  var createAutocompletePlugin = exports.createAutocompletePlugin = function createAutocompletePlugin(options, api) {
258
- var _options$surface, _options$locale;
338
+ var _options$surface, _options$locale, _registeredSlowLaneSt;
259
339
  var surface = (_options$surface = options === null || options === void 0 ? void 0 : options.surface) !== null && _options$surface !== void 0 ? _options$surface : 'editor';
260
340
  var locale = (_options$locale = options === null || options === void 0 ? void 0 : options.locale) !== null && _options$locale !== void 0 ? _options$locale : typeof navigator !== 'undefined' ? navigator.language : undefined;
261
341
  var isAutocompleteEnabled = isEnglishLocale(locale);
262
342
  var debounceTimer = null;
343
+ var decisionDeadlineTimer = null;
263
344
  var hasIngestedPage = false;
264
345
  var resolvedContext;
265
346
  /**
@@ -269,6 +350,10 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
269
350
  */
270
351
  var currentView = null;
271
352
  var unsubscribeFromContextUpdates;
353
+ // "Prime, don't ask-and-read": semantic, Tier-A, and Tier-B results land
354
+ // asynchronously, often with no following keystroke. Re-run prediction when
355
+ // they arrive so the caches are consumed immediately.
356
+ var reschedulePredictionOnSlowLaneResult = null;
272
357
  /**
273
358
  * Set after accepting a suggestion so the next doc-change update
274
359
  * skips scheduling a new prediction for the just-inserted text.
@@ -282,8 +367,8 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
282
367
  * re-showing the same suggestion. Resets to null as soon as the text changes.
283
368
  */
284
369
  var dismissedContext = null;
285
- var lastSuggestionTypedLength = 0;
286
- var lastSuggestionLength = 0;
370
+ var decisionRevision = 0;
371
+ var activeDecision;
287
372
 
288
373
  /**
289
374
  * cold → no slow-lane vector received yet; frequency-only trie scoring
@@ -348,10 +433,10 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
348
433
  }
349
434
  });
350
435
  };
351
- var fireSuggestionInsertedAnalytics = function fireSuggestionInsertedAnalytics(ghostText) {
436
+ var fireSuggestionInsertedAnalytics = function fireSuggestionInsertedAnalytics(suggestion) {
352
437
  var _api$analytics4;
353
- var typedLength = lastSuggestionTypedLength;
354
- var suggestionLength = lastSuggestionLength || typedLength + ghostText.length;
438
+ var typedLength = Math.max(0, suggestion.surface.length - suggestion.ghostText.length);
439
+ var suggestionLength = suggestion.surface.length;
355
440
  var kssDelta = suggestionLength - typedLength;
356
441
  api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || _api$analytics4.actions.fireAnalyticsEvent({
357
442
  action: _analytics.ACTION.SUGGESTION_INSERTED,
@@ -370,13 +455,59 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
370
455
  debounceMs: LOCAL_SLOW_LANE_DEBOUNCE_MS,
371
456
  onLoadSuccess: fireLocalModelLoadedAnalytics,
372
457
  onLoadError: fireLocalModelLoadFailedAnalytics,
458
+ // Re-run prediction for each independently scheduled model result.
459
+ onUpdate: function onUpdate() {
460
+ var _reschedulePrediction;
461
+ return (_reschedulePrediction = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction === void 0 ? void 0 : _reschedulePrediction({
462
+ kind: 'semantic'
463
+ });
464
+ },
465
+ onBoundaryLmUpdate: function onBoundaryLmUpdate(_ref) {
466
+ var _reschedulePrediction2;
467
+ var contextKey = _ref.contextKey,
468
+ familyKey = _ref.familyKey,
469
+ latencyMs = _ref.latencyMs;
470
+ return (_reschedulePrediction2 = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction2 === void 0 ? void 0 : _reschedulePrediction2({
471
+ contextKey: contextKey,
472
+ familyKey: familyKey,
473
+ kind: 'boundary',
474
+ latencyMs: latencyMs
475
+ });
476
+ },
477
+ onSurfaceScoreUpdate: function onSurfaceScoreUpdate(_ref2) {
478
+ var _reschedulePrediction3;
479
+ var contextKey = _ref2.contextKey,
480
+ familyKey = _ref2.familyKey,
481
+ latencyMs = _ref2.latencyMs;
482
+ return (_reschedulePrediction3 = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction3 === void 0 ? void 0 : _reschedulePrediction3({
483
+ contextKey: contextKey,
484
+ familyKey: familyKey,
485
+ kind: 'surface',
486
+ latencyMs: latencyMs
487
+ });
488
+ },
373
489
  surface: surface
374
490
  }) : (0, _slowLaneClient.createSlowLaneClient)({
375
491
  baseUrl: '',
376
492
  debounceMs: NETWORK_SLOW_LANE_DEBOUNCE_MS,
493
+ // Re-run prediction when the BE semantic vector / LM logits land so
494
+ // warm-mode unigram ranking applies without waiting for a keystroke.
495
+ onUpdate: function onUpdate() {
496
+ var _reschedulePrediction4;
497
+ return (_reschedulePrediction4 = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction4 === void 0 ? void 0 : _reschedulePrediction4({
498
+ kind: 'semantic'
499
+ });
500
+ },
377
501
  surface: surface
378
502
  });
379
- (0, _slowLaneClient.setDefaultSlowLaneClient)(slowLaneClient);
503
+ var slowLaneClientKind = options !== null && options !== void 0 && options.useLocalModel ? 'localLlm' : 'server';
504
+ var slowLaneClientId = "".concat(surface, ":").concat(slowLaneClientKind, ":").concat(++slowLaneClientInstanceSequence);
505
+ (0, _slowLaneClient.setDefaultSlowLaneClient)(slowLaneClient, {
506
+ clientId: slowLaneClientId,
507
+ kind: slowLaneClientKind
508
+ });
509
+ var registeredSlowLaneStatus = (0, _slowLaneClient.getDefaultSlowLaneClientStatus)();
510
+ (0, _debugMode.ctcTag)('init', "slow lane registered \xB7 id=".concat(slowLaneClientId, " \xB7 selected=").concat(slowLaneClientKind, " \xB7 canonical=").concat(registeredSlowLaneStatus.canonicalScoringSupported ? 'yes' : 'no', " \xB7 ready=").concat((_registeredSlowLaneSt = registeredSlowLaneStatus.localModelReady) !== null && _registeredSlowLaneSt !== void 0 ? _registeredSlowLaneSt : 'n/a'), slowLaneClientKind === 'localLlm' ? _debugMode.CTC_STYLES.good : _debugMode.CTC_STYLES.warn);
380
511
  var contextRequestInFlight = false;
381
512
  var lastContextRefreshAt = 0;
382
513
  // Bounds the word-boundary retry loop so it terminates even when the editor is
@@ -385,7 +516,72 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
385
516
  // Set when the plugin is torn down so in-flight getContext() resolutions don't
386
517
  // mutate the global text-predictor state after destruction.
387
518
  var destroyed = false;
388
- var ingestedContextTexts = new Set();
519
+ // L1 ingestion cannot run before the vocabulary has loaded: `incrementSessionFreq`
520
+ // only touches trie nodes that already exist, so an empty trie silently rejects
521
+ // every word. Text that arrives first — which a page usually does, since the
522
+ // chat resolves it on focus in the same tick as the load starts — is held here
523
+ // and applied once the load has settled.
524
+ var pendingSessionContextTexts = new Set();
525
+ var sessionIngestedContextTexts = new Set();
526
+ var isVocabularyReady = false;
527
+ var vocabularyLoadPromise;
528
+ var addBoundedContextText = function addBoundedContextText(texts, text) {
529
+ texts.add(text);
530
+ // Evict oldest entries (Set preserves insertion order) to bound memory.
531
+ while (texts.size > MAX_INGESTED_CONTEXT_TEXTS) {
532
+ var oldest = texts.values().next().value;
533
+ if (oldest === undefined) {
534
+ break;
535
+ }
536
+ texts.delete(oldest);
537
+ }
538
+ };
539
+ var flushPendingSessionContext = function flushPendingSessionContext() {
540
+ if (!isVocabularyReady || destroyed) {
541
+ return;
542
+ }
543
+ var _iterator = _createForOfIteratorHelper(pendingSessionContextTexts),
544
+ _step;
545
+ try {
546
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
547
+ var text = _step.value;
548
+ if (!sessionIngestedContextTexts.has(text)) {
549
+ (0, _textPredictor.ingestDocumentPage)(text);
550
+ addBoundedContextText(sessionIngestedContextTexts, text);
551
+ }
552
+ pendingSessionContextTexts.delete(text);
553
+ }
554
+ } catch (err) {
555
+ _iterator.e(err);
556
+ } finally {
557
+ _iterator.f();
558
+ }
559
+ };
560
+ var ensureVocabularyReady = function ensureVocabularyReady() {
561
+ var _options$useLocalMode;
562
+ if (isVocabularyReady) {
563
+ flushPendingSessionContext();
564
+ return Promise.resolve();
565
+ }
566
+ vocabularyLoadPromise !== null && vocabularyLoadPromise !== void 0 ? vocabularyLoadPromise : vocabularyLoadPromise = (0, _textPredictor.loadDefaultVocabulary)({
567
+ isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
568
+ surface: surface
569
+ }).then(function () {
570
+ if (destroyed) {
571
+ return;
572
+ }
573
+ isVocabularyReady = true;
574
+ flushPendingSessionContext();
575
+ }).catch(function (error) {
576
+ // Do not consume the pending text on failure. A later focus retries the
577
+ // load and can still apply the original context exactly once.
578
+ vocabularyLoadPromise = undefined;
579
+ (0, _monitoring.logException)(error, {
580
+ location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
581
+ });
582
+ });
583
+ return vocabularyLoadPromise;
584
+ };
389
585
  var logContextResolved = function logContextResolved(source, context) {
390
586
  var _context$parentCommen, _context$siblingComme4, _context$siblingComme5;
391
587
  if (!(0, _debugMode.isAutocompleteDebugEnabled)()) {
@@ -393,7 +589,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
393
589
  }
394
590
 
395
591
  // eslint-disable-next-line no-console
396
- console.log('%c[Autocomplete] %cgetContext resolved', 'color: #00b8d9; font-weight: bold;', 'color: inherit;', {
592
+ console.log('%c[CTC:signal]%c getContext resolved', _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
397
593
  source: source,
398
594
  hasParentComment: !!(context !== null && context !== void 0 && context.parentCommentContent),
399
595
  parentCommentPreview: context === null || context === void 0 || (_context$parentCommen = context.parentCommentContent) === null || _context$parentCommen === void 0 ? void 0 : _context$parentCommen.slice(0, 80),
@@ -408,44 +604,36 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
408
604
  // fullPageContent, so replacing would drop previously resolved context.
409
605
  // Strip undefined values first so a field explicitly set to undefined by
410
606
  // getContext doesn't overwrite a previously resolved value.
411
- var definedContext = Object.fromEntries(Object.entries(context).filter(function (_ref) {
412
- var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
413
- value = _ref2[1];
607
+ var definedContext = Object.fromEntries(Object.entries(context).filter(function (_ref3) {
608
+ var _ref4 = (0, _slicedToArray2.default)(_ref3, 2),
609
+ value = _ref4[1];
414
610
  return value !== undefined;
415
611
  }));
416
612
  resolvedContext = _objectSpread(_objectSpread({}, resolvedContext), definedContext);
417
613
  var ingestContextText = function ingestContextText(text) {
418
- if (!text || ingestedContextTexts.has(text)) {
614
+ if (!text || sessionIngestedContextTexts.has(text)) {
419
615
  return;
420
616
  }
421
- ingestedContextTexts.add(text);
422
- // Evict oldest entries (Set preserves insertion order) to bound memory.
423
- while (ingestedContextTexts.size > MAX_INGESTED_CONTEXT_TEXTS) {
424
- var oldest = ingestedContextTexts.values().next().value;
425
- if (oldest === undefined) {
426
- break;
427
- }
428
- ingestedContextTexts.delete(oldest);
429
- }
430
- (0, _textPredictor.ingestDocumentPage)(text);
617
+ addBoundedContextText(pendingSessionContextTexts, text);
431
618
  };
432
619
  ingestContextText(context.fullPageContent);
433
620
  ingestContextText(context.parentCommentContent);
434
- var _iterator = _createForOfIteratorHelper((_context$siblingComme6 = context.siblingCommentsContents) !== null && _context$siblingComme6 !== void 0 ? _context$siblingComme6 : []),
435
- _step;
621
+ var _iterator2 = _createForOfIteratorHelper((_context$siblingComme6 = context.siblingCommentsContents) !== null && _context$siblingComme6 !== void 0 ? _context$siblingComme6 : []),
622
+ _step2;
436
623
  try {
437
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
438
- var siblingCommentContent = _step.value;
624
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
625
+ var siblingCommentContent = _step2.value;
439
626
  ingestContextText(siblingCommentContent);
440
627
  }
441
-
442
- // Context arrived after word boundaries may already have fired. Re-send
443
- // slow-lane context immediately so the next inference includes the thread.
444
628
  } catch (err) {
445
- _iterator.e(err);
629
+ _iterator2.e(err);
446
630
  } finally {
447
- _iterator.f();
631
+ _iterator2.f();
448
632
  }
633
+ flushPendingSessionContext();
634
+
635
+ // Context arrived after word boundaries may already have fired. Re-send
636
+ // slow-lane context immediately so the next inference includes the thread.
449
637
  if (currentView) {
450
638
  slowLaneClient.updateContext(buildSlowLaneText(currentView.state.doc.textContent, resolvedContext));
451
639
  }
@@ -456,10 +644,10 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
456
644
  * (no getContext, a request already in flight, or throttled). Callers that
457
645
  * track a retry budget should only count attempts where this returns true.
458
646
  */
459
- var refreshContext = function refreshContext(_ref3) {
460
- var source = _ref3.source,
461
- _ref3$allowThrottle = _ref3.allowThrottle,
462
- allowThrottle = _ref3$allowThrottle === void 0 ? true : _ref3$allowThrottle;
647
+ var refreshContext = function refreshContext(_ref5) {
648
+ var source = _ref5.source,
649
+ _ref5$allowThrottle = _ref5.allowThrottle,
650
+ allowThrottle = _ref5$allowThrottle === void 0 ? true : _ref5$allowThrottle;
463
651
  if (!(options !== null && options !== void 0 && options.getContext) || contextRequestInFlight) {
464
652
  return false;
465
653
  }
@@ -490,73 +678,230 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
490
678
  });
491
679
  return true;
492
680
  };
493
-
494
- /**
495
- * Schedule a prediction after a short debounce.
496
- * Tier 1 predictions are synchronous (<0.1ms) but we still debounce
497
- * to avoid unnecessary work on rapid keystrokes.
498
- */
499
- var schedulePrediction = function schedulePrediction(view) {
681
+ var clearDecisionTimers = function clearDecisionTimers() {
500
682
  if (debounceTimer) {
501
683
  clearTimeout(debounceTimer);
684
+ debounceTimer = null;
502
685
  }
503
- debounceTimer = setTimeout(function () {
504
- try {
505
- var state = view.state;
506
- var selection = state.selection;
507
- if (!selection.empty) {
508
- return;
509
- }
686
+ if (decisionDeadlineTimer) {
687
+ clearTimeout(decisionDeadlineTimer);
688
+ decisionDeadlineTimer = null;
689
+ }
690
+ };
691
+ var cancelActiveDecision = function cancelActiveDecision() {
692
+ clearDecisionTimers();
693
+ activeDecision = undefined;
694
+ };
695
+ var isDecisionSnapshotCurrent = function isDecisionSnapshotCurrent(view, decision) {
696
+ var state = view.state;
697
+ return state.selection.empty && state.selection.from === decision.position && getTextBeforeCursor(state) === decision.textBefore;
698
+ };
699
+ var isDecisionCurrent = function isDecisionCurrent(view, decision) {
700
+ var _activeDecision;
701
+ return ((_activeDecision = activeDecision) === null || _activeDecision === void 0 ? void 0 : _activeDecision.revision) === decision.revision && isDecisionSnapshotCurrent(view, decision);
702
+ };
703
+ var expireActiveDecision = function expireActiveDecision(decision) {
704
+ var _activeDecision2;
705
+ if (((_activeDecision2 = activeDecision) === null || _activeDecision2 === void 0 ? void 0 : _activeDecision2.revision) !== decision.revision) {
706
+ return;
707
+ }
708
+ cancelActiveDecision();
709
+ };
710
+ var evaluateActiveDecision = function evaluateActiveDecision(view, revision) {
711
+ var decision = activeDecision;
712
+ if (!decision || decision.revision !== revision || !isDecisionCurrent(view, decision)) {
713
+ return;
714
+ }
715
+ if (performance.now() > decision.deadlineAt) {
716
+ expireActiveDecision(decision);
717
+ return;
718
+ }
719
+ decision.evaluations++;
720
+ try {
721
+ var state = view.state;
722
+ var selection = state.selection;
510
723
 
511
- // Suppress suggestions when the cursor is mid-word — only offer
512
- // completions when the cursor is at the trailing edge of a token.
513
- // nodeAfter correctly handles inline atoms (mentions, emojis) where
514
- // parentOffset and textContent indices diverge.
515
- var nodeAfter = selection.$from.nodeAfter;
516
- var charAfterCursor = nodeAfter !== null && nodeAfter !== void 0 && nodeAfter.isText ? getLeadingTextCharacter(nodeAfter.text) : undefined;
517
- // Only suppress for Unicode letters, digits, and underscore — hyphens,
518
- // apostrophes, and similar punctuation are valid left-edge boundaries
519
- // and should not block suggestions (e.g. cursor before '-' in compound-word).
520
- if (charAfterCursor && isMidWordCharacter(charAfterCursor)) {
521
- return;
522
- }
523
- var textBefore = getTextBeforeCursor(state);
724
+ // Suppress suggestions when the cursor is mid-word — only offer
725
+ // completions when the cursor is at the trailing edge of a token.
726
+ var nodeAfter = selection.$from.nodeAfter;
727
+ var charAfterCursor = nodeAfter !== null && nodeAfter !== void 0 && nodeAfter.isText ? getLeadingTextCharacter(nodeAfter.text) : undefined;
728
+ if (charAfterCursor && isMidWordCharacter(charAfterCursor)) {
729
+ cancelActiveDecision();
730
+ return;
731
+ }
732
+ if (decision.textBefore === dismissedContext) {
733
+ cancelActiveDecision();
734
+ return;
735
+ }
736
+ dismissedContext = null;
524
737
 
525
- // Suppress re-showing the same suggestion the user just dismissed.
526
- // Once the text context changes (user types or deletes), this clears automatically.
527
- if (textBefore === dismissedContext) {
528
- return;
529
- }
530
- dismissedContext = null;
531
- if (textBefore.trim().length < 3) {
532
- return;
738
+ // Two characters are enough to prefetch the canonical shortlist. The
739
+ // predictor itself withholds display until the three-character gate.
740
+ if (decision.textBefore.trim().length < 2) {
741
+ cancelActiveDecision();
742
+ return;
743
+ }
744
+ var prediction = (0, _textPredictor.predict)(decision.textBefore);
745
+ if (!prediction || prediction.text.length === 0) {
746
+ // Remain in `collecting` until an async signal arrives or the hard
747
+ // deadline expires. We never display a provisional fallback.
748
+ return;
749
+ }
750
+ var readyAtMs = performance.now() - decision.startedAt;
751
+ if (readyAtMs > GHOST_DECISION_BUDGET_MS) {
752
+ cancelActiveDecision();
753
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
754
+ // eslint-disable-next-line no-console
755
+ console.log('%c[CTC:budget]%c fully gated after render deadline (render suppressed)', _debugMode.CTC_STYLES.section, _debugMode.CTC_STYLES.body, {
756
+ revision: decision.revision,
757
+ readyAtMs: readyAtMs,
758
+ surface: prediction.surface
759
+ });
533
760
  }
534
- var prediction = (0, _textPredictor.predict)(textBefore);
535
- if (prediction && prediction.length > 0) {
536
- var typedLength = getTypedLengthForPrediction(textBefore);
537
- lastSuggestionTypedLength = typedLength;
538
- lastSuggestionLength = typedLength + prediction.length;
539
- showGhostText(view, prediction, selection.from);
540
- if (prediction !== lastShownGhostText) {
541
- var _api$analytics5;
542
- lastShownGhostText = prediction;
543
- api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 || _api$analytics5.actions.fireAnalyticsEvent({
544
- action: _analytics.ACTION.SUGGESTION_VIEWED,
545
- actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
546
- eventType: _analytics.EVENT_TYPE.TRACK,
547
- attributes: {
548
- completionSource: getCompletionSource(),
549
- surface: surface
550
- }
551
- });
761
+ return;
762
+ }
763
+ var suggestion = showGhostText(view, prediction, decision.position, decision.revision, decision.startedAt);
764
+ if (!suggestion) {
765
+ cancelActiveDecision();
766
+ return;
767
+ }
768
+ cancelActiveDecision();
769
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
770
+ // eslint-disable-next-line no-console
771
+ console.log('%c[CTC:decision]%c committed immutable ghost', _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
772
+ revision: suggestion.revision,
773
+ surface: suggestion.surface,
774
+ ghostText: suggestion.ghostText,
775
+ evidenceTier: suggestion.evidenceTier,
776
+ rankScore: suggestion.rankScore,
777
+ winnerMargin: suggestion.winnerMargin,
778
+ decisionLatencyMs: suggestion.decisionLatencyMs,
779
+ budgetMs: GHOST_DECISION_BUDGET_MS,
780
+ typedPrefixLength: getTrailingSurfacePrefixLength(decision.textBefore),
781
+ evaluations: decision.evaluations,
782
+ asyncSignals: decision.asyncSignals,
783
+ readyWithinBudget: suggestion.decisionLatencyMs <= GHOST_DECISION_BUDGET_MS
784
+ });
785
+ }
786
+ if (suggestion.ghostText !== lastShownGhostText) {
787
+ var _api$analytics5;
788
+ lastShownGhostText = suggestion.ghostText;
789
+ api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 || _api$analytics5.actions.fireAnalyticsEvent({
790
+ action: _analytics.ACTION.SUGGESTION_VIEWED,
791
+ actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
792
+ eventType: _analytics.EVENT_TYPE.TRACK,
793
+ attributes: {
794
+ completionSource: getCompletionSource(),
795
+ surface: surface
552
796
  }
553
- }
554
- } catch (error) {
555
- (0, _monitoring.logException)(error, {
556
- location: 'editor-plugin-autocomplete/schedulePrediction'
557
797
  });
558
798
  }
559
- }, DEBOUNCE_MS);
799
+ } catch (error) {
800
+ cancelActiveDecision();
801
+ (0, _monitoring.logException)(error, {
802
+ location: 'editor-plugin-autocomplete/evaluateActiveDecision'
803
+ });
804
+ }
805
+ };
806
+ var beginPredictionDecision = function beginPredictionDecision(view) {
807
+ cancelActiveDecision();
808
+ var state = view.state;
809
+ if (!state.selection.empty) {
810
+ return;
811
+ }
812
+ var startedAt = performance.now();
813
+ var textBefore = getTextBeforeCursor(state);
814
+ var revision = ++decisionRevision;
815
+ activeDecision = {
816
+ asyncSignals: 0,
817
+ deadlineAt: startedAt + GHOST_DECISION_BUDGET_MS,
818
+ evaluations: 0,
819
+ position: state.selection.from,
820
+ revision: revision,
821
+ startedAt: startedAt,
822
+ textBefore: textBefore
823
+ };
824
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
825
+ // eslint-disable-next-line no-console
826
+ console.log('%c[CTC:decision]%c collecting', _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
827
+ revision: revision,
828
+ budgetMs: GHOST_DECISION_BUDGET_MS,
829
+ coalesceMs: PREDICTION_COALESCE_MS,
830
+ typedPrefixLength: getTrailingSurfacePrefixLength(activeDecision.textBefore),
831
+ textBefore: activeDecision.textBefore.slice(-80)
832
+ });
833
+ }
834
+ debounceTimer = setTimeout(function () {
835
+ debounceTimer = null;
836
+ evaluateActiveDecision(view, revision);
837
+ }, PREDICTION_COALESCE_MS);
838
+ decisionDeadlineTimer = setTimeout(function () {
839
+ var _activeDecision3;
840
+ decisionDeadlineTimer = null;
841
+ if (((_activeDecision3 = activeDecision) === null || _activeDecision3 === void 0 ? void 0 : _activeDecision3.revision) === revision) {
842
+ var expiredDecision = activeDecision;
843
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
844
+ var elapsedMs = performance.now() - expiredDecision.startedAt;
845
+ var predictionDebug = (0, _textPredictor.getLastPredictionDebug)();
846
+ var matchingPredictionDebug = (predictionDebug === null || predictionDebug === void 0 ? void 0 : predictionDebug.textBefore) === expiredDecision.textBefore ? predictionDebug : null;
847
+ var abstentionPrefix = '— abstain: ';
848
+ var predictorDecision = matchingPredictionDebug === null || matchingPredictionDebug === void 0 ? void 0 : matchingPredictionDebug.decision;
849
+ var predictorReason = predictorDecision !== null && predictorDecision !== void 0 && predictorDecision.startsWith(abstentionPrefix) ? predictorDecision.slice(abstentionPrefix.length) : predictorDecision;
850
+ var decisionMessage = predictorReason && !(matchingPredictionDebug !== null && matchingPredictionDebug !== void 0 && matchingPredictionDebug.awaitingAsyncEvidence) ? "abstain: ".concat(predictorReason) : "abstain: ".concat(GHOST_DECISION_BUDGET_MS, "ms decision budget expired").concat(predictorReason ? " \xB7 ".concat(predictorReason) : '');
851
+ // eslint-disable-next-line no-console
852
+ console.log("%c[CTC:decision]%c ".concat(decisionMessage), _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
853
+ revision: revision,
854
+ budgetMs: GHOST_DECISION_BUDGET_MS,
855
+ elapsedMs: elapsedMs,
856
+ typedPrefixLength: getTrailingSurfacePrefixLength(expiredDecision.textBefore),
857
+ evaluations: expiredDecision.evaluations,
858
+ asyncSignals: expiredDecision.asyncSignals,
859
+ textBefore: expiredDecision.textBefore.slice(-80),
860
+ predictorDecision: predictorReason !== null && predictorReason !== void 0 ? predictorReason : null
861
+ });
862
+ }
863
+ expireActiveDecision(expiredDecision);
864
+ }
865
+ }, GHOST_DECISION_BUDGET_MS);
866
+ };
867
+
868
+ // Async semantic/canonical results may complete the active decision, but they
869
+ // never create a new decision or replace an already committed ghost.
870
+ reschedulePredictionOnSlowLaneResult = function reschedulePredictionOnSlowLaneResult(signal) {
871
+ if (destroyed || !currentView) {
872
+ return;
873
+ }
874
+ if (!activeDecision) {
875
+ return;
876
+ }
877
+ var revision = activeDecision.revision;
878
+ var elapsedMs = performance.now() - activeDecision.startedAt;
879
+ var remainingMs = activeDecision.deadlineAt - performance.now();
880
+ if (remainingMs < 0) {
881
+ var expiredDecision = activeDecision;
882
+ expireActiveDecision(expiredDecision);
883
+ return;
884
+ }
885
+ activeDecision.asyncSignals++;
886
+ if ((0, _debugMode.isAutocompleteDebugVerbose)()) {
887
+ // eslint-disable-next-line no-console
888
+ console.log('%c[CTC:readiness]%c async evidence signal', _debugMode.CTC_STYLES.section, _debugMode.CTC_STYLES.body, _objectSpread(_objectSpread({}, signal), {}, {
889
+ revision: revision,
890
+ elapsedMs: elapsedMs,
891
+ remainingMs: Math.max(0, remainingMs),
892
+ typedPrefixLength: getTrailingSurfacePrefixLength(activeDecision.textBefore),
893
+ withinBudget: remainingMs >= 0
894
+ }));
895
+ }
896
+ if (debounceTimer) {
897
+ clearTimeout(debounceTimer);
898
+ }
899
+ debounceTimer = setTimeout(function () {
900
+ debounceTimer = null;
901
+ if (currentView) {
902
+ evaluateActiveDecision(currentView, revision);
903
+ }
904
+ }, 0);
560
905
  };
561
906
  var maybeUpdateSessionFrequency = function maybeUpdateSessionFrequency(view, prevState) {
562
907
  var newText = getTextBeforeCursor(view.state);
@@ -594,20 +939,14 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
594
939
  return _objectSpread(_objectSpread({}, pluginState), meta);
595
940
  }
596
941
 
597
- // A new prediction is scheduled from view.update.
942
+ // A new prediction is scheduled from view.update either way; the
943
+ // surviving ghost only covers the gap until it commits.
598
944
  if (tr.docChanged) {
599
- return _objectSpread(_objectSpread({}, pluginState), {}, {
600
- ghostText: '',
601
- ghostPosition: -1,
602
- decorationSet: _view.DecorationSet.empty
603
- });
945
+ var _advanceGhostThroughT;
946
+ return (_advanceGhostThroughT = advanceGhostThroughTypedCharacter(tr, pluginState)) !== null && _advanceGhostThroughT !== void 0 ? _advanceGhostThroughT : clearGhostState(pluginState);
604
947
  }
605
948
  if (tr.selectionSet && pluginState.ghostText) {
606
- return _objectSpread(_objectSpread({}, pluginState), {}, {
607
- ghostText: '',
608
- ghostPosition: -1,
609
- decorationSet: _view.DecorationSet.empty
610
- });
949
+ return clearGhostState(pluginState);
611
950
  }
612
951
  return pluginState;
613
952
  }
@@ -620,22 +959,25 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
620
959
  },
621
960
  handleKeyDown: (0, _keymap.keydownHandler)({
622
961
  Tab: function Tab(state, dispatch) {
623
- return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
962
+ return acceptGhostTextWithAnalytics(state, dispatch, function (suggestion) {
624
963
  justAccepted = true;
625
964
  lastShownGhostText = '';
626
- fireSuggestionInsertedAnalytics(ghostText);
965
+ cancelActiveDecision();
966
+ fireSuggestionInsertedAnalytics(suggestion);
627
967
  });
628
968
  },
629
969
  ArrowRight: function ArrowRight(state, dispatch) {
630
- return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
970
+ return acceptGhostTextWithAnalytics(state, dispatch, function (suggestion) {
631
971
  justAccepted = true;
632
972
  lastShownGhostText = '';
633
- fireSuggestionInsertedAnalytics(ghostText);
973
+ cancelActiveDecision();
974
+ fireSuggestionInsertedAnalytics(suggestion);
634
975
  });
635
976
  },
636
977
  Escape: function Escape(state, dispatch) {
637
978
  var didClear = clearGhostText(state, dispatch);
638
979
  if (didClear) {
980
+ cancelActiveDecision();
639
981
  dismissedContext = getTextBeforeCursor(state);
640
982
  fireSuggestionDismissedAnalytics('escape');
641
983
  }
@@ -650,6 +992,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
650
992
  var pluginState = autocompletePluginKey.getState(view.state);
651
993
  if (pluginState !== null && pluginState !== void 0 && pluginState.ghostText) {
652
994
  clearGhostText(view.state, view.dispatch);
995
+ cancelActiveDecision();
653
996
  fireSuggestionDismissedAnalytics('blur');
654
997
  }
655
998
  return false;
@@ -661,6 +1004,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
661
1004
  if (!event.target.closest('[data-autocomplete-ghost="true"]')) {
662
1005
  var didClear = clearGhostText(view.state, view.dispatch);
663
1006
  if (didClear) {
1007
+ cancelActiveDecision();
664
1008
  dismissedContext = getTextBeforeCursor(view.state);
665
1009
  lastShownGhostText = '';
666
1010
  fireSuggestionDismissedAnalytics('click');
@@ -668,10 +1012,11 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
668
1012
  return false;
669
1013
  }
670
1014
  event.preventDefault();
671
- var accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, function (ghostText) {
1015
+ var accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, function (suggestion) {
672
1016
  justAccepted = true;
673
1017
  lastShownGhostText = '';
674
- fireSuggestionInsertedAnalytics(ghostText);
1018
+ cancelActiveDecision();
1019
+ fireSuggestionInsertedAnalytics(suggestion);
675
1020
  });
676
1021
  if (accepted) {
677
1022
  view.focus();
@@ -679,18 +1024,11 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
679
1024
  return accepted;
680
1025
  },
681
1026
  focus: function focus() {
682
- var _options$useLocalMode, _options$useLocalMode2, _options$useLocalMode3;
1027
+ var _options$useLocalMode2, _options$useLocalMode3;
683
1028
  if (!isAutocompleteEnabled) {
684
1029
  return false;
685
1030
  }
686
- (0, _textPredictor.loadDefaultVocabulary)({
687
- isLocalLLM: (_options$useLocalMode = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode !== void 0 ? _options$useLocalMode : false,
688
- surface: surface
689
- }).catch(function (error) {
690
- (0, _monitoring.logException)(error, {
691
- location: 'editor-plugin-autocomplete/loadDefaultVocabulary'
692
- });
693
- });
1031
+ void ensureVocabularyReady();
694
1032
  (0, _textPredictor.loadVectorsAsync)({
695
1033
  isLocalLLM: (_options$useLocalMode2 = options === null || options === void 0 ? void 0 : options.useLocalModel) !== null && _options$useLocalMode2 !== void 0 ? _options$useLocalMode2 : false,
696
1034
  surface: surface
@@ -746,9 +1084,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
746
1084
  // Snapshot the post-acceptance text so follow-up transactions hit
747
1085
  // the dismissedContext guard and abort until the user types again.
748
1086
  dismissedContext = getTextBeforeCursor(view.state);
749
- if (debounceTimer) {
750
- clearTimeout(debounceTimer);
751
- }
1087
+ cancelActiveDecision();
752
1088
  return;
753
1089
  }
754
1090
  maybeUpdateSessionFrequency(view, prevState);
@@ -773,7 +1109,9 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
773
1109
  }
774
1110
  }
775
1111
  }
776
- schedulePrediction(view);
1112
+ beginPredictionDecision(view);
1113
+ } else if (!prevState.selection.eq(view.state.selection)) {
1114
+ cancelActiveDecision();
777
1115
  }
778
1116
  },
779
1117
  destroy: function destroy() {
@@ -782,14 +1120,14 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
782
1120
  currentView = null;
783
1121
  (_unsubscribeFromConte = unsubscribeFromContextUpdates) === null || _unsubscribeFromConte === void 0 || _unsubscribeFromConte();
784
1122
  unsubscribeFromContextUpdates = undefined;
785
- if (debounceTimer) {
786
- clearTimeout(debounceTimer);
787
- }
1123
+ cancelActiveDecision();
1124
+ var releasedDefaultClient = (0, _slowLaneClient.clearDefaultSlowLaneClient)(slowLaneClient);
1125
+ (0, _debugMode.ctcTag)('init', "slow lane teardown \xB7 id=".concat(slowLaneClientId, " \xB7 default=").concat(releasedDefaultClient ? 'released' : 'retained newer owner'), releasedDefaultClient ? _debugMode.CTC_STYLES.dim : _debugMode.CTC_STYLES.warn);
788
1126
  if (hasDestroy(slowLaneClient)) {
789
1127
  slowLaneClient.destroy();
790
1128
  }
791
- ingestedContextTexts.clear();
792
- (0, _slowLaneClient.setDefaultSlowLaneClient)(null);
1129
+ pendingSessionContextTexts.clear();
1130
+ sessionIngestedContextTexts.clear();
793
1131
  }
794
1132
  };
795
1133
  }