pi-ghost-autocomplete 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +561 -0
  2. package/README.md +186 -4
  3. package/dist/bench-cli.js +1 -123
  4. package/dist/bench.d.ts +7 -3
  5. package/dist/bench.js +1 -522
  6. package/dist/config.d.ts +46 -3
  7. package/dist/context-aggregator.d.ts +4 -1
  8. package/dist/cycle-manager.d.ts +2 -21
  9. package/dist/entropy-stop.d.ts +4 -1
  10. package/dist/eval-dataset.d.ts +2 -13
  11. package/dist/fuzzy-matcher.d.ts +4 -1
  12. package/dist/ghost-editor.d.ts +11 -2
  13. package/dist/index.d.ts +7 -2
  14. package/dist/index.js +1 -289
  15. package/dist/intent.d.ts +179 -0
  16. package/dist/metrics.d.ts +4 -1
  17. package/dist/path-index.d.ts +4 -1
  18. package/dist/path-matcher.d.ts +4 -1
  19. package/dist/profile-store.d.ts +4 -1
  20. package/dist/profile.d.ts +2 -20
  21. package/dist/providers/cloud-provider.d.ts +4 -1
  22. package/dist/providers/local-provider.d.ts +4 -1
  23. package/dist/providers/openai-compat-chat-provider.d.ts +31 -0
  24. package/dist/providers/openai-compat-provider.d.ts +24 -1
  25. package/dist/providers/race.d.ts +4 -1
  26. package/dist/providers/router.d.ts +59 -0
  27. package/dist/providers/types.d.ts +13 -1
  28. package/dist/recent-paths.d.ts +4 -1
  29. package/dist/replay-cli.js +1 -166
  30. package/dist/replay.d.ts +2 -7
  31. package/package.json +10 -6
  32. package/dist/bench-cli.d.ts +0 -3
  33. package/dist/bench-cli.d.ts.map +0 -1
  34. package/dist/bench-cli.js.map +0 -1
  35. package/dist/bench.d.ts.map +0 -1
  36. package/dist/bench.js.map +0 -1
  37. package/dist/cache.d.ts +0 -124
  38. package/dist/cache.d.ts.map +0 -1
  39. package/dist/cache.js +0 -173
  40. package/dist/cache.js.map +0 -1
  41. package/dist/candidate-rerank.d.ts +0 -57
  42. package/dist/candidate-rerank.d.ts.map +0 -1
  43. package/dist/candidate-rerank.js +0 -78
  44. package/dist/candidate-rerank.js.map +0 -1
  45. package/dist/config.d.ts.map +0 -1
  46. package/dist/config.js +0 -317
  47. package/dist/config.js.map +0 -1
  48. package/dist/context-aggregator.d.ts.map +0 -1
  49. package/dist/context-aggregator.js +0 -87
  50. package/dist/context-aggregator.js.map +0 -1
  51. package/dist/context-selector.d.ts +0 -128
  52. package/dist/context-selector.d.ts.map +0 -1
  53. package/dist/context-selector.js +0 -300
  54. package/dist/context-selector.js.map +0 -1
  55. package/dist/cycle-manager.d.ts.map +0 -1
  56. package/dist/cycle-manager.js +0 -168
  57. package/dist/cycle-manager.js.map +0 -1
  58. package/dist/edit-history-ring.d.ts +0 -148
  59. package/dist/edit-history-ring.d.ts.map +0 -1
  60. package/dist/edit-history-ring.js +0 -262
  61. package/dist/edit-history-ring.js.map +0 -1
  62. package/dist/entropy-stop.d.ts.map +0 -1
  63. package/dist/entropy-stop.js +0 -141
  64. package/dist/entropy-stop.js.map +0 -1
  65. package/dist/eval-dataset.d.ts.map +0 -1
  66. package/dist/eval-dataset.js +0 -127
  67. package/dist/eval-dataset.js.map +0 -1
  68. package/dist/fast-path-engine.d.ts +0 -286
  69. package/dist/fast-path-engine.d.ts.map +0 -1
  70. package/dist/fast-path-engine.js +0 -341
  71. package/dist/fast-path-engine.js.map +0 -1
  72. package/dist/fuzzy-matcher.d.ts.map +0 -1
  73. package/dist/fuzzy-matcher.js +0 -162
  74. package/dist/fuzzy-matcher.js.map +0 -1
  75. package/dist/ghost-editor.d.ts.map +0 -1
  76. package/dist/ghost-editor.js +0 -1491
  77. package/dist/ghost-editor.js.map +0 -1
  78. package/dist/index.d.ts.map +0 -1
  79. package/dist/index.js.map +0 -1
  80. package/dist/keystroke-timer.d.ts +0 -59
  81. package/dist/keystroke-timer.d.ts.map +0 -1
  82. package/dist/keystroke-timer.js +0 -94
  83. package/dist/keystroke-timer.js.map +0 -1
  84. package/dist/metrics-builder.d.ts +0 -71
  85. package/dist/metrics-builder.d.ts.map +0 -1
  86. package/dist/metrics-builder.js +0 -71
  87. package/dist/metrics-builder.js.map +0 -1
  88. package/dist/metrics.d.ts.map +0 -1
  89. package/dist/metrics.js +0 -212
  90. package/dist/metrics.js.map +0 -1
  91. package/dist/path-index.d.ts.map +0 -1
  92. package/dist/path-index.js +0 -148
  93. package/dist/path-index.js.map +0 -1
  94. package/dist/path-matcher.d.ts.map +0 -1
  95. package/dist/path-matcher.js +0 -88
  96. package/dist/path-matcher.js.map +0 -1
  97. package/dist/profile-store.d.ts.map +0 -1
  98. package/dist/profile-store.js +0 -199
  99. package/dist/profile-store.js.map +0 -1
  100. package/dist/profile.d.ts.map +0 -1
  101. package/dist/profile.js +0 -434
  102. package/dist/profile.js.map +0 -1
  103. package/dist/providers/cloud-provider.d.ts.map +0 -1
  104. package/dist/providers/cloud-provider.js +0 -109
  105. package/dist/providers/cloud-provider.js.map +0 -1
  106. package/dist/providers/local-provider.d.ts.map +0 -1
  107. package/dist/providers/local-provider.js +0 -48
  108. package/dist/providers/local-provider.js.map +0 -1
  109. package/dist/providers/openai-compat-provider.d.ts.map +0 -1
  110. package/dist/providers/openai-compat-provider.js +0 -215
  111. package/dist/providers/openai-compat-provider.js.map +0 -1
  112. package/dist/providers/openai-completions-runner.d.ts +0 -52
  113. package/dist/providers/openai-completions-runner.d.ts.map +0 -1
  114. package/dist/providers/openai-completions-runner.js +0 -141
  115. package/dist/providers/openai-completions-runner.js.map +0 -1
  116. package/dist/providers/race.d.ts.map +0 -1
  117. package/dist/providers/race.js +0 -441
  118. package/dist/providers/race.js.map +0 -1
  119. package/dist/providers/truncate.d.ts +0 -7
  120. package/dist/providers/truncate.d.ts.map +0 -1
  121. package/dist/providers/truncate.js +0 -57
  122. package/dist/providers/truncate.js.map +0 -1
  123. package/dist/providers/types.d.ts.map +0 -1
  124. package/dist/providers/types.js +0 -60
  125. package/dist/providers/types.js.map +0 -1
  126. package/dist/provisional-manager.d.ts +0 -93
  127. package/dist/provisional-manager.d.ts.map +0 -1
  128. package/dist/provisional-manager.js +0 -98
  129. package/dist/provisional-manager.js.map +0 -1
  130. package/dist/provisional.d.ts +0 -150
  131. package/dist/provisional.d.ts.map +0 -1
  132. package/dist/provisional.js +0 -238
  133. package/dist/provisional.js.map +0 -1
  134. package/dist/recent-paths.d.ts.map +0 -1
  135. package/dist/recent-paths.js +0 -114
  136. package/dist/recent-paths.js.map +0 -1
  137. package/dist/regret-tracker.d.ts +0 -84
  138. package/dist/regret-tracker.d.ts.map +0 -1
  139. package/dist/regret-tracker.js +0 -145
  140. package/dist/regret-tracker.js.map +0 -1
  141. package/dist/replay-cli.d.ts +0 -13
  142. package/dist/replay-cli.d.ts.map +0 -1
  143. package/dist/replay-cli.js.map +0 -1
  144. package/dist/replay.d.ts.map +0 -1
  145. package/dist/replay.js +0 -225
  146. package/dist/replay.js.map +0 -1
  147. package/dist/reranker.d.ts +0 -181
  148. package/dist/reranker.d.ts.map +0 -1
  149. package/dist/reranker.js +0 -324
  150. package/dist/reranker.js.map +0 -1
  151. package/dist/session-trie.d.ts +0 -103
  152. package/dist/session-trie.d.ts.map +0 -1
  153. package/dist/session-trie.js +0 -280
  154. package/dist/session-trie.js.map +0 -1
  155. package/dist/speculative.d.ts +0 -74
  156. package/dist/speculative.d.ts.map +0 -1
  157. package/dist/speculative.js +0 -107
  158. package/dist/speculative.js.map +0 -1
  159. package/dist/tool-summarize.d.ts +0 -40
  160. package/dist/tool-summarize.d.ts.map +0 -1
  161. package/dist/tool-summarize.js +0 -245
  162. package/dist/tool-summarize.js.map +0 -1
  163. package/dist/trie-sanitize.d.ts +0 -22
  164. package/dist/trie-sanitize.d.ts.map +0 -1
  165. package/dist/trie-sanitize.js +0 -142
  166. package/dist/trie-sanitize.js.map +0 -1
  167. package/dist/versions.d.ts +0 -23
  168. package/dist/versions.d.ts.map +0 -1
  169. package/dist/versions.js +0 -31
  170. package/dist/versions.js.map +0 -1
@@ -1,181 +0,0 @@
1
- /**
2
- * Multi-source candidate reranker. See PRD §M3c.
3
- *
4
- * Pure function (`candidates, opts → ranked[]`). No I/O, no provider calls,
5
- * no editor state — easy to unit-test without mocks.
6
- *
7
- * Pipeline:
8
- * 1. Merge candidates by exact text (collapsing race-member duplicates,
9
- * taking the max logprob across sources and accumulating the source set).
10
- * 2. Score each merged candidate as a weighted sum of normalized features:
11
- * logprob, profile-bias (M4 hook), length-prior, agreement bonus.
12
- * 3. Tie-break (within 1e-6) on length-around-median, local-over-cloud,
13
- * lexicographic.
14
- *
15
- * Missing logprobs (Mercury FIM today) map to the neutral mid-value 0.5
16
- * after normalization so a single-provider Mercury candidate isn't
17
- * penalized against a multi-provider race that returns logprobs.
18
- */
19
- import type { GhostCandidate } from "./providers/types.js";
20
- export declare const TIE_EPSILON = 0.000001;
21
- export declare const LENGTH_PRIOR_LOW = 5;
22
- export declare const LENGTH_PRIOR_HIGH = 30;
23
- export declare const LENGTH_PRIOR_ZERO_AT = 80;
24
- /**
25
- * Prefix-length threshold above which the lengthPrior plateau and decay
26
- * tail scale up. Empirically (ChaI-TeA + Copilot data): the longer the
27
- * typed prefix, the longer the completion the user actually wants. Below
28
- * this threshold the curve matches the original (prefix-blind) behavior.
29
- */
30
- export declare const PREFIX_LENGTH_SCALE_THRESHOLD = 30;
31
- export declare const FALLBACK_MEDIAN_LENGTH = 15;
32
- export declare const MISSING_LOGPROB_NEUTRAL = 0.5;
33
- export interface RerankWeights {
34
- logprob: number;
35
- profileBias: number;
36
- lengthPrior: number;
37
- agreement: number;
38
- /**
39
- * Enhancement #1: weight on the edit-history proximity feature. Default
40
- * 0.10. Set to 0 to disable. Trimmed from `logprob` (0.05) and
41
- * `agreement` (0.05) so the weight sum remains 1.0.
42
- */
43
- editProximity: number;
44
- }
45
- export declare const DEFAULT_WEIGHTS: RerankWeights;
46
- export interface RerankerInput extends GhostCandidate {
47
- /** Producing provider name. Multiple sources collapse on merge. */
48
- provider: string;
49
- /** True when `provider` is a `local` kind (Ollama / vLLM). */
50
- local?: boolean;
51
- }
52
- export interface RerankerOpts {
53
- weights?: RerankWeights;
54
- /**
55
- * Number of race members that participated. Used to normalize the
56
- * agreement bonus: `(sources - 1) / (raceMembers - 1)`. Default 1.
57
- */
58
- raceMembers?: number;
59
- /**
60
- * Optional profile-bias scorer (M4 hook). Receives raw candidate text,
61
- * returns a non-negative score. Missing → all candidates score 0.
62
- */
63
- profileBias?: (text: string) => number;
64
- /**
65
- * Enhancement #1: edit-history proximity scorer. Receives raw candidate
66
- * text; returns a real number (negative permitted — candidates that
67
- * resurrect recently-deleted tokens score below neutral). Missing →
68
- * all candidates score 0.
69
- */
70
- editProximityScorer?: (text: string) => number;
71
- /** Median length of historically-accepted ghosts. Default 15. */
72
- medianAcceptedLength?: number;
73
- /**
74
- * Length of the typed prefix at the cursor (active line). When supplied
75
- * the lengthPrior curve scales above `PREFIX_LENGTH_SCALE_THRESHOLD` so
76
- * long-prefix queries are not penalized for long completions
77
- * (empirical finding from ChaI-TeA / Copilot data).
78
- */
79
- prefixLen?: number;
80
- }
81
- export interface RerankedCandidate {
82
- text: string;
83
- score: number;
84
- avgLogprob?: number;
85
- sources: string[];
86
- /** Internal — exposed for diagnostics + tie-break tests. */
87
- scoreBreakdown: {
88
- logprob: number;
89
- profileBias: number;
90
- lengthPrior: number;
91
- agreement: number;
92
- editProximity: number;
93
- };
94
- }
95
- export interface MergedCandidate {
96
- text: string;
97
- avgLogprob?: number;
98
- sources: Set<string>;
99
- anyLocal: boolean;
100
- }
101
- /**
102
- * Merge candidates by exact text, accumulating sources and taking the max
103
- * logprob across providers (agreement = positive evidence).
104
- */
105
- export declare function mergeCandidates(cands: RerankerInput[]): MergedCandidate[];
106
- /**
107
- * Length prior for a candidate of `len` characters. `prefixLen` adjusts the
108
- * plateau and decay bounds: completions get scored against a curve scaled to
109
- * the typed prefix length, so long prefixes don't penalize long completions.
110
- *
111
- * When `prefixLen <= PREFIX_LENGTH_SCALE_THRESHOLD` (or omitted), the curve
112
- * matches the original prefix-blind behavior: plateau over
113
- * `[LENGTH_PRIOR_LOW, LENGTH_PRIOR_HIGH]`, linear ramp below LOW, linear
114
- * decay between HIGH and `LENGTH_PRIOR_ZERO_AT`, and zero above ZERO_AT.
115
- *
116
- * When `prefixLen > PREFIX_LENGTH_SCALE_THRESHOLD`, the upper plateau (HIGH)
117
- * and the zero-crossing (ZERO_AT) both scale by `prefixLen / THRESHOLD`:
118
- * - prefixLen = 30: scale = 1.0 → HIGH=30, ZERO_AT=80 (unchanged)
119
- * - prefixLen = 60: scale = 2.0 → HIGH=60, ZERO_AT=160
120
- * - prefixLen = 120: scale = 4.0 → HIGH=120, ZERO_AT=320
121
- * LOW stays fixed — even very long prefixes still penalize trivially-short
122
- * (1–4 char) completions, matching empirical user behavior.
123
- */
124
- export declare function lengthPrior(len: number, prefixLen?: number): number;
125
- /**
126
- * Compute the prefix-length-aware HIGH and ZERO_AT bounds. Exposed for
127
- * diagnostics + tests so the scaling logic can be verified directly.
128
- */
129
- export declare function lengthPriorBounds(prefixLen: number): {
130
- high: number;
131
- zeroAt: number;
132
- };
133
- export declare function rerank(cands: RerankerInput[], opts?: RerankerOpts): RerankedCandidate[];
134
- /** Default confidence gate threshold (PRD §M3c.1). Set to 0 to disable. */
135
- export declare const DEFAULT_MIN_CONFIDENCE = 0.55;
136
- /** Default top-vs-second margin gate (PRD §M3c.1). */
137
- export declare const DEFAULT_DISAGREEMENT_MARGIN = 0.05;
138
- export interface ConfidenceGateOpts {
139
- /** Suppress the ghost when the top score is below this. Range [0, 1]. */
140
- minConfidence?: number;
141
- /** Suppress when top - 2nd margin is below this. */
142
- minMargin?: number;
143
- }
144
- /**
145
- * After rerank, decide whether to show the top candidate at all. Returns the
146
- * top candidate when both gates pass, else `null` (caller should fall back to
147
- * cache miss / no ghost). PRD §M3c.1.
148
- *
149
- * Both gates apply only to the top vs. second-best. With a single candidate,
150
- * the margin gate trivially passes (no rival to disagree with) and only
151
- * `minConfidence` matters.
152
- *
153
- * Score range: with default weights summing to 1.0 (PRD §M3c) and each
154
- * feature normalized to [0, 1], the weighted sum lands in [0, 1] too —
155
- * `minConfidence=0.55` and `minMargin=0.05` are calibrated against that
156
- * range. User-supplied weights via `PI_GHOST_RERANK_WEIGHTS` that don't
157
- * sum to 1.0 shift the effective score range; adjust gates accordingly
158
- * or set them to 0 to disable.
159
- *
160
- * PRD §M3c.1 lists a third gate ("`avgLogprob` exists and falls below a
161
- * calibrated provider-specific threshold"). It depends on accept-rate
162
- * buckets from M5/M5c replay — deferred until that data is in hand.
163
- * Setting `minConfidence=0` disables both implemented gates.
164
- */
165
- export declare function applyConfidenceGate(ranked: RerankedCandidate[], opts?: ConfidenceGateOpts): RerankedCandidate | null;
166
- /**
167
- * Parse `PI_GHOST_MIN_CONFIDENCE`. Returns fallback when unset, non-finite,
168
- * or outside [0, 1].
169
- */
170
- export declare function parseMinConfidenceEnv(raw: string | undefined): number;
171
- /**
172
- * Parse `PI_GHOST_RERANK_WEIGHTS=a,b,c,d[,e]` into a `RerankWeights`.
173
- * Accepts 4 or 5 comma-separated weights:
174
- * - 4 values: `logprob,profileBias,lengthPrior,agreement` (legacy form;
175
- * `editProximity` defaults to 0 to preserve pre-#1 behavior).
176
- * - 5 values: same plus `editProximity` (Enhancement #1).
177
- * Falls back to defaults on parse error or invalid count. Negative weights
178
- * are clamped to 0 ("ignore this signal").
179
- */
180
- export declare function parseWeightsEnv(raw: string | undefined): RerankWeights;
181
- //# sourceMappingURL=reranker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"reranker.d.ts","sourceRoot":"","sources":["../src/reranker.ts"],"names":[],"mappings":"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"}
package/dist/reranker.js DELETED
@@ -1,324 +0,0 @@
1
- /**
2
- * Multi-source candidate reranker. See PRD §M3c.
3
- *
4
- * Pure function (`candidates, opts → ranked[]`). No I/O, no provider calls,
5
- * no editor state — easy to unit-test without mocks.
6
- *
7
- * Pipeline:
8
- * 1. Merge candidates by exact text (collapsing race-member duplicates,
9
- * taking the max logprob across sources and accumulating the source set).
10
- * 2. Score each merged candidate as a weighted sum of normalized features:
11
- * logprob, profile-bias (M4 hook), length-prior, agreement bonus.
12
- * 3. Tie-break (within 1e-6) on length-around-median, local-over-cloud,
13
- * lexicographic.
14
- *
15
- * Missing logprobs (Mercury FIM today) map to the neutral mid-value 0.5
16
- * after normalization so a single-provider Mercury candidate isn't
17
- * penalized against a multi-provider race that returns logprobs.
18
- */
19
- export const TIE_EPSILON = 1e-6;
20
- export const LENGTH_PRIOR_LOW = 5;
21
- export const LENGTH_PRIOR_HIGH = 30;
22
- export const LENGTH_PRIOR_ZERO_AT = 80;
23
- /**
24
- * Prefix-length threshold above which the lengthPrior plateau and decay
25
- * tail scale up. Empirically (ChaI-TeA + Copilot data): the longer the
26
- * typed prefix, the longer the completion the user actually wants. Below
27
- * this threshold the curve matches the original (prefix-blind) behavior.
28
- */
29
- export const PREFIX_LENGTH_SCALE_THRESHOLD = 30;
30
- export const FALLBACK_MEDIAN_LENGTH = 15;
31
- export const MISSING_LOGPROB_NEUTRAL = 0.5;
32
- export const DEFAULT_WEIGHTS = {
33
- logprob: 0.40,
34
- profileBias: 0.25,
35
- lengthPrior: 0.15,
36
- agreement: 0.10,
37
- editProximity: 0.10,
38
- };
39
- /**
40
- * Merge candidates by exact text, accumulating sources and taking the max
41
- * logprob across providers (agreement = positive evidence).
42
- */
43
- export function mergeCandidates(cands) {
44
- const map = new Map();
45
- for (const c of cands) {
46
- const existing = map.get(c.text);
47
- if (existing) {
48
- existing.sources.add(c.provider);
49
- if (c.local)
50
- existing.anyLocal = true;
51
- if (c.avgLogprob !== undefined) {
52
- if (existing.avgLogprob === undefined || c.avgLogprob > existing.avgLogprob) {
53
- existing.avgLogprob = c.avgLogprob;
54
- }
55
- }
56
- }
57
- else {
58
- map.set(c.text, {
59
- text: c.text,
60
- avgLogprob: c.avgLogprob,
61
- sources: new Set([c.provider]),
62
- anyLocal: !!c.local,
63
- });
64
- }
65
- }
66
- return [...map.values()];
67
- }
68
- /**
69
- * Length prior for a candidate of `len` characters. `prefixLen` adjusts the
70
- * plateau and decay bounds: completions get scored against a curve scaled to
71
- * the typed prefix length, so long prefixes don't penalize long completions.
72
- *
73
- * When `prefixLen <= PREFIX_LENGTH_SCALE_THRESHOLD` (or omitted), the curve
74
- * matches the original prefix-blind behavior: plateau over
75
- * `[LENGTH_PRIOR_LOW, LENGTH_PRIOR_HIGH]`, linear ramp below LOW, linear
76
- * decay between HIGH and `LENGTH_PRIOR_ZERO_AT`, and zero above ZERO_AT.
77
- *
78
- * When `prefixLen > PREFIX_LENGTH_SCALE_THRESHOLD`, the upper plateau (HIGH)
79
- * and the zero-crossing (ZERO_AT) both scale by `prefixLen / THRESHOLD`:
80
- * - prefixLen = 30: scale = 1.0 → HIGH=30, ZERO_AT=80 (unchanged)
81
- * - prefixLen = 60: scale = 2.0 → HIGH=60, ZERO_AT=160
82
- * - prefixLen = 120: scale = 4.0 → HIGH=120, ZERO_AT=320
83
- * LOW stays fixed — even very long prefixes still penalize trivially-short
84
- * (1–4 char) completions, matching empirical user behavior.
85
- */
86
- export function lengthPrior(len, prefixLen = 0) {
87
- const bounds = lengthPriorBounds(prefixLen);
88
- if (len <= 0 || len >= bounds.zeroAt)
89
- return 0;
90
- if (len >= LENGTH_PRIOR_LOW && len <= bounds.high)
91
- return 1;
92
- if (len < LENGTH_PRIOR_LOW)
93
- return len / LENGTH_PRIOR_LOW;
94
- // len between HIGH and ZERO_AT — linear decay
95
- return (bounds.zeroAt - len) / (bounds.zeroAt - bounds.high);
96
- }
97
- /**
98
- * Compute the prefix-length-aware HIGH and ZERO_AT bounds. Exposed for
99
- * diagnostics + tests so the scaling logic can be verified directly.
100
- */
101
- export function lengthPriorBounds(prefixLen) {
102
- if (!Number.isFinite(prefixLen) || prefixLen <= PREFIX_LENGTH_SCALE_THRESHOLD) {
103
- return { high: LENGTH_PRIOR_HIGH, zeroAt: LENGTH_PRIOR_ZERO_AT };
104
- }
105
- const scale = prefixLen / PREFIX_LENGTH_SCALE_THRESHOLD;
106
- return {
107
- high: LENGTH_PRIOR_HIGH * scale,
108
- zeroAt: LENGTH_PRIOR_ZERO_AT * scale,
109
- };
110
- }
111
- /**
112
- * Min-max normalize `xs` into [0, 1]. If the spread is below `TIE_EPSILON`,
113
- * every entry maps to 0.5 (neutral); this matches the spec's "missing
114
- * logprob → 0.5" rule when applied to a uniform-logprob set.
115
- */
116
- function minMaxNormalize(xs) {
117
- if (xs.length === 0)
118
- return [];
119
- let min = Infinity;
120
- let max = -Infinity;
121
- for (const x of xs) {
122
- if (x < min)
123
- min = x;
124
- if (x > max)
125
- max = x;
126
- }
127
- const spread = max - min;
128
- if (spread < TIE_EPSILON)
129
- return xs.map(() => 0.5);
130
- return xs.map((x) => (x - min) / spread);
131
- }
132
- export function rerank(cands, opts = {}) {
133
- const w = opts.weights ?? DEFAULT_WEIGHTS;
134
- const raceMembers = Math.max(1, opts.raceMembers ?? 1);
135
- const profileBias = opts.profileBias ?? (() => 0);
136
- // Track whether an editProximityScorer was supplied. Without one, the
137
- // feature contributes nothing (raw zeros → uniform 0.5 after min-max
138
- // would dilute all other signals by `w.editProximity` × 0.5). We
139
- // short-circuit that by zeroing the editProximity term in the score
140
- // sum when no signal is present.
141
- const editProximityScorer = opts.editProximityScorer;
142
- const median = opts.medianAcceptedLength ?? FALLBACK_MEDIAN_LENGTH;
143
- const merged = mergeCandidates(cands);
144
- if (merged.length === 0)
145
- return [];
146
- // Raw feature extraction.
147
- const logprobs = merged.map((m) => m.avgLogprob === undefined ? Number.NaN : m.avgLogprob);
148
- const profile = merged.map((m) => profileBias(m.text));
149
- const editProx = editProximityScorer
150
- ? merged.map((m) => editProximityScorer(m.text))
151
- : merged.map(() => 0);
152
- // `hasEditSignal` is true only when at least two raw values differ
153
- // (so min-max norm produces useful ordering, not the uniform-0.5
154
- // fallback). Single-candidate runs also count as no signal.
155
- const editProxMin = editProx.length > 0 ? Math.min(...editProx) : 0;
156
- const editProxMax = editProx.length > 0 ? Math.max(...editProx) : 0;
157
- const hasEditSignal = editProxMax - editProxMin > TIE_EPSILON;
158
- const prefixLen = opts.prefixLen ?? 0;
159
- const lengths = merged.map((m) => lengthPrior(m.text.length, prefixLen));
160
- const agreement = merged.map((m) => raceMembers > 1 ? (m.sources.size - 1) / (raceMembers - 1) : 0);
161
- // Normalize each feature axis independently. For logprob, NaN slots get
162
- // replaced with the neutral mid-value 0.5 after normalization.
163
- const logprobsClean = logprobs.filter((x) => !Number.isNaN(x));
164
- const normLp = logprobsClean.length > 0 ? minMaxNormalize(logprobsClean) : [];
165
- let lpIdx = 0;
166
- const logprobNorm = logprobs.map((x) => Number.isNaN(x) ? MISSING_LOGPROB_NEUTRAL : normLp[lpIdx++]);
167
- const profileNorm = minMaxNormalize(profile);
168
- const editProxNorm = minMaxNormalize(editProx);
169
- const lengthNorm = minMaxNormalize(lengths);
170
- // Agreement is already in [0, 1] — no normalization (PRD §M3c step 2).
171
- const scored = merged.map((m, i) => {
172
- const lp = logprobNorm[i];
173
- const pb = profileNorm[i];
174
- const lpr = lengthNorm[i];
175
- const agr = agreement[i];
176
- const ep = editProxNorm[i];
177
- // `editProximity` may be undefined if the caller built RerankWeights
178
- // via JSON / pre-#1 fixtures. Treat as 0 to preserve legacy behavior.
179
- // When `hasEditSignal` is false (no scorer, or scorer produces a flat
180
- // vector), min-max normalize would map every entry to the neutral
181
- // 0.5, contributing a constant `w.editProximity * 0.5` to every
182
- // score. Two harms: (1) dilutes effective contrast of all other
183
- // signals; (2) shifts the score range below the calibrated
184
- // `applyConfidenceGate` threshold. Fix: when dormant, zero this term
185
- // AND scale the four other-feature weights up so the active weights
186
- // sum back to the original total (preserves score range + threshold
187
- // calibration).
188
- //
189
- // Caveat: the renormalization only restores the [0, 1] range when
190
- // the other four weights summed to exactly `1 - editProximity`
191
- // before scaling. Default `DEFAULT_WEIGHTS` and the parsed-env
192
- // shapes satisfy this; arbitrary externally-supplied weights with
193
- // a non-unit total may still shift the score range.
194
- const wEp = w.editProximity ?? 0;
195
- const inactive = !hasEditSignal && wEp > 0;
196
- const scale = inactive ? 1 / Math.max(TIE_EPSILON, 1 - wEp) : 1;
197
- const score = inactive
198
- ? (w.logprob * lp + w.profileBias * pb + w.lengthPrior * lpr + w.agreement * agr) * scale
199
- : w.logprob * lp + w.profileBias * pb + w.lengthPrior * lpr + w.agreement * agr + wEp * ep;
200
- return {
201
- text: m.text,
202
- score,
203
- avgLogprob: m.avgLogprob,
204
- sources: [...m.sources].sort(),
205
- scoreBreakdown: {
206
- logprob: lp,
207
- profileBias: pb,
208
- lengthPrior: lpr,
209
- agreement: agr,
210
- editProximity: ep,
211
- },
212
- };
213
- });
214
- // Sort with tie-break chain.
215
- scored.sort((a, b) => {
216
- const ds = b.score - a.score;
217
- if (Math.abs(ds) > TIE_EPSILON)
218
- return ds;
219
- // 1. Length closest to median.
220
- const da = Math.abs(a.text.length - median);
221
- const db = Math.abs(b.text.length - median);
222
- if (da !== db)
223
- return da - db;
224
- // 2. Local provider preferred.
225
- const aLocal = mergedHasLocal(merged, a.text);
226
- const bLocal = mergedHasLocal(merged, b.text);
227
- if (aLocal !== bLocal)
228
- return aLocal ? -1 : 1;
229
- // 3. Byte-compare (NOT localeCompare) for cross-machine determinism.
230
- // localeCompare varies by locale and could change cycling order
231
- // between Windows/Linux users on the same input.
232
- if (a.text < b.text)
233
- return -1;
234
- if (a.text > b.text)
235
- return 1;
236
- return 0;
237
- });
238
- return scored;
239
- }
240
- function mergedHasLocal(merged, text) {
241
- for (const m of merged)
242
- if (m.text === text)
243
- return m.anyLocal;
244
- return false;
245
- }
246
- /** Default confidence gate threshold (PRD §M3c.1). Set to 0 to disable. */
247
- export const DEFAULT_MIN_CONFIDENCE = 0.55;
248
- /** Default top-vs-second margin gate (PRD §M3c.1). */
249
- export const DEFAULT_DISAGREEMENT_MARGIN = 0.05;
250
- /**
251
- * After rerank, decide whether to show the top candidate at all. Returns the
252
- * top candidate when both gates pass, else `null` (caller should fall back to
253
- * cache miss / no ghost). PRD §M3c.1.
254
- *
255
- * Both gates apply only to the top vs. second-best. With a single candidate,
256
- * the margin gate trivially passes (no rival to disagree with) and only
257
- * `minConfidence` matters.
258
- *
259
- * Score range: with default weights summing to 1.0 (PRD §M3c) and each
260
- * feature normalized to [0, 1], the weighted sum lands in [0, 1] too —
261
- * `minConfidence=0.55` and `minMargin=0.05` are calibrated against that
262
- * range. User-supplied weights via `PI_GHOST_RERANK_WEIGHTS` that don't
263
- * sum to 1.0 shift the effective score range; adjust gates accordingly
264
- * or set them to 0 to disable.
265
- *
266
- * PRD §M3c.1 lists a third gate ("`avgLogprob` exists and falls below a
267
- * calibrated provider-specific threshold"). It depends on accept-rate
268
- * buckets from M5/M5c replay — deferred until that data is in hand.
269
- * Setting `minConfidence=0` disables both implemented gates.
270
- */
271
- export function applyConfidenceGate(ranked, opts = {}) {
272
- if (ranked.length === 0)
273
- return null;
274
- const minConfidence = opts.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
275
- const minMargin = opts.minMargin ?? DEFAULT_DISAGREEMENT_MARGIN;
276
- const top = ranked[0];
277
- if (top.score < minConfidence)
278
- return null;
279
- if (ranked.length >= 2) {
280
- const second = ranked[1];
281
- if (top.score - second.score < minMargin)
282
- return null;
283
- }
284
- return top;
285
- }
286
- /**
287
- * Parse `PI_GHOST_MIN_CONFIDENCE`. Returns fallback when unset, non-finite,
288
- * or outside [0, 1].
289
- */
290
- export function parseMinConfidenceEnv(raw) {
291
- if (raw === undefined)
292
- return DEFAULT_MIN_CONFIDENCE;
293
- const v = Number(raw);
294
- if (!Number.isFinite(v) || v < 0 || v > 1)
295
- return DEFAULT_MIN_CONFIDENCE;
296
- return v;
297
- }
298
- /**
299
- * Parse `PI_GHOST_RERANK_WEIGHTS=a,b,c,d[,e]` into a `RerankWeights`.
300
- * Accepts 4 or 5 comma-separated weights:
301
- * - 4 values: `logprob,profileBias,lengthPrior,agreement` (legacy form;
302
- * `editProximity` defaults to 0 to preserve pre-#1 behavior).
303
- * - 5 values: same plus `editProximity` (Enhancement #1).
304
- * Falls back to defaults on parse error or invalid count. Negative weights
305
- * are clamped to 0 ("ignore this signal").
306
- */
307
- export function parseWeightsEnv(raw) {
308
- if (!raw)
309
- return DEFAULT_WEIGHTS;
310
- const parts = raw.split(",").map((s) => Number(s.trim()));
311
- if ((parts.length !== 4 && parts.length !== 5) || parts.some((n) => !Number.isFinite(n))) {
312
- return DEFAULT_WEIGHTS;
313
- }
314
- const clamped = parts.map((n) => Math.max(0, n));
315
- const [logprob, profileBias, lengthPrior, agreement, editProximity = 0] = clamped;
316
- return {
317
- logprob: logprob,
318
- profileBias: profileBias,
319
- lengthPrior: lengthPrior,
320
- agreement: agreement,
321
- editProximity,
322
- };
323
- }
324
- //# sourceMappingURL=reranker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"reranker.js","sourceRoot":"","sources":["../src/reranker.ts"],"names":[],"mappings":"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"}
@@ -1,103 +0,0 @@
1
- /**
2
- * Session trie — fast-path completion source backed by the user's own past
3
- * accepts and committed messages. See PRD §M2.
4
- *
5
- * Structurally this is `Map<prefix, Map<suffix, weight>>` rather than a true
6
- * trie. At the PRD's 5000-entry cap, hash-lookup-by-exact-prefix is faster
7
- * than walking a character trie, and the simpler shape is easier to reason
8
- * about for decay and eviction.
9
- *
10
- * Insertion sources and weights (PRD §M2 "Insertion signals"):
11
- * - full accept: +3
12
- * - partial accept: +2 on the partial word, +1 on the full candidate
13
- * - committed user message: +1, prefix length 3..12 chars, suffix capped at
14
- * 4 word-boundary shingles
15
- * - divergent dismiss: -0.5 (caller decides what counts as divergent;
16
- * per-keystroke dismisses must NOT call here, per PRD)
17
- *
18
- * Lookup gates (PRD §M2 "Lookup"):
19
- * - prefix length ≥ 3
20
- * - winner weight ≥ 1.5
21
- * - winner margin over runner-up ≥ 1.0
22
- */
23
- export declare const MIN_PREFIX_LEN = 3;
24
- export declare const MIN_WEIGHT = 1.5;
25
- export declare const MIN_MARGIN = 1;
26
- export declare const DEFAULT_CAPACITY = 5000;
27
- export declare const DEFAULT_DECAY_EVERY = 200;
28
- export declare const DEFAULT_DECAY_FACTOR = 0.5;
29
- export declare const MAX_COMMITTED_PREFIX_LEN = 12;
30
- export declare const MAX_COMMITTED_SUFFIX_WORDS = 4;
31
- export interface TrieMatch {
32
- ghost: string;
33
- weight: number;
34
- margin: number;
35
- }
36
- export interface TrieStats {
37
- prefixes: number;
38
- candidates: number;
39
- insertsSinceDecay: number;
40
- }
41
- export declare class SessionTrie {
42
- private readonly capacity;
43
- private readonly decayEvery;
44
- private readonly decayFactor;
45
- /**
46
- * `Map` insertion order is the LRU stamp — we re-insert a prefix key after
47
- * touching it. Beyond capacity, the oldest key (first in iteration order)
48
- * is evicted.
49
- */
50
- private readonly map;
51
- private insertsSinceDecay;
52
- constructor(capacity?: number, decayEvery?: number, decayFactor?: number);
53
- get size(): number;
54
- get stats(): TrieStats;
55
- insert(prefix: string, suffix: string, weight: number): void;
56
- /**
57
- * Insert prefix→remainder pairs from an accepted ghost: prefix is the
58
- * editor text immediately before the ghost; the full accepted suffix is
59
- * the value. Weight is the caller's choice (+3 full, +2 partial-word, +1
60
- * full-candidate-on-partial). Caller handles signal selection.
61
- */
62
- insertFromAccept(prefix: string, suffix: string, weight: number): void;
63
- /**
64
- * Insert sliding-window prefix→remainder pairs from a committed user
65
- * message at weight +1 each (PRD §M2). Prefix lengths 3..12 chars,
66
- * remainder capped at 4 word-boundary shingles to limit memory and avoid
67
- * memorizing entire messages.
68
- *
69
- * Skips the whole message if any token matches a sensitive pattern.
70
- */
71
- insertFromCommittedMessage(text: string, weightPerShingle?: number): void;
72
- /**
73
- * Penalize an entry that diverged from the user's eventual commit.
74
- * Per-keystroke dismisses must NOT call this (would penalize correct
75
- * ghosts mid-typing). See PRD §M2.
76
- */
77
- penalize(prefix: string, suffix: string, magnitude?: number): void;
78
- lookup(prefix: string): TrieMatch | null;
79
- clear(): void;
80
- /**
81
- * Halve all weights. Exposed for testing; callers normally rely on the
82
- * automatic decay every `decayEvery` inserts.
83
- */
84
- decayNow(): void;
85
- private bumpCandidate;
86
- private tickDecayCounter;
87
- private enforceCapacity;
88
- }
89
- /**
90
- * Return the end-of-word offsets in `text` (exclusive). For "ab cd ef", returns
91
- * [2, 5, 8]. Used to align committed-message shingles to word boundaries.
92
- */
93
- /**
94
- * Pure helper used by `GhostEditor.onPromptCommitted`. Seeds `trie` from the
95
- * committed text. If `accepted` is non-null AND the committed text contains
96
- * the accepted ghost, the per-shingle weight drops from +1 to +0.25 to avoid
97
- * double-counting (PRD §M2 "Insertion signals").
98
- */
99
- export declare function seedTrieFromCommit(trie: SessionTrie, text: string, accepted: {
100
- prefix: string;
101
- ghost: string;
102
- } | null): void;
103
- //# sourceMappingURL=session-trie.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-trie.d.ts","sourceRoot":"","sources":["../src/session-trie.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,eAAO,MAAM,UAAU,MAAM,CAAC;AAC9B,eAAO,MAAM,UAAU,IAAM,CAAC;AAC9B,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,MAAM,WAAW,SAAS;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,WAAW;IAUtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAX7B;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0C;IAC9D,OAAO,CAAC,iBAAiB,CAAK;gBAGZ,QAAQ,GAAE,MAAyB,EACnC,UAAU,GAAE,MAA4B,EACxC,WAAW,GAAE,MAA6B;IAO5D,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,KAAK,IAAI,SAAS,CAQrB;IAED,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAQ5D;;;;;OAKG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAItE;;;;;;;OAOG;IACH,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,SAAI,GAAG,IAAI;IAyBpE;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,IAAI;IAe/D,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IA8CxC,KAAK,IAAI,IAAI;IAKb;;;OAGG;IACH,QAAQ,IAAI,IAAI;IAehB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,eAAe;CAOvB;AAED;;;GAGG;AACH;;;;;GAKG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAChD,IAAI,CAIN"}