Rl-Auto / apps /api /src /config.ts
Lazywords's picture
Deploy RL Auto Docker Space
c4ae742
Raw
History Blame Contribute Delete
3.41 kB
// apps/api/src/config.ts
// Centralized environment-variable parsing. All API keys live ONLY here.
// Never exposed to clients, never written to logs (pino redaction in log.ts).
import { z } from "zod";
const ConfigSchema = z.object({
port: z.number().int().positive().default(3001),
logLevel: z
.enum(["fatal", "error", "warn", "info", "debug", "trace"])
.default("info"),
// Default analyzer model
defaultModel: z.string().default("deepseek-v4-pro"),
defaultBaseURL: z
.string()
.default("https://api.deepseek.com"),
defaultApiKey: z.string().default(""),
defaultApiMode: z.enum(["chat", "responses"]).default("chat"),
// Judge model
judgeModel: z.string().default("gpt-5.5"),
judgeBaseURL: z
.string()
.default("https://app-hk.ppapi.ai/v1/chat/completions"),
judgeApiKey: z.string().default(""),
judgeApiMode: z.enum(["chat", "responses"]).default("chat"),
// Rubric generation model (falls back to default if unset)
rubricGenModel: z.string().default("gpt-5.5"),
rubricGenBaseURL: z
.string()
.default("https://app-hk.ppapi.ai/v1/chat/completions"),
rubricGenApiKey: z.string().default(""),
rubricGenApiMode: z.enum(["chat", "responses"]).default("chat"),
// Storage
sqlitePath: z.string().default("/app/data/tasks.db"),
databaseUrl: z.string().default(""),
storeBackend: z.enum(["sqlite", "postgres"]).default("sqlite"),
uploadDir: z.string().default("/app/data/uploads"),
exportDir: z.string().default("/app/data/exports"),
// Upload limits
maxUploadMB: z.number().int().positive().default(100),
maxBatchFiles: z.number().int().positive().default(20),
itemMaxAttempts: z.number().int().positive().default(3),
globalLlmConcurrency: z.number().int().nonnegative().default(0),
// Optional outbound proxy for AI provider calls (replaces legacy proxy.mjs)
upstreamProxy: z.string().default(""),
});
export type Config = z.infer<typeof ConfigSchema>;
function envInt(value: string | undefined, fallback: number): number {
if (!value) return fallback;
const n = Number(value);
return Number.isFinite(n) ? Math.trunc(n) : fallback;
}
export function loadConfig(): Config {
const parsed = ConfigSchema.parse({
port: envInt(process.env.PORT, 3001),
logLevel: process.env.LOG_LEVEL,
defaultModel: process.env.DEFAULT_MODEL,
defaultBaseURL: process.env.DEFAULT_BASE_URL,
defaultApiKey: process.env.DEFAULT_API_KEY,
defaultApiMode: process.env.DEFAULT_API_MODE,
judgeModel: process.env.JUDGE_MODEL,
judgeBaseURL: process.env.JUDGE_BASE_URL,
judgeApiKey: process.env.JUDGE_API_KEY,
judgeApiMode: process.env.JUDGE_API_MODE,
rubricGenModel: process.env.RUBRIC_GEN_MODEL,
rubricGenBaseURL: process.env.RUBRIC_GEN_BASE_URL,
rubricGenApiKey: process.env.RUBRIC_GEN_API_KEY,
rubricGenApiMode: process.env.RUBRIC_GEN_API_MODE,
sqlitePath: process.env.SQLITE_PATH,
databaseUrl: process.env.DATABASE_URL,
storeBackend: process.env.STORE_BACKEND,
uploadDir: process.env.UPLOAD_DIR,
exportDir: process.env.EXPORT_DIR,
maxUploadMB: envInt(process.env.MAX_UPLOAD_MB, 100),
maxBatchFiles: envInt(process.env.MAX_BATCH_FILES, 20),
itemMaxAttempts: envInt(process.env.ITEM_MAX_ATTEMPTS, 3),
globalLlmConcurrency: envInt(process.env.GLOBAL_LLM_CONCURRENCY, 0),
upstreamProxy: process.env.UPSTREAM_PROXY,
});
return parsed;
}