Files
EJClaw/src/config.ts

152 lines
6.3 KiB
TypeScript

import { loadConfig } from './config/load-config.js';
import type { MoaConfig } from './moa.js';
import type { RoleModelConfig } from './config/schema.js';
export type { AppConfig, RoleModelConfig } from './config/schema.js';
export { loadConfig } from './config/load-config.js';
const CONFIG = loadConfig();
export const ASSISTANT_NAME = CONFIG.assistant.name;
export const ASSISTANT_HAS_OWN_NUMBER = CONFIG.assistant.hasOwnNumber;
export const SERVICE_ID = CONFIG.service.id;
export const CLAUDE_SERVICE_ID = CONFIG.service.claudeId;
export const CODEX_MAIN_SERVICE_ID = CONFIG.service.codexMainId;
export const CODEX_REVIEW_SERVICE_ID = CONFIG.service.codexReviewId;
export function normalizeServiceId(serviceId: string): string {
if (serviceId === 'codex') {
return CODEX_MAIN_SERVICE_ID;
}
return serviceId;
}
export const SERVICE_SESSION_SCOPE = normalizeServiceId(SERVICE_ID);
export function isClaudeService(serviceId: string = SERVICE_ID): boolean {
return normalizeServiceId(serviceId) === CLAUDE_SERVICE_ID;
}
export function isCodexMainService(serviceId: string = SERVICE_ID): boolean {
return normalizeServiceId(serviceId) === CODEX_MAIN_SERVICE_ID;
}
export function isReviewService(serviceId: string = SERVICE_ID): boolean {
return normalizeServiceId(serviceId) === CODEX_REVIEW_SERVICE_ID;
}
export const POLL_INTERVAL = CONFIG.runtime.pollInterval;
export const SCHEDULER_POLL_INTERVAL = CONFIG.runtime.schedulerPollInterval;
/** Minimum time (ms) a failover lease stays active before Claude can reclaim it. */
export const FAILOVER_MIN_DURATION_MS = CONFIG.runtime.failoverMinDurationMs;
export const SENDER_ALLOWLIST_PATH = CONFIG.paths.senderAllowlistPath;
export const STORE_DIR = CONFIG.paths.storeDir;
export const GROUPS_DIR = CONFIG.paths.groupsDir;
export const DATA_DIR = CONFIG.paths.dataDir;
export const CACHE_DIR = CONFIG.paths.cacheDir;
export const AGENT_TIMEOUT = CONFIG.runtime.agentTimeout;
export const AGENT_MAX_OUTPUT_SIZE = CONFIG.runtime.agentMaxOutputSize;
export const IPC_POLL_INTERVAL = CONFIG.runtime.ipcPollInterval;
export const IDLE_TIMEOUT = CONFIG.runtime.idleTimeout;
export const MAX_CONCURRENT_AGENTS = CONFIG.runtime.maxConcurrentAgents;
export const RECOVERY_CONCURRENT_AGENTS =
CONFIG.runtime.recoveryConcurrentAgents;
export const LOG_LEVEL = CONFIG.logging.level;
export const IS_TEST_ENV = CONFIG.logging.isTestEnv;
// ── Paired review ─────────────────────────────────────────────────
/** Owner agent type. Default: codex. Set OWNER_AGENT_TYPE=claude-code to use Claude as owner. */
export const OWNER_AGENT_TYPE = CONFIG.paired.ownerAgentType;
/** Reviewer agent type. Default: claude-code. Set REVIEWER_AGENT_TYPE=codex to use Codex as reviewer. */
export const REVIEWER_AGENT_TYPE = CONFIG.paired.reviewerAgentType;
/** Service ID for the reviewer based on agent type. */
export const REVIEWER_SERVICE_ID_FOR_TYPE =
CONFIG.paired.reviewerServiceIdForType;
/** Arbiter agent type. Disabled by default. Set ARBITER_AGENT_TYPE=codex or claude-code to enable. */
export const ARBITER_AGENT_TYPE = CONFIG.paired.arbiterAgentType;
/** Service ID for the arbiter. Defaults to codex-review for internal routing when arbiter is enabled. */
export const ARBITER_SERVICE_ID = CONFIG.paired.arbiterServiceId;
/** Language for agent responses. When set, a language instruction is appended to all paired room prompts. */
export const AGENT_LANGUAGE = CONFIG.paired.agentLanguage;
/** Number of consecutive owner↔reviewer round trips before arbiter is auto-requested. */
export const ARBITER_DEADLOCK_THRESHOLD =
CONFIG.paired.arbiterDeadlockThreshold;
export function isArbiterEnabled(): boolean {
return ARBITER_AGENT_TYPE !== undefined;
}
// ── Per-role model configuration ─────────────────────────────────
export const OWNER_MODEL_CONFIG = CONFIG.models.owner;
export const REVIEWER_MODEL_CONFIG = CONFIG.models.reviewer;
export const ARBITER_MODEL_CONFIG = CONFIG.models.arbiter;
export const DEFAULT_CLAUDE_MODEL = CONFIG.providers.claudeDefaultModel;
export const DEFAULT_CODEX_MODEL = CONFIG.providers.codexDefaultModel;
export function getRoleModelConfig(
role: 'owner' | 'reviewer' | 'arbiter',
): RoleModelConfig {
switch (role) {
case 'owner':
return OWNER_MODEL_CONFIG;
case 'reviewer':
return REVIEWER_MODEL_CONFIG;
case 'arbiter':
return ARBITER_MODEL_CONFIG;
}
}
// ── Mixture of Agents (MoA) ──────────────────────────────────────
export function getMoaConfig(): MoaConfig {
return CONFIG.moa;
}
export const PAIRED_MAX_ROUND_TRIPS = CONFIG.paired.maxRoundTrips;
export const RECOVERY_STAGGER_MS = CONFIG.runtime.recoveryStaggerMs;
export const RECOVERY_DURATION_MS = CONFIG.runtime.recoveryDurationMs;
export const TRIGGER_PATTERN = CONFIG.assistant.triggerPattern;
// Status dashboard: Discord channel ID for live agent status updates
export const STATUS_CHANNEL_ID = CONFIG.status.channelId;
export const STATUS_UPDATE_INTERVAL = CONFIG.status.updateInterval;
export const USAGE_UPDATE_INTERVAL = CONFIG.status.usageUpdateInterval;
export const STATUS_SHOW_ROOMS = CONFIG.status.showRooms;
export const STATUS_SHOW_ROOM_DETAILS = CONFIG.status.showRoomDetails;
export const USAGE_DASHBOARD_ENABLED = CONFIG.status.usageDashboardEnabled;
// Timezone for scheduled tasks (cron expressions, etc.)
// Uses system timezone by default
export const TIMEZONE = CONFIG.status.timezone;
const SESSION_COMMAND_ALLOWED_SENDERS = CONFIG.sessionCommands.allowedSenders;
export function isSessionCommandSenderAllowed(sender: string): boolean {
return SESSION_COMMAND_ALLOWED_SENDERS.has(sender);
}
// Delta handoff: cross-provider session continuity with probe + fallback
export const DELTA_HANDOFF_ENABLED = CONFIG.deltaHandoff.enabled;
export const DELTA_HANDOFF_CANARY_GROUPS = CONFIG.deltaHandoff.canaryGroups;
export function isDeltaHandoffEnabledForGroup(groupFolder: string): boolean {
if (!DELTA_HANDOFF_ENABLED) return false;
// If canary groups are specified, only enable for those groups
if (DELTA_HANDOFF_CANARY_GROUPS.size > 0) {
return DELTA_HANDOFF_CANARY_GROUPS.has(groupFolder);
}
return true;
}