-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathautocomplete.ts
More file actions
63 lines (55 loc) · 2.61 KB
/
Copy pathautocomplete.ts
File metadata and controls
63 lines (55 loc) · 2.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
import type { AgenticodingState } from "../state.js";
import { getEffectiveModelGroups } from "./router.js";
import type { ModelGroupModel, ResolvedModelGroup } from "./types.js";
const registeredUis = new WeakSet<object>();
function isUnavailable(group: ResolvedModelGroup, entry: ModelGroupModel): boolean {
return group.validation.unavailableRefs.some((ref) => ref.provider === entry.provider && ref.modelId === entry.modelId);
}
function formatModelGroupRouteDetails(group: ResolvedModelGroup): string {
if (group.models.length === 0) return "No models configured";
return group.models
.map((entry) => {
const thinking = entry.thinkingLevel ?? "inherit";
const unavailable = isUnavailable(group, entry) ? " (unavailable)" : "";
return `${entry.provider}/${entry.modelId} • ${thinking}${unavailable}`;
})
.join("; ");
}
export function createModelGroupAutocompleteProvider(state: AgenticodingState) {
return (current: any) => ({
async getSuggestions(lines: string[], cursorLine: number, cursorCol: number, options: unknown) {
const line = lines[cursorLine] ?? "";
const beforeCursor = line.slice(0, cursorCol);
const match = beforeCursor.match(/(?:^|[\t ])#([^\s#]*)$/);
if (!match) {
return current.getSuggestions(lines, cursorLine, cursorCol, options);
}
const partial = (match[1] ?? "").toLowerCase();
const groups = getEffectiveModelGroups(state.modelGroups.groups);
const items = groups
.filter((group) => group.name.toLowerCase().startsWith(partial))
.map((group) => ({
value: `#${group.name}`,
label: `#${group.name}`,
description: formatModelGroupRouteDetails(group),
}));
return { prefix: `#${match[1] ?? ""}`, items };
},
applyCompletion(lines: string[], cursorLine: number, cursorCol: number, item: unknown, prefix: string) {
return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
},
shouldTriggerFileCompletion(lines: string[], cursorLine: number, cursorCol: number) {
return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;
},
});
}
export function registerModelGroupAutocomplete(ctx: ExtensionContext, state: AgenticodingState): void {
if (!ctx.hasUI) return;
const ui = ctx.ui as unknown as { addAutocompleteProvider?: (factory: ReturnType<typeof createModelGroupAutocompleteProvider>) => void };
if (typeof ui.addAutocompleteProvider !== "function") return;
const key = ui as object;
if (registeredUis.has(key)) return;
registeredUis.add(key);
ui.addAutocompleteProvider(createModelGroupAutocompleteProvider(state));
}