Parent directory

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}