config.ts
2501 bytes
1import type { PiReasoningEffort, ReviewerConfig } from "./types";
2
3function objectValue(value: unknown): Record<string, unknown> | undefined {
4 return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
5}
6
7function stringValue(value: unknown): string | undefined {
8 return typeof value === "string" && value.trim() ? value.trim() : undefined;
9}
10
11function booleanValue(value: unknown, field: string, fallback: boolean): boolean {
12 if (value === undefined) return fallback;
13 if (typeof value === "boolean") return value;
14 throw new Error(`${field} must be a boolean`);
15}
16
17function reasoningEffort(value: unknown): PiReasoningEffort | undefined {
18 if (value === undefined) return undefined;
19 if (
20 value === "none" ||
21 value === "minimal" ||
22 value === "low" ||
23 value === "medium" ||
24 value === "high" ||
25 value === "xhigh" ||
26 value === "max"
27 ) {
28 return value;
29 }
30 throw new Error('reviewer.reasoningEffort must be "none", "minimal", "low", "medium", "high", "xhigh", or "max"');
31}
32
33export function parseReviewerConfig(value: unknown): ReviewerConfig {
34 const data = objectValue(value);
35 const reviewer = data && objectValue(data.reviewer);
36 if (!reviewer) {
37 return {
38 kind: "pi",
39 provider: "openai-codex",
40 model: "gpt-5.6-luna",
41 reasoningEffort: "minimal",
42 };
43 }
44 if (reviewer.kind === "none") return { kind: "none" };
45
46 const model = stringValue(reviewer.model);
47 if (!model) throw new Error("reviewer.model must be a non-empty string");
48 if (reviewer.kind === "llama.cpp") {
49 const baseUrl = stringValue(reviewer.baseUrl);
50 if (!baseUrl) throw new Error("reviewer.baseUrl must be a non-empty string");
51 return {
52 kind: "llama.cpp",
53 baseUrl,
54 model,
55 enableThinking: booleanValue(reviewer.enableThinking, "reviewer.enableThinking", false),
56 };
57 }
58 if (reviewer.kind !== "pi") throw new Error('reviewer.kind must be "none", "pi", or "llama.cpp"');
59
60 const provider = stringValue(reviewer.provider);
61 if (!provider) throw new Error("reviewer.provider must be a non-empty string");
62 const promptCacheKey = stringValue(reviewer.promptCacheKey);
63 if (reviewer.promptCacheKey !== undefined && !promptCacheKey) {
64 throw new Error("reviewer.promptCacheKey must be a non-empty string");
65 }
66 return {
67 kind: "pi",
68 provider,
69 model,
70 reasoningEffort: reasoningEffort(reviewer.reasoningEffort),
71 promptCacheKey,
72 };
73}