model-utils.ts

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: MIT
 4
 5import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
 6
 7export type SetModelResult =
 8	| { ok: true }
 9	| { ok: false; reason: "invalid-format" | "unknown-model" | "set-failed"; detail: string };
10
11/**
12 * Parse a "provider/modelId" string, look it up in the model registry, and
13 * set it as the active model. Returns a result describing what happened.
14 */
15export async function parseAndSetModel(spec: string, ctx: ExtensionContext, pi: ExtensionAPI): Promise<SetModelResult> {
16	const slashIdx = spec.indexOf("/");
17	if (slashIdx <= 0 || slashIdx === spec.length - 1) {
18		return { ok: false, reason: "invalid-format", detail: `Invalid model format "${spec}", expected provider/modelId` };
19	}
20
21	const provider = spec.slice(0, slashIdx);
22	const modelId = spec.slice(slashIdx + 1);
23	const model = ctx.modelRegistry.find(provider, modelId);
24
25	if (!model) {
26		return { ok: false, reason: "unknown-model", detail: `Unknown model: ${spec}` };
27	}
28
29	try {
30		await pi.setModel(model);
31	} catch (err) {
32		const msg = err instanceof Error ? err.message : String(err);
33		return { ok: false, reason: "set-failed", detail: `Failed to set model ${spec}: ${msg}` };
34	}
35
36	return { ok: true };
37}
38
39/**
40 * Convenience wrapper: parse and set the model, notifying the user on failure.
41 */
42export async function parseAndSetModelWithNotify(
43	spec: string,
44	ctx: ExtensionContext,
45	pi: ExtensionAPI,
46): Promise<SetModelResult> {
47	const result = await parseAndSetModel(spec, ctx, pi);
48	if (!result.ok) {
49		ctx.ui.notify(result.detail, "warning");
50	}
51	return result;
52}