feat: expose safe pi management api

This commit is contained in:
2026-08-05 00:31:44 +02:00
parent 09eeea17e5
commit d6b4a08a02
10 changed files with 744 additions and 61 deletions
+15 -2
View File
@@ -4,6 +4,7 @@ import type { WorkspaceRegistryConfig } from "./workspaces/types.js";
export interface AppConfig {
host: string; port: number; harnessDir: string; thtBin: string; piBin: string;
authMode: "none" | "mock" | "upstream";
publicExposure: boolean;
sessionStorage: {
mode: "local" | "postgres";
host?: string; port?: number; database?: string; runtimeUser?: string;
@@ -15,6 +16,7 @@ export interface AppConfig {
maintenanceFile: string;
dataRoot?: string;
ollamaEnsureTimeoutMs: number;
piManagementTimeoutMs: number;
secretsFile?: string;
secretFiles: Readonly<Record<string, string | undefined>>;
modelApiKeyFile?: string;
@@ -91,19 +93,28 @@ function diagnosticTimeout(value: string | undefined): number {
return timeout;
}
function piManagementTimeout(value: string | undefined): number {
const timeout = Number(value ?? 8_000);
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 30_000) {
throw new Error("Pi management timeout configuration is invalid");
}
return timeout;
}
export function loadConfig(env: Record<string, string | undefined>): AppConfig {
const authMode = env.AUTH_MODE ?? "none";
if (!(["none", "mock", "upstream"] as const).includes(authMode as AppConfig["authMode"])) {
throw new Error(`unsupported AUTH_MODE=${authMode}; use none, mock, or upstream`);
}
if (env.THOTH_PUBLIC_EXPOSURE === "true" && authMode !== "upstream") {
const publicExposure = env.THOTH_PUBLIC_EXPOSURE === "true";
if (publicExposure && authMode !== "upstream") {
throw new Error("public exposure requires AUTH_MODE=upstream behind a trusted proxy");
}
const sessionStorageMode = env.THT_SESSION_STORAGE ?? "local";
if (sessionStorageMode !== "local" && sessionStorageMode !== "postgres") {
throw new Error("session storage configuration is invalid");
}
if (sessionStorageMode === "local" && env.THOTH_PUBLIC_EXPOSURE === "true") {
if (sessionStorageMode === "local" && publicExposure) {
throw new Error("local session storage requires loopback-only deployment");
}
const legacyWorkspaceMode = env.THT_LEGACY_WORKSPACE_MODE;
@@ -204,6 +215,7 @@ export function loadConfig(env: Record<string, string | undefined>): AppConfig {
thtBin: env.THT_BIN ?? "tht",
piBin: env.PI_BIN ?? "pi",
authMode: authMode as AppConfig["authMode"],
publicExposure,
sessionStorage,
defaults: { provider: env.PI_PROVIDER, model: env.PI_MODEL, thinking: env.PI_THINKING },
maxPiProcesses: Number(env.MAX_PI_PROCESSES ?? 4),
@@ -211,6 +223,7 @@ export function loadConfig(env: Record<string, string | undefined>): AppConfig {
maintenanceFile: env.THT_MAINTENANCE_FILE ?? path.join(path.dirname(settingsFile), "maintenance.json"),
dataRoot: env.THT_DATA_ROOT,
ollamaEnsureTimeoutMs: Number(env.OLLAMA_ENSURE_TIMEOUT_MS ?? 60000),
piManagementTimeoutMs: piManagementTimeout(env.PI_MANAGEMENT_TIMEOUT_MS),
secretsFile,
secretFiles,
modelApiKeyFile,