refactor: remove SERVICE_AGENT_TYPE legacy constant

SERVICE_AGENT_TYPE was always 'claude-code' in the unified service,
making it a misleading constant. Each group already has its own
agentType field.

- Removed SERVICE_AGENT_TYPE from config.ts
- Session functions now accept agentType parameter (default: 'claude-code')
- Task scheduler uses task-level agent_type for token rotation decisions
- All fallback defaults changed to 'claude-code' literal
- Logging uses 'unified' instead of the misleading type
This commit is contained in:
Eyejoker
2026-03-30 23:10:48 +09:00
parent 5562e30ce1
commit 4a5edaceb6
12 changed files with 56 additions and 54 deletions

View File

@@ -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<void> {
timestamp,
requiresTriggerInt,
isMainInt,
SERVICE_AGENT_TYPE,
'claude-code',
);
db.close();

View File

@@ -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');

View File

@@ -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,

View File

@@ -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. */

View File

@@ -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<string, string> {
.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

View File

@@ -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<void> {
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,

View File

@@ -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',
);

View File

@@ -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',

View File

@@ -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;
}

View File

@@ -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(

View File

@@ -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,

View File

@@ -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',