pi-ghost-autocomplete 0.3.1 → 0.3.2
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/README.md +101 -6
- package/dist/bench-cli.js +81 -5
- package/dist/bench-cli.js.map +1 -1
- package/dist/bench.d.ts +130 -2
- package/dist/bench.d.ts.map +1 -1
- package/dist/bench.js +285 -4
- package/dist/bench.js.map +1 -1
- package/dist/cache.d.ts +124 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +173 -0
- package/dist/cache.js.map +1 -0
- package/dist/candidate-rerank.d.ts +57 -0
- package/dist/candidate-rerank.d.ts.map +1 -0
- package/dist/candidate-rerank.js +78 -0
- package/dist/candidate-rerank.js.map +1 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +148 -18
- package/dist/config.js.map +1 -1
- package/dist/context-aggregator.d.ts +14 -5
- package/dist/context-aggregator.d.ts.map +1 -1
- package/dist/context-aggregator.js +38 -9
- package/dist/context-aggregator.js.map +1 -1
- package/dist/context-selector.d.ts +128 -0
- package/dist/context-selector.d.ts.map +1 -0
- package/dist/context-selector.js +300 -0
- package/dist/context-selector.js.map +1 -0
- package/dist/cycle-manager.d.ts +102 -0
- package/dist/cycle-manager.d.ts.map +1 -0
- package/dist/cycle-manager.js +168 -0
- package/dist/cycle-manager.js.map +1 -0
- package/dist/edit-history-ring.d.ts +148 -0
- package/dist/edit-history-ring.d.ts.map +1 -0
- package/dist/edit-history-ring.js +262 -0
- package/dist/edit-history-ring.js.map +1 -0
- package/dist/entropy-stop.d.ts +102 -0
- package/dist/entropy-stop.d.ts.map +1 -0
- package/dist/entropy-stop.js +141 -0
- package/dist/entropy-stop.js.map +1 -0
- package/dist/eval-dataset.d.ts +66 -0
- package/dist/eval-dataset.d.ts.map +1 -0
- package/dist/eval-dataset.js +127 -0
- package/dist/eval-dataset.js.map +1 -0
- package/dist/fast-path-engine.d.ts +286 -0
- package/dist/fast-path-engine.d.ts.map +1 -0
- package/dist/fast-path-engine.js +341 -0
- package/dist/fast-path-engine.js.map +1 -0
- package/dist/fuzzy-matcher.d.ts +8 -0
- package/dist/fuzzy-matcher.d.ts.map +1 -1
- package/dist/fuzzy-matcher.js +5 -3
- package/dist/fuzzy-matcher.js.map +1 -1
- package/dist/ghost-editor.d.ts +321 -4
- package/dist/ghost-editor.d.ts.map +1 -1
- package/dist/ghost-editor.js +1190 -144
- package/dist/ghost-editor.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +81 -2
- package/dist/index.js.map +1 -1
- package/dist/keystroke-timer.d.ts +59 -0
- package/dist/keystroke-timer.d.ts.map +1 -0
- package/dist/keystroke-timer.js +94 -0
- package/dist/keystroke-timer.js.map +1 -0
- package/dist/metrics-builder.d.ts +71 -0
- package/dist/metrics-builder.d.ts.map +1 -0
- package/dist/metrics-builder.js +71 -0
- package/dist/metrics-builder.js.map +1 -0
- package/dist/metrics.d.ts +99 -2
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +131 -17
- package/dist/metrics.js.map +1 -1
- package/dist/path-matcher.d.ts +9 -0
- package/dist/path-matcher.d.ts.map +1 -1
- package/dist/path-matcher.js +5 -2
- package/dist/path-matcher.js.map +1 -1
- package/dist/profile-store.d.ts +82 -0
- package/dist/profile-store.d.ts.map +1 -0
- package/dist/profile-store.js +199 -0
- package/dist/profile-store.js.map +1 -0
- package/dist/profile.d.ts +185 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +434 -0
- package/dist/profile.js.map +1 -0
- package/dist/providers/cloud-provider.d.ts +10 -1
- package/dist/providers/cloud-provider.d.ts.map +1 -1
- package/dist/providers/cloud-provider.js +71 -14
- package/dist/providers/cloud-provider.js.map +1 -1
- package/dist/providers/local-provider.d.ts +8 -1
- package/dist/providers/local-provider.d.ts.map +1 -1
- package/dist/providers/local-provider.js +15 -3
- package/dist/providers/local-provider.js.map +1 -1
- package/dist/providers/openai-compat-provider.d.ts +11 -1
- package/dist/providers/openai-compat-provider.d.ts.map +1 -1
- package/dist/providers/openai-compat-provider.js +93 -6
- package/dist/providers/openai-compat-provider.js.map +1 -1
- package/dist/providers/openai-completions-runner.d.ts +25 -1
- package/dist/providers/openai-completions-runner.d.ts.map +1 -1
- package/dist/providers/openai-completions-runner.js +109 -14
- package/dist/providers/openai-completions-runner.js.map +1 -1
- package/dist/providers/race.d.ts +58 -1
- package/dist/providers/race.d.ts.map +1 -1
- package/dist/providers/race.js +317 -4
- package/dist/providers/race.js.map +1 -1
- package/dist/providers/truncate.d.ts.map +1 -1
- package/dist/providers/truncate.js +20 -2
- package/dist/providers/truncate.js.map +1 -1
- package/dist/providers/types.d.ts +96 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +59 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/provisional-manager.d.ts +93 -0
- package/dist/provisional-manager.d.ts.map +1 -0
- package/dist/provisional-manager.js +98 -0
- package/dist/provisional-manager.js.map +1 -0
- package/dist/provisional.d.ts +150 -0
- package/dist/provisional.d.ts.map +1 -0
- package/dist/provisional.js +238 -0
- package/dist/provisional.js.map +1 -0
- package/dist/regret-tracker.d.ts +84 -0
- package/dist/regret-tracker.d.ts.map +1 -0
- package/dist/regret-tracker.js +145 -0
- package/dist/regret-tracker.js.map +1 -0
- package/dist/replay-cli.d.ts +13 -0
- package/dist/replay-cli.d.ts.map +1 -0
- package/dist/replay-cli.js +167 -0
- package/dist/replay-cli.js.map +1 -0
- package/dist/replay.d.ts +107 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +225 -0
- package/dist/replay.js.map +1 -0
- package/dist/reranker.d.ts +181 -0
- package/dist/reranker.d.ts.map +1 -0
- package/dist/reranker.js +324 -0
- package/dist/reranker.js.map +1 -0
- package/dist/session-trie.d.ts +103 -0
- package/dist/session-trie.d.ts.map +1 -0
- package/dist/session-trie.js +280 -0
- package/dist/session-trie.js.map +1 -0
- package/dist/speculative.d.ts +74 -0
- package/dist/speculative.d.ts.map +1 -0
- package/dist/speculative.js +107 -0
- package/dist/speculative.js.map +1 -0
- package/dist/tool-summarize.d.ts +40 -0
- package/dist/tool-summarize.d.ts.map +1 -0
- package/dist/tool-summarize.js +245 -0
- package/dist/tool-summarize.js.map +1 -0
- package/dist/trie-sanitize.d.ts +22 -0
- package/dist/trie-sanitize.d.ts.map +1 -0
- package/dist/trie-sanitize.js +142 -0
- package/dist/trie-sanitize.js.map +1 -0
- package/dist/versions.d.ts +23 -0
- package/dist/versions.d.ts.map +1 -0
- package/dist/versions.js +31 -0
- package/dist/versions.js.map +1 -0
- package/package.json +3 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OpenAICompatProviderConfig } from "../config.js";
|
|
2
|
-
import type { GhostProvider, GhostRequest } from "./types.js";
|
|
2
|
+
import type { CandidateSet, GhostProvider, GhostRequest } from "./types.js";
|
|
3
3
|
export interface PreflightResult {
|
|
4
4
|
ok: boolean;
|
|
5
5
|
status?: number;
|
|
@@ -25,5 +25,15 @@ export declare class OpenAICompatProvider implements GhostProvider {
|
|
|
25
25
|
*/
|
|
26
26
|
preflight(): Promise<PreflightResult>;
|
|
27
27
|
predict(req: GhostRequest): Promise<string | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Multi-candidate prediction. Fires `config.parallelN` FIM requests in
|
|
30
|
+
* parallel and dedupes by exact text. PRD §M3b: FIM does not support
|
|
31
|
+
* the `n` parameter, so parallel POSTs are the only n>1 path. Parallel
|
|
32
|
+
* fire is only useful at temperature > 0 — at temp=0 every call returns
|
|
33
|
+
* the same greedy result. We downgrade silently to n=1 in that case.
|
|
34
|
+
*/
|
|
35
|
+
predictMulti(req: GhostRequest): Promise<CandidateSet | null>;
|
|
36
|
+
private effectiveParallelN;
|
|
37
|
+
private fireOne;
|
|
28
38
|
}
|
|
29
39
|
//# sourceMappingURL=openai-compat-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-compat-provider.d.ts","sourceRoot":"","sources":["../../src/providers/openai-compat-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"openai-compat-provider.d.ts","sourceRoot":"","sources":["../../src/providers/openai-compat-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAU5E,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IAG7C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEO,MAAM,EAAE,0BAA0B;IAI/D,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IA+BrC,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIxD;;;;;;OAMG;IACG,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAsBnE,OAAO,CAAC,kBAAkB;YAgBZ,OAAO;CAoDrB"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { sanitizeCompletion } from "./truncate.js";
|
|
2
2
|
const PREFLIGHT_TIMEOUT_MS = 5_000;
|
|
3
|
+
/**
|
|
4
|
+
* Absolute upper bound on a single FIM POST. The user's abort signal still
|
|
5
|
+
* cancels earlier under normal typing; this guards against hung connections
|
|
6
|
+
* when the user isn't typing (no fresh keystroke → no fresh abort). SEC-3.
|
|
7
|
+
*/
|
|
8
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
3
9
|
/**
|
|
4
10
|
* Provider for FIM-completions backends (e.g. Mercury Edit 2 by Inception
|
|
5
11
|
* Labs). Calls `/fim/completions` with `prompt`/`suffix` and returns the
|
|
@@ -57,10 +63,70 @@ export class OpenAICompatProvider {
|
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
async predict(req) {
|
|
66
|
+
return this.fireOne(req);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Multi-candidate prediction. Fires `config.parallelN` FIM requests in
|
|
70
|
+
* parallel and dedupes by exact text. PRD §M3b: FIM does not support
|
|
71
|
+
* the `n` parameter, so parallel POSTs are the only n>1 path. Parallel
|
|
72
|
+
* fire is only useful at temperature > 0 — at temp=0 every call returns
|
|
73
|
+
* the same greedy result. We downgrade silently to n=1 in that case.
|
|
74
|
+
*/
|
|
75
|
+
async predictMulti(req) {
|
|
76
|
+
const n = this.effectiveParallelN();
|
|
77
|
+
if (n <= 1) {
|
|
78
|
+
const text = await this.fireOne(req);
|
|
79
|
+
if (!text)
|
|
80
|
+
return null;
|
|
81
|
+
return { candidates: [{ text }] };
|
|
82
|
+
}
|
|
83
|
+
const results = await Promise.all(Array.from({ length: n }, () => this.fireOne(req)));
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
const candidates = [];
|
|
86
|
+
for (const text of results) {
|
|
87
|
+
if (!text)
|
|
88
|
+
continue;
|
|
89
|
+
if (seen.has(text))
|
|
90
|
+
continue;
|
|
91
|
+
seen.add(text);
|
|
92
|
+
candidates.push({ text });
|
|
93
|
+
}
|
|
94
|
+
if (candidates.length === 0)
|
|
95
|
+
return null;
|
|
96
|
+
return { candidates };
|
|
97
|
+
}
|
|
98
|
+
effectiveParallelN() {
|
|
99
|
+
const n = this.config.parallelN;
|
|
100
|
+
// Guard against NaN / non-finite — a corrupted config should never
|
|
101
|
+
// make us hit Array.from({length: NaN}).
|
|
102
|
+
if (!Number.isFinite(n) || n <= 1)
|
|
103
|
+
return 1;
|
|
104
|
+
// At temp=0 parallel-fire produces identical greedy outputs. Cost
|
|
105
|
+
// without value → downgrade. PRD §M3b documents this case.
|
|
106
|
+
//
|
|
107
|
+
// Assumption: at temperature>0 the backend (Mercury Edit FIM) actually
|
|
108
|
+
// samples non-deterministically. If a future backend caches by
|
|
109
|
+
// prompt+temp without sampling jitter, parallel-fire degenerates to
|
|
110
|
+
// the same downgrade scenario. Worth re-testing per-vendor.
|
|
111
|
+
if (this.config.temperature === 0)
|
|
112
|
+
return 1;
|
|
113
|
+
return Math.floor(n);
|
|
114
|
+
}
|
|
115
|
+
async fireOne(req) {
|
|
60
116
|
const apiKey = this.config.apiKey;
|
|
61
117
|
if (!apiKey)
|
|
62
118
|
return null;
|
|
63
119
|
const { prompt, suffix } = buildFIMPrompt(req, this.config.maxRecentMessages);
|
|
120
|
+
// Combine the caller's abort with an absolute timeout. SEC-3:
|
|
121
|
+
// without this, a hung TCP connection could pin resources until
|
|
122
|
+
// the user types again (the only thing that fires `req.signal`).
|
|
123
|
+
const localCtrl = new AbortController();
|
|
124
|
+
const onUserAbort = () => localCtrl.abort();
|
|
125
|
+
if (req.signal.aborted)
|
|
126
|
+
localCtrl.abort();
|
|
127
|
+
else
|
|
128
|
+
req.signal.addEventListener("abort", onUserAbort, { once: true });
|
|
129
|
+
const timeoutHandle = setTimeout(() => localCtrl.abort(), REQUEST_TIMEOUT_MS);
|
|
64
130
|
try {
|
|
65
131
|
const res = await fetch(`${trimSlash(this.config.baseUrl)}/fim/completions`, {
|
|
66
132
|
method: "POST",
|
|
@@ -73,19 +139,32 @@ export class OpenAICompatProvider {
|
|
|
73
139
|
prompt,
|
|
74
140
|
suffix,
|
|
75
141
|
max_tokens: this.config.maxTokens,
|
|
76
|
-
temperature:
|
|
142
|
+
temperature: this.config.temperature,
|
|
77
143
|
}),
|
|
78
|
-
signal:
|
|
144
|
+
signal: localCtrl.signal,
|
|
79
145
|
});
|
|
80
146
|
if (!res.ok)
|
|
81
147
|
return null;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
148
|
+
try {
|
|
149
|
+
const data = (await res.json());
|
|
150
|
+
const text = data.choices?.[0]?.text ?? "";
|
|
151
|
+
return sanitizeCompletion(text, req.editorTextBeforeCursor, 200);
|
|
152
|
+
}
|
|
153
|
+
catch (parseErr) {
|
|
154
|
+
if (parseErr instanceof SyntaxError) {
|
|
155
|
+
console.error(`[OpenAICompatProvider] malformed JSON response (status ${res.status})`);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
throw parseErr;
|
|
159
|
+
}
|
|
85
160
|
}
|
|
86
161
|
catch {
|
|
87
162
|
return null;
|
|
88
163
|
}
|
|
164
|
+
finally {
|
|
165
|
+
clearTimeout(timeoutHandle);
|
|
166
|
+
req.signal.removeEventListener("abort", onUserAbort);
|
|
167
|
+
}
|
|
89
168
|
}
|
|
90
169
|
}
|
|
91
170
|
/**
|
|
@@ -97,7 +176,15 @@ export class OpenAICompatProvider {
|
|
|
97
176
|
function buildFIMPrompt(req, maxRecent) {
|
|
98
177
|
const recent = req.recentMessages
|
|
99
178
|
.slice(-maxRecent)
|
|
100
|
-
.map((m) =>
|
|
179
|
+
.map((m) => {
|
|
180
|
+
// PRD §M6a: tool entries render with a distinguishing prefix so
|
|
181
|
+
// the model can tell prior tool output from conversational turns.
|
|
182
|
+
if (m.role === "tool") {
|
|
183
|
+
const label = m.toolName ? `tool ${m.toolName}` : "tool";
|
|
184
|
+
return `# ${label}: ${truncate(m.text, 280)}`;
|
|
185
|
+
}
|
|
186
|
+
return `# ${m.role}: ${truncate(m.text, 280)}`;
|
|
187
|
+
})
|
|
101
188
|
.join("\n");
|
|
102
189
|
const ctx = recent ? `${recent}\n\n` : "";
|
|
103
190
|
// Split the editor text at cursor to form prompt (before) / suffix (after).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-compat-provider.js","sourceRoot":"","sources":["../../src/providers/openai-compat-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnD,MAAM,oBAAoB,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"openai-compat-provider.js","sourceRoot":"","sources":["../../src/providers/openai-compat-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AssistantMessageEventStream } from "@earendil-works/pi-ai";
|
|
2
|
+
import type { GhostRequest, StreamDelta } from "./types.js";
|
|
2
3
|
export interface OpenAICompletionsCallOpts {
|
|
3
4
|
baseUrl: string;
|
|
4
5
|
apiKey: string;
|
|
@@ -12,6 +13,7 @@ export interface OpenAICompletionsCallOpts {
|
|
|
12
13
|
maxTokens: number;
|
|
13
14
|
maxRecentMessages: number;
|
|
14
15
|
contextWindow: number;
|
|
16
|
+
temperature: number;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* Shared OpenAI-completions request path used by both {@link LocalProvider}
|
|
@@ -25,4 +27,26 @@ export interface OpenAICompletionsCallOpts {
|
|
|
25
27
|
*/
|
|
26
28
|
export declare function runOpenAICompletion(req: GhostRequest, opts: OpenAICompletionsCallOpts): Promise<string | null>;
|
|
27
29
|
export declare function trimSlash(url: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Streaming variant of {@link runOpenAICompletion}. Yields {@link StreamDelta}
|
|
32
|
+
* chunks as pi-ai's `stream()` produces `text_delta` events. Sanitization
|
|
33
|
+
* runs on the running cumulative (not per-delta) — per-delta would clip
|
|
34
|
+
* mid-token and break ghost rendering.
|
|
35
|
+
*
|
|
36
|
+
* Yields nothing on auth/connectivity failure, abort, or when the model
|
|
37
|
+
* record can't be built. The generator's `finally` block clears the
|
|
38
|
+
* SEC-3 timer and detaches the user-abort listener.
|
|
39
|
+
*/
|
|
40
|
+
export declare function runOpenAICompletionStream(req: GhostRequest, opts: OpenAICompletionsCallOpts): AsyncIterable<StreamDelta>;
|
|
41
|
+
/**
|
|
42
|
+
* Iterate a pi-ai `AssistantMessageEventStream`, filtering for non-empty
|
|
43
|
+
* `text_delta` events and emitting them through `sanitizeCompletion` as
|
|
44
|
+
* `StreamDelta` chunks. Sanitization runs on the running cumulative
|
|
45
|
+
* (NOT per-delta) since per-token clipping would break ghost rendering.
|
|
46
|
+
*
|
|
47
|
+
* Shared by `runOpenAICompletionStream` (Local) and CloudProvider's
|
|
48
|
+
* `predictStream` so the two paths can't drift on filter/sanitize
|
|
49
|
+
* semantics.
|
|
50
|
+
*/
|
|
51
|
+
export declare function streamWithSanitize(events: AssistantMessageEventStream, prefix: string): AsyncIterable<StreamDelta>;
|
|
28
52
|
//# sourceMappingURL=openai-completions-runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-completions-runner.d.ts","sourceRoot":"","sources":["../../src/providers/openai-completions-runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"openai-completions-runner.d.ts","sourceRoot":"","sources":["../../src/providers/openai-completions-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,2BAA2B,EAKhC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAU5D,MAAM,WAAW,yBAAyB;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACxC,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,yBAAyB,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2CxB;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;;;;;;;;GASG;AACH,wBAAuB,yBAAyB,CAC/C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,yBAAyB,GAC7B,aAAa,CAAC,WAAW,CAAC,CAoC5B;AAED;;;;;;;;;GASG;AACH,wBAAuB,kBAAkB,CACxC,MAAM,EAAE,2BAA2B,EACnC,MAAM,EAAE,MAAM,GACZ,aAAa,CAAC,WAAW,CAAC,CAa5B"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import { complete } from "@earendil-works/pi-ai";
|
|
1
|
+
import { complete, stream, } from "@earendil-works/pi-ai";
|
|
2
2
|
import { buildPromptMessages, sanitizeCompletion } from "./truncate.js";
|
|
3
|
+
/**
|
|
4
|
+
* Absolute upper bound on a single completion call. Backs SEC-3 for the
|
|
5
|
+
* pi-ai-backed paths (CloudProvider, LocalProvider). The user's keystroke
|
|
6
|
+
* abort still cancels earlier; this is the guard for a stationary user
|
|
7
|
+
* facing a hung backend.
|
|
8
|
+
*/
|
|
9
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
3
10
|
/**
|
|
4
11
|
* Shared OpenAI-completions request path used by both {@link LocalProvider}
|
|
5
12
|
* and {@link OpenAICompatProvider}. Builds the pi-ai model record, sends one
|
|
@@ -26,21 +33,109 @@ export async function runOpenAICompletion(req, opts) {
|
|
|
26
33
|
const { systemPrompt, user } = buildPromptMessages(req, opts.maxRecentMessages);
|
|
27
34
|
const messages = [{ role: "user", content: user, timestamp: Date.now() }];
|
|
28
35
|
const ctx = { systemPrompt, messages };
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
// Combine the caller's abort with an absolute timeout (SEC-3).
|
|
37
|
+
const localCtrl = new AbortController();
|
|
38
|
+
const onUserAbort = () => localCtrl.abort();
|
|
39
|
+
if (req.signal.aborted)
|
|
40
|
+
localCtrl.abort();
|
|
41
|
+
else
|
|
42
|
+
req.signal.addEventListener("abort", onUserAbort, { once: true });
|
|
43
|
+
const timeoutHandle = setTimeout(() => localCtrl.abort(), REQUEST_TIMEOUT_MS);
|
|
44
|
+
try {
|
|
45
|
+
const result = await complete(model, ctx, {
|
|
46
|
+
signal: localCtrl.signal,
|
|
47
|
+
temperature: opts.temperature,
|
|
48
|
+
maxTokens: opts.maxTokens,
|
|
49
|
+
apiKey: opts.apiKey,
|
|
50
|
+
});
|
|
51
|
+
if (result.stopReason === "error" || result.stopReason === "aborted")
|
|
52
|
+
return null;
|
|
53
|
+
const text = result.content
|
|
54
|
+
.filter((c) => c.type === "text")
|
|
55
|
+
.map((c) => c.text)
|
|
56
|
+
.join("");
|
|
57
|
+
return sanitizeCompletion(text, req.editorTextBeforeCursor, 200);
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
clearTimeout(timeoutHandle);
|
|
61
|
+
req.signal.removeEventListener("abort", onUserAbort);
|
|
62
|
+
}
|
|
42
63
|
}
|
|
43
64
|
export function trimSlash(url) {
|
|
44
65
|
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
45
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Streaming variant of {@link runOpenAICompletion}. Yields {@link StreamDelta}
|
|
69
|
+
* chunks as pi-ai's `stream()` produces `text_delta` events. Sanitization
|
|
70
|
+
* runs on the running cumulative (not per-delta) — per-delta would clip
|
|
71
|
+
* mid-token and break ghost rendering.
|
|
72
|
+
*
|
|
73
|
+
* Yields nothing on auth/connectivity failure, abort, or when the model
|
|
74
|
+
* record can't be built. The generator's `finally` block clears the
|
|
75
|
+
* SEC-3 timer and detaches the user-abort listener.
|
|
76
|
+
*/
|
|
77
|
+
export async function* runOpenAICompletionStream(req, opts) {
|
|
78
|
+
const model = {
|
|
79
|
+
id: opts.modelId,
|
|
80
|
+
name: opts.modelId,
|
|
81
|
+
api: "openai-completions",
|
|
82
|
+
provider: opts.providerTag,
|
|
83
|
+
baseUrl: trimSlash(opts.baseUrl),
|
|
84
|
+
reasoning: false,
|
|
85
|
+
input: ["text"],
|
|
86
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
87
|
+
contextWindow: opts.contextWindow,
|
|
88
|
+
maxTokens: opts.maxTokens,
|
|
89
|
+
};
|
|
90
|
+
const { systemPrompt, user } = buildPromptMessages(req, opts.maxRecentMessages);
|
|
91
|
+
const messages = [{ role: "user", content: user, timestamp: Date.now() }];
|
|
92
|
+
const ctx = { systemPrompt, messages };
|
|
93
|
+
const localCtrl = new AbortController();
|
|
94
|
+
const onUserAbort = () => localCtrl.abort();
|
|
95
|
+
if (req.signal.aborted)
|
|
96
|
+
localCtrl.abort();
|
|
97
|
+
else
|
|
98
|
+
req.signal.addEventListener("abort", onUserAbort, { once: true });
|
|
99
|
+
const timeoutHandle = setTimeout(() => localCtrl.abort(), REQUEST_TIMEOUT_MS);
|
|
100
|
+
try {
|
|
101
|
+
const events = stream(model, ctx, {
|
|
102
|
+
signal: localCtrl.signal,
|
|
103
|
+
temperature: opts.temperature,
|
|
104
|
+
maxTokens: opts.maxTokens,
|
|
105
|
+
apiKey: opts.apiKey,
|
|
106
|
+
});
|
|
107
|
+
yield* streamWithSanitize(events, req.editorTextBeforeCursor);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
clearTimeout(timeoutHandle);
|
|
111
|
+
req.signal.removeEventListener("abort", onUserAbort);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Iterate a pi-ai `AssistantMessageEventStream`, filtering for non-empty
|
|
116
|
+
* `text_delta` events and emitting them through `sanitizeCompletion` as
|
|
117
|
+
* `StreamDelta` chunks. Sanitization runs on the running cumulative
|
|
118
|
+
* (NOT per-delta) since per-token clipping would break ghost rendering.
|
|
119
|
+
*
|
|
120
|
+
* Shared by `runOpenAICompletionStream` (Local) and CloudProvider's
|
|
121
|
+
* `predictStream` so the two paths can't drift on filter/sanitize
|
|
122
|
+
* semantics.
|
|
123
|
+
*/
|
|
124
|
+
export async function* streamWithSanitize(events, prefix) {
|
|
125
|
+
let raw = "";
|
|
126
|
+
let firstEmitted = false;
|
|
127
|
+
for await (const ev of events) {
|
|
128
|
+
if (ev.type !== "text_delta")
|
|
129
|
+
continue;
|
|
130
|
+
if (!ev.delta)
|
|
131
|
+
continue;
|
|
132
|
+
raw += ev.delta;
|
|
133
|
+
const sanitized = sanitizeCompletion(raw, prefix, 200);
|
|
134
|
+
if (!sanitized)
|
|
135
|
+
continue;
|
|
136
|
+
const firstChunk = !firstEmitted;
|
|
137
|
+
firstEmitted = true;
|
|
138
|
+
yield { delta: ev.delta, cumulative: sanitized, firstChunk };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
46
141
|
//# sourceMappingURL=openai-completions-runner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-completions-runner.js","sourceRoot":"","sources":["../../src/providers/openai-completions-runner.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"openai-completions-runner.js","sourceRoot":"","sources":["../../src/providers/openai-completions-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/providers/race.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ProviderLatency } from "../metrics.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type GhostProvider, type GhostRequest, type StreamDelta } from "./types.js";
|
|
3
3
|
export interface RaceConfig {
|
|
4
4
|
/** Pause/debounce before race starts. Reported as `debounceMs`. */
|
|
5
5
|
pauseMs: number;
|
|
@@ -11,6 +11,8 @@ export interface RaceConfig {
|
|
|
11
11
|
export interface RaceTrace {
|
|
12
12
|
providers: ProviderLatency[];
|
|
13
13
|
winner?: string;
|
|
14
|
+
/** Members that the weighting policy declined to fire (PRD §M8). */
|
|
15
|
+
skipped?: string[];
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Implements {@link GhostProvider} by racing several providers in parallel.
|
|
@@ -26,10 +28,65 @@ export declare class RaceProvider implements GhostProvider {
|
|
|
26
28
|
readonly name: string;
|
|
27
29
|
private cooldownUntil;
|
|
28
30
|
private lastTrace;
|
|
31
|
+
private readonly stats;
|
|
29
32
|
constructor(members: GhostProvider[], cfg: RaceConfig);
|
|
33
|
+
/** Snapshot of per-member weighting stats. Test/diagnostic only. */
|
|
34
|
+
getMemberStats(): Array<{
|
|
35
|
+
name: string;
|
|
36
|
+
slowCount: number;
|
|
37
|
+
wins: number;
|
|
38
|
+
skipRemaining: number;
|
|
39
|
+
}>;
|
|
30
40
|
get debounceMs(): number;
|
|
31
41
|
consumeLastTrace(): RaceTrace | null;
|
|
42
|
+
/**
|
|
43
|
+
* Cooldown snapshot for speculative cache warm. The editor consults this
|
|
44
|
+
* synchronously in `handleTextChange` to decide whether the backspace-of-N
|
|
45
|
+
* branch may serve a result (it is the most aggressive branch and is only
|
|
46
|
+
* appropriate when a fresh race would no-op anyway). See PRD §6 M1b.
|
|
47
|
+
*/
|
|
48
|
+
getCooldownState(now?: number): {
|
|
49
|
+
active: boolean;
|
|
50
|
+
remainingMs: number;
|
|
51
|
+
};
|
|
32
52
|
predict(req: GhostRequest): Promise<string | null>;
|
|
53
|
+
/**
|
|
54
|
+
* After a race resolves, update per-member rolling stats and decide who
|
|
55
|
+
* gets a skip penalty for the next `SKIP_RACES`. A member earns "slow"
|
|
56
|
+
* if it ran but didn't win this race (when there was a winner).
|
|
57
|
+
*
|
|
58
|
+
* `userAborted` distinguishes user-keystroke cancellation from
|
|
59
|
+
* race-cancellation-by-winner. Member's trace result is "aborted" in
|
|
60
|
+
* both cases; we only penalize the latter (the member could have run
|
|
61
|
+
* to completion but lost the race). User keystrokes shouldn't drift
|
|
62
|
+
* the weighting at all.
|
|
63
|
+
*/
|
|
64
|
+
private recordRaceOutcome;
|
|
65
|
+
/**
|
|
66
|
+
* PRD §M3.5a — streaming variant of `predict`. Each member runs its own
|
|
67
|
+
* stream under a dedicated AbortController; first member to emit a
|
|
68
|
+
* non-empty delta wins. Losing members are aborted and their iterators
|
|
69
|
+
* released. The winner's remaining chunks pass through untouched.
|
|
70
|
+
*
|
|
71
|
+
* Trace + stats are recorded identically to `predict()` so M8 weighting
|
|
72
|
+
* works the same way: winner = first to first-chunk; losers that also
|
|
73
|
+
* produced are still marked `produced` (they did emit), losers aborted
|
|
74
|
+
* before producing are `aborted`.
|
|
75
|
+
*/
|
|
76
|
+
predictStream(req: GhostRequest): AsyncIterable<StreamDelta>;
|
|
77
|
+
/**
|
|
78
|
+
* Pump a member's stream until its first non-empty delta. Resolves to
|
|
79
|
+
* the parked iterator + that delta when produced; null on
|
|
80
|
+
* empty/aborted/error. Trace is appended for terminal outcomes; the
|
|
81
|
+
* `produced` entry is pushed once the first non-empty delta arrives so
|
|
82
|
+
* its latency reflects TTFT, not end-of-stream.
|
|
83
|
+
*/
|
|
84
|
+
private firstChunkOf;
|
|
85
|
+
/**
|
|
86
|
+
* Reset all rolling stats (PRD §M8: "Reset state on `setProvider` /
|
|
87
|
+
* extension reload"). Public for editor reset paths.
|
|
88
|
+
*/
|
|
89
|
+
resetStats(): void;
|
|
33
90
|
private runMember;
|
|
34
91
|
}
|
|
35
92
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"race.d.ts","sourceRoot":"","sources":["../../src/providers/race.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"race.d.ts","sourceRoot":"","sources":["../../src/providers/race.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAgB,MAAM,YAAY,CAAC;AAEnG,MAAM,WAAW,UAAU;IAC1B,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACzB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAqBD;;;;;;;GAOG;AACH,qBAAa,YAAa,YAAW,aAAa;IAOhD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;gBAG/B,OAAO,EAAE,aAAa,EAAE,EACxB,GAAG,EAAE,UAAU;IASjC,oEAAoE;IACpE,cAAc,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAYjG,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,gBAAgB,IAAI,SAAS,GAAG,IAAI;IAMpC;;;;;OAKG;IACH,gBAAgB,CAAC,GAAG,GAAE,MAAmB,GAAG;QAC3C,MAAM,EAAE,OAAO,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACpB;IAKK,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgFxD;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;;;;;;;;;OAUG;IACI,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,aAAa,CAAC,WAAW,CAAC;IAgHnE;;;;;;OAMG;YACW,YAAY;IA4C1B;;;OAGG;IACH,UAAU,IAAI,IAAI;YAQJ,SAAS;CA8BvB;AAqCD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAyBrF"}
|