@atlaskit/editor-plugin-autocomplete 8.0.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/dist/cjs/analytics/ufo.js +2 -1
- package/dist/cjs/pm-plugins/artifact-loader.js +135 -0
- package/dist/cjs/pm-plugins/artifacts-manifest.js +3 -0
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +416 -129
- package/dist/cjs/pm-plugins/canonical-lm-scoring.js +371 -0
- package/dist/cjs/pm-plugins/debug-mode.js +90 -7
- package/dist/cjs/pm-plugins/ghost-text-decoration.js +12 -3
- package/dist/cjs/pm-plugins/local-slow-lane-client.js +1202 -453
- package/dist/cjs/pm-plugins/scoring-pipeline.js +164 -19
- package/dist/cjs/pm-plugins/slow-lane-client.js +100 -37
- package/dist/cjs/pm-plugins/text-predictor.js +1951 -273
- package/dist/es2019/analytics/ufo.js +2 -0
- package/dist/es2019/pm-plugins/artifact-loader.js +70 -0
- package/dist/es2019/pm-plugins/artifacts-manifest.js +3 -0
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +425 -130
- package/dist/es2019/pm-plugins/canonical-lm-scoring.js +270 -0
- package/dist/es2019/pm-plugins/debug-mode.js +87 -7
- package/dist/es2019/pm-plugins/ghost-text-decoration.js +12 -3
- package/dist/es2019/pm-plugins/local-slow-lane-client.js +940 -326
- package/dist/es2019/pm-plugins/scoring-pipeline.js +137 -13
- package/dist/es2019/pm-plugins/slow-lane-client.js +94 -37
- package/dist/es2019/pm-plugins/text-predictor.js +1603 -199
- package/dist/esm/analytics/ufo.js +2 -1
- package/dist/esm/pm-plugins/artifact-loader.js +128 -0
- package/dist/esm/pm-plugins/artifacts-manifest.js +3 -0
- package/dist/esm/pm-plugins/autocomplete-plugin.js +419 -132
- package/dist/esm/pm-plugins/canonical-lm-scoring.js +364 -0
- package/dist/esm/pm-plugins/debug-mode.js +89 -6
- package/dist/esm/pm-plugins/ghost-text-decoration.js +12 -3
- package/dist/esm/pm-plugins/local-slow-lane-client.js +1200 -451
- package/dist/esm/pm-plugins/scoring-pipeline.js +163 -18
- package/dist/esm/pm-plugins/slow-lane-client.js +100 -37
- package/dist/esm/pm-plugins/text-predictor.js +1953 -277
- package/dist/types/analytics/ufo.d.ts +1 -0
- package/dist/types/pm-plugins/artifact-loader.d.ts +44 -0
- package/dist/types/pm-plugins/artifacts-manifest.d.ts +3 -0
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +39 -0
- package/dist/types/pm-plugins/canonical-lm-scoring.d.ts +158 -0
- package/dist/types/pm-plugins/debug-mode.d.ts +36 -1
- package/dist/types/pm-plugins/ghost-text-decoration.d.ts +5 -2
- package/dist/types/pm-plugins/local-slow-lane-client.d.ts +87 -54
- package/dist/types/pm-plugins/scoring-pipeline.d.ts +33 -1
- package/dist/types/pm-plugins/slow-lane-client.d.ts +51 -3
- package/dist/types/pm-plugins/text-predictor.d.ts +120 -2
- package/package.json +2 -2
- package/src/analytics/ufo.ts +5 -0
- package/src/pm-plugins/artifact-loader.ts +92 -0
- package/src/pm-plugins/artifacts-manifest.ts +3 -0
- package/src/pm-plugins/autocomplete-plugin.ts +517 -133
- package/src/pm-plugins/canonical-lm-scoring.ts +412 -0
- package/src/pm-plugins/debug-mode.ts +109 -7
- package/src/pm-plugins/ghost-text-decoration.ts +13 -4
- package/src/pm-plugins/local-slow-lane-client.ts +1302 -386
- package/src/pm-plugins/scoring-pipeline.ts +167 -17
- package/src/pm-plugins/slow-lane-client.ts +147 -62
- package/src/pm-plugins/text-predictor.ts +2006 -255
- package/CANONICAL_FIX__DO_NOT_USE_ME_A/package.json +0 -8
- package/CANONICAL_FIX__DO_NOT_USE_ME_B/package.json +0 -8
- package/CANONICAL_FIX__DO_NOT_USE_ME_C/package.json +0 -8
- package/dist/cjs/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -18
- package/dist/cjs/entry-points/src-pm-plugins-slow-lane-client.js +0 -36
- package/dist/cjs/entry-points/src-pm-plugins-text-predictor.js +0 -66
- package/dist/es2019/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
- package/dist/es2019/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
- package/dist/es2019/entry-points/src-pm-plugins-text-predictor.js +0 -2
- package/dist/esm/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
- package/dist/esm/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
- package/dist/esm/entry-points/src-pm-plugins-text-predictor.js +0 -2
- package/dist/types/entry-points/src-pm-plugins-autocomplete-plugin.d.ts +0 -2
- package/dist/types/entry-points/src-pm-plugins-slow-lane-client.d.ts +0 -2
- package/dist/types/entry-points/src-pm-plugins-text-predictor.d.ts +0 -2
- package/scripts/gen_first_token_to_words.py +0 -170
- package/src/entry-points/src-pm-plugins-autocomplete-plugin.ts +0 -7
- package/src/entry-points/src-pm-plugins-slow-lane-client.ts +0 -13
- package/src/entry-points/src-pm-plugins-text-predictor.ts +0 -14
- package/src/pm-plugins/autocomplete-plugin/package.json +0 -8
- package/src/pm-plugins/slow-lane-client/package.json +0 -8
- package/src/pm-plugins/text-predictor/package.json +0 -8
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
3
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
4
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
4
|
-
import
|
|
5
|
-
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
6
|
-
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
7
|
-
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; }
|
|
8
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
|
+
import _typeof from "@babel/runtime/helpers/typeof";
|
|
9
6
|
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; } } }; }
|
|
10
7
|
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; } }
|
|
11
8
|
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; }
|
|
9
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
10
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
12
11
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
13
12
|
/**
|
|
14
13
|
* Local Slow Lane Client: On-device inference via @mlc-ai/web-llm.
|
|
@@ -17,11 +16,9 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
17
16
|
* a backend API, this client runs two models in the browser via WebGPU, in a
|
|
18
17
|
* single MLCEngine, to reproduce the BE encoder's outputs on-device:
|
|
19
18
|
*
|
|
20
|
-
* - Causal LM (SmolLM2-135M-Instruct): one
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* port of the BE `CausalLMEncoder._get_top_k_probs` (masked softmax over the
|
|
24
|
-
* vocab's first-tokens, prefix expansion, L2 reservation, log-space pooling).
|
|
19
|
+
* - Causal LM (SmolLM2-135M-Instruct): context-keyed one-step boundary primes
|
|
20
|
+
* provide canonical first-token logits. A persistent token-prefix scheduler
|
|
21
|
+
* expands shared paths and exact-scores only plausible finalists.
|
|
25
22
|
* - Semantic embedder (Snowflake Arctic Embed S): produces the real 384-d
|
|
26
23
|
* `semantic_vector`. Inputs are wrapped as passages (see `wrapForArctic`) so
|
|
27
24
|
* the runtime vector lands in the same space as the precomputed word bin.
|
|
@@ -31,7 +28,7 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
31
28
|
* the main thread is viable:
|
|
32
29
|
*
|
|
33
30
|
* - WebGPU GPU compute is inherently async (doesn't block the main thread)
|
|
34
|
-
* - CPU overhead
|
|
31
|
+
* - CPU overhead for named-token reads and cache bookkeeping is small
|
|
35
32
|
* - Per-inference latency is well within autocomplete expectations
|
|
36
33
|
* (~250 ms between word boundaries)
|
|
37
34
|
*
|
|
@@ -42,16 +39,21 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
42
39
|
* - Standard npm import — just works
|
|
43
40
|
*
|
|
44
41
|
* ── Interface ────────────────────────────────────────────────────────────
|
|
45
|
-
* Same shape as createSlowLaneClient
|
|
46
|
-
*
|
|
47
|
-
*
|
|
42
|
+
* Same base shape as createSlowLaneClient, plus on-device canonical-surface
|
|
43
|
+
* scoring. Semantic updates remain word-boundary timed; causal work is requested
|
|
44
|
+
* independently for exact pre-surface contexts.
|
|
48
45
|
*/
|
|
49
46
|
|
|
50
47
|
import { abortExp, EXPERIENCE_NAME, failExp, startExp, succeedExp } from '../analytics/ufo';
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
48
|
+
import { fetchAutocompleteArtifactJson } from './artifact-loader';
|
|
49
|
+
import { ARTIFACT_NAME } from './artifacts-manifest';
|
|
50
|
+
import { CanonicalLogitProcessor, CanonicalSurfaceTokenTrie, logSoftmaxAt, logSumExp } from './canonical-lm-scoring';
|
|
51
|
+
import { CTC_STYLES, isAutocompleteDebugEnabled, isAutocompleteDebugVerbose } from './debug-mode';
|
|
52
|
+
import { MIN_WINNER_MARGIN, STAGE1_WEIGHT, STAGE2_WEIGHT } from './scoring-pipeline';
|
|
53
53
|
import { isWordBoundary } from './slow-lane-client';
|
|
54
54
|
|
|
55
|
+
/** Which of the two causal-LM call shapes a measurement or log line describes. */
|
|
56
|
+
|
|
55
57
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
56
58
|
|
|
57
59
|
// Same return type as createSlowLaneClient for drop-in compatibility
|
|
@@ -103,22 +105,7 @@ export var LOCAL_MLC_EMBEDDING_MODEL_ID = 'snowflake-arctic-embed-s-q0f32-MLC-b4
|
|
|
103
105
|
export var wrapForArctic = function wrapForArctic(text) {
|
|
104
106
|
return "[CLS] ".concat(text, " [SEP]");
|
|
105
107
|
};
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* BE-parity constants — must match `CausalLMEncoder` defaults in the Python
|
|
109
|
-
* sidecar (`cc-smarts/python-sidecar/src/causal_lm_encoder.py`) and
|
|
110
|
-
* `SlowLaneEngine` (`typeahead_context_encoding.py`) so local payloads behave
|
|
111
|
-
* identically to the server-client setup.
|
|
112
|
-
*/
|
|
113
|
-
export var BE_PARITY = {
|
|
114
|
-
/** Final payload size cap (BE: `top_k_words`). */
|
|
115
|
-
TOP_K_WORDS: 2000,
|
|
116
|
-
/** L2 (domain) words admitted unconditionally before pooling (BE: `reserved_l2_slots`). */
|
|
117
|
-
RESERVED_L2_SLOTS: 500,
|
|
118
|
-
/** Log-space additive bias favouring L2 over L3 in the pool (BE: `l2_bias`). */
|
|
119
|
-
L2_BIAS: 1.0,
|
|
120
|
-
/** Drop words below this probability from the final payload (BE: `> 0.00001`). */
|
|
121
|
-
MIN_PROB: 0.00001,
|
|
108
|
+
export var LOCAL_INFERENCE = {
|
|
122
109
|
/**
|
|
123
110
|
* Word-level approximation of the BE causal LM token limit.
|
|
124
111
|
*
|
|
@@ -139,6 +126,72 @@ export var BE_PARITY = {
|
|
|
139
126
|
*/
|
|
140
127
|
MAX_CONTEXT_WORDS: 100
|
|
141
128
|
};
|
|
129
|
+
export var CANONICAL_SCORING = {
|
|
130
|
+
/**
|
|
131
|
+
* How many contexts keep their prefilled state before the oldest is dropped.
|
|
132
|
+
*
|
|
133
|
+
* Sizes every context-keyed cache together on purpose: an expansion needs
|
|
134
|
+
* both the boundary logits and the candidate list to still be resident, so
|
|
135
|
+
* bounding them separately would evict half of a context and strand the
|
|
136
|
+
* other half.
|
|
137
|
+
*
|
|
138
|
+
* The context of a keystroke is the text *before* the word being typed,
|
|
139
|
+
* which does not change while that word is typed, so one word should cost
|
|
140
|
+
* one prefill and then hit. Measured hit rate was 45% over the first 84s of
|
|
141
|
+
* a session and 24% over the following four minutes, well short of that, and
|
|
142
|
+
* prompt prefills per decision rose 0.80 → 1.25 across the same split while
|
|
143
|
+
* cost per prefill stayed flat. Contexts were being dropped while still live.
|
|
144
|
+
*
|
|
145
|
+
* A boundary entry holds a `Float32Array` over the 49,152-token vocabulary,
|
|
146
|
+
* so each one is ~192KB and this bound is the dominant term in the scorer's
|
|
147
|
+
* footprint: ~24MB resident here, against ~6MB at the 32 this replaced. That
|
|
148
|
+
* cost is what kept the bound low, not a hit rate anyone had measured.
|
|
149
|
+
*/
|
|
150
|
+
BOUNDARY_CACHE_MAX: 128,
|
|
151
|
+
EXACT_MAX_TARGET_TOKENS: 8,
|
|
152
|
+
PREFIX_CACHE_MAX: 256,
|
|
153
|
+
/**
|
|
154
|
+
* How many candidates compete for expansion in one context.
|
|
155
|
+
*
|
|
156
|
+
* Each distinct token prefix among them is a separate branch, and a branch
|
|
157
|
+
* the engine is not already standing on costs a prompt prefill before its
|
|
158
|
+
* first decode. A wide field therefore spreads a decision's round trips
|
|
159
|
+
* across candidates and finishes none of them inside the budget.
|
|
160
|
+
*/
|
|
161
|
+
PROGRESSIVE_CANDIDATES_MAX: 8,
|
|
162
|
+
/**
|
|
163
|
+
* Ceiling on distinct token prefixes explored per context.
|
|
164
|
+
*
|
|
165
|
+
* Raising this to 8 to give long surfaces more room did the opposite: model
|
|
166
|
+
* calls per decision went 2.35 → 4.32, the warm-KV extend share fell 40% →
|
|
167
|
+
* 31% as the extra branches displaced the live path, the prefix queue backed
|
|
168
|
+
* up to 29 deep, and acceptances per thousand decisions fell 9.3 → 6.7. No
|
|
169
|
+
* phrase was shown either way, so breadth was never the binding constraint.
|
|
170
|
+
*
|
|
171
|
+
* What blocked them then was normalisation against a short word's per-token
|
|
172
|
+
* mean, which has since been replaced by a posterior over sequence
|
|
173
|
+
* log-likelihoods. That removes the bias towards short surfaces but does not
|
|
174
|
+
* by itself make phrases reachable: a longer surface is strictly less likely
|
|
175
|
+
* than a shorter one, so a phrase sharing a shortlist with a unigram still
|
|
176
|
+
* holds little of its mass. Whether the remaining gap is the threshold or the
|
|
177
|
+
* comparison is still open.
|
|
178
|
+
*/
|
|
179
|
+
PROGRESSIVE_EXPANSIONS_PER_CONTEXT_MAX: 4,
|
|
180
|
+
PROGRESSIVE_INPUT_MAX: 400,
|
|
181
|
+
SURFACE_CACHE_MAX: 128,
|
|
182
|
+
TIER_A_PRIMES_MAX: 3
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* How much optimistic score we give up to stay on the warm KV path.
|
|
186
|
+
*
|
|
187
|
+
* Expanding a prefix the cache already holds costs one decode step, while
|
|
188
|
+
* branching to any other prefix costs a full prompt prefill first. Measured,
|
|
189
|
+
* that is about 30ms against about 66ms, so continuing the live path is worth
|
|
190
|
+
* roughly half a round trip and the margin has to be wide enough to reflect
|
|
191
|
+
* that. At the previous 0.05 almost any ranking difference was enough to
|
|
192
|
+
* abandon the sequence, and 70% of expansions ended up re-prefilling.
|
|
193
|
+
*/
|
|
194
|
+
var PROGRESSIVE_WARM_PATH_MARGIN = 0.25;
|
|
142
195
|
var splitOnWhitespace = function splitOnWhitespace(text) {
|
|
143
196
|
var trimmed = text.trim();
|
|
144
197
|
if (trimmed === '') {
|
|
@@ -173,114 +226,60 @@ var truncateToLastNWords = function truncateToLastNWords(text, n) {
|
|
|
173
226
|
return words.length <= n ? text : words.slice(-n).join(' ');
|
|
174
227
|
};
|
|
175
228
|
|
|
176
|
-
// ─── Logit capture ─────────────────────────────────────────────────────────
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* A LogitProcessor that captures the raw next-token logits and passes them
|
|
180
|
-
* through unmodified.
|
|
181
|
-
*
|
|
182
|
-
* web-llm invokes `processLogits` on the CPU after the model's forward pass and
|
|
183
|
-
* before sampling, handing us the full `Float32Array(vocab_size)` at the current
|
|
184
|
-
* decode position. We copy it off web-llm's shared buffer (which it may reuse
|
|
185
|
-
* across calls) and return the original untouched so sampling is unaffected.
|
|
186
|
-
*
|
|
187
|
-
* This is the raw-logit access the BE-parity algorithm needs (masked softmax +
|
|
188
|
-
* prefix expansion, consumed in a later step). Registered for the causal LM
|
|
189
|
-
* only — the embedder never decodes tokens, so it produces no logits.
|
|
190
|
-
*/
|
|
191
|
-
var CapturingLogitProcessor = /*#__PURE__*/_createClass(function CapturingLogitProcessor() {
|
|
192
|
-
var _this = this;
|
|
193
|
-
_classCallCheck(this, CapturingLogitProcessor);
|
|
194
|
-
_defineProperty(this, "captured", null);
|
|
195
|
-
_defineProperty(this, "processLogits", function (logits) {
|
|
196
|
-
// Copy off web-llm's shared buffer — it may reuse `logits` across calls.
|
|
197
|
-
_this.captured = new Float32Array(logits);
|
|
198
|
-
return logits;
|
|
199
|
-
});
|
|
200
|
-
_defineProperty(this, "processSampledToken", function () {
|
|
201
|
-
// No-op — we don't track sampled tokens.
|
|
202
|
-
});
|
|
203
|
-
_defineProperty(this, "resetState", function () {
|
|
204
|
-
_this.captured = null;
|
|
205
|
-
});
|
|
206
|
-
}); // ─── BE-parity data + algorithm ──────────────────────────────────────────────
|
|
207
229
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* (`CausalLMEncoder._ensure_loaded`).
|
|
212
|
-
*
|
|
213
|
-
* Populated lazily by `loadBePayloadData()` from a dynamically-imported JSON so
|
|
214
|
-
* the (large) payload is only fetched when the local client is actually
|
|
215
|
-
* initialised — keeping it out of the editor's main chunk for the vast majority
|
|
216
|
-
* of users (who run with `useLocalModel` off).
|
|
230
|
+
* Full canonical leading-space token sequence for every served surface. The
|
|
231
|
+
* producer keeps the existing `phrase-continuation-tokens.json` wire name while
|
|
232
|
+
* expanding its key set to the complete word/bigram/phrase union.
|
|
217
233
|
*/
|
|
218
|
-
var
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* L2 (Atlassian-domain) word set, derived from the keys of `vocabulary_10k.json`.
|
|
222
|
-
* Used by `computeBePayload` for tier-aware ranking: any word in the prefix map
|
|
223
|
-
* that is not in this set is treated as L3 (general English), matching the BE.
|
|
224
|
-
* Populated lazily alongside `firstTokenToWords` — see `loadBePayloadData()`.
|
|
225
|
-
*/
|
|
226
|
-
var l2Words = new Set();
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Array of token IDs that appear as a first token for at least one vocabulary
|
|
230
|
-
* word. Derived from `firstTokenToWords` when the data loads so `computeBePayload`
|
|
231
|
-
* does not re-allocate this array on every word-boundary call.
|
|
232
|
-
*/
|
|
233
|
-
var prefixMapTokenIds = [];
|
|
234
|
+
var surfaceTokenIds = new Map();
|
|
235
|
+
var surfaceTokenTrie = new CanonicalSurfaceTokenTrie();
|
|
234
236
|
|
|
235
237
|
/** De-dupes concurrent loads and lets repeated calls await the same payload. */
|
|
236
|
-
var
|
|
238
|
+
var surfaceTokenIdsPromise;
|
|
239
|
+
var isPhraseContinuationTokens = function isPhraseContinuationTokens(payload) {
|
|
240
|
+
if (payload == null || _typeof(payload) !== 'object') {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
return Object.values(payload).every(function (value) {
|
|
244
|
+
return Array.isArray(value) && value.every(function (entry) {
|
|
245
|
+
return typeof entry === 'number' && entry >= 0;
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
};
|
|
237
249
|
|
|
238
|
-
/**
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
* :returns:
|
|
244
|
-
* A promise that resolves once `firstTokenToWords`, `l2Words` and
|
|
245
|
-
* `prefixMapTokenIds` are populated.
|
|
246
|
-
*/
|
|
247
|
-
var loadBePayloadData = function loadBePayloadData() {
|
|
248
|
-
if (!bePayloadDataPromise) {
|
|
249
|
-
bePayloadDataPromise = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
250
|
-
var _yield$Promise$all, _yield$Promise$all2, firstTokenToWordsData, vocabularyData;
|
|
250
|
+
/** Lazily load the producer's full-union canonical surface token map. */
|
|
251
|
+
var loadCanonicalSurfaceTokens = function loadCanonicalSurfaceTokens() {
|
|
252
|
+
if (!surfaceTokenIdsPromise) {
|
|
253
|
+
surfaceTokenIdsPromise = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
254
|
+
var continuationTokensData;
|
|
251
255
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
252
256
|
while (1) switch (_context.prev = _context.next) {
|
|
253
257
|
case 0:
|
|
254
258
|
_context.next = 1;
|
|
255
|
-
return
|
|
259
|
+
return fetchAutocompleteArtifactJson(ARTIFACT_NAME.PHRASE_CONTINUATION_TOKENS, {
|
|
260
|
+
summarize: function summarize(payload) {
|
|
261
|
+
return "".concat(Object.keys(payload).length, " surfaces");
|
|
262
|
+
},
|
|
263
|
+
validate: isPhraseContinuationTokens
|
|
264
|
+
}).catch(function () {
|
|
265
|
+
return null;
|
|
266
|
+
});
|
|
256
267
|
case 1:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
firstTokenToWordsData = _yield$Promise$all2[0];
|
|
260
|
-
vocabularyData = _yield$Promise$all2[1];
|
|
261
|
-
if (!(firstTokenToWordsData == null || (vocabularyData === null || vocabularyData === void 0 ? void 0 : vocabularyData.words) == null)) {
|
|
262
|
-
_context.next = 2;
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
265
|
-
throw new Error("[LocalSlowLane] unexpected artifact payload \u2014 " + "firstTokenToWordsData=".concat(firstTokenToWordsData == null ? 'null/undefined' : 'defined', ", ") + "vocabularyData=".concat(vocabularyData == null ? 'null/undefined' : vocabularyData.words == null ? 'defined but missing .words' : 'defined'));
|
|
266
|
-
case 2:
|
|
267
|
-
firstTokenToWords = new Map(Object.entries(firstTokenToWordsData).map(function (_ref2) {
|
|
268
|
+
continuationTokensData = _context.sent;
|
|
269
|
+
surfaceTokenIds = new Map(Object.entries(continuationTokensData !== null && continuationTokensData !== void 0 ? continuationTokensData : {}).map(function (_ref2) {
|
|
268
270
|
var _ref3 = _slicedToArray(_ref2, 2),
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return [
|
|
271
|
+
surface = _ref3[0],
|
|
272
|
+
tokenIds = _ref3[1];
|
|
273
|
+
return [surface.toLowerCase(), tokenIds];
|
|
272
274
|
}));
|
|
273
|
-
|
|
274
|
-
prefixMapTokenIds = Array.from(firstTokenToWords.keys());
|
|
275
|
+
surfaceTokenTrie = new CanonicalSurfaceTokenTrie(surfaceTokenIds.entries());
|
|
275
276
|
if (isAutocompleteDebugEnabled()) {
|
|
276
277
|
// eslint-disable-next-line no-console
|
|
277
|
-
console.log(
|
|
278
|
-
|
|
279
|
-
l2WordsCount: l2Words.size,
|
|
280
|
-
prefixMapTokenIdsLength: prefixMapTokenIds.length
|
|
278
|
+
console.log("%c[CTC:model] %c".concat(surfaceTokenIds.size > 0 ? '✅ canonical surface tokens loaded:' : '⚠️ canonical surface tokens unavailable — LM evidence will remain absent:'), 'color: #9c27b0; font-weight: bold;', surfaceTokenIds.size > 0 ? 'color: #4caf50; font-weight: bold;' : 'color: #ff9800; font-weight: bold;', {
|
|
279
|
+
surfaces: surfaceTokenIds.size
|
|
281
280
|
});
|
|
282
281
|
}
|
|
283
|
-
case
|
|
282
|
+
case 2:
|
|
284
283
|
case "end":
|
|
285
284
|
return _context.stop();
|
|
286
285
|
}
|
|
@@ -289,225 +288,11 @@ var loadBePayloadData = function loadBePayloadData() {
|
|
|
289
288
|
// Don't cache a rejected promise — a transient import failure would
|
|
290
289
|
// otherwise prevent the local model from ever initialising again this
|
|
291
290
|
// session. Reset so the next init attempt retries.
|
|
292
|
-
|
|
291
|
+
surfaceTokenIdsPromise = undefined;
|
|
293
292
|
throw e;
|
|
294
293
|
});
|
|
295
294
|
}
|
|
296
|
-
return
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Convert a raw next-token logit vector into a whole-word probability payload,
|
|
301
|
-
* faithfully porting the BE `CausalLMEncoder._get_top_k_probs`
|
|
302
|
-
* (`cc-smarts/python-sidecar/src/causal_lm_encoder.py`).
|
|
303
|
-
*
|
|
304
|
-
* Steps: (1) numerically-stable masked softmax over only the token ids present
|
|
305
|
-
* in the prefix-expansion map; (2) spread each token's probability to every
|
|
306
|
-
* whole word sharing that first token, taking the max; (3) reserve the top L2
|
|
307
|
-
* words unconditionally; (4) rank the remainder in a log-space pool with an
|
|
308
|
-
* additive L2 bias; (5) emit raw probabilities for the survivors, lowercased
|
|
309
|
-
* and trimmed at `MIN_PROB`.
|
|
310
|
-
*
|
|
311
|
-
* :params:
|
|
312
|
-
* rawLogits: Full-vocabulary logits from the LM's single decode step
|
|
313
|
-
* prefixMap: Map of first-token id to the words starting with that token
|
|
314
|
-
* domainWords: Set of L2 (domain) words, for tier-aware ranking
|
|
315
|
-
* :returns:
|
|
316
|
-
* A record of lowercase word to probability — the BE `lm_logits` payload
|
|
317
|
-
*/
|
|
318
|
-
export var computeBePayload = function computeBePayload(rawLogits, prefixMap, domainWords) {
|
|
319
|
-
var validTokenIds = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : prefixMapTokenIds;
|
|
320
|
-
// 1. Numerically-stable masked softmax over validTokenIds only.
|
|
321
|
-
var maxLogit = -Infinity;
|
|
322
|
-
var _iterator = _createForOfIteratorHelper(validTokenIds),
|
|
323
|
-
_step;
|
|
324
|
-
try {
|
|
325
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
326
|
-
var id = _step.value;
|
|
327
|
-
var v = rawLogits[id];
|
|
328
|
-
if (v > maxLogit) {
|
|
329
|
-
maxLogit = v;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
} catch (err) {
|
|
333
|
-
_iterator.e(err);
|
|
334
|
-
} finally {
|
|
335
|
-
_iterator.f();
|
|
336
|
-
}
|
|
337
|
-
var sumExp = 0;
|
|
338
|
-
var expByToken = new Map();
|
|
339
|
-
var _iterator2 = _createForOfIteratorHelper(validTokenIds),
|
|
340
|
-
_step2;
|
|
341
|
-
try {
|
|
342
|
-
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
343
|
-
var _id = _step2.value;
|
|
344
|
-
var e = Math.exp(rawLogits[_id] - maxLogit);
|
|
345
|
-
expByToken.set(_id, e);
|
|
346
|
-
sumExp += e;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// 2. Prefix expansion with max aggregation (probabilities sum to 1 over the
|
|
350
|
-
// masked subset, so divide each token's exp by sumExp on the fly).
|
|
351
|
-
} catch (err) {
|
|
352
|
-
_iterator2.e(err);
|
|
353
|
-
} finally {
|
|
354
|
-
_iterator2.f();
|
|
355
|
-
}
|
|
356
|
-
var wordProbs = new Map();
|
|
357
|
-
var _iterator3 = _createForOfIteratorHelper(prefixMap),
|
|
358
|
-
_step3;
|
|
359
|
-
try {
|
|
360
|
-
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
361
|
-
var _expByToken$get;
|
|
362
|
-
var _step3$value = _slicedToArray(_step3.value, 2),
|
|
363
|
-
_id2 = _step3$value[0],
|
|
364
|
-
words = _step3$value[1];
|
|
365
|
-
var _p = sumExp > 0 ? ((_expByToken$get = expByToken.get(_id2)) !== null && _expByToken$get !== void 0 ? _expByToken$get : 0) / sumExp : 0;
|
|
366
|
-
var _iterator8 = _createForOfIteratorHelper(words),
|
|
367
|
-
_step8;
|
|
368
|
-
try {
|
|
369
|
-
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
370
|
-
var _wordProbs$get2;
|
|
371
|
-
var _w = _step8.value;
|
|
372
|
-
var prev = (_wordProbs$get2 = wordProbs.get(_w)) !== null && _wordProbs$get2 !== void 0 ? _wordProbs$get2 : 0;
|
|
373
|
-
if (_p > prev) {
|
|
374
|
-
wordProbs.set(_w, _p);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
} catch (err) {
|
|
378
|
-
_iterator8.e(err);
|
|
379
|
-
} finally {
|
|
380
|
-
_iterator8.f();
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// 3. Split into L2 / L3 and reserve the top L2 slots unconditionally.
|
|
385
|
-
} catch (err) {
|
|
386
|
-
_iterator3.e(err);
|
|
387
|
-
} finally {
|
|
388
|
-
_iterator3.f();
|
|
389
|
-
}
|
|
390
|
-
var l2Matches = [];
|
|
391
|
-
var l3Matches = [];
|
|
392
|
-
var _iterator4 = _createForOfIteratorHelper(wordProbs),
|
|
393
|
-
_step4;
|
|
394
|
-
try {
|
|
395
|
-
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
396
|
-
var _step4$value = _slicedToArray(_step4.value, 2),
|
|
397
|
-
_w2 = _step4$value[0],
|
|
398
|
-
_p2 = _step4$value[1];
|
|
399
|
-
if (domainWords.has(_w2)) {
|
|
400
|
-
l2Matches.push([_w2, _p2]);
|
|
401
|
-
} else {
|
|
402
|
-
l3Matches.push([_w2, _p2]);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
} catch (err) {
|
|
406
|
-
_iterator4.e(err);
|
|
407
|
-
} finally {
|
|
408
|
-
_iterator4.f();
|
|
409
|
-
}
|
|
410
|
-
l2Matches.sort(function (a, b) {
|
|
411
|
-
return b[1] - a[1];
|
|
412
|
-
});
|
|
413
|
-
var reserved = l2Matches.slice(0, BE_PARITY.RESERVED_L2_SLOTS);
|
|
414
|
-
|
|
415
|
-
// 4. Pool the leftovers in log space; the L2 bias only affects ranking here.
|
|
416
|
-
// Words in l2Matches are unique and the array is sorted descending, so the
|
|
417
|
-
// non-reserved entries are exactly the tail after the reserved prefix — slice
|
|
418
|
-
// it directly rather than allocating a Set and scanning every entry on this
|
|
419
|
-
// hot path (runs ~every word boundary while typing).
|
|
420
|
-
var pool = [];
|
|
421
|
-
var _iterator5 = _createForOfIteratorHelper(l2Matches.slice(BE_PARITY.RESERVED_L2_SLOTS)),
|
|
422
|
-
_step5;
|
|
423
|
-
try {
|
|
424
|
-
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
425
|
-
var _step5$value = _slicedToArray(_step5.value, 2),
|
|
426
|
-
_w3 = _step5$value[0],
|
|
427
|
-
_p3 = _step5$value[1];
|
|
428
|
-
pool.push([_w3, Math.log(Math.max(_p3, 1e-10)) + BE_PARITY.L2_BIAS]);
|
|
429
|
-
}
|
|
430
|
-
} catch (err) {
|
|
431
|
-
_iterator5.e(err);
|
|
432
|
-
} finally {
|
|
433
|
-
_iterator5.f();
|
|
434
|
-
}
|
|
435
|
-
for (var _i = 0, _l3Matches = l3Matches; _i < _l3Matches.length; _i++) {
|
|
436
|
-
var _l3Matches$_i = _slicedToArray(_l3Matches[_i], 2),
|
|
437
|
-
w = _l3Matches$_i[0],
|
|
438
|
-
p = _l3Matches$_i[1];
|
|
439
|
-
pool.push([w, Math.log(Math.max(p, 1e-10))]);
|
|
440
|
-
}
|
|
441
|
-
pool.sort(function (a, b) {
|
|
442
|
-
return b[1] - a[1];
|
|
443
|
-
});
|
|
444
|
-
var remainingSlots = Math.max(0, BE_PARITY.TOP_K_WORDS - reserved.length);
|
|
445
|
-
var poolWinners = pool.slice(0, remainingSlots);
|
|
446
|
-
|
|
447
|
-
// 5. Assemble payload: store RAW probabilities (the bias was ranking-only),
|
|
448
|
-
// lowercase keys, trimmed at MIN_PROB. Reserved first, then pool winners.
|
|
449
|
-
// Reserved entries are written first; pool-winner writes must NOT clobber a
|
|
450
|
-
// reserved entry whose normalised key collides (two source words can
|
|
451
|
-
// `.trim().toLowerCase()` to the same key — e.g. "Function" vs "function ").
|
|
452
|
-
// Without the existence guard, a low-probability pool winner would silently
|
|
453
|
-
// overwrite the (higher-probability) reserved entry, degrading top-K
|
|
454
|
-
// quality in a way that's invisible from the debug summary.
|
|
455
|
-
var result = {};
|
|
456
|
-
var addEntry = function addEntry(word, prob, allowOverwrite) {
|
|
457
|
-
if (prob <= BE_PARITY.MIN_PROB) {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
var key = word.trim().toLowerCase();
|
|
461
|
-
if (!allowOverwrite && key in result) {
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
result[key] = prob;
|
|
465
|
-
};
|
|
466
|
-
var _iterator6 = _createForOfIteratorHelper(reserved),
|
|
467
|
-
_step6;
|
|
468
|
-
try {
|
|
469
|
-
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
470
|
-
var _step6$value = _slicedToArray(_step6.value, 2),
|
|
471
|
-
_w4 = _step6$value[0],
|
|
472
|
-
_p4 = _step6$value[1];
|
|
473
|
-
addEntry(_w4, _p4, true);
|
|
474
|
-
}
|
|
475
|
-
} catch (err) {
|
|
476
|
-
_iterator6.e(err);
|
|
477
|
-
} finally {
|
|
478
|
-
_iterator6.f();
|
|
479
|
-
}
|
|
480
|
-
var _iterator7 = _createForOfIteratorHelper(poolWinners),
|
|
481
|
-
_step7;
|
|
482
|
-
try {
|
|
483
|
-
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
484
|
-
var _wordProbs$get3;
|
|
485
|
-
var _step7$value = _slicedToArray(_step7.value, 1),
|
|
486
|
-
_w5 = _step7$value[0];
|
|
487
|
-
addEntry(_w5, (_wordProbs$get3 = wordProbs.get(_w5)) !== null && _wordProbs$get3 !== void 0 ? _wordProbs$get3 : 0, false);
|
|
488
|
-
}
|
|
489
|
-
} catch (err) {
|
|
490
|
-
_iterator7.e(err);
|
|
491
|
-
} finally {
|
|
492
|
-
_iterator7.f();
|
|
493
|
-
}
|
|
494
|
-
if (isAutocompleteDebugEnabled()) {
|
|
495
|
-
var topReserved = reserved.slice(0, 5).map(function (_ref4) {
|
|
496
|
-
var _ref5 = _slicedToArray(_ref4, 2),
|
|
497
|
-
w = _ref5[0],
|
|
498
|
-
p = _ref5[1];
|
|
499
|
-
return "".concat(w, ":").concat((p * 100).toFixed(2), "%");
|
|
500
|
-
}).join(', ');
|
|
501
|
-
var topPool = poolWinners.slice(0, 5).map(function (_ref6) {
|
|
502
|
-
var _wordProbs$get;
|
|
503
|
-
var _ref7 = _slicedToArray(_ref6, 1),
|
|
504
|
-
w = _ref7[0];
|
|
505
|
-
return "".concat(w, ":").concat((((_wordProbs$get = wordProbs.get(w)) !== null && _wordProbs$get !== void 0 ? _wordProbs$get : 0) * 100).toFixed(2), "%");
|
|
506
|
-
}).join(', ');
|
|
507
|
-
// eslint-disable-next-line no-console
|
|
508
|
-
console.log('%c[computeBePayload] %c%d valid tokens → %d words expanded | L2: %d / L3: %d | reserved: %d | pool winners: %d | final: %d words\n maxLogit(masked): %s | sumExp: %s\n top reserved L2: %s\n top pool: %s', 'color: #9c27b0; font-weight: bold;', 'color: inherit;', validTokenIds.length, wordProbs.size, l2Matches.length, l3Matches.length, reserved.length, poolWinners.length, Object.keys(result).length, maxLogit.toFixed(3), sumExp.toFixed(1), topReserved || '(none)', topPool || '(none)');
|
|
509
|
-
}
|
|
510
|
-
return result;
|
|
295
|
+
return surfaceTokenIdsPromise;
|
|
511
296
|
};
|
|
512
297
|
|
|
513
298
|
// ─── Factory ─────────────────────────────────────────────────────────────────
|
|
@@ -523,9 +308,8 @@ export var computeBePayload = function computeBePayload(rawLogits, prefixMap, do
|
|
|
523
308
|
* const client = createLocalSlowLaneClient({ debounceMs: 300 });
|
|
524
309
|
* // On word boundaries:
|
|
525
310
|
* client.updateContext(docText);
|
|
526
|
-
* //
|
|
527
|
-
*
|
|
528
|
-
* const logits = client.getLmLogits();
|
|
311
|
+
* // Candidate scoring independently calls
|
|
312
|
+
* // primeBoundaryLm/requestProgressiveSurfaceScores.
|
|
529
313
|
* // On plugin teardown:
|
|
530
314
|
* client.destroy();
|
|
531
315
|
* ```
|
|
@@ -535,6 +319,8 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
535
319
|
var _config$debounceMs = config.debounceMs,
|
|
536
320
|
debounceMs = _config$debounceMs === void 0 ? DEFAULT_DEBOUNCE_MS : _config$debounceMs,
|
|
537
321
|
onUpdate = config.onUpdate,
|
|
322
|
+
onBoundaryLmUpdate = config.onBoundaryLmUpdate,
|
|
323
|
+
onSurfaceScoreUpdate = config.onSurfaceScoreUpdate,
|
|
538
324
|
onStatus = config.onStatus,
|
|
539
325
|
onLoadError = config.onLoadError,
|
|
540
326
|
onLoadSuccess = config.onLoadSuccess,
|
|
@@ -544,8 +330,54 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
544
330
|
surface = config.surface;
|
|
545
331
|
|
|
546
332
|
// ── State ──────────────────────────────────────────────────────────────
|
|
333
|
+
var storedContextInput = null;
|
|
547
334
|
var storedContextVector = null;
|
|
548
335
|
var storedLmLogits = null;
|
|
336
|
+
var boundaryCache = new Map();
|
|
337
|
+
var prefixExpansionCache = new Map();
|
|
338
|
+
var surfaceScoreCache = new Map();
|
|
339
|
+
var causalInFlight = false;
|
|
340
|
+
var inFlightBoundaryContextKey = null;
|
|
341
|
+
var latestCausalFamilyKey = '';
|
|
342
|
+
var causalRequestsThisFamily = 0;
|
|
343
|
+
var causalGeneratedTokensThisFamily = 0;
|
|
344
|
+
var tierAPrimeCacheHitsThisFamily = 0;
|
|
345
|
+
var tierAPrimeCacheMissesThisFamily = 0;
|
|
346
|
+
var causalInferenceOrdinal = 0;
|
|
347
|
+
var causalInferenceByContext = new Map();
|
|
348
|
+
var causalInferenceByFamily = new Map();
|
|
349
|
+
var exactEvidenceCountByContext = new Map();
|
|
350
|
+
var pendingBoundaryPrimes = new Map();
|
|
351
|
+
var pendingPrefixExpansions = new Map();
|
|
352
|
+
var inFlightPrefixExpansions = new Set();
|
|
353
|
+
// The engine holds exactly one linear KV sequence. WebLLM lets us extend it
|
|
354
|
+
// (`forwardTokensAndSample`) or drop it (a text completion always resets
|
|
355
|
+
// first), but never fork or rewind it. Tracking what is currently
|
|
356
|
+
// materialised is what makes decoding continuous: expanding a token prefix
|
|
357
|
+
// that extends `kvPath` costs a single decode step, while any other prefix
|
|
358
|
+
// costs a fresh prompt prefill.
|
|
359
|
+
var kvContextKey = null;
|
|
360
|
+
var kvPath = [];
|
|
361
|
+
var isPrefixOf = function isPrefixOf(prefix, path) {
|
|
362
|
+
return prefix.length <= path.length && prefix.every(function (token, index) {
|
|
363
|
+
return token === path[index];
|
|
364
|
+
});
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* Whether running this expansion would extend the sequence the engine is
|
|
368
|
+
* already holding rather than discarding it for a fresh prompt prefill.
|
|
369
|
+
*
|
|
370
|
+
* `planProgressiveExpansion` also prefers a warm group, but it decides when
|
|
371
|
+
* the work is queued and the queue is drained later. A boundary prime or
|
|
372
|
+
* another context's expansion running in between moves the path out from
|
|
373
|
+
* under that choice, so the preference has to be re-checked at the moment
|
|
374
|
+
* something is picked up.
|
|
375
|
+
*/
|
|
376
|
+
var extendsLiveKvPath = function extendsLiveKvPath(request) {
|
|
377
|
+
return kvContextKey === request.contextKey && isPrefixOf(kvPath, request.tokenPrefix);
|
|
378
|
+
};
|
|
379
|
+
var progressiveRequests = new Map();
|
|
380
|
+
var progressivePrefixesByContext = new Map();
|
|
549
381
|
var debounceTimer = null;
|
|
550
382
|
var lastRequestedText = '';
|
|
551
383
|
var requestCounter = 0;
|
|
@@ -563,14 +395,12 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
563
395
|
var initFailed = false;
|
|
564
396
|
var engine = null;
|
|
565
397
|
var engineInitPromise = null;
|
|
566
|
-
|
|
567
|
-
// with the engine below; `lmLogitsCapture.captured` is consumed in a later step.
|
|
568
|
-
var lmLogitsCapture = new CapturingLogitProcessor();
|
|
398
|
+
var causalLogitProcessor = new CanonicalLogitProcessor();
|
|
569
399
|
var unloadEngine = function unloadEngine(engineToUnload) {
|
|
570
400
|
engineToUnload.unload().catch(function (error) {
|
|
571
401
|
if (isAutocompleteDebugEnabled()) {
|
|
572
402
|
// eslint-disable-next-line no-console
|
|
573
|
-
console.log('%c[
|
|
403
|
+
console.log('%c[CTC:model] %cFailed to unload engine', 'color: #9c27b0; font-weight: bold;', 'color: inherit;', error);
|
|
574
404
|
}
|
|
575
405
|
});
|
|
576
406
|
};
|
|
@@ -581,7 +411,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
581
411
|
var message = "[".concat((progress.progress * 100).toFixed(0), "%] ").concat(progress.text);
|
|
582
412
|
if (isAutocompleteDebugEnabled()) {
|
|
583
413
|
// eslint-disable-next-line no-console
|
|
584
|
-
console.log("%c[
|
|
414
|
+
console.log("%c[CTC:model] %c\uD83D\uDD04 ".concat(message), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
585
415
|
}
|
|
586
416
|
onStatus === null || onStatus === void 0 || onStatus(message);
|
|
587
417
|
};
|
|
@@ -594,8 +424,8 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
594
424
|
* to a concrete hardware/browser limitation rather than a generic error.
|
|
595
425
|
*/
|
|
596
426
|
var probeWebGpuCapabilities = /*#__PURE__*/function () {
|
|
597
|
-
var
|
|
598
|
-
var gpu, _adapter$limits, _adapter$limits2, adapter, vendor, architecture, _info, _requestAdapterInfo,
|
|
427
|
+
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
428
|
+
var gpu, _adapter$limits, _adapter$limits2, adapter, vendor, architecture, _info, _requestAdapterInfo, _ref5, info, _t, _t2, _t3;
|
|
599
429
|
return _regeneratorRuntime.wrap(function (_context2) {
|
|
600
430
|
while (1) switch (_context2.prev = _context2.next) {
|
|
601
431
|
case 0:
|
|
@@ -632,7 +462,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
632
462
|
break;
|
|
633
463
|
case 4:
|
|
634
464
|
_context2.next = 5;
|
|
635
|
-
return (_requestAdapterInfo = (
|
|
465
|
+
return (_requestAdapterInfo = (_ref5 = adapter).requestAdapterInfo) === null || _requestAdapterInfo === void 0 ? void 0 : _requestAdapterInfo.call(_ref5);
|
|
636
466
|
case 5:
|
|
637
467
|
_t = _context2.sent;
|
|
638
468
|
case 6:
|
|
@@ -668,7 +498,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
668
498
|
}, _callee2, null, [[1, 9], [3, 7]]);
|
|
669
499
|
}));
|
|
670
500
|
return function probeWebGpuCapabilities() {
|
|
671
|
-
return
|
|
501
|
+
return _ref4.apply(this, arguments);
|
|
672
502
|
};
|
|
673
503
|
}();
|
|
674
504
|
|
|
@@ -710,7 +540,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
710
540
|
var message = LOAD_FAILURE_MESSAGE[reason];
|
|
711
541
|
if (isAutocompleteDebugEnabled()) {
|
|
712
542
|
// eslint-disable-next-line no-console
|
|
713
|
-
console.log("[
|
|
543
|
+
console.log("[CTC:model] Engine initialisation failed (".concat(reason, "): ").concat(debugDetail !== null && debugDetail !== void 0 ? debugDetail : message));
|
|
714
544
|
}
|
|
715
545
|
onStatus === null || onStatus === void 0 || onStatus("Engine initialisation failed: ".concat(message));
|
|
716
546
|
onLoadError === null || onLoadError === void 0 || onLoadError({
|
|
@@ -724,8 +554,8 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
724
554
|
initFailed = true;
|
|
725
555
|
};
|
|
726
556
|
var initEngine = /*#__PURE__*/function () {
|
|
727
|
-
var
|
|
728
|
-
var capabilities, startTime, _yield$Promise$
|
|
557
|
+
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
558
|
+
var capabilities, startTime, _yield$Promise$all, _yield$Promise$all2, _yield$Promise$all2$, MLCEngineCtor, prebuiltAppConfig, customModelRecord, appConfig, newEngine, loadDurationMs, errorMsg, _t4;
|
|
729
559
|
return _regeneratorRuntime.wrap(function (_context3) {
|
|
730
560
|
while (1) switch (_context3.prev = _context3.next) {
|
|
731
561
|
case 0:
|
|
@@ -758,20 +588,20 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
758
588
|
_context3.prev = 5;
|
|
759
589
|
if (isAutocompleteDebugEnabled()) {
|
|
760
590
|
// eslint-disable-next-line no-console
|
|
761
|
-
console.log("%c[
|
|
591
|
+
console.log("%c[CTC:model] %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;');
|
|
762
592
|
}
|
|
763
593
|
onStatus === null || onStatus === void 0 || onStatus("Initialising models: ".concat(modelId, " + ").concat(LOCAL_MLC_EMBEDDING_MODEL_ID, "\u2026"));
|
|
764
594
|
|
|
765
|
-
// Fetch the web-llm runtime and
|
|
595
|
+
// Fetch the web-llm runtime and canonical token artifact in parallel;
|
|
766
596
|
// both are dynamically imported so they stay out of the main editor chunk.
|
|
767
597
|
_context3.next = 6;
|
|
768
|
-
return Promise.all([import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-mlc-web-llm" */'@mlc-ai/web-llm'),
|
|
598
|
+
return Promise.all([import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-autocomplete-mlc-web-llm" */'@mlc-ai/web-llm'), loadCanonicalSurfaceTokens()]);
|
|
769
599
|
case 6:
|
|
770
|
-
_yield$Promise$
|
|
771
|
-
_yield$Promise$
|
|
772
|
-
_yield$Promise$
|
|
773
|
-
MLCEngineCtor = _yield$Promise$
|
|
774
|
-
prebuiltAppConfig = _yield$Promise$
|
|
600
|
+
_yield$Promise$all = _context3.sent;
|
|
601
|
+
_yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 1);
|
|
602
|
+
_yield$Promise$all2$ = _yield$Promise$all2[0];
|
|
603
|
+
MLCEngineCtor = _yield$Promise$all2$.MLCEngine;
|
|
604
|
+
prebuiltAppConfig = _yield$Promise$all2$.prebuiltAppConfig;
|
|
775
605
|
customModelRecord = customModelConfig ? _objectSpread(_objectSpread({
|
|
776
606
|
model: customModelConfig.model,
|
|
777
607
|
model_id: modelId,
|
|
@@ -793,7 +623,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
793
623
|
newEngine = new MLCEngineCtor({
|
|
794
624
|
appConfig: appConfig,
|
|
795
625
|
initProgressCallback: initProgressCallback,
|
|
796
|
-
logitProcessorRegistry: new Map([[modelId,
|
|
626
|
+
logitProcessorRegistry: new Map([[modelId, causalLogitProcessor]])
|
|
797
627
|
});
|
|
798
628
|
_context3.next = 7;
|
|
799
629
|
return newEngine.reload([modelId, LOCAL_MLC_EMBEDDING_MODEL_ID]);
|
|
@@ -811,13 +641,13 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
811
641
|
loadDurationMs = Math.round(performance.now() - startTime);
|
|
812
642
|
if (isAutocompleteDebugEnabled()) {
|
|
813
643
|
// eslint-disable-next-line no-console
|
|
814
|
-
console.log('%c[
|
|
644
|
+
console.log('%c[CTC:model] %c✅ Both models loaded and ready', 'color: #9c27b0; font-weight: bold;', 'color: #4caf50;');
|
|
815
645
|
// One-time identity summary so you can confirm which models are active
|
|
816
646
|
// without digging through the init-progress scroll.
|
|
817
647
|
// eslint-disable-next-line no-console
|
|
818
|
-
console.log('%c[
|
|
648
|
+
console.log('%c[CTC:model] %c🧠 Causal LM →', 'color: #9c27b0; font-weight: bold;', 'color: #2196f3; font-weight: bold;', modelId);
|
|
819
649
|
// eslint-disable-next-line no-console
|
|
820
|
-
console.log('%c[
|
|
650
|
+
console.log('%c[CTC:model] %c🔢 Embedder →', 'color: #9c27b0; font-weight: bold;', 'color: #009688; font-weight: bold;', LOCAL_MLC_EMBEDDING_MODEL_ID);
|
|
821
651
|
}
|
|
822
652
|
onStatus === null || onStatus === void 0 || onStatus('Model loaded and ready.');
|
|
823
653
|
onLoadSuccess === null || onLoadSuccess === void 0 || onLoadSuccess({
|
|
@@ -840,7 +670,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
840
670
|
}, _callee3, null, [[5, 9]]);
|
|
841
671
|
}));
|
|
842
672
|
return function initEngine() {
|
|
843
|
-
return
|
|
673
|
+
return _ref6.apply(this, arguments);
|
|
844
674
|
};
|
|
845
675
|
}();
|
|
846
676
|
var ensureEngineInitialized = function ensureEngineInitialized() {
|
|
@@ -855,53 +685,25 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
855
685
|
|
|
856
686
|
// ── Inference ──────────────────────────────────────────────────────────
|
|
857
687
|
|
|
858
|
-
/**
|
|
859
|
-
* Run a single forward pass to produce the BE-parity slow-lane outputs.
|
|
860
|
-
*
|
|
861
|
-
* Two calls run in parallel on the shared engine:
|
|
862
|
-
* - `completions.create({ max_tokens: 1 })` runs the causal LM for exactly
|
|
863
|
-
* one decode step. We ignore the generated text; the LogitProcessor
|
|
864
|
-
* captures the raw next-token logits during that step, which we turn into
|
|
865
|
-
* a whole-word payload via `computeBePayload`.
|
|
866
|
-
* - `embeddings.create(...)` runs the Arctic embedder to produce the real
|
|
867
|
-
* 384-d semantic vector (passage-encoded; see `wrapForArctic`).
|
|
868
|
-
*/
|
|
688
|
+
/** Run the boundary-timed Arctic semantic inference independently of the LM. */
|
|
869
689
|
var runInference = /*#__PURE__*/function () {
|
|
870
|
-
var
|
|
871
|
-
var experienceId,
|
|
690
|
+
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(text, requestId) {
|
|
691
|
+
var experienceId, semanticText, arcticInput, _data, tStart, embeddingResponse, tEmbDone, embedding, sumSq, i, errorMsg, _t5;
|
|
872
692
|
return _regeneratorRuntime.wrap(function (_context4) {
|
|
873
693
|
while (1) switch (_context4.prev = _context4.next) {
|
|
874
694
|
case 0:
|
|
875
|
-
captureCompletionTime = function _captureCompletionTim(promise, onResolved) {
|
|
876
|
-
return promise.then(function (value) {
|
|
877
|
-
onResolved(performance.now());
|
|
878
|
-
return value;
|
|
879
|
-
});
|
|
880
|
-
};
|
|
881
695
|
if (!(!engine || destroyed)) {
|
|
882
696
|
_context4.next = 1;
|
|
883
697
|
break;
|
|
884
698
|
}
|
|
885
699
|
return _context4.abrupt("return");
|
|
886
700
|
case 1:
|
|
887
|
-
experienceId = String(requestId);
|
|
888
|
-
|
|
889
|
-
// latest request's decode step is the last to populate `captured` before
|
|
890
|
-
// we read it below; stale requests bail on the latestRequestId guard.
|
|
891
|
-
lmLogitsCapture.resetState();
|
|
892
|
-
|
|
893
|
-
// Apply BE-parity rolling-window truncation before both encoders.
|
|
894
|
-
// BE semantic: last max_context_words words (typeahead_context_encoding.py:36)
|
|
895
|
-
// BE causal LM: last max_context_tokens BPE tokens (causal_lm_encoder.py:194–198),
|
|
896
|
-
// approximated here with word count (no tokenizer available on FE).
|
|
897
|
-
lmText = truncateToLastNWords(text, BE_PARITY.MAX_CONTEXT_TOKENS);
|
|
898
|
-
semanticText = truncateToLastNWords(text, BE_PARITY.MAX_CONTEXT_WORDS);
|
|
701
|
+
experienceId = String(requestId);
|
|
702
|
+
semanticText = truncateToLastNWords(text, LOCAL_INFERENCE.MAX_CONTEXT_WORDS);
|
|
899
703
|
arcticInput = wrapForArctic(semanticText);
|
|
900
|
-
if (
|
|
901
|
-
// eslint-disable-next-line no-console
|
|
902
|
-
console.log("%c[LocalSlowLane] %c\uD83D\uDD22 Arctic input (".concat(arcticInput.length, " chars, ").concat(splitOnWhitespace(semanticText).length, " words): \"").concat(arcticInput.length > 100 ? "".concat(arcticInput.slice(0, 100), "\u2026") : arcticInput, "\""), 'color: #9c27b0; font-weight: bold;', 'color: #009688;');
|
|
704
|
+
if (isAutocompleteDebugVerbose()) {
|
|
903
705
|
// eslint-disable-next-line no-console
|
|
904
|
-
console.log("%c[
|
|
706
|
+
console.log("%c[CTC:model] %c\uD83D\uDD22 Arctic input (".concat(arcticInput.length, " chars, ").concat(splitOnWhitespace(semanticText).length, " words): \"").concat(arcticInput.length > 100 ? "".concat(arcticInput.slice(0, 100), "\u2026") : arcticInput, "\""), 'color: #9c27b0; font-weight: bold;', 'color: #009688;');
|
|
905
707
|
}
|
|
906
708
|
_context4.prev = 2;
|
|
907
709
|
// Reuse the network slow-lane-fetch UFO experience (tagged isLocalLLM:true,
|
|
@@ -917,30 +719,17 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
917
719
|
surface: surface
|
|
918
720
|
} : {}));
|
|
919
721
|
tStart = performance.now();
|
|
920
|
-
tLmDone = 0;
|
|
921
|
-
tEmbDone = 0;
|
|
922
722
|
_context4.next = 3;
|
|
923
|
-
return
|
|
924
|
-
model: modelId,
|
|
925
|
-
prompt: lmText,
|
|
926
|
-
max_tokens: 1,
|
|
927
|
-
temperature: 0,
|
|
928
|
-
logprobs: false
|
|
929
|
-
}), function (resolvedAt) {
|
|
930
|
-
tLmDone = resolvedAt;
|
|
931
|
-
}), captureCompletionTime(engine.embeddings.create({
|
|
723
|
+
return engine.embeddings.create({
|
|
932
724
|
model: LOCAL_MLC_EMBEDDING_MODEL_ID,
|
|
933
725
|
input: arcticInput
|
|
934
|
-
})
|
|
935
|
-
tEmbDone = resolvedAt;
|
|
936
|
-
})]);
|
|
726
|
+
});
|
|
937
727
|
case 3:
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
embeddingResponse = _yield$Promise$all6[1];
|
|
728
|
+
embeddingResponse = _context4.sent;
|
|
729
|
+
tEmbDone = performance.now();
|
|
941
730
|
if (isAutocompleteDebugEnabled()) {
|
|
942
731
|
// eslint-disable-next-line no-console
|
|
943
|
-
console.log("%c[
|
|
732
|
+
console.log("%c[CTC:model] %c\u23F1 Embedder: ".concat((tEmbDone - tStart).toFixed(0), "ms"), 'color: #9c27b0; font-weight: bold;', 'color: #ff9800;');
|
|
944
733
|
}
|
|
945
734
|
|
|
946
735
|
// Discard stale results
|
|
@@ -955,24 +744,16 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
955
744
|
} : {}));
|
|
956
745
|
return _context4.abrupt("return");
|
|
957
746
|
case 4:
|
|
958
|
-
// ── LM logits: whole-word BE-parity payload ──────────────────
|
|
959
|
-
rawLogits = lmLogitsCapture.captured;
|
|
960
|
-
if (rawLogits) {
|
|
961
|
-
payload = computeBePayload(rawLogits, firstTokenToWords, l2Words);
|
|
962
|
-
storedLmLogits = Object.keys(payload).length > 0 ? payload : null;
|
|
963
|
-
} else {
|
|
964
|
-
storedLmLogits = null;
|
|
965
|
-
}
|
|
966
|
-
|
|
967
747
|
// ── Semantic vector: real 384-d Arctic embedding ─────────────
|
|
968
748
|
// Guard against base64-encoded responses (encoding_format: 'base64' would
|
|
969
749
|
// yield a string, and new Float32Array(string) silently produces an empty
|
|
970
750
|
// array, corrupting downstream cosine-similarity scoring).
|
|
971
751
|
embedding = (_data = embeddingResponse.data) === null || _data === void 0 || (_data = _data[0]) === null || _data === void 0 ? void 0 : _data.embedding;
|
|
972
752
|
storedContextVector = Array.isArray(embedding) && embedding.length > 0 ? new Float32Array(embedding) : null;
|
|
753
|
+
storedContextInput = storedContextVector ? semanticText : null;
|
|
973
754
|
if (isAutocompleteDebugEnabled()) {
|
|
974
755
|
// eslint-disable-next-line no-console
|
|
975
|
-
console.groupCollapsed("%c[
|
|
756
|
+
console.groupCollapsed("%c[CTC:model] %c\uD83D\uDCE5 Inference result (request #".concat(requestId, ")"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
976
757
|
if (storedContextVector) {
|
|
977
758
|
sumSq = 0;
|
|
978
759
|
for (i = 0; i < storedContextVector.length; i++) {
|
|
@@ -985,29 +766,14 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
985
766
|
console.log('❌ No vector');
|
|
986
767
|
}
|
|
987
768
|
// eslint-disable-next-line no-console
|
|
988
|
-
console.log(
|
|
989
|
-
if (storedLmLogits) {
|
|
990
|
-
topTokens = Object.entries(storedLmLogits).sort(function (_ref10, _ref11) {
|
|
991
|
-
var _ref12 = _slicedToArray(_ref10, 2),
|
|
992
|
-
a = _ref12[1];
|
|
993
|
-
var _ref13 = _slicedToArray(_ref11, 2),
|
|
994
|
-
b = _ref13[1];
|
|
995
|
-
return b - a;
|
|
996
|
-
}).slice(0, 10); // eslint-disable-next-line no-console
|
|
997
|
-
console.log('Top 10 predictions:', topTokens.map(function (_ref14) {
|
|
998
|
-
var _ref15 = _slicedToArray(_ref14, 2),
|
|
999
|
-
t = _ref15[0],
|
|
1000
|
-
p = _ref15[1];
|
|
1001
|
-
return "".concat(t, ": ").concat((p * 100).toFixed(1), "%");
|
|
1002
|
-
}).join(', '));
|
|
1003
|
-
}
|
|
769
|
+
console.log('🧠 causal LM: independently primed by exact candidate contexts');
|
|
1004
770
|
// eslint-disable-next-line no-console
|
|
1005
771
|
console.groupEnd();
|
|
1006
772
|
}
|
|
1007
773
|
succeedExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, experienceId, _objectSpread({
|
|
1008
774
|
textLength: text.length,
|
|
1009
775
|
hasVector: storedContextVector !== null,
|
|
1010
|
-
hasLmLogits:
|
|
776
|
+
hasLmLogits: false,
|
|
1011
777
|
isLocalLLM: true
|
|
1012
778
|
}, surface ? {
|
|
1013
779
|
surface: surface
|
|
@@ -1015,7 +781,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
1015
781
|
onUpdate === null || onUpdate === void 0 || onUpdate({
|
|
1016
782
|
textLength: text.length,
|
|
1017
783
|
hasVector: storedContextVector !== null,
|
|
1018
|
-
hasLmLogits:
|
|
784
|
+
hasLmLogits: false
|
|
1019
785
|
});
|
|
1020
786
|
_context4.next = 7;
|
|
1021
787
|
break;
|
|
@@ -1033,6 +799,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
1033
799
|
} : {}));
|
|
1034
800
|
return _context4.abrupt("return");
|
|
1035
801
|
case 6:
|
|
802
|
+
storedContextInput = null;
|
|
1036
803
|
storedContextVector = null;
|
|
1037
804
|
storedLmLogits = null;
|
|
1038
805
|
failExp(EXPERIENCE_NAME.SLOW_LANE_FETCH, experienceId, _objectSpread({
|
|
@@ -1049,7 +816,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
1049
816
|
errorMsg = _t5 instanceof Error ? _t5.message : String(_t5);
|
|
1050
817
|
if (isAutocompleteDebugEnabled()) {
|
|
1051
818
|
// eslint-disable-next-line no-console
|
|
1052
|
-
console.log("%c[
|
|
819
|
+
console.log("%c[CTC:model] %c\u274C Inference error (request #".concat(requestId, "): ").concat(errorMsg), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
1053
820
|
}
|
|
1054
821
|
case 7:
|
|
1055
822
|
case "end":
|
|
@@ -1058,9 +825,859 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
1058
825
|
}, _callee4, null, [[2, 5]]);
|
|
1059
826
|
}));
|
|
1060
827
|
return function runInference(_x, _x2) {
|
|
828
|
+
return _ref7.apply(this, arguments);
|
|
829
|
+
};
|
|
830
|
+
}();
|
|
831
|
+
|
|
832
|
+
// ── Canonical causal scorer ─────────────────────────────────────────────
|
|
833
|
+
|
|
834
|
+
var surfaceCacheKey = function surfaceCacheKey(contextKey, surface) {
|
|
835
|
+
var _surfaceTokenIds$get;
|
|
836
|
+
var tokenIds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : (_surfaceTokenIds$get = surfaceTokenIds.get(surface.toLowerCase())) !== null && _surfaceTokenIds$get !== void 0 ? _surfaceTokenIds$get : [];
|
|
837
|
+
return "".concat(contextKey, "\0").concat(surface.toLowerCase(), "\0").concat(tokenIds.join(','));
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
// Declared as functions rather than generic arrows: this file carries a `webpackChunkName`
|
|
841
|
+
// comment, which opts it into a build-time parse that reads `<T>(` as a JSX tag.
|
|
842
|
+
function getLru(cache, key) {
|
|
843
|
+
var value = cache.get(key);
|
|
844
|
+
if (value === undefined) {
|
|
845
|
+
return null;
|
|
846
|
+
}
|
|
847
|
+
cache.delete(key);
|
|
848
|
+
cache.set(key, value);
|
|
849
|
+
return value;
|
|
850
|
+
}
|
|
851
|
+
function setLru(cache, key, value, maxSize) {
|
|
852
|
+
cache.delete(key);
|
|
853
|
+
cache.set(key, value);
|
|
854
|
+
while (cache.size > maxSize) {
|
|
855
|
+
var oldest = cache.keys().next().value;
|
|
856
|
+
if (oldest === undefined) {
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
cache.delete(oldest);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
var prefixCacheKey = function prefixCacheKey(contextKey, tokenPrefix) {
|
|
863
|
+
return "".concat(contextKey, "\0").concat(tokenPrefix.join(','));
|
|
864
|
+
};
|
|
865
|
+
var logProgressiveState = function logProgressiveState(state, detail) {
|
|
866
|
+
if (!isAutocompleteDebugEnabled()) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
// eslint-disable-next-line no-console
|
|
870
|
+
console.log("%c[CTC:model] %c\uD83D\uDD00 grouped ".concat(state, " \xB7 ").concat(detail), 'color: #9c27b0; font-weight: bold;', state === 'failed' ? 'color: #f44336;' : state === 'completed' || state === 'cached' ? 'color: #4caf50;' : 'color: #2196f3;');
|
|
871
|
+
};
|
|
872
|
+
var createCausalInferenceAggregate = function createCausalInferenceAggregate(startedAt) {
|
|
873
|
+
return {
|
|
874
|
+
e2eLatencyMs: 0,
|
|
875
|
+
failedRequests: 0,
|
|
876
|
+
firstStartedAt: startedAt,
|
|
877
|
+
promptTokens: 0,
|
|
878
|
+
promptUsageSamples: 0,
|
|
879
|
+
requestedCompletionTokens: 0,
|
|
880
|
+
requests: 0,
|
|
881
|
+
sampledOutputTokens: 0,
|
|
882
|
+
timeToFirstTokenMs: 0,
|
|
883
|
+
wallClockMs: 0,
|
|
884
|
+
webLlmDecodeSteps: 0,
|
|
885
|
+
webLlmUsageSamples: 0
|
|
886
|
+
};
|
|
887
|
+
};
|
|
888
|
+
var updateCausalInferenceAggregate = function updateCausalInferenceAggregate(cache, key, measurement) {
|
|
889
|
+
var _getLru;
|
|
890
|
+
var aggregate = (_getLru = getLru(cache, key)) !== null && _getLru !== void 0 ? _getLru : createCausalInferenceAggregate(performance.now() - measurement.wallClockMs);
|
|
891
|
+
aggregate.requests++;
|
|
892
|
+
aggregate.requestedCompletionTokens += measurement.requestedCompletionTokens;
|
|
893
|
+
aggregate.wallClockMs += measurement.wallClockMs;
|
|
894
|
+
if (measurement.outcome === 'failed') {
|
|
895
|
+
aggregate.failedRequests++;
|
|
896
|
+
}
|
|
897
|
+
if (measurement.promptTokens !== null) {
|
|
898
|
+
aggregate.promptTokens += measurement.promptTokens;
|
|
899
|
+
aggregate.promptUsageSamples++;
|
|
900
|
+
}
|
|
901
|
+
if (measurement.sampledOutputTokens !== null && measurement.webLlmDecodeSteps !== null) {
|
|
902
|
+
aggregate.sampledOutputTokens += measurement.sampledOutputTokens;
|
|
903
|
+
aggregate.webLlmDecodeSteps += measurement.webLlmDecodeSteps;
|
|
904
|
+
aggregate.webLlmUsageSamples++;
|
|
905
|
+
}
|
|
906
|
+
if (measurement.timeToFirstTokenMs !== null) {
|
|
907
|
+
aggregate.timeToFirstTokenMs += measurement.timeToFirstTokenMs;
|
|
908
|
+
}
|
|
909
|
+
if (measurement.e2eLatencyMs !== null) {
|
|
910
|
+
aggregate.e2eLatencyMs += measurement.e2eLatencyMs;
|
|
911
|
+
}
|
|
912
|
+
setLru(cache, key, aggregate, CANONICAL_SCORING.BOUNDARY_CACHE_MAX);
|
|
913
|
+
return aggregate;
|
|
914
|
+
};
|
|
915
|
+
var causalAggregateForLog = function causalAggregateForLog(aggregate) {
|
|
916
|
+
return {
|
|
917
|
+
calls: aggregate.requests,
|
|
918
|
+
elapsedMs: Number((performance.now() - aggregate.firstStartedAt).toFixed(1)),
|
|
919
|
+
failedCalls: aggregate.failedRequests,
|
|
920
|
+
inferenceWallMs: Number(aggregate.wallClockMs.toFixed(1)),
|
|
921
|
+
promptTokens: aggregate.promptUsageSamples > 0 ? aggregate.promptTokens : 'unreported',
|
|
922
|
+
requestedOutputTokens: aggregate.requestedCompletionTokens,
|
|
923
|
+
sampledOutputTokens: aggregate.webLlmUsageSamples > 0 ? aggregate.sampledOutputTokens : 'unreported',
|
|
924
|
+
timeToFirstTokenMs: aggregate.timeToFirstTokenMs > 0 ? Number(aggregate.timeToFirstTokenMs.toFixed(1)) : 'unreported',
|
|
925
|
+
webLlmE2eMs: aggregate.e2eLatencyMs > 0 ? Number(aggregate.e2eLatencyMs.toFixed(1)) : 'unreported',
|
|
926
|
+
webLlmDecodeSteps: aggregate.webLlmUsageSamples > 0 ? aggregate.webLlmDecodeSteps : 'unreported'
|
|
927
|
+
};
|
|
928
|
+
};
|
|
929
|
+
var recordCausalInference = function recordCausalInference(measurement) {
|
|
930
|
+
var _measurement$promptTo, _measurement$sampledO, _measurement$webLlmDe, _measurement$timeToFi, _measurement$timeToFi2;
|
|
931
|
+
if (!isAutocompleteDebugEnabled()) {
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
var familyAggregate = updateCausalInferenceAggregate(causalInferenceByFamily, measurement.familyKey, measurement);
|
|
935
|
+
var contextAggregate = updateCausalInferenceAggregate(causalInferenceByContext, measurement.contextKey, measurement);
|
|
936
|
+
// One line plus two nested objects per LM call is heavy enough to distort
|
|
937
|
+
// the latencies it reports, so keep the per-call breakdown behind verbose.
|
|
938
|
+
if (!isAutocompleteDebugVerbose()) {
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
// eslint-disable-next-line no-console
|
|
942
|
+
console.log("%c[CTC:model-cost]%c ".concat(measurement.kind, " ").concat(measurement.outcome, " \xB7 ").concat(measurement.wallClockMs.toFixed(1), "ms \xB7 prompt ").concat((_measurement$promptTo = measurement.promptTokens) !== null && _measurement$promptTo !== void 0 ? _measurement$promptTo : '?', " tok/").concat(measurement.promptWords, " words \xB7 output ").concat((_measurement$sampledO = measurement.sampledOutputTokens) !== null && _measurement$sampledO !== void 0 ? _measurement$sampledO : '?', " sampled/").concat(measurement.requestedCompletionTokens, " requested \xB7 decode ").concat((_measurement$webLlmDe = measurement.webLlmDecodeSteps) !== null && _measurement$webLlmDe !== void 0 ? _measurement$webLlmDe : '?', " step").concat(measurement.webLlmDecodeSteps === 1 ? '' : 's', " \xB7 TTFT ").concat((_measurement$timeToFi = (_measurement$timeToFi2 = measurement.timeToFirstTokenMs) === null || _measurement$timeToFi2 === void 0 ? void 0 : _measurement$timeToFi2.toFixed(1)) !== null && _measurement$timeToFi !== void 0 ? _measurement$timeToFi : '?', "ms \xB7 ").concat(measurement.warmState), CTC_STYLES.section, CTC_STYLES.body, {
|
|
943
|
+
request: {
|
|
944
|
+
contextKey: measurement.contextKey,
|
|
945
|
+
familyKey: measurement.familyKey,
|
|
946
|
+
kind: measurement.kind,
|
|
947
|
+
outcome: measurement.outcome,
|
|
948
|
+
warmState: measurement.warmState
|
|
949
|
+
},
|
|
950
|
+
actual: {
|
|
951
|
+
decodeTokensPerSecond: measurement.decodeTokensPerSecond,
|
|
952
|
+
e2eLatencyMs: measurement.e2eLatencyMs,
|
|
953
|
+
prefillTokensPerSecond: measurement.prefillTokensPerSecond,
|
|
954
|
+
promptTokens: measurement.promptTokens,
|
|
955
|
+
promptWords: measurement.promptWords,
|
|
956
|
+
sampledOutputTokens: measurement.sampledOutputTokens,
|
|
957
|
+
timePerDecodeTokenMs: measurement.timePerDecodeTokenMs,
|
|
958
|
+
timeToFirstTokenMs: measurement.timeToFirstTokenMs,
|
|
959
|
+
wallClockMs: measurement.wallClockMs,
|
|
960
|
+
webLlmDecodeSteps: measurement.webLlmDecodeSteps
|
|
961
|
+
},
|
|
962
|
+
context: causalAggregateForLog(contextAggregate),
|
|
963
|
+
family: causalAggregateForLog(familyAggregate)
|
|
964
|
+
});
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* Pull the captured distribution out of the processor, timing the handover.
|
|
969
|
+
*
|
|
970
|
+
* Every call yields one array the width of the vocabulary. If that width is
|
|
971
|
+
* large and the handover is slow, thousands of calls per session turn into
|
|
972
|
+
* allocation churn that shows up as latency without any model work behind it.
|
|
973
|
+
*/
|
|
974
|
+
var captureLogits = function captureLogits() {
|
|
975
|
+
return causalLogitProcessor.getCapturedLogits();
|
|
976
|
+
};
|
|
977
|
+
var createMeasuredCausalCompletion = /*#__PURE__*/function () {
|
|
978
|
+
var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(activeEngine, input) {
|
|
979
|
+
var prompt, promptWords, startedAt, warmState, _usage$completion_tok, _usage$extra$decode_t, _usage$extra, _usage$extra2, _usage$extra$prefill_, _usage$extra3, _usage$prompt_tokens, _usage$extra4, _usage$extra5, completion, latencyMs, usage, webLlmDecodeSteps, sampledOutputTokens, _latencyMs, _t6;
|
|
980
|
+
return _regeneratorRuntime.wrap(function (_context5) {
|
|
981
|
+
while (1) switch (_context5.prev = _context5.next) {
|
|
982
|
+
case 0:
|
|
983
|
+
prompt = truncateToLastNWords(input.prompt, LOCAL_INFERENCE.MAX_CONTEXT_TOKENS);
|
|
984
|
+
promptWords = splitOnWhitespace(prompt).length;
|
|
985
|
+
startedAt = performance.now();
|
|
986
|
+
warmState = ++causalInferenceOrdinal === 1 ? 'cold-first-call' : 'warm';
|
|
987
|
+
_context5.prev = 1;
|
|
988
|
+
_context5.next = 2;
|
|
989
|
+
return activeEngine.completions.create({
|
|
990
|
+
model: modelId,
|
|
991
|
+
prompt: prompt,
|
|
992
|
+
max_tokens: input.requestedCompletionTokens,
|
|
993
|
+
temperature: 0,
|
|
994
|
+
logprobs: false,
|
|
995
|
+
ignore_eos: true
|
|
996
|
+
});
|
|
997
|
+
case 2:
|
|
998
|
+
completion = _context5.sent;
|
|
999
|
+
latencyMs = performance.now() - startedAt;
|
|
1000
|
+
usage = completion.usage;
|
|
1001
|
+
webLlmDecodeSteps = (_usage$completion_tok = usage === null || usage === void 0 ? void 0 : usage.completion_tokens) !== null && _usage$completion_tok !== void 0 ? _usage$completion_tok : null; // WebLLM samples the first output token during prefill, but its
|
|
1002
|
+
// completion_tokens usage counter increments only in decodeStep().
|
|
1003
|
+
// Add that prefill-sampled token back without exceeding max_tokens.
|
|
1004
|
+
sampledOutputTokens = webLlmDecodeSteps === null ? null : Math.min(input.requestedCompletionTokens, webLlmDecodeSteps + 1);
|
|
1005
|
+
recordCausalInference({
|
|
1006
|
+
contextKey: input.contextKey,
|
|
1007
|
+
decodeTokensPerSecond: (_usage$extra$decode_t = usage === null || usage === void 0 || (_usage$extra = usage.extra) === null || _usage$extra === void 0 ? void 0 : _usage$extra.decode_tokens_per_s) !== null && _usage$extra$decode_t !== void 0 ? _usage$extra$decode_t : null,
|
|
1008
|
+
e2eLatencyMs: (usage === null || usage === void 0 || (_usage$extra2 = usage.extra) === null || _usage$extra2 === void 0 ? void 0 : _usage$extra2.e2e_latency_s) !== undefined ? usage.extra.e2e_latency_s * 1000 : null,
|
|
1009
|
+
familyKey: input.familyKey,
|
|
1010
|
+
kind: input.kind,
|
|
1011
|
+
outcome: 'completed',
|
|
1012
|
+
prefillTokensPerSecond: (_usage$extra$prefill_ = usage === null || usage === void 0 || (_usage$extra3 = usage.extra) === null || _usage$extra3 === void 0 ? void 0 : _usage$extra3.prefill_tokens_per_s) !== null && _usage$extra$prefill_ !== void 0 ? _usage$extra$prefill_ : null,
|
|
1013
|
+
promptTokens: (_usage$prompt_tokens = usage === null || usage === void 0 ? void 0 : usage.prompt_tokens) !== null && _usage$prompt_tokens !== void 0 ? _usage$prompt_tokens : null,
|
|
1014
|
+
promptWords: promptWords,
|
|
1015
|
+
requestedCompletionTokens: input.requestedCompletionTokens,
|
|
1016
|
+
sampledOutputTokens: sampledOutputTokens,
|
|
1017
|
+
timePerDecodeTokenMs: (usage === null || usage === void 0 || (_usage$extra4 = usage.extra) === null || _usage$extra4 === void 0 ? void 0 : _usage$extra4.time_per_output_token_s) !== undefined ? usage.extra.time_per_output_token_s * 1000 : null,
|
|
1018
|
+
timeToFirstTokenMs: (usage === null || usage === void 0 || (_usage$extra5 = usage.extra) === null || _usage$extra5 === void 0 ? void 0 : _usage$extra5.time_to_first_token_s) !== undefined ? usage.extra.time_to_first_token_s * 1000 : null,
|
|
1019
|
+
wallClockMs: latencyMs,
|
|
1020
|
+
warmState: warmState,
|
|
1021
|
+
webLlmDecodeSteps: webLlmDecodeSteps
|
|
1022
|
+
});
|
|
1023
|
+
return _context5.abrupt("return", {
|
|
1024
|
+
latencyMs: latencyMs
|
|
1025
|
+
});
|
|
1026
|
+
case 3:
|
|
1027
|
+
_context5.prev = 3;
|
|
1028
|
+
_t6 = _context5["catch"](1);
|
|
1029
|
+
_latencyMs = performance.now() - startedAt;
|
|
1030
|
+
recordCausalInference({
|
|
1031
|
+
contextKey: input.contextKey,
|
|
1032
|
+
decodeTokensPerSecond: null,
|
|
1033
|
+
e2eLatencyMs: null,
|
|
1034
|
+
familyKey: input.familyKey,
|
|
1035
|
+
kind: input.kind,
|
|
1036
|
+
outcome: 'failed',
|
|
1037
|
+
prefillTokensPerSecond: null,
|
|
1038
|
+
promptTokens: null,
|
|
1039
|
+
promptWords: promptWords,
|
|
1040
|
+
requestedCompletionTokens: input.requestedCompletionTokens,
|
|
1041
|
+
sampledOutputTokens: null,
|
|
1042
|
+
timePerDecodeTokenMs: null,
|
|
1043
|
+
timeToFirstTokenMs: null,
|
|
1044
|
+
wallClockMs: _latencyMs,
|
|
1045
|
+
warmState: warmState,
|
|
1046
|
+
webLlmDecodeSteps: null
|
|
1047
|
+
});
|
|
1048
|
+
throw _t6;
|
|
1049
|
+
case 4:
|
|
1050
|
+
case "end":
|
|
1051
|
+
return _context5.stop();
|
|
1052
|
+
}
|
|
1053
|
+
}, _callee5, null, [[1, 3]]);
|
|
1054
|
+
}));
|
|
1055
|
+
return function createMeasuredCausalCompletion(_x3, _x4) {
|
|
1056
|
+
return _ref8.apply(this, arguments);
|
|
1057
|
+
};
|
|
1058
|
+
}();
|
|
1059
|
+
var logExactEvidenceReadiness = function logExactEvidenceReadiness(contextKey, familyKey, exactSurfaceCount, source) {
|
|
1060
|
+
var _exactEvidenceCountBy;
|
|
1061
|
+
if (!isAutocompleteDebugEnabled()) {
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
var previousCount = (_exactEvidenceCountBy = exactEvidenceCountByContext.get(contextKey)) !== null && _exactEvidenceCountBy !== void 0 ? _exactEvidenceCountBy : 0;
|
|
1065
|
+
if (exactSurfaceCount <= previousCount) {
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
setLru(exactEvidenceCountByContext, contextKey, exactSurfaceCount, CANONICAL_SCORING.BOUNDARY_CACHE_MAX);
|
|
1069
|
+
var contextAggregate = getLru(causalInferenceByContext, contextKey);
|
|
1070
|
+
var familyAggregate = getLru(causalInferenceByFamily, familyKey);
|
|
1071
|
+
// eslint-disable-next-line no-console
|
|
1072
|
+
console.log("%c[CTC:readiness]%c exact evidence \xB7 ".concat(exactSurfaceCount, " surface").concat(exactSurfaceCount === 1 ? '' : 's', " \xB7 source=").concat(source, " \xB7 ctx=").concat(contextKey.slice(0, 64)), CTC_STYLES.good, CTC_STYLES.body, {
|
|
1073
|
+
context: contextAggregate ? causalAggregateForLog(contextAggregate) : null,
|
|
1074
|
+
contextKey: contextKey,
|
|
1075
|
+
exactSurfaceCount: exactSurfaceCount,
|
|
1076
|
+
family: familyAggregate ? causalAggregateForLog(familyAggregate) : null,
|
|
1077
|
+
familyKey: familyKey,
|
|
1078
|
+
source: source
|
|
1079
|
+
});
|
|
1080
|
+
};
|
|
1081
|
+
var getProgressiveEvidence = function getProgressiveEvidence(contextKey, candidateSurface) {
|
|
1082
|
+
var _surfaceTokenTrie$get;
|
|
1083
|
+
var tokenIds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : (_surfaceTokenTrie$get = surfaceTokenTrie.getTokenIds(candidateSurface)) !== null && _surfaceTokenTrie$get !== void 0 ? _surfaceTokenTrie$get : [];
|
|
1084
|
+
if (tokenIds.length === 0) {
|
|
1085
|
+
return null;
|
|
1086
|
+
}
|
|
1087
|
+
var exactKey = surfaceCacheKey(contextKey, candidateSurface, tokenIds);
|
|
1088
|
+
var exact = getLru(surfaceScoreCache, exactKey);
|
|
1089
|
+
if (exact) {
|
|
1090
|
+
return {
|
|
1091
|
+
meanTokenLogProbabilityUpperBound: exact.meanTokenLogProbability,
|
|
1092
|
+
scoredTokenCount: exact.tokenCount,
|
|
1093
|
+
totalLogProbability: exact.totalLogProbability,
|
|
1094
|
+
totalTokenCount: exact.tokenCount
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
var boundary = getLru(boundaryCache, contextKey);
|
|
1098
|
+
var firstToken = tokenIds[0];
|
|
1099
|
+
if (!boundary || firstToken === undefined) {
|
|
1100
|
+
return null;
|
|
1101
|
+
}
|
|
1102
|
+
var totalLogProbability = logSoftmaxAt(boundary.rawLogits, firstToken);
|
|
1103
|
+
if (!Number.isFinite(totalLogProbability)) {
|
|
1104
|
+
return null;
|
|
1105
|
+
}
|
|
1106
|
+
var scoredTokenCount = 1;
|
|
1107
|
+
while (scoredTokenCount < tokenIds.length) {
|
|
1108
|
+
var prefix = tokenIds.slice(0, scoredTokenCount);
|
|
1109
|
+
var expansion = getLru(prefixExpansionCache, prefixCacheKey(contextKey, prefix));
|
|
1110
|
+
if (!expansion) {
|
|
1111
|
+
break;
|
|
1112
|
+
}
|
|
1113
|
+
var nextTokenLogProbability = logSoftmaxAt(expansion.rawNextTokenLogits, tokenIds[scoredTokenCount]);
|
|
1114
|
+
if (!Number.isFinite(nextTokenLogProbability)) {
|
|
1115
|
+
break;
|
|
1116
|
+
}
|
|
1117
|
+
totalLogProbability = expansion.totalLogProbability + nextTokenLogProbability;
|
|
1118
|
+
scoredTokenCount++;
|
|
1119
|
+
}
|
|
1120
|
+
if (scoredTokenCount === tokenIds.length) {
|
|
1121
|
+
var exactScore = {
|
|
1122
|
+
contextKey: contextKey,
|
|
1123
|
+
surface: candidateSurface,
|
|
1124
|
+
totalLogProbability: totalLogProbability,
|
|
1125
|
+
meanTokenLogProbability: totalLogProbability / tokenIds.length,
|
|
1126
|
+
tokenCount: tokenIds.length
|
|
1127
|
+
};
|
|
1128
|
+
setLru(surfaceScoreCache, exactKey, exactScore, CANONICAL_SCORING.SURFACE_CACHE_MAX);
|
|
1129
|
+
}
|
|
1130
|
+
return {
|
|
1131
|
+
// Every unscored future token has log probability <= 0. Dividing the
|
|
1132
|
+
// scored total by the final token count is therefore a safe optimistic
|
|
1133
|
+
// bound on the eventual mean.
|
|
1134
|
+
meanTokenLogProbabilityUpperBound: totalLogProbability / tokenIds.length,
|
|
1135
|
+
scoredTokenCount: scoredTokenCount,
|
|
1136
|
+
totalLogProbability: totalLogProbability,
|
|
1137
|
+
totalTokenCount: tokenIds.length
|
|
1138
|
+
};
|
|
1139
|
+
};
|
|
1140
|
+
var _planProgressiveExpansion = function planProgressiveExpansion(contextKey) {
|
|
1141
|
+
var _progressivePrefixesB;
|
|
1142
|
+
var request = progressiveRequests.get(contextKey);
|
|
1143
|
+
if (!request || destroyed || !boundaryCache.has(contextKey)) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
var eligible = request.candidates.filter(function (candidate) {
|
|
1147
|
+
return candidate.tokenIds.length > 0 && candidate.tokenIds.length <= CANONICAL_SCORING.EXACT_MAX_TARGET_TOKENS;
|
|
1148
|
+
}).map(function (candidate) {
|
|
1149
|
+
return _objectSpread(_objectSpread({}, candidate), {}, {
|
|
1150
|
+
evidence: getProgressiveEvidence(contextKey, candidate.surface, candidate.tokenIds)
|
|
1151
|
+
});
|
|
1152
|
+
}).filter(function (candidate) {
|
|
1153
|
+
return candidate.evidence !== null;
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
// Score candidates the way arbitration will: a posterior over sequence
|
|
1157
|
+
// log-likelihoods, blended with the corpus prior at the shipped weights.
|
|
1158
|
+
//
|
|
1159
|
+
// Sharing the rule is the point. Ranking on `exp(per-token mean)` instead
|
|
1160
|
+
// answers a different question — it favours short surfaces, because
|
|
1161
|
+
// dividing by fewer tokens flatters them — so this scheduler used to stop
|
|
1162
|
+
// reading on a margin the decision layer did not recognise, and then
|
|
1163
|
+
// abstain for want of the very tokens it declined to read. Nothing about
|
|
1164
|
+
// that was visible from either side.
|
|
1165
|
+
//
|
|
1166
|
+
// The normaliser spans every eligible candidate rather than only the
|
|
1167
|
+
// scheduled ones. That can only make each posterior smaller and each margin
|
|
1168
|
+
// narrower, so the error is always towards reading another token instead of
|
|
1169
|
+
// stopping early — the safe direction ahead of a precision-first gate.
|
|
1170
|
+
var normalizer = logSumExp(eligible.map(function (candidate) {
|
|
1171
|
+
return candidate.evidence.totalLogProbability;
|
|
1172
|
+
}));
|
|
1173
|
+
var confidenceScore = function confidenceScore(candidate) {
|
|
1174
|
+
var _candidate$rankHint;
|
|
1175
|
+
return STAGE1_WEIGHT * ((_candidate$rankHint = candidate.rankHint) !== null && _candidate$rankHint !== void 0 ? _candidate$rankHint : 0) + STAGE2_WEIGHT * (Number.isFinite(normalizer) ? Math.exp(candidate.evidence.totalLogProbability - normalizer) : 0);
|
|
1176
|
+
};
|
|
1177
|
+
var candidates = eligible.sort(function (a, b) {
|
|
1178
|
+
return confidenceScore(b) - confidenceScore(a);
|
|
1179
|
+
}).slice(0, CANONICAL_SCORING.PROGRESSIVE_CANDIDATES_MAX);
|
|
1180
|
+
var unresolved = candidates.filter(function (candidate) {
|
|
1181
|
+
return candidate.evidence.scoredTokenCount < candidate.tokenIds.length;
|
|
1182
|
+
});
|
|
1183
|
+
if (unresolved.length === 0) {
|
|
1184
|
+
logProgressiveState('completed', "ctx=".concat(contextKey.slice(0, 48), " \xB7 exact=").concat(candidates.length, "/").concat(candidates.length));
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
var bestExactScore = Math.max.apply(Math, _toConsumableArray(candidates.filter(function (candidate) {
|
|
1188
|
+
return candidate.evidence.scoredTokenCount === candidate.tokenIds.length;
|
|
1189
|
+
}).map(confidenceScore)).concat([-Infinity]));
|
|
1190
|
+
var bestUnresolvedScore = Math.max.apply(Math, _toConsumableArray(unresolved.map(confidenceScore)).concat([-Infinity]));
|
|
1191
|
+
if (bestExactScore - bestUnresolvedScore >= MIN_WINNER_MARGIN) {
|
|
1192
|
+
logProgressiveState('completed', "safe bound \xB7 ctx=".concat(contextKey.slice(0, 40), " \xB7 margin=").concat((bestExactScore - bestUnresolvedScore).toFixed(2), " \xB7 unresolved=").concat(unresolved.length));
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
var groups = surfaceTokenTrie.groupByScoredPrefix(unresolved.map(function (candidate) {
|
|
1196
|
+
return {
|
|
1197
|
+
surface: candidate.surface,
|
|
1198
|
+
tokenIds: candidate.tokenIds,
|
|
1199
|
+
scoredTokenCount: candidate.evidence.scoredTokenCount
|
|
1200
|
+
};
|
|
1201
|
+
}));
|
|
1202
|
+
var bySurface = new Map(candidates.map(function (candidate) {
|
|
1203
|
+
return [candidate.surface, candidate];
|
|
1204
|
+
}));
|
|
1205
|
+
var rankedGroups = groups.map(function (group) {
|
|
1206
|
+
var members = group.surfaces.map(function (candidateSurface) {
|
|
1207
|
+
return bySurface.get(candidateSurface);
|
|
1208
|
+
}).filter(function (candidate) {
|
|
1209
|
+
return Boolean(candidate);
|
|
1210
|
+
});
|
|
1211
|
+
var optimisticScore = Math.max.apply(Math, _toConsumableArray(members.map(confidenceScore)));
|
|
1212
|
+
return _objectSpread(_objectSpread({}, group), {}, {
|
|
1213
|
+
optimisticScore: optimisticScore
|
|
1214
|
+
});
|
|
1215
|
+
}).sort(function (a, b) {
|
|
1216
|
+
return b.optimisticScore - a.optimisticScore;
|
|
1217
|
+
});
|
|
1218
|
+
var bestGroup = rankedGroups[0];
|
|
1219
|
+
if (!bestGroup) {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
var warmGroup = kvContextKey === contextKey ? rankedGroups.find(function (group) {
|
|
1223
|
+
return isPrefixOf(kvPath, group.tokenPrefix);
|
|
1224
|
+
}) : undefined;
|
|
1225
|
+
var nextGroup = warmGroup && warmGroup.optimisticScore >= bestGroup.optimisticScore - PROGRESSIVE_WARM_PATH_MARGIN ? warmGroup : bestGroup;
|
|
1226
|
+
var contextPrefixes = (_progressivePrefixesB = progressivePrefixesByContext.get(contextKey)) !== null && _progressivePrefixesB !== void 0 ? _progressivePrefixesB : new Set();
|
|
1227
|
+
progressivePrefixesByContext.set(contextKey, contextPrefixes);
|
|
1228
|
+
var key = prefixCacheKey(contextKey, nextGroup.tokenPrefix);
|
|
1229
|
+
if (getLru(prefixExpansionCache, key)) {
|
|
1230
|
+
logProgressiveState('cached', "ctx=".concat(contextKey.slice(0, 40), " \xB7 prefix=[").concat(nextGroup.tokenPrefix.join(','), "]"));
|
|
1231
|
+
_planProgressiveExpansion(contextKey);
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
if (pendingPrefixExpansions.has(key) || inFlightPrefixExpansions.has(key)) {
|
|
1235
|
+
logProgressiveState('deduplicated', "ctx=".concat(contextKey.slice(0, 40), " \xB7 prefix=[").concat(nextGroup.tokenPrefix.join(','), "]"));
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
if (contextPrefixes.size >= CANONICAL_SCORING.PROGRESSIVE_EXPANSIONS_PER_CONTEXT_MAX) {
|
|
1239
|
+
logProgressiveState('completed', "ctx=".concat(contextKey.slice(0, 48), " \xB7 expansion cap=").concat(contextPrefixes.size, " \xB7 unresolved=").concat(unresolved.length));
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
contextPrefixes.add(key);
|
|
1243
|
+
pendingPrefixExpansions.set(key, {
|
|
1244
|
+
contextKey: contextKey,
|
|
1245
|
+
familyKey: request.familyKey,
|
|
1246
|
+
prompt: request.prompt,
|
|
1247
|
+
tokenPrefix: nextGroup.tokenPrefix,
|
|
1248
|
+
surfaces: nextGroup.surfaces
|
|
1249
|
+
});
|
|
1250
|
+
logProgressiveState('queued', "ctx=".concat(contextKey.slice(0, 40), " \xB7 prefix=[").concat(nextGroup.tokenPrefix.join(','), "] \xB7 surfaces=").concat(nextGroup.surfaces.length));
|
|
1251
|
+
_drainCausalQueue();
|
|
1252
|
+
};
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Prefill `prompt` and cache the boundary distribution that follows it.
|
|
1256
|
+
*
|
|
1257
|
+
* A text completion resets the KV cache before prefilling, so asking for a
|
|
1258
|
+
* single token leaves the cache holding exactly the prompt. That is the
|
|
1259
|
+
* anchor every later decode step extends.
|
|
1260
|
+
*/
|
|
1261
|
+
var prefillBoundary = /*#__PURE__*/function () {
|
|
1262
|
+
var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(activeEngine, request) {
|
|
1263
|
+
var _yield$createMeasured, latencyMs, rawLogits;
|
|
1264
|
+
return _regeneratorRuntime.wrap(function (_context6) {
|
|
1265
|
+
while (1) switch (_context6.prev = _context6.next) {
|
|
1266
|
+
case 0:
|
|
1267
|
+
kvContextKey = null;
|
|
1268
|
+
kvPath = [];
|
|
1269
|
+
causalRequestsThisFamily++;
|
|
1270
|
+
causalGeneratedTokensThisFamily++;
|
|
1271
|
+
causalLogitProcessor.startCapture();
|
|
1272
|
+
_context6.next = 1;
|
|
1273
|
+
return createMeasuredCausalCompletion(activeEngine, {
|
|
1274
|
+
contextKey: request.contextKey,
|
|
1275
|
+
familyKey: request.familyKey,
|
|
1276
|
+
kind: 'boundary',
|
|
1277
|
+
prompt: request.prompt,
|
|
1278
|
+
requestedCompletionTokens: 1
|
|
1279
|
+
});
|
|
1280
|
+
case 1:
|
|
1281
|
+
_yield$createMeasured = _context6.sent;
|
|
1282
|
+
latencyMs = _yield$createMeasured.latencyMs;
|
|
1283
|
+
rawLogits = captureLogits();
|
|
1284
|
+
if (rawLogits) {
|
|
1285
|
+
_context6.next = 2;
|
|
1286
|
+
break;
|
|
1287
|
+
}
|
|
1288
|
+
return _context6.abrupt("return", null);
|
|
1289
|
+
case 2:
|
|
1290
|
+
setLru(boundaryCache, request.contextKey, {
|
|
1291
|
+
contextKey: request.contextKey,
|
|
1292
|
+
prompt: request.prompt,
|
|
1293
|
+
rawLogits: rawLogits
|
|
1294
|
+
}, CANONICAL_SCORING.BOUNDARY_CACHE_MAX);
|
|
1295
|
+
kvContextKey = request.contextKey;
|
|
1296
|
+
kvPath = [];
|
|
1297
|
+
return _context6.abrupt("return", {
|
|
1298
|
+
latencyMs: latencyMs,
|
|
1299
|
+
rawLogits: rawLogits
|
|
1300
|
+
});
|
|
1301
|
+
case 3:
|
|
1302
|
+
case "end":
|
|
1303
|
+
return _context6.stop();
|
|
1304
|
+
}
|
|
1305
|
+
}, _callee6);
|
|
1306
|
+
}));
|
|
1307
|
+
return function prefillBoundary(_x5, _x6) {
|
|
1308
|
+
return _ref9.apply(this, arguments);
|
|
1309
|
+
};
|
|
1310
|
+
}();
|
|
1311
|
+
|
|
1312
|
+
/**
|
|
1313
|
+
* Append one token to the KV cache and return the distribution that follows.
|
|
1314
|
+
*
|
|
1315
|
+
* This deliberately bypasses the completion API: a completion would reset the
|
|
1316
|
+
* cache and re-prefill the whole prompt, whereas this forwards a single token
|
|
1317
|
+
* on top of the work already done.
|
|
1318
|
+
*/
|
|
1319
|
+
var decodeOneToken = /*#__PURE__*/function () {
|
|
1320
|
+
var _ref0 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(activeEngine, token) {
|
|
1321
|
+
var _t7;
|
|
1322
|
+
return _regeneratorRuntime.wrap(function (_context7) {
|
|
1323
|
+
while (1) switch (_context7.prev = _context7.next) {
|
|
1324
|
+
case 0:
|
|
1325
|
+
causalLogitProcessor.startCapture();
|
|
1326
|
+
_context7.prev = 1;
|
|
1327
|
+
_context7.next = 2;
|
|
1328
|
+
return activeEngine.forwardTokensAndSample([token], false, modelId);
|
|
1329
|
+
case 2:
|
|
1330
|
+
_context7.next = 4;
|
|
1331
|
+
break;
|
|
1332
|
+
case 3:
|
|
1333
|
+
_context7.prev = 3;
|
|
1334
|
+
_t7 = _context7["catch"](1);
|
|
1335
|
+
kvContextKey = null;
|
|
1336
|
+
kvPath = [];
|
|
1337
|
+
throw _t7;
|
|
1338
|
+
case 4:
|
|
1339
|
+
causalRequestsThisFamily++;
|
|
1340
|
+
causalGeneratedTokensThisFamily++;
|
|
1341
|
+
return _context7.abrupt("return", captureLogits());
|
|
1342
|
+
case 5:
|
|
1343
|
+
case "end":
|
|
1344
|
+
return _context7.stop();
|
|
1345
|
+
}
|
|
1346
|
+
}, _callee7, null, [[1, 3]]);
|
|
1347
|
+
}));
|
|
1348
|
+
return function decodeOneToken(_x7, _x8) {
|
|
1349
|
+
return _ref0.apply(this, arguments);
|
|
1350
|
+
};
|
|
1351
|
+
}();
|
|
1352
|
+
var runBoundaryPrime = /*#__PURE__*/function () {
|
|
1353
|
+
var _ref1 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8(request) {
|
|
1354
|
+
var _progressiveRequest$c, _progressiveRequest$f, _progressiveRequests$, _progressiveRequests$2;
|
|
1355
|
+
var primed, latencyMs, rawLogits, progressiveRequest, exactSurfaceCount, callbackFamilyKey;
|
|
1356
|
+
return _regeneratorRuntime.wrap(function (_context8) {
|
|
1357
|
+
while (1) switch (_context8.prev = _context8.next) {
|
|
1358
|
+
case 0:
|
|
1359
|
+
if (!(!engine || destroyed)) {
|
|
1360
|
+
_context8.next = 1;
|
|
1361
|
+
break;
|
|
1362
|
+
}
|
|
1363
|
+
return _context8.abrupt("return");
|
|
1364
|
+
case 1:
|
|
1365
|
+
_context8.next = 2;
|
|
1366
|
+
return prefillBoundary(engine, request);
|
|
1367
|
+
case 2:
|
|
1368
|
+
primed = _context8.sent;
|
|
1369
|
+
if (primed) {
|
|
1370
|
+
_context8.next = 3;
|
|
1371
|
+
break;
|
|
1372
|
+
}
|
|
1373
|
+
return _context8.abrupt("return");
|
|
1374
|
+
case 3:
|
|
1375
|
+
latencyMs = primed.latencyMs, rawLogits = primed.rawLogits;
|
|
1376
|
+
_planProgressiveExpansion(request.contextKey);
|
|
1377
|
+
progressiveRequest = progressiveRequests.get(request.contextKey);
|
|
1378
|
+
exactSurfaceCount = (_progressiveRequest$c = progressiveRequest === null || progressiveRequest === void 0 ? void 0 : progressiveRequest.candidates.filter(function (candidate) {
|
|
1379
|
+
var evidence = getProgressiveEvidence(request.contextKey, candidate.surface, candidate.tokenIds);
|
|
1380
|
+
return evidence !== null && evidence.scoredTokenCount === evidence.totalTokenCount;
|
|
1381
|
+
}).length) !== null && _progressiveRequest$c !== void 0 ? _progressiveRequest$c : 0;
|
|
1382
|
+
logExactEvidenceReadiness(request.contextKey, (_progressiveRequest$f = progressiveRequest === null || progressiveRequest === void 0 ? void 0 : progressiveRequest.familyKey) !== null && _progressiveRequest$f !== void 0 ? _progressiveRequest$f : request.familyKey, exactSurfaceCount, 'boundary');
|
|
1383
|
+
if (isAutocompleteDebugEnabled()) {
|
|
1384
|
+
// eslint-disable-next-line no-console
|
|
1385
|
+
console.log("%c[CTC:model] %c\uD83E\uDDE0 Tier A prime #".concat(request.priority + 1, " \xB7 ctx=").concat(request.contextKey.slice(0, 48), " \xB7 ").concat(rawLogits.length, " logits \xB7 ").concat(latencyMs.toFixed(0), "ms \xB7 family req:").concat(causalRequestsThisFamily, " tok:").concat(causalGeneratedTokensThisFamily, " A hit/miss:").concat(tierAPrimeCacheHitsThisFamily, "/").concat(tierAPrimeCacheMissesThisFamily), 'color: #9c27b0; font-weight: bold;', 'color: #2196f3;');
|
|
1386
|
+
}
|
|
1387
|
+
callbackFamilyKey = (_progressiveRequests$ = (_progressiveRequests$2 = progressiveRequests.get(request.contextKey)) === null || _progressiveRequests$2 === void 0 ? void 0 : _progressiveRequests$2.familyKey) !== null && _progressiveRequests$ !== void 0 ? _progressiveRequests$ : request.familyKey;
|
|
1388
|
+
if (callbackFamilyKey === latestCausalFamilyKey && !destroyed) {
|
|
1389
|
+
onBoundaryLmUpdate === null || onBoundaryLmUpdate === void 0 || onBoundaryLmUpdate({
|
|
1390
|
+
contextKey: request.contextKey,
|
|
1391
|
+
familyKey: callbackFamilyKey,
|
|
1392
|
+
latencyMs: latencyMs
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
case 4:
|
|
1396
|
+
case "end":
|
|
1397
|
+
return _context8.stop();
|
|
1398
|
+
}
|
|
1399
|
+
}, _callee8);
|
|
1400
|
+
}));
|
|
1401
|
+
return function runBoundaryPrime(_x9) {
|
|
1061
1402
|
return _ref1.apply(this, arguments);
|
|
1062
1403
|
};
|
|
1063
1404
|
}();
|
|
1405
|
+
var runPrefixExpansion = /*#__PURE__*/function () {
|
|
1406
|
+
var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9(request) {
|
|
1407
|
+
var _progressivePrefixesB2, _progressiveRequest$f2, _progressiveRequests$3, _progressiveRequests$4;
|
|
1408
|
+
var activeEngine, startedAt, logitsAtPath, totalAtPath, pathIsLive, _getLru$rawLogits, _getLru2, _resume$rawNextTokenL, _resume$totalLogProba, resume, primed, contextPrefixes, index, token, stepLogProbability, nextLogits, stepKey, expansion, latencyMs, progressiveRequest, newlyExact, exactSurfaceCount, _iterator, _step, candidate, exactKey, wasExact, evidence, callbackFamilyKey;
|
|
1409
|
+
return _regeneratorRuntime.wrap(function (_context9) {
|
|
1410
|
+
while (1) switch (_context9.prev = _context9.next) {
|
|
1411
|
+
case 0:
|
|
1412
|
+
if (!(!engine || destroyed)) {
|
|
1413
|
+
_context9.next = 1;
|
|
1414
|
+
break;
|
|
1415
|
+
}
|
|
1416
|
+
return _context9.abrupt("return");
|
|
1417
|
+
case 1:
|
|
1418
|
+
activeEngine = engine;
|
|
1419
|
+
startedAt = performance.now();
|
|
1420
|
+
logProgressiveState('started', "ctx=".concat(request.contextKey.slice(0, 40), " \xB7 prefix=[").concat(request.tokenPrefix.join(','), "] \xB7 surfaces=").concat(request.surfaces.length));
|
|
1421
|
+
|
|
1422
|
+
// Resume from whatever the KV cache already holds for this context, and
|
|
1423
|
+
// fall back to a prompt prefill only when the requested prefix branches
|
|
1424
|
+
// away from it.
|
|
1425
|
+
logitsAtPath = null;
|
|
1426
|
+
totalAtPath = 0;
|
|
1427
|
+
pathIsLive = extendsLiveKvPath(request);
|
|
1428
|
+
if (pathIsLive) {
|
|
1429
|
+
if (kvPath.length === 0) {
|
|
1430
|
+
logitsAtPath = (_getLru$rawLogits = (_getLru2 = getLru(boundaryCache, request.contextKey)) === null || _getLru2 === void 0 ? void 0 : _getLru2.rawLogits) !== null && _getLru$rawLogits !== void 0 ? _getLru$rawLogits : null;
|
|
1431
|
+
} else {
|
|
1432
|
+
resume = getLru(prefixExpansionCache, prefixCacheKey(request.contextKey, kvPath));
|
|
1433
|
+
logitsAtPath = (_resume$rawNextTokenL = resume === null || resume === void 0 ? void 0 : resume.rawNextTokenLogits) !== null && _resume$rawNextTokenL !== void 0 ? _resume$rawNextTokenL : null;
|
|
1434
|
+
totalAtPath = (_resume$totalLogProba = resume === null || resume === void 0 ? void 0 : resume.totalLogProbability) !== null && _resume$totalLogProba !== void 0 ? _resume$totalLogProba : 0;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
if (logitsAtPath) {
|
|
1438
|
+
_context9.next = 4;
|
|
1439
|
+
break;
|
|
1440
|
+
}
|
|
1441
|
+
_context9.next = 2;
|
|
1442
|
+
return prefillBoundary(activeEngine, request);
|
|
1443
|
+
case 2:
|
|
1444
|
+
primed = _context9.sent;
|
|
1445
|
+
if (primed) {
|
|
1446
|
+
_context9.next = 3;
|
|
1447
|
+
break;
|
|
1448
|
+
}
|
|
1449
|
+
logProgressiveState('failed', "ctx=".concat(request.contextKey.slice(0, 40), " \xB7 prefix=[").concat(request.tokenPrefix.join(','), "] \xB7 missing boundary logits"));
|
|
1450
|
+
return _context9.abrupt("return");
|
|
1451
|
+
case 3:
|
|
1452
|
+
logitsAtPath = primed.rawLogits;
|
|
1453
|
+
totalAtPath = 0;
|
|
1454
|
+
case 4:
|
|
1455
|
+
// Walking the path caches every depth along it, not just the requested
|
|
1456
|
+
// one, so a later expansion that shares this prefix costs nothing.
|
|
1457
|
+
contextPrefixes = (_progressivePrefixesB2 = progressivePrefixesByContext.get(request.contextKey)) !== null && _progressivePrefixesB2 !== void 0 ? _progressivePrefixesB2 : new Set();
|
|
1458
|
+
progressivePrefixesByContext.set(request.contextKey, contextPrefixes);
|
|
1459
|
+
index = kvPath.length;
|
|
1460
|
+
case 5:
|
|
1461
|
+
if (!(index < request.tokenPrefix.length)) {
|
|
1462
|
+
_context9.next = 11;
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
token = request.tokenPrefix[index];
|
|
1466
|
+
if (!(token === undefined)) {
|
|
1467
|
+
_context9.next = 6;
|
|
1468
|
+
break;
|
|
1469
|
+
}
|
|
1470
|
+
return _context9.abrupt("continue", 11);
|
|
1471
|
+
case 6:
|
|
1472
|
+
stepLogProbability = logSoftmaxAt(logitsAtPath, token);
|
|
1473
|
+
if (Number.isFinite(stepLogProbability)) {
|
|
1474
|
+
_context9.next = 7;
|
|
1475
|
+
break;
|
|
1476
|
+
}
|
|
1477
|
+
logProgressiveState('failed', "ctx=".concat(request.contextKey.slice(0, 40), " \xB7 prefix=[").concat(request.tokenPrefix.join(','), "] \xB7 token ").concat(token, " unscoreable"));
|
|
1478
|
+
return _context9.abrupt("return");
|
|
1479
|
+
case 7:
|
|
1480
|
+
_context9.next = 8;
|
|
1481
|
+
return decodeOneToken(activeEngine, token);
|
|
1482
|
+
case 8:
|
|
1483
|
+
nextLogits = _context9.sent;
|
|
1484
|
+
if (!(!nextLogits || destroyed)) {
|
|
1485
|
+
_context9.next = 9;
|
|
1486
|
+
break;
|
|
1487
|
+
}
|
|
1488
|
+
kvContextKey = null;
|
|
1489
|
+
kvPath = [];
|
|
1490
|
+
logProgressiveState('failed', "ctx=".concat(request.contextKey.slice(0, 40), " \xB7 prefix=[").concat(request.tokenPrefix.join(','), "] \xB7 missing logits"));
|
|
1491
|
+
return _context9.abrupt("return");
|
|
1492
|
+
case 9:
|
|
1493
|
+
kvContextKey = request.contextKey;
|
|
1494
|
+
kvPath = [].concat(_toConsumableArray(kvPath), [token]);
|
|
1495
|
+
totalAtPath += stepLogProbability;
|
|
1496
|
+
logitsAtPath = nextLogits;
|
|
1497
|
+
stepKey = prefixCacheKey(request.contextKey, kvPath);
|
|
1498
|
+
expansion = {
|
|
1499
|
+
contextKey: request.contextKey,
|
|
1500
|
+
tokenPrefix: _toConsumableArray(kvPath),
|
|
1501
|
+
totalLogProbability: totalAtPath,
|
|
1502
|
+
rawNextTokenLogits: nextLogits
|
|
1503
|
+
};
|
|
1504
|
+
setLru(prefixExpansionCache, stepKey, expansion, CANONICAL_SCORING.PREFIX_CACHE_MAX);
|
|
1505
|
+
contextPrefixes.add(stepKey);
|
|
1506
|
+
case 10:
|
|
1507
|
+
index++;
|
|
1508
|
+
_context9.next = 5;
|
|
1509
|
+
break;
|
|
1510
|
+
case 11:
|
|
1511
|
+
latencyMs = performance.now() - startedAt;
|
|
1512
|
+
progressiveRequest = progressiveRequests.get(request.contextKey);
|
|
1513
|
+
newlyExact = 0;
|
|
1514
|
+
exactSurfaceCount = 0;
|
|
1515
|
+
if (progressiveRequest) {
|
|
1516
|
+
_iterator = _createForOfIteratorHelper(progressiveRequest.candidates);
|
|
1517
|
+
try {
|
|
1518
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1519
|
+
candidate = _step.value;
|
|
1520
|
+
exactKey = surfaceCacheKey(request.contextKey, candidate.surface, candidate.tokenIds);
|
|
1521
|
+
wasExact = surfaceScoreCache.has(exactKey);
|
|
1522
|
+
evidence = getProgressiveEvidence(request.contextKey, candidate.surface, candidate.tokenIds);
|
|
1523
|
+
if (!wasExact && evidence !== null && evidence.scoredTokenCount === evidence.totalTokenCount && surfaceScoreCache.has(exactKey)) {
|
|
1524
|
+
newlyExact++;
|
|
1525
|
+
}
|
|
1526
|
+
if (evidence !== null && evidence.scoredTokenCount === evidence.totalTokenCount) {
|
|
1527
|
+
exactSurfaceCount++;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
} catch (err) {
|
|
1531
|
+
_iterator.e(err);
|
|
1532
|
+
} finally {
|
|
1533
|
+
_iterator.f();
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
logExactEvidenceReadiness(request.contextKey, (_progressiveRequest$f2 = progressiveRequest === null || progressiveRequest === void 0 ? void 0 : progressiveRequest.familyKey) !== null && _progressiveRequest$f2 !== void 0 ? _progressiveRequest$f2 : request.familyKey, exactSurfaceCount, 'prefix');
|
|
1537
|
+
logProgressiveState('expanded', "ctx=".concat(request.contextKey.slice(0, 40), " \xB7 prefix=[").concat(request.tokenPrefix.join(','), "] \xB7 exact+").concat(newlyExact, " \xB7 ").concat(latencyMs.toFixed(0), "ms"));
|
|
1538
|
+
_planProgressiveExpansion(request.contextKey);
|
|
1539
|
+
callbackFamilyKey = (_progressiveRequests$3 = (_progressiveRequests$4 = progressiveRequests.get(request.contextKey)) === null || _progressiveRequests$4 === void 0 ? void 0 : _progressiveRequests$4.familyKey) !== null && _progressiveRequests$3 !== void 0 ? _progressiveRequests$3 : request.familyKey;
|
|
1540
|
+
if (callbackFamilyKey === latestCausalFamilyKey && !destroyed) {
|
|
1541
|
+
onSurfaceScoreUpdate === null || onSurfaceScoreUpdate === void 0 || onSurfaceScoreUpdate({
|
|
1542
|
+
contextKey: request.contextKey,
|
|
1543
|
+
count: newlyExact,
|
|
1544
|
+
familyKey: callbackFamilyKey,
|
|
1545
|
+
latencyMs: latencyMs
|
|
1546
|
+
});
|
|
1547
|
+
} else {
|
|
1548
|
+
logProgressiveState('stale', "cached only \xB7 ctx=".concat(request.contextKey.slice(0, 40), " \xB7 family=").concat(request.familyKey.slice(0, 32)));
|
|
1549
|
+
}
|
|
1550
|
+
case 12:
|
|
1551
|
+
case "end":
|
|
1552
|
+
return _context9.stop();
|
|
1553
|
+
}
|
|
1554
|
+
}, _callee9);
|
|
1555
|
+
}));
|
|
1556
|
+
return function runPrefixExpansion(_x0) {
|
|
1557
|
+
return _ref10.apply(this, arguments);
|
|
1558
|
+
};
|
|
1559
|
+
}();
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* Whether any live decision would still take this request's result.
|
|
1563
|
+
*
|
|
1564
|
+
* Ranking on the family a request was created under, as this used to, misses
|
|
1565
|
+
* in both directions. Work queued a keystroke ago for a context still under
|
|
1566
|
+
* the cursor sorts as stale even though the callbacks resolve delivery
|
|
1567
|
+
* through `progressiveRequests` and would hand it over. Work for a context
|
|
1568
|
+
* nothing asks about any more sorts as runnable even though the same
|
|
1569
|
+
* resolution drops it on arrival — and that one is expensive, because an
|
|
1570
|
+
* abandoned context is never the one the KV cache holds, so running it pays
|
|
1571
|
+
* a prompt prefill and leaves the live context evicted, charging the next
|
|
1572
|
+
* live request a second prefill. Two prefills for a discarded result.
|
|
1573
|
+
*
|
|
1574
|
+
* Either signal alone is enough to keep the work, which matters because a
|
|
1575
|
+
* boundary prime is queued before its context's surfaces are requested: at
|
|
1576
|
+
* that moment the stored family is still the previous decision's, and only
|
|
1577
|
+
* the request's own family says it is current.
|
|
1578
|
+
*
|
|
1579
|
+
* Agreeing with the layer being fed is the correction the expansion planner
|
|
1580
|
+
* already carries for arbitration's scoring rule — a scheduler deciding on
|
|
1581
|
+
* its own rule stops on margins the consumer does not recognise.
|
|
1582
|
+
*/
|
|
1583
|
+
var stillWanted = function stillWanted(request) {
|
|
1584
|
+
var _progressiveRequests$5;
|
|
1585
|
+
return request.familyKey === latestCausalFamilyKey || ((_progressiveRequests$5 = progressiveRequests.get(request.contextKey)) === null || _progressiveRequests$5 === void 0 ? void 0 : _progressiveRequests$5.familyKey) === latestCausalFamilyKey;
|
|
1586
|
+
};
|
|
1587
|
+
var _drainCausalQueue = function drainCausalQueue() {
|
|
1588
|
+
if (causalInFlight || destroyed) {
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
// Drop abandoned work rather than leaving it to be picked up whenever the
|
|
1592
|
+
// live family happens to have nothing queued. Its cached side effects are
|
|
1593
|
+
// speculative — they only pay off if the user deletes back into exactly
|
|
1594
|
+
// this context and prefix — and the prefill pair above is certain.
|
|
1595
|
+
var _iterator2 = _createForOfIteratorHelper(pendingPrefixExpansions),
|
|
1596
|
+
_step2;
|
|
1597
|
+
try {
|
|
1598
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
1599
|
+
var _step2$value = _slicedToArray(_step2.value, 2),
|
|
1600
|
+
key = _step2$value[0],
|
|
1601
|
+
request = _step2$value[1];
|
|
1602
|
+
if (!stillWanted(request)) {
|
|
1603
|
+
pendingPrefixExpansions.delete(key);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
} catch (err) {
|
|
1607
|
+
_iterator2.e(err);
|
|
1608
|
+
} finally {
|
|
1609
|
+
_iterator2.f();
|
|
1610
|
+
}
|
|
1611
|
+
var _iterator3 = _createForOfIteratorHelper(pendingBoundaryPrimes),
|
|
1612
|
+
_step3;
|
|
1613
|
+
try {
|
|
1614
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
1615
|
+
var _step3$value = _slicedToArray(_step3.value, 2),
|
|
1616
|
+
contextKey = _step3$value[0],
|
|
1617
|
+
_request = _step3$value[1];
|
|
1618
|
+
if (!stillWanted(_request)) {
|
|
1619
|
+
pendingBoundaryPrimes.delete(contextKey);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
} catch (err) {
|
|
1623
|
+
_iterator3.e(err);
|
|
1624
|
+
} finally {
|
|
1625
|
+
_iterator3.f();
|
|
1626
|
+
}
|
|
1627
|
+
var sortedPrimes = Array.from(pendingBoundaryPrimes.values()).sort(function (a, b) {
|
|
1628
|
+
return a.priority - b.priority;
|
|
1629
|
+
});
|
|
1630
|
+
// Everything left is wanted, so relevance no longer needs a sort key.
|
|
1631
|
+
// Take whichever request continues the live sequence: that expansion costs
|
|
1632
|
+
// one decode step where any other costs a full prompt prefill, and nothing
|
|
1633
|
+
// is skipped, only reordered.
|
|
1634
|
+
//
|
|
1635
|
+
// Staying inside the live context when nothing continues it was tried and
|
|
1636
|
+
// reverted. It moved re-primes from `reprime-context` to `reprime-branch`
|
|
1637
|
+
// and left the total flat, because both pay for a prompt prefill: a
|
|
1638
|
+
// context whose remaining prefixes diverge at the first token re-primes as
|
|
1639
|
+
// a branch instead of as a context. Ordering cannot recover that; only
|
|
1640
|
+
// queueing fewer divergent branches can, which is what the prune above
|
|
1641
|
+
// does.
|
|
1642
|
+
var sortedPrefixes = Array.from(pendingPrefixExpansions.values()).sort(function (a, b) {
|
|
1643
|
+
return Number(extendsLiveKvPath(b)) - Number(extendsLiveKvPath(a));
|
|
1644
|
+
});
|
|
1645
|
+
var nextPrefix = sortedPrefixes[0];
|
|
1646
|
+
var nextPrime = nextPrefix ? undefined : sortedPrimes[0];
|
|
1647
|
+
if (!nextPrefix && !nextPrime) {
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
causalInFlight = true;
|
|
1651
|
+
var prefixKey = null;
|
|
1652
|
+
if (nextPrefix) {
|
|
1653
|
+
prefixKey = prefixCacheKey(nextPrefix.contextKey, nextPrefix.tokenPrefix);
|
|
1654
|
+
pendingPrefixExpansions.delete(prefixKey);
|
|
1655
|
+
inFlightPrefixExpansions.add(prefixKey);
|
|
1656
|
+
} else if (nextPrime) {
|
|
1657
|
+
pendingBoundaryPrimes.delete(nextPrime.contextKey);
|
|
1658
|
+
inFlightBoundaryContextKey = nextPrime.contextKey;
|
|
1659
|
+
}
|
|
1660
|
+
void ensureEngineInitialized().then(function () {
|
|
1661
|
+
return nextPrefix ? runPrefixExpansion(nextPrefix) : nextPrime ? runBoundaryPrime(nextPrime) : undefined;
|
|
1662
|
+
}).catch(function (error) {
|
|
1663
|
+
if (nextPrefix) {
|
|
1664
|
+
logProgressiveState('failed', "ctx=".concat(nextPrefix.contextKey.slice(0, 40), " \xB7 prefix=[").concat(nextPrefix.tokenPrefix.join(','), "] \xB7 ").concat(error instanceof Error ? error.message : String(error)));
|
|
1665
|
+
}
|
|
1666
|
+
if (isAutocompleteDebugEnabled()) {
|
|
1667
|
+
// eslint-disable-next-line no-console
|
|
1668
|
+
console.log("%c[CTC:model] %c\u274C canonical causal request failed: ".concat(error instanceof Error ? error.message : String(error)), 'color: #9c27b0; font-weight: bold;', 'color: #f44336;');
|
|
1669
|
+
}
|
|
1670
|
+
}).finally(function () {
|
|
1671
|
+
if (prefixKey) {
|
|
1672
|
+
inFlightPrefixExpansions.delete(prefixKey);
|
|
1673
|
+
}
|
|
1674
|
+
if (nextPrime) {
|
|
1675
|
+
inFlightBoundaryContextKey = null;
|
|
1676
|
+
}
|
|
1677
|
+
causalInFlight = false;
|
|
1678
|
+
_drainCausalQueue();
|
|
1679
|
+
});
|
|
1680
|
+
};
|
|
1064
1681
|
|
|
1065
1682
|
// ── Context update (debounced) ─────────────────────────────────────────
|
|
1066
1683
|
|
|
@@ -1110,7 +1727,7 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
1110
1727
|
latestRequestId = requestId;
|
|
1111
1728
|
if (isAutocompleteDebugEnabled()) {
|
|
1112
1729
|
// eslint-disable-next-line no-console
|
|
1113
|
-
console.groupCollapsed("%c[
|
|
1730
|
+
console.groupCollapsed("%c[CTC:model] %c\uD83D\uDCE4 Context update (request #".concat(requestId, ") | ").concat(text.length, " chars"), 'color: #9c27b0; font-weight: bold;', 'color: inherit;');
|
|
1114
1731
|
var lines = text.split('\n');
|
|
1115
1732
|
lines.forEach(function (line, i) {
|
|
1116
1733
|
// eslint-disable-next-line no-console
|
|
@@ -1146,22 +1763,136 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
1146
1763
|
doUpdateContext(lastRequestedText);
|
|
1147
1764
|
}, debounceMs);
|
|
1148
1765
|
};
|
|
1766
|
+
var setLatestCausalFamily = function setLatestCausalFamily(familyKey) {
|
|
1767
|
+
if (familyKey === latestCausalFamilyKey) {
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
latestCausalFamilyKey = familyKey;
|
|
1771
|
+
causalRequestsThisFamily = 0;
|
|
1772
|
+
causalGeneratedTokensThisFamily = 0;
|
|
1773
|
+
tierAPrimeCacheHitsThisFamily = 0;
|
|
1774
|
+
tierAPrimeCacheMissesThisFamily = 0;
|
|
1775
|
+
};
|
|
1776
|
+
var primeBoundaryLm = function primeBoundaryLm(input) {
|
|
1777
|
+
if (destroyed) {
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
setLatestCausalFamily(input.familyKey);
|
|
1781
|
+
if (getLru(boundaryCache, input.contextKey)) {
|
|
1782
|
+
tierAPrimeCacheHitsThisFamily++;
|
|
1783
|
+
if (isAutocompleteDebugVerbose()) {
|
|
1784
|
+
// eslint-disable-next-line no-console
|
|
1785
|
+
console.log("%c[CTC:model] %c\u26A1 Tier A cache hit \xB7 ctx=".concat(input.contextKey.slice(0, 48)), 'color: #9c27b0; font-weight: bold;', 'color: #2196f3;');
|
|
1786
|
+
}
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1789
|
+
if (pendingBoundaryPrimes.has(input.contextKey) || inFlightBoundaryContextKey === input.contextKey) {
|
|
1790
|
+
logProgressiveState('deduplicated', "boundary \xB7 ctx=".concat(input.contextKey.slice(0, 48)));
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
if (pendingBoundaryPrimes.size >= CANONICAL_SCORING.TIER_A_PRIMES_MAX) {
|
|
1794
|
+
var stalePending = Array.from(pendingBoundaryPrimes.entries()).find(function (_ref11) {
|
|
1795
|
+
var _ref12 = _slicedToArray(_ref11, 2),
|
|
1796
|
+
request = _ref12[1];
|
|
1797
|
+
return request.familyKey !== latestCausalFamilyKey;
|
|
1798
|
+
});
|
|
1799
|
+
if (stalePending) {
|
|
1800
|
+
pendingBoundaryPrimes.delete(stalePending[0]);
|
|
1801
|
+
logProgressiveState('stale', "dropped unstarted boundary \xB7 ctx=".concat(stalePending[0].slice(0, 48)));
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
if (pendingBoundaryPrimes.size < CANONICAL_SCORING.TIER_A_PRIMES_MAX) {
|
|
1805
|
+
tierAPrimeCacheMissesThisFamily++;
|
|
1806
|
+
pendingBoundaryPrimes.set(input.contextKey, input);
|
|
1807
|
+
}
|
|
1808
|
+
_drainCausalQueue();
|
|
1809
|
+
};
|
|
1810
|
+
var requestProgressiveSurfaceScores = function requestProgressiveSurfaceScores(input) {
|
|
1811
|
+
if (destroyed) {
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
setLatestCausalFamily(input.familyKey);
|
|
1815
|
+
var candidates = input.candidates.filter(function (candidate) {
|
|
1816
|
+
return candidate.tokenIds.length > 0 && candidate.tokenIds.length <= CANONICAL_SCORING.EXACT_MAX_TARGET_TOKENS;
|
|
1817
|
+
}).slice(0, CANONICAL_SCORING.PROGRESSIVE_INPUT_MAX);
|
|
1818
|
+
if (candidates.length === 0) {
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
var previous = progressiveRequests.get(input.contextKey);
|
|
1822
|
+
var candidateSignature = candidates.map(function (candidate) {
|
|
1823
|
+
return "".concat(candidate.surface, ":").concat(candidate.tokenIds.join(','));
|
|
1824
|
+
}).join("\x01");
|
|
1825
|
+
var previousSignature = previous === null || previous === void 0 ? void 0 : previous.candidates.map(function (candidate) {
|
|
1826
|
+
return "".concat(candidate.surface, ":").concat(candidate.tokenIds.join(','));
|
|
1827
|
+
}).join("\x01");
|
|
1828
|
+
setLru(progressiveRequests, input.contextKey, _objectSpread(_objectSpread({}, input), {}, {
|
|
1829
|
+
candidates: candidates
|
|
1830
|
+
}), CANONICAL_SCORING.BOUNDARY_CACHE_MAX);
|
|
1831
|
+
var _iterator4 = _createForOfIteratorHelper(progressivePrefixesByContext.keys()),
|
|
1832
|
+
_step4;
|
|
1833
|
+
try {
|
|
1834
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
1835
|
+
var cachedContextKey = _step4.value;
|
|
1836
|
+
if (!progressiveRequests.has(cachedContextKey)) {
|
|
1837
|
+
progressivePrefixesByContext.delete(cachedContextKey);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
} catch (err) {
|
|
1841
|
+
_iterator4.e(err);
|
|
1842
|
+
} finally {
|
|
1843
|
+
_iterator4.f();
|
|
1844
|
+
}
|
|
1845
|
+
var cachedProgressCount = candidates.filter(function (candidate) {
|
|
1846
|
+
var evidence = getProgressiveEvidence(input.contextKey, candidate.surface, candidate.tokenIds);
|
|
1847
|
+
return evidence !== null && (evidence.scoredTokenCount > 1 || evidence.scoredTokenCount === evidence.totalTokenCount);
|
|
1848
|
+
}).length;
|
|
1849
|
+
if (cachedProgressCount > 0) {
|
|
1850
|
+
logProgressiveState('cached', "ctx=".concat(input.contextKey.slice(0, 40), " \xB7 surfaces=").concat(cachedProgressCount, "/").concat(candidates.length));
|
|
1851
|
+
}
|
|
1852
|
+
if (candidateSignature === previousSignature) {
|
|
1853
|
+
logProgressiveState('deduplicated', "candidate set \xB7 ctx=".concat(input.contextKey.slice(0, 40), " \xB7 surfaces=").concat(candidates.length));
|
|
1854
|
+
} else {
|
|
1855
|
+
logProgressiveState('queued', "candidate set \xB7 ctx=".concat(input.contextKey.slice(0, 40), " \xB7 surfaces=").concat(candidates.length));
|
|
1856
|
+
}
|
|
1857
|
+
_planProgressiveExpansion(input.contextKey);
|
|
1858
|
+
};
|
|
1149
1859
|
|
|
1150
1860
|
// ── Public API (same shape as createSlowLaneClient) ────────────────────
|
|
1151
1861
|
return {
|
|
1152
1862
|
updateContext: updateContextDebounced,
|
|
1863
|
+
getBoundaryLmState: function getBoundaryLmState(contextKey) {
|
|
1864
|
+
return getLru(boundaryCache, contextKey);
|
|
1865
|
+
},
|
|
1866
|
+
getCanonicalSurfaceTokenIds: function getCanonicalSurfaceTokenIds(candidateSurface) {
|
|
1867
|
+
return surfaceTokenTrie.getTokenIds(candidateSurface);
|
|
1868
|
+
},
|
|
1869
|
+
getCanonicalSurfaceCount: function getCanonicalSurfaceCount() {
|
|
1870
|
+
return surfaceTokenIds.size;
|
|
1871
|
+
},
|
|
1872
|
+
getContextInput: function getContextInput() {
|
|
1873
|
+
return storedContextInput;
|
|
1874
|
+
},
|
|
1153
1875
|
getContextVector: function getContextVector() {
|
|
1154
1876
|
return storedContextVector;
|
|
1155
1877
|
},
|
|
1156
1878
|
getLmLogits: function getLmLogits() {
|
|
1157
1879
|
return storedLmLogits;
|
|
1158
1880
|
},
|
|
1881
|
+
getProgressiveSurfaceEvidence: function getProgressiveSurfaceEvidence(contextKey, candidateSurface) {
|
|
1882
|
+
return getProgressiveEvidence(contextKey, candidateSurface);
|
|
1883
|
+
},
|
|
1884
|
+
getSurfaceScore: function getSurfaceScore(contextKey, candidateSurface) {
|
|
1885
|
+
return getLru(surfaceScoreCache, surfaceCacheKey(contextKey, candidateSurface));
|
|
1886
|
+
},
|
|
1159
1887
|
setContextVector: function setContextVector(vector) {
|
|
1888
|
+
storedContextInput = null;
|
|
1160
1889
|
storedContextVector = vector;
|
|
1161
1890
|
},
|
|
1162
1891
|
setLmLogits: function setLmLogits(logits) {
|
|
1163
1892
|
storedLmLogits = logits;
|
|
1164
1893
|
},
|
|
1894
|
+
primeBoundaryLm: primeBoundaryLm,
|
|
1895
|
+
requestProgressiveSurfaceScores: requestProgressiveSurfaceScores,
|
|
1165
1896
|
isWordBoundary: isWordBoundary,
|
|
1166
1897
|
isReady: function isReady() {
|
|
1167
1898
|
return ready;
|
|
@@ -1182,8 +1913,26 @@ export var createLocalSlowLaneClient = function createLocalSlowLaneClient() {
|
|
|
1182
1913
|
activeInferenceText = null;
|
|
1183
1914
|
activeInferenceRequestId = -1;
|
|
1184
1915
|
pendingInference = null;
|
|
1916
|
+
storedContextInput = null;
|
|
1185
1917
|
storedContextVector = null;
|
|
1186
1918
|
storedLmLogits = null;
|
|
1919
|
+
causalInFlight = false;
|
|
1920
|
+
inFlightBoundaryContextKey = null;
|
|
1921
|
+
kvContextKey = null;
|
|
1922
|
+
kvPath = [];
|
|
1923
|
+
latestCausalFamilyKey = '';
|
|
1924
|
+
pendingBoundaryPrimes.clear();
|
|
1925
|
+
pendingPrefixExpansions.clear();
|
|
1926
|
+
inFlightPrefixExpansions.clear();
|
|
1927
|
+
progressiveRequests.clear();
|
|
1928
|
+
progressivePrefixesByContext.clear();
|
|
1929
|
+
boundaryCache.clear();
|
|
1930
|
+
causalInferenceByContext.clear();
|
|
1931
|
+
causalInferenceByFamily.clear();
|
|
1932
|
+
exactEvidenceCountByContext.clear();
|
|
1933
|
+
prefixExpansionCache.clear();
|
|
1934
|
+
surfaceScoreCache.clear();
|
|
1935
|
+
causalLogitProcessor.resetState();
|
|
1187
1936
|
}
|
|
1188
1937
|
};
|
|
1189
1938
|
};
|