Repository Public
1/** Worker configuration from the environment (CONTRACT §1, §7). Fails fast with a message an operator can act on. */2import os from 'node:os';3import path from 'node:path';45export class ConfigError extends Error {6 constructor(message: string) {7 super(message);8 this.name = 'ConfigError';9 }10}1112export interface WorkerConfig {13 databaseUrl: string;14 dataDir: string;15 /** null ⇒ sibling projects cannot be hidden from the sandbox (a warning is logged). */16 workspaceRoot: string | null;17 workerId: string;18 concurrency: number;19 logLevel: string;20 /** Which provider keys are present. Booleans only: the keys themselves never leave `process.env`. */21 providers: { anthropic: boolean; openai: boolean };22}2324const present = (v: string | undefined): v is string => typeof v === 'string' && v.trim().length > 0;2526export function loadConfig(env: NodeJS.ProcessEnv = process.env): WorkerConfig {27 const problems: string[] = [];28 if (!present(env.DATABASE_URL)) problems.push('DATABASE_URL is not set (PostgreSQL connection string shared with the server).');29 if (!present(env.AOS_DATA_DIR)) problems.push('AOS_DATA_DIR is not set (directory shared with the server; artifacts live under <dir>/artifacts).');30 else if (!path.isAbsolute(env.AOS_DATA_DIR)) problems.push('AOS_DATA_DIR must be an absolute path.');31 if (present(env.AOS_WORKSPACE_ROOT) && !path.isAbsolute(env.AOS_WORKSPACE_ROOT)) problems.push('AOS_WORKSPACE_ROOT must be an absolute path.');32 const providers = { anthropic: present(env.ANTHROPIC_API_KEY), openai: present(env.OPENAI_API_KEY) };33 if (!providers.anthropic && !providers.openai) {34 problems.push('No model provider key is configured: set ANTHROPIC_API_KEY and/or OPENAI_API_KEY. Without one the worker cannot run any mission.');35 }36 let concurrency = 4;37 if (present(env.AOS_MAX_CONCURRENT_RUNS)) {38 const n = Number(env.AOS_MAX_CONCURRENT_RUNS);39 if (!Number.isInteger(n) || n < 1 || n > 32) problems.push('AOS_MAX_CONCURRENT_RUNS must be an integer between 1 and 32.');40 else concurrency = n;41 }42 if (problems.length > 0) throw new ConfigError(`Agent OS worker cannot start:\n${problems.map((p) => ` - ${p}`).join('\n')}`);43 return {44 databaseUrl: env.DATABASE_URL as string,45 dataDir: env.AOS_DATA_DIR as string,46 workspaceRoot: present(env.AOS_WORKSPACE_ROOT) ? env.AOS_WORKSPACE_ROOT : null,47 workerId: present(env.AOS_WORKER_ID) ? env.AOS_WORKER_ID : `${os.hostname()}-${process.pid}`,48 concurrency,49 logLevel: present(env.AOS_LOG_LEVEL) ? env.AOS_LOG_LEVEL : 'info',50 providers,51 };52}53