diff --git a/setup/register.ts b/setup/register.ts index 954f5fa..0c0b86b 100644 --- a/setup/register.ts +++ b/setup/register.ts @@ -9,7 +9,7 @@ import path from 'path'; import Database from 'better-sqlite3'; -import { SERVICE_AGENT_TYPE, STORE_DIR } from '../src/config.js'; +import { STORE_DIR } from '../src/config.js'; import { isValidGroupFolder } from '../src/group-folder.js'; import { logger } from '../src/logger.js'; import { emitStatus } from './status.js'; @@ -156,7 +156,7 @@ export async function run(args: string[]): Promise { timestamp, requiresTriggerInt, isMainInt, - SERVICE_AGENT_TYPE, + 'claude-code', ); db.close(); diff --git a/src/agent-runner-environment.ts b/src/agent-runner-environment.ts index b2452d7..144df19 100644 --- a/src/agent-runner-environment.ts +++ b/src/agent-runner-environment.ts @@ -530,7 +530,13 @@ export function prepareContainerSessionEnvironment(args: { memoryBriefing?: string; role?: 'reviewer' | 'arbiter'; }): void { - const { sessionDir, chatJid, isMain, memoryBriefing, role = 'reviewer' } = args; + const { + sessionDir, + chatJid, + isMain, + memoryBriefing, + role = 'reviewer', + } = args; const projectRoot = process.cwd(); fs.mkdirSync(sessionDir, { recursive: true }); @@ -546,9 +552,9 @@ export function prepareContainerSessionEnvironment(args: { // Build CLAUDE.md with role-appropriate prompts (reviewer or arbiter) const claudePlatformPrompt = readPlatformPrompt('claude-code', projectRoot); const claudePairedRoomPrompt = isPairedRoomJid(chatJid) - ? (role === 'arbiter' - ? readArbiterPrompt(projectRoot) - : readPairedRoomPrompt('claude-code', projectRoot)) + ? role === 'arbiter' + ? readArbiterPrompt(projectRoot) + : readPairedRoomPrompt('claude-code', projectRoot) : undefined; const globalDir = path.join(GROUPS_DIR, 'global'); const globalClaudeMdPath = path.join(globalDir, 'CLAUDE.md'); diff --git a/src/agent-runner.ts b/src/agent-runner.ts index 1421e7a..a84e0e8 100644 --- a/src/agent-runner.ts +++ b/src/agent-runner.ts @@ -75,7 +75,10 @@ export async function runAgentProcess( // ── Reviewer container mode ───────────────────────────────────── // Reviewers always run inside a Docker container with read-only source // mount for kernel-level write protection. Docker is required. - if (envOverrides?.EJCLAW_REVIEWER_RUNTIME === '1' || envOverrides?.EJCLAW_ARBITER_RUNTIME === '1') { + if ( + envOverrides?.EJCLAW_REVIEWER_RUNTIME === '1' || + envOverrides?.EJCLAW_ARBITER_RUNTIME === '1' + ) { const ownerWorkspaceDir = envOverrides?.EJCLAW_WORK_DIR || group.workDir || process.cwd(); @@ -83,7 +86,10 @@ export async function runAgentProcess( // so the Claude SDK inside the container has platform & paired room prompts. const sessionDir = envOverrides?.CLAUDE_CONFIG_DIR; if (sessionDir) { - const containerRole = envOverrides?.EJCLAW_ARBITER_RUNTIME === '1' ? 'arbiter' as const : 'reviewer' as const; + const containerRole = + envOverrides?.EJCLAW_ARBITER_RUNTIME === '1' + ? ('arbiter' as const) + : ('reviewer' as const); prepareContainerSessionEnvironment({ sessionDir, chatJid: input.chatJid, diff --git a/src/config.ts b/src/config.ts index 1986f38..a8fac3e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,19 +8,12 @@ export const ASSISTANT_NAME = getEnv('ASSISTANT_NAME') || 'Andy'; export const ASSISTANT_HAS_OWN_NUMBER = getEnv('ASSISTANT_HAS_OWN_NUMBER') === 'true'; const ASSISTANT_SLUG = ASSISTANT_NAME.trim().toLowerCase(); -const rawServiceAgentType = getEnv('SERVICE_AGENT_TYPE'); export const SERVICE_ID = getEnv('SERVICE_ID') || ASSISTANT_SLUG; export const CLAUDE_SERVICE_ID = getEnv('CLAUDE_SERVICE_ID') || 'claude'; export const CODEX_MAIN_SERVICE_ID = getEnv('CODEX_MAIN_SERVICE_ID') || 'codex-main'; export const CODEX_REVIEW_SERVICE_ID = getEnv('CODEX_REVIEW_SERVICE_ID') || 'codex-review'; -export const SERVICE_AGENT_TYPE: AgentType = - rawServiceAgentType === 'codex' || rawServiceAgentType === 'claude-code' - ? rawServiceAgentType - : ASSISTANT_SLUG === 'codex' - ? 'codex' - : 'claude-code'; export function normalizeServiceId(serviceId: string): string { if (serviceId === 'codex') { @@ -119,7 +112,7 @@ export const ARBITER_AGENT_TYPE: AgentType | undefined = /** Service ID for the arbiter. Re-uses codex-review bot by default when arbiter is enabled. */ export const ARBITER_SERVICE_ID = ARBITER_AGENT_TYPE - ? (getEnv('ARBITER_SERVICE_ID') || CODEX_REVIEW_SERVICE_ID) + ? getEnv('ARBITER_SERVICE_ID') || CODEX_REVIEW_SERVICE_ID : null; /** Number of consecutive owner↔reviewer round trips before arbiter is auto-requested. */ diff --git a/src/db.ts b/src/db.ts index 5987bcd..8ab2de9 100644 --- a/src/db.ts +++ b/src/db.ts @@ -9,7 +9,6 @@ import { CODEX_REVIEW_SERVICE_ID, DATA_DIR, normalizeServiceId, - SERVICE_AGENT_TYPE, SERVICE_ID, SERVICE_SESSION_SCOPE, STORE_DIR, @@ -729,7 +728,7 @@ function createSchema(database: Database.Database): void { `INSERT INTO sessions_new (group_folder, agent_type, session_id) SELECT group_folder, ?, session_id FROM sessions`, ) - .run(SERVICE_AGENT_TYPE); + .run('claude-code'); database.exec(` DROP TABLE sessions; ALTER TABLE sessions_new RENAME TO sessions; @@ -1151,7 +1150,7 @@ export function hasRecentRestartAnnouncement( export function getOpenWorkItem( chatJid: string, - agentType: AgentType = SERVICE_AGENT_TYPE, + agentType: AgentType = 'claude-code', serviceId: string = SERVICE_SESSION_SCOPE, ): WorkItem | undefined { return db @@ -1176,7 +1175,7 @@ export function createProducedWorkItem(input: { result_payload: string; }): WorkItem { const now = new Date().toISOString(); - const agentType = input.agent_type || SERVICE_AGENT_TYPE; + const agentType = input.agent_type || 'claude-code'; const serviceId = input.service_id || SERVICE_SESSION_SCOPE; const result = db .prepare( @@ -1267,7 +1266,7 @@ export function createTask( task.id, task.group_folder, task.chat_jid, - task.agent_type || SERVICE_AGENT_TYPE, + task.agent_type || 'claude-code', task.ci_provider ?? null, task.ci_metadata ?? null, task.max_duration_ms ?? null, @@ -1596,7 +1595,10 @@ export function setRouterStateForService( // --- Session accessors --- -export function getSession(groupFolder: string): string | undefined { +export function getSession( + groupFolder: string, + agentType: AgentType = 'claude-code', +): string | undefined { const serviceScopedRow = db .prepare( 'SELECT session_id FROM service_sessions WHERE group_folder = ? AND service_id = ?', @@ -1612,26 +1614,33 @@ export function getSession(groupFolder: string): string | undefined { .prepare( 'SELECT session_id FROM sessions WHERE group_folder = ? AND agent_type = ?', ) - .get(groupFolder, SERVICE_AGENT_TYPE) as { session_id: string } | undefined; + .get(groupFolder, agentType) as { session_id: string } | undefined; return row?.session_id; } -export function setSession(groupFolder: string, sessionId: string): void { +export function setSession( + groupFolder: string, + sessionId: string, + agentType: AgentType = 'claude-code', +): void { db.prepare( 'INSERT OR REPLACE INTO service_sessions (group_folder, service_id, session_id) VALUES (?, ?, ?)', ).run(groupFolder, SERVICE_SESSION_SCOPE, sessionId); db.prepare( 'INSERT OR REPLACE INTO sessions (group_folder, agent_type, session_id) VALUES (?, ?, ?)', - ).run(groupFolder, SERVICE_AGENT_TYPE, sessionId); + ).run(groupFolder, agentType, sessionId); } -export function deleteSession(groupFolder: string): void { +export function deleteSession( + groupFolder: string, + agentType: AgentType = 'claude-code', +): void { db.prepare( 'DELETE FROM service_sessions WHERE group_folder = ? AND service_id = ?', ).run(groupFolder, SERVICE_SESSION_SCOPE); db.prepare( 'DELETE FROM sessions WHERE group_folder = ? AND agent_type = ?', - ).run(groupFolder, SERVICE_AGENT_TYPE); + ).run(groupFolder, agentType); } export function deleteAllSessionsForGroup(groupFolder: string): void { @@ -1662,7 +1671,7 @@ export function getAllSessions(): Record { .prepare( 'SELECT group_folder, session_id FROM sessions WHERE agent_type = ?', ) - .all(SERVICE_AGENT_TYPE) as Array<{ + .all('claude-code') as Array<{ group_folder: string; session_id: string; }>; @@ -2125,7 +2134,7 @@ export function listPairedWorkspacesForTask(taskId: string): PairedWorkspace[] { */ export function getLastBotFinalMessage( chatJid: string, - _agentType: AgentType = SERVICE_AGENT_TYPE, + _agentType: AgentType = 'claude-code', limit: number = 1, ): Array<{ content: string; timestamp: string }> { const rows = db diff --git a/src/index.ts b/src/index.ts index 6705b7b..059a017 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,6 @@ import { POLL_INTERVAL, REVIEWER_AGENT_TYPE, SERVICE_ID, - SERVICE_AGENT_TYPE, isSessionCommandSenderAllowed, STATUS_CHANNEL_ID, STATUS_UPDATE_INTERVAL, @@ -194,7 +193,7 @@ function loadState(): void { logger.info( { groupCount: Object.keys(registeredGroups).length, - agentType: SERVICE_AGENT_TYPE, + agentType: 'unified', }, 'State loaded', ); @@ -520,7 +519,7 @@ async function main(): Promise { await startUnifiedDashboard({ assistantName: ASSISTANT_NAME, serviceId: SERVICE_ID, - serviceAgentType: SERVICE_AGENT_TYPE, + serviceAgentType: 'claude-code', statusChannelId: STATUS_CHANNEL_ID, statusUpdateInterval: STATUS_UPDATE_INTERVAL, usageUpdateInterval: USAGE_UPDATE_INTERVAL, diff --git a/src/ipc.ts b/src/ipc.ts index 8043a69..1f27695 100644 --- a/src/ipc.ts +++ b/src/ipc.ts @@ -6,7 +6,6 @@ import { CronExpressionParser } from 'cron-parser'; import { DATA_DIR, IPC_POLL_INTERVAL, - SERVICE_AGENT_TYPE, TIMEZONE, } from './config.js'; import { readJsonFile } from './utils.js'; @@ -433,7 +432,7 @@ export async function processTaskIpc( id: taskId, group_folder: targetFolder, chat_jid: resolvedTargetJid, - agent_type: targetGroupEntry.agentType || SERVICE_AGENT_TYPE, + agent_type: targetGroupEntry.agentType || 'claude-code', ci_provider: data.ci_provider ?? null, ci_metadata: data.ci_metadata ?? null, max_duration_ms: isWatchCiTask({ prompt: data.prompt }) @@ -453,7 +452,7 @@ export async function processTaskIpc( sourceGroup, targetFolder, contextMode, - agentType: targetGroupEntry.agentType || SERVICE_AGENT_TYPE, + agentType: targetGroupEntry.agentType || 'claude-code', }, 'Task created via IPC', ); diff --git a/src/message-runtime.test.ts b/src/message-runtime.test.ts index ed5e8af..01231d9 100644 --- a/src/message-runtime.test.ts +++ b/src/message-runtime.test.ts @@ -14,7 +14,6 @@ vi.mock('./agent-runner.js', () => ({ vi.mock('./config.js', () => ({ DATA_DIR: '/tmp/ejclaw-test-data', SERVICE_ID: 'claude', - SERVICE_AGENT_TYPE: 'claude-code', SERVICE_SESSION_SCOPE: 'claude', CODEX_MAIN_SERVICE_ID: 'codex-main', CODEX_REVIEW_SERVICE_ID: 'codex-review', diff --git a/src/message-runtime.ts b/src/message-runtime.ts index 8ee1a16..e55a7c6 100644 --- a/src/message-runtime.ts +++ b/src/message-runtime.ts @@ -26,7 +26,6 @@ import { CODEX_REVIEW_SERVICE_ID, isSessionCommandSenderAllowed, REVIEWER_AGENT_TYPE, - SERVICE_AGENT_TYPE, SERVICE_ID, } from './config.js'; import { GroupQueue, GroupRunContext } from './group-queue.js'; @@ -75,7 +74,7 @@ export function isDuplicateOfLastBotFinal( } // Get the last bot final message from DB (any bot, not just this service) - const lastMessages = getLastBotFinalMessage(chatJid, SERVICE_AGENT_TYPE, 1); + const lastMessages = getLastBotFinalMessage(chatJid, 'claude-code', 1); if (lastMessages.length === 0) { return false; } diff --git a/src/platform-prompts.ts b/src/platform-prompts.ts index 038a2c8..0e9332d 100644 --- a/src/platform-prompts.ts +++ b/src/platform-prompts.ts @@ -63,13 +63,8 @@ export function readPairedRoomPrompt( return prompt || undefined; } -export function getArbiterPromptPath( - projectRoot = process.cwd(), -): string { - return path.join( - getPlatformPromptsDir(projectRoot), - ARBITER_PROMPT_FILE, - ); +export function getArbiterPromptPath(projectRoot = process.cwd()): string { + return path.join(getPlatformPromptsDir(projectRoot), ARBITER_PROMPT_FILE); } export function readArbiterPrompt( diff --git a/src/service-routing.ts b/src/service-routing.ts index 5238070..e28bf9d 100644 --- a/src/service-routing.ts +++ b/src/service-routing.ts @@ -5,7 +5,6 @@ import { CODEX_REVIEW_SERVICE_ID, OWNER_AGENT_TYPE, REVIEWER_SERVICE_ID_FOR_TYPE, - SERVICE_AGENT_TYPE, SERVICE_ID, isArbiterEnabled, normalizeServiceId, @@ -99,9 +98,7 @@ function getDefaultLease(chatJid: string): EffectiveChannelLease { return { chat_jid: chatJid, owner_service_id: - SERVICE_AGENT_TYPE === 'codex' - ? CODEX_MAIN_SERVICE_ID - : CLAUDE_SERVICE_ID, + CLAUDE_SERVICE_ID, reviewer_service_id: null, arbiter_service_id: null, activated_at: null, diff --git a/src/task-scheduler.ts b/src/task-scheduler.ts index 1cd7a11..9f6dbe9 100644 --- a/src/task-scheduler.ts +++ b/src/task-scheduler.ts @@ -7,7 +7,6 @@ import { getErrorMessage } from './utils.js'; import { ASSISTANT_NAME, SCHEDULER_POLL_INTERVAL, - SERVICE_AGENT_TYPE, TIMEZONE, } from './config.js'; import { @@ -201,7 +200,7 @@ function resolveTaskExecutionContext( const isMain = group.isMain === true; const taskAgentType = - task.agent_type || deps.serviceAgentType || SERVICE_AGENT_TYPE; + task.agent_type || deps.serviceAgentType || 'claude-code'; const sessions = deps.getSessions(); const runtimeTaskId = getTaskRuntimeTaskId(task); const useTaskScopedSession = shouldUseTaskScopedSession(task); @@ -641,7 +640,8 @@ async function runTask( // Try token rotation before suspending if (error) { - const isCodex = SERVICE_AGENT_TYPE === 'codex'; + const effectiveAgentType = context.taskAgentType; + const isCodex = effectiveAgentType === 'codex'; if (isCodex) { const trigger = detectCodexRotationTrigger(error); if (trigger.shouldRotate) { @@ -650,7 +650,7 @@ async function runTask( logger.info( { taskId: task.id, - agent: SERVICE_AGENT_TYPE, + agent: effectiveAgentType, reason: trigger.reason, }, 'Task rate-limited, rotated token — will retry on next schedule', @@ -668,7 +668,7 @@ async function runTask( logger.info( { taskId: task.id, - agent: SERVICE_AGENT_TYPE, + agent: effectiveAgentType, reason: trigger.reason, }, 'Task rate-limited, rotated token — will retry on next schedule',