import { registerAs } from "@nestjs/config"; const normalizeAiProvider = (): "ollama" | "claude" | "openai" => { const provider = process.env.AI_PROVIDER?.trim().toLowerCase(); if (!provider) { return "ollama"; } if (provider !== "ollama" && provider !== "claude" && provider !== "openai") { return "ollama"; } return provider; }; const parseValkeyUrl = (url: string): { host?: string; port?: number; password?: string } => { try { const parsed = new URL(url); const port = parsed.port ? parseInt(parsed.port, 10) : undefined; return { host: parsed.hostname || undefined, port: Number.isNaN(port) ? undefined : port, password: parsed.password ? decodeURIComponent(parsed.password) : undefined, }; } catch { return {}; } }; export const orchestratorConfig = registerAs("orchestrator", () => { const valkeyUrl = process.env.VALKEY_URL ?? "redis://localhost:6379"; const parsedValkeyUrl = parseValkeyUrl(valkeyUrl); return { host: process.env.HOST ?? process.env.BIND_ADDRESS ?? "127.0.0.1", port: parseInt(process.env.ORCHESTRATOR_PORT ?? "3001", 10), valkey: { host: process.env.VALKEY_HOST ?? parsedValkeyUrl.host ?? "localhost", port: parseInt(process.env.VALKEY_PORT ?? String(parsedValkeyUrl.port ?? 6379), 10), password: process.env.VALKEY_PASSWORD ?? parsedValkeyUrl.password, url: valkeyUrl, connectTimeout: parseInt(process.env.VALKEY_CONNECT_TIMEOUT_MS ?? "5000", 10), commandTimeout: parseInt(process.env.VALKEY_COMMAND_TIMEOUT_MS ?? "3000", 10), }, claude: { apiKey: process.env.CLAUDE_API_KEY, }, aiProvider: normalizeAiProvider(), docker: { socketPath: process.env.DOCKER_SOCKET ?? "/var/run/docker.sock", }, git: { userName: process.env.GIT_USER_NAME ?? "Mosaic Orchestrator", userEmail: process.env.GIT_USER_EMAIL ?? "orchestrator@mosaicstack.dev", }, killswitch: { enabled: process.env.KILLSWITCH_ENABLED === "true", }, sandbox: { enabled: process.env.SANDBOX_ENABLED !== "false", defaultImage: process.env.SANDBOX_DEFAULT_IMAGE ?? "node:20-alpine", defaultMemoryMB: parseInt(process.env.SANDBOX_DEFAULT_MEMORY_MB ?? "256", 10), defaultCpuLimit: parseFloat(process.env.SANDBOX_DEFAULT_CPU_LIMIT ?? "1.0"), networkMode: process.env.SANDBOX_NETWORK_MODE ?? "none", }, coordinator: { url: process.env.COORDINATOR_URL ?? "http://localhost:8000", timeout: parseInt(process.env.COORDINATOR_TIMEOUT_MS ?? "30000", 10), retries: parseInt(process.env.COORDINATOR_RETRIES ?? "3", 10), apiKey: process.env.COORDINATOR_API_KEY, }, yolo: { enabled: process.env.YOLO_MODE === "true", }, spawner: { maxConcurrentAgents: parseInt(process.env.MAX_CONCURRENT_AGENTS ?? "2", 10), sessionCleanupDelayMs: parseInt(process.env.SESSION_CLEANUP_DELAY_MS ?? "30000", 10), }, queue: { name: process.env.ORCHESTRATOR_QUEUE_NAME ?? "orchestrator-tasks", maxRetries: parseInt(process.env.ORCHESTRATOR_QUEUE_MAX_RETRIES ?? "3", 10), baseDelay: parseInt(process.env.ORCHESTRATOR_QUEUE_BASE_DELAY_MS ?? "1000", 10), maxDelay: parseInt(process.env.ORCHESTRATOR_QUEUE_MAX_DELAY_MS ?? "60000", 10), concurrency: parseInt(process.env.ORCHESTRATOR_QUEUE_CONCURRENCY ?? "1", 10), completedRetentionCount: parseInt(process.env.QUEUE_COMPLETED_RETENTION_COUNT ?? "100", 10), completedRetentionAgeSeconds: parseInt( process.env.QUEUE_COMPLETED_RETENTION_AGE_S ?? "3600", 10 ), failedRetentionCount: parseInt(process.env.QUEUE_FAILED_RETENTION_COUNT ?? "1000", 10), failedRetentionAgeSeconds: parseInt(process.env.QUEUE_FAILED_RETENTION_AGE_S ?? "86400", 10), }, }; });