pi-ghost-autocomplete 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +513 -513
- package/dist/bench-cli.js +1 -1
- package/dist/bench.d.ts +11 -0
- package/dist/bench.js +1 -1
- package/dist/command-registry.d.ts +45 -0
- package/dist/config.d.ts +1 -1
- package/dist/eval-dataset.d.ts +4 -0
- package/dist/ghost-editor.d.ts +60 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/dist/metrics.d.ts +21 -1
- package/dist/providers/openai-compat-chat-provider.d.ts +6 -1
- package/dist/providers/openai-compat-provider.d.ts +11 -1
- package/dist/providers/router.d.ts +9 -1
- package/dist/providers/types.d.ts +19 -0
- package/dist/replay-cli.js +1 -1
- package/dist/session-harvest.d.ts +35 -0
- package/package.json +91 -84
package/dist/metrics.d.ts
CHANGED
|
@@ -7,12 +7,30 @@
|
|
|
7
7
|
* and the parser whitelist (runtime, in `bench.ts`) derive from this array so
|
|
8
8
|
* adding a mode means updating one place.
|
|
9
9
|
*/
|
|
10
|
-
export declare const COMPLETION_MODES: readonly ["deterministic", "llm", "cache", "trie", "speculative-warm", "provisional", "profile-slash"];
|
|
10
|
+
export declare const COMPLETION_MODES: readonly ["deterministic", "llm", "cache", "trie", "speculative-warm", "provisional", "profile-slash", "command-slash"];
|
|
11
11
|
export type CompletionMode = (typeof COMPLETION_MODES)[number];
|
|
12
12
|
export type RequestResult = "produced" | "empty" | "rejected" | "aborted" | "error";
|
|
13
13
|
export type AcceptanceOutcome = "accepted" | "accepted-partial" | "dismissed" | "stale" | "expired";
|
|
14
14
|
export type QualityAttribution = "accepted" | "dismissed-attributed" | "unknown";
|
|
15
15
|
export type RejectionReason = "stale-text" | "newline" | "too-long" | "assistant-phrasing" | "duplicate-suffix" | "markdown" | "empty" | "echo-token";
|
|
16
|
+
/**
|
|
17
|
+
* Diagnosed cause of an `empty` LLM verdict (session-51 todo #4). Without this
|
|
18
|
+
* the metrics can't distinguish a model that returned a bare newline from one
|
|
19
|
+
* whose output the sanitizer dropped, or a request that never reached the
|
|
20
|
+
* backend — that distinction previously needed synthetic probing.
|
|
21
|
+
*
|
|
22
|
+
* - `model-empty` — the model returned empty/whitespace-only text (the
|
|
23
|
+
* Mercury Edit "nothing to insert" case from session 51).
|
|
24
|
+
* - `sanitizer-null`— the model returned content but `sanitizeCompletion`
|
|
25
|
+
* rejected it (echo / filename-in-prose / markdown).
|
|
26
|
+
* - `http-error` — the request failed: missing key, non-2xx, malformed
|
|
27
|
+
* JSON, fetch throw, or timeout.
|
|
28
|
+
*
|
|
29
|
+
* Only set by providers that implement `consumeLastEmptyReason()`. Records from
|
|
30
|
+
* providers that don't (or that predate this field) omit it — bench buckets
|
|
31
|
+
* those as `unattributed`.
|
|
32
|
+
*/
|
|
33
|
+
export type EmptyReason = "model-empty" | "sanitizer-null" | "http-error";
|
|
16
34
|
export interface ProviderLatency {
|
|
17
35
|
provider: string;
|
|
18
36
|
latencyMs: number;
|
|
@@ -27,6 +45,8 @@ export interface MetricsRecord {
|
|
|
27
45
|
winner?: string;
|
|
28
46
|
result: RequestResult;
|
|
29
47
|
rejectionReason?: RejectionReason;
|
|
48
|
+
/** When `result === "empty"`, the diagnosed cause (session-51 todo #4). */
|
|
49
|
+
emptyReason?: EmptyReason;
|
|
30
50
|
completionLength?: number;
|
|
31
51
|
shown?: boolean;
|
|
32
52
|
acceptance?: AcceptanceOutcome;
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { OpenAICompatChatProviderConfig } from "../config.js";
|
|
6
6
|
import type { PreflightResult } from "./openai-compat-provider.js";
|
|
7
|
-
import type
|
|
7
|
+
import { type GhostProvider, type GhostRequest } from "./types.js";
|
|
8
|
+
import type { EmptyReason } from "../metrics.js";
|
|
8
9
|
/**
|
|
9
10
|
* Chat-register provider for OpenAI-compatible `/chat/completions` backends
|
|
10
11
|
* (e.g. Inception Mercury's conversational model). Sibling of
|
|
@@ -20,8 +21,12 @@ import type { GhostProvider, GhostRequest } from "./types.js";
|
|
|
20
21
|
export declare class OpenAICompatChatProvider implements GhostProvider {
|
|
21
22
|
private readonly config;
|
|
22
23
|
readonly name: string;
|
|
24
|
+
/** Why the most recent `predict` resolved empty; consumed by the editor. */
|
|
25
|
+
private lastEmptyReason;
|
|
23
26
|
constructor(config: OpenAICompatChatProviderConfig);
|
|
24
27
|
get debounceMs(): number;
|
|
28
|
+
/** Return + clear the cause of the last empty completion (session-51 #4). */
|
|
29
|
+
consumeLastEmptyReason(): EmptyReason | null;
|
|
25
30
|
/**
|
|
26
31
|
* Validate the API key with a minimal chat request. A successful response
|
|
27
32
|
* (even an empty completion) proves auth + connectivity.
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
|
|
4
4
|
*/
|
|
5
5
|
import type { OpenAICompatProviderConfig } from "../config.js";
|
|
6
|
-
import type
|
|
6
|
+
import { type CandidateSet, type GhostProvider, type GhostRequest } from "./types.js";
|
|
7
|
+
import type { EmptyReason } from "../metrics.js";
|
|
7
8
|
import { type PromptIntent } from "../intent.js";
|
|
8
9
|
export interface PreflightResult {
|
|
9
10
|
ok: boolean;
|
|
@@ -22,8 +23,17 @@ export interface PreflightResult {
|
|
|
22
23
|
export declare class OpenAICompatProvider implements GhostProvider {
|
|
23
24
|
private readonly config;
|
|
24
25
|
readonly name: string;
|
|
26
|
+
/** Why the most recent `fireOne` resolved empty; consumed by the editor. */
|
|
27
|
+
private lastEmptyReason;
|
|
25
28
|
constructor(config: OpenAICompatProviderConfig);
|
|
26
29
|
get debounceMs(): number;
|
|
30
|
+
/**
|
|
31
|
+
* Return + clear the cause of the last empty completion (session-51 todo
|
|
32
|
+
* #4). With `parallelN > 1` this reflects the last FIM call to resolve;
|
|
33
|
+
* since the editor only consumes it when the whole candidate set is empty,
|
|
34
|
+
* every parallel call was empty and the reasons are typically identical.
|
|
35
|
+
*/
|
|
36
|
+
consumeLastEmptyReason(): EmptyReason | null;
|
|
27
37
|
/**
|
|
28
38
|
* Validate the API key with a minimal FIM request. A successful
|
|
29
39
|
* response (even an empty completion) proves auth + connectivity.
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* reachable chat backend never regresses.
|
|
21
21
|
*/
|
|
22
22
|
import type { PromptIntent } from "../intent.js";
|
|
23
|
+
import type { EmptyReason } from "../metrics.js";
|
|
23
24
|
import type { PreflightResult } from "./openai-compat-provider.js";
|
|
24
25
|
import { type CandidateSet, type GhostProvider, type GhostRequest } from "./types.js";
|
|
25
26
|
/** Pure routing predicate — exported for direct testing. */
|
|
@@ -28,6 +29,9 @@ export declare class RouterProvider implements GhostProvider {
|
|
|
28
29
|
private readonly fim;
|
|
29
30
|
private readonly chat;
|
|
30
31
|
readonly name = "ghost-router";
|
|
32
|
+
/** Leg that served the most recent request — the one to query for the
|
|
33
|
+
* empty-cause diagnostic so it reflects the register that actually ran. */
|
|
34
|
+
private lastLeg;
|
|
31
35
|
constructor(fim: GhostProvider, chat: GhostProvider | null);
|
|
32
36
|
get debounceMs(): number;
|
|
33
37
|
/**
|
|
@@ -38,8 +42,12 @@ export declare class RouterProvider implements GhostProvider {
|
|
|
38
42
|
*/
|
|
39
43
|
legFor(intent: PromptIntent | undefined): "fim" | "chat";
|
|
40
44
|
/** Choose the leg for this request. Chat leg only when present AND the
|
|
41
|
-
* intent is natural-language; otherwise FIM.
|
|
45
|
+
* intent is natural-language; otherwise FIM. Records the choice so
|
|
46
|
+
* `consumeLastEmptyReason` can forward to the leg that actually ran. */
|
|
42
47
|
private leg;
|
|
48
|
+
/** Forward the empty-cause diagnostic to whichever leg last served a
|
|
49
|
+
* request. Null when no request has run yet or the leg doesn't track it. */
|
|
50
|
+
consumeLastEmptyReason(): EmptyReason | null;
|
|
43
51
|
predict(req: GhostRequest): Promise<string | null>;
|
|
44
52
|
/**
|
|
45
53
|
* Route, then adapt the chosen leg to the multi-candidate surface. The
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { PreflightResult } from "./openai-compat-provider.js";
|
|
6
6
|
import type { PromptIntent } from "../intent.js";
|
|
7
|
+
import type { EmptyReason } from "../metrics.js";
|
|
7
8
|
export interface GhostRequest {
|
|
8
9
|
editorText: string;
|
|
9
10
|
editorTextBeforeCursor: string;
|
|
@@ -75,6 +76,16 @@ export interface GhostProvider {
|
|
|
75
76
|
*/
|
|
76
77
|
predictStream?(req: GhostRequest): AsyncIterable<StreamDelta>;
|
|
77
78
|
preflight?(): Promise<boolean | PreflightResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Optional empty-cause diagnostic (session-51 todo #4). When the provider's
|
|
81
|
+
* last `predict`/`predictMulti` resolved to null/empty, returns *why*
|
|
82
|
+
* (`model-empty` / `sanitizer-null` / `http-error`) and clears it; returns
|
|
83
|
+
* null otherwise. The editor reads this only when it's about to log an
|
|
84
|
+
* `empty` result, so the value reflects the just-resolved request. Providers
|
|
85
|
+
* that don't implement it leave the metric's `emptyReason` unset
|
|
86
|
+
* (bench buckets those as `unattributed`).
|
|
87
|
+
*/
|
|
88
|
+
consumeLastEmptyReason?(): EmptyReason | null;
|
|
78
89
|
/**
|
|
79
90
|
* PRD §M3g / §M7 capability flag — true iff the provider populates
|
|
80
91
|
* per-token logprob values on streamed `StreamDelta` events (M7
|
|
@@ -87,6 +98,14 @@ export interface GhostProvider {
|
|
|
87
98
|
*/
|
|
88
99
|
readonly supportsLogprobs?: boolean;
|
|
89
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Classify an empty completion from the raw model text. Shared by providers
|
|
103
|
+
* that run text through `sanitizeCompletion`: a whitespace-only raw response is
|
|
104
|
+
* the model declining to insert (`model-empty`); non-empty raw that sanitized
|
|
105
|
+
* to null/empty was dropped by the sanitizer (`sanitizer-null`). HTTP/transport
|
|
106
|
+
* failures are classified `http-error` at the call site, not here.
|
|
107
|
+
*/
|
|
108
|
+
export declare function classifyEmpty(rawModelText: string): "model-empty" | "sanitizer-null";
|
|
90
109
|
/**
|
|
91
110
|
* Adapt a `predict()`-only provider into the `CandidateSet | null` shape.
|
|
92
111
|
* Used by the editor to give every provider a uniform multi-candidate
|