refactor: split message executor target preparation (#190)

This commit is contained in:
Eyejoker
2026-05-29 19:52:20 +09:00
committed by GitHub
parent 87eb2f0488
commit e876a509a5
2 changed files with 466 additions and 263 deletions

View File

@@ -109,11 +109,6 @@
"maxFunctionLines": 314, "maxFunctionLines": 314,
"owner": "main service entrypoint hotspot" "owner": "main service entrypoint hotspot"
}, },
"src/message-agent-executor-target.ts": {
"maxFunctionLines": 274,
"maxComplexity": 48,
"owner": "message executor target hotspot"
},
"src/message-agent-executor.test.ts": { "src/message-agent-executor.test.ts": {
"maxLines": 3847, "maxLines": 3847,
"maxFunctionLines": 2500, "maxFunctionLines": 2500,

View File

@@ -16,24 +16,24 @@ import {
markPairedTurnRunning, markPairedTurnRunning,
} from './db.js'; } from './db.js';
import { createScopedLogger } from './logger.js'; import { createScopedLogger } from './logger.js';
import { buildRoomMemoryBriefing } from './sqlite-memory-store.js'; import { resolveExecutionTarget } from './message-runtime-rules.js';
import type { PreparedPairedExecutionContext } from './paired-execution-context.js'; import type { PreparedPairedExecutionContext } from './paired-execution-context.js';
import { preparePairedExecutionContext } from './paired-execution-context.js'; import { preparePairedExecutionContext } from './paired-execution-context.js';
import { import {
resolveRuntimePairedTurnIdentity, resolveRuntimePairedTurnIdentity,
type PairedTurnIdentity, type PairedTurnIdentity,
} from './paired-turn-identity.js'; } from './paired-turn-identity.js';
import { resolveExecutionTarget } from './message-runtime-rules.js';
import { buildRoomRoleContext } from './room-role-context.js'; import { buildRoomRoleContext } from './room-role-context.js';
import { getEffectiveChannelLease } from './service-routing.js'; import { getEffectiveChannelLease } from './service-routing.js';
import { buildRoomMemoryBriefing } from './sqlite-memory-store.js';
import { getTokenCount } from './token-rotation.js'; import { getTokenCount } from './token-rotation.js';
import { writeGroupsSnapshot, writeTasksSnapshot } from './agent-runner.js';
import type { import type {
AgentType, AgentType,
PairedRoomRole, PairedRoomRole,
RegisteredGroup, RegisteredGroup,
RoomRoleContext, RoomRoleContext,
} from './types.js'; } from './types.js';
import { writeGroupsSnapshot, writeTasksSnapshot } from './agent-runner.js';
interface ExecutionTargetDeps { interface ExecutionTargetDeps {
assistantName: string; assistantName: string;
@@ -79,77 +79,201 @@ export interface PreparedMessageAgentExecution {
clearRoleSdkSessions: () => void; clearRoleSdkSessions: () => void;
} }
type CurrentChannelLease = ReturnType<typeof getEffectiveChannelLease>;
type LatestOpenPairedTask = ReturnType<typeof getLatestOpenPairedTaskForChat>;
type ResolvedExecutionTarget = ReturnType<typeof resolveExecutionTarget>;
interface ResolvedRoleExecutionState {
reviewerMode: boolean;
arbiterMode: boolean;
effectiveGroup: RegisteredGroup;
isClaudeCodeAgent: boolean;
forceFreshClaudeReviewerSession: boolean;
shouldPersistSession: boolean;
currentSessionId: string | undefined;
provider: 'claude' | 'codex';
}
interface RuntimePairedTurnResolution {
preparedTurnTaskUpdatedAt: string | undefined;
runtimePairedTurnIdentity: PairedTurnIdentity | undefined;
}
export async function prepareMessageAgentExecutionTarget( export async function prepareMessageAgentExecutionTarget(
deps: ExecutionTargetDeps, deps: ExecutionTargetDeps,
args: ExecutionTargetArgs, args: ExecutionTargetArgs,
): Promise<PreparedMessageAgentExecution> { ): Promise<PreparedMessageAgentExecution> {
const { group, chatJid, runId, startSeq, endSeq } = args; return new MessageAgentExecutionTargetPreparer(deps, args).run();
const isMain = group.isMain === true; }
const sessions = deps.getSessions();
const currentLease = getEffectiveChannelLease(chatJid); class MessageAgentExecutionTargetPreparer {
const pairedTask = currentLease.reviewer_agent_type constructor(
? getLatestOpenPairedTaskForChat(chatJid) private readonly deps: ExecutionTargetDeps,
private readonly args: ExecutionTargetArgs,
) {}
async run(): Promise<PreparedMessageAgentExecution> {
const currentLease = getEffectiveChannelLease(this.args.chatJid);
const pairedTask = this.resolveLatestPairedTask(currentLease);
const executionTarget = this.resolveTarget(currentLease, pairedTask);
const roleState = this.resolveRoleExecutionState(executionTarget);
const memoryBriefing = await this.resolveMemoryBriefing(
roleState.currentSessionId,
);
this.writeAgentSnapshots(executionTarget.roleAgentPlan.ownerAgentType);
const canRetryClaudeCredentials = this.canRetryClaudeCredentials(
roleState.isClaudeCodeAgent,
);
const roomRoleContext = buildRoomRoleContext(
currentLease,
executionTarget.effectiveServiceId,
executionTarget.activeRole,
);
const pairedExecutionContext = this.preparePairedContext(roomRoleContext);
const runtimeTurn = this.resolveRuntimePairedTurnIdentity({
pairedTask,
pairedExecutionContext,
activeRole: executionTarget.activeRole,
});
this.validateRuntimePairedTurnIdentity({
pairedTask,
pairedExecutionContext,
activeRole: executionTarget.activeRole,
runtimeTurn,
});
this.markRuntimePairedTurnRunning(
runtimeTurn.runtimePairedTurnIdentity,
executionTarget,
);
this.applyPairedEnvOverrides({
pairedExecutionContext,
runtimePairedTurnIdentity: runtimeTurn.runtimePairedTurnIdentity,
activeRole: executionTarget.activeRole,
isClaudeCodeAgent: roleState.isClaudeCodeAgent,
});
const log = this.createExecutionLogger({
currentLease,
pairedTask,
executionTarget,
roleState,
runtimePairedTurnIdentity: runtimeTurn.runtimePairedTurnIdentity,
});
return {
currentLease,
pairedTask,
activeRole: executionTarget.activeRole,
effectiveServiceId: executionTarget.effectiveServiceId,
effectiveAgentType: executionTarget.effectiveAgentType,
sessionFolder: executionTarget.sessionFolder,
reviewerMode: roleState.reviewerMode,
arbiterMode: roleState.arbiterMode,
effectiveGroup: roleState.effectiveGroup,
isClaudeCodeAgent: roleState.isClaudeCodeAgent,
forceFreshClaudeReviewerSession:
roleState.forceFreshClaudeReviewerSession,
shouldPersistSession: roleState.shouldPersistSession,
currentSessionId: roleState.currentSessionId,
provider: roleState.provider,
memoryBriefing,
canRetryClaudeCredentials,
roomRoleContext,
pairedExecutionContext,
runtimePairedTurnIdentity: runtimeTurn.runtimePairedTurnIdentity,
log,
clearRoleSdkSessions: this.createClearRoleSdkSessions(
pairedExecutionContext,
log,
),
};
}
private resolveLatestPairedTask(
currentLease: CurrentChannelLease,
): LatestOpenPairedTask | null {
return currentLease.reviewer_agent_type
? getLatestOpenPairedTaskForChat(this.args.chatJid)
: null; : null;
const executionTarget = resolveExecutionTarget({ }
private resolveTarget(
currentLease: CurrentChannelLease,
pairedTask: LatestOpenPairedTask | null,
): ResolvedExecutionTarget {
return resolveExecutionTarget({
lease: currentLease, lease: currentLease,
pairedTaskStatus: pairedTask?.status, pairedTaskStatus: pairedTask?.status,
groupFolder: group.folder, groupFolder: this.args.group.folder,
groupAgentType: group.agentType, groupAgentType: this.args.group.agentType,
forcedRole: args.forcedRole, forcedRole: this.args.forcedRole,
forcedAgentType: args.forcedAgentType, forcedAgentType: this.args.forcedAgentType,
}); });
const { }
inferredRole,
canHonorForcedRole, private resolveRoleExecutionState(
activeRole, executionTarget: ResolvedExecutionTarget,
effectiveServiceId, ): ResolvedRoleExecutionState {
reviewerServiceId, const reviewerMode = executionTarget.activeRole === 'reviewer';
arbiterServiceId, const arbiterMode = executionTarget.activeRole === 'arbiter';
roleAgentPlan,
configuredAgentType,
effectiveAgentType,
sessionFolder,
} = executionTarget;
const reviewerMode = activeRole === 'reviewer';
const arbiterMode = activeRole === 'arbiter';
const effectiveGroup = const effectiveGroup =
effectiveAgentType !== roleAgentPlan.ownerAgentType executionTarget.effectiveAgentType !==
? { ...group, agentType: effectiveAgentType } executionTarget.roleAgentPlan.ownerAgentType
: group; ? {
const isClaudeCodeAgent = effectiveAgentType === 'claude-code'; ...this.args.group,
const unsafeHostPairedMode = isUnsafeHostPairedModeEnabled(); agentType: executionTarget.effectiveAgentType,
}
: this.args.group;
const isClaudeCodeAgent =
executionTarget.effectiveAgentType === 'claude-code';
const forceFreshClaudeReviewerSession = const forceFreshClaudeReviewerSession =
reviewerMode && reviewerMode &&
isClaudeCodeAgent && isClaudeCodeAgent &&
unsafeHostPairedMode && isUnsafeHostPairedModeEnabled() &&
shouldForceFreshClaudeReviewerSessionInUnsafeHostMode(); shouldForceFreshClaudeReviewerSessionInUnsafeHostMode();
const shouldPersistSession = const shouldPersistSession =
activeRole !== 'arbiter' && executionTarget.activeRole !== 'arbiter' &&
!args.forcedAgentType && !this.args.forcedAgentType &&
!forceFreshClaudeReviewerSession; !forceFreshClaudeReviewerSession;
const storedSessionId = sessions[sessionFolder]; const storedSessionId =
this.deps.getSessions()[executionTarget.sessionFolder];
if (forceFreshClaudeReviewerSession && storedSessionId) { if (forceFreshClaudeReviewerSession && storedSessionId) {
deps.clearSession(sessionFolder); this.deps.clearSession(executionTarget.sessionFolder);
} }
const currentSessionId = const currentSessionId =
activeRole === 'arbiter' || executionTarget.activeRole === 'arbiter' ||
args.forcedAgentType || this.args.forcedAgentType ||
forceFreshClaudeReviewerSession forceFreshClaudeReviewerSession
? undefined ? undefined
: storedSessionId; : storedSessionId;
const provider = isClaudeCodeAgent ? 'claude' : 'codex'; return {
const memoryBriefing = currentSessionId reviewerMode,
? undefined arbiterMode,
: await buildRoomMemoryBriefing({ effectiveGroup,
groupFolder: group.folder, isClaudeCodeAgent,
groupName: group.name, forceFreshClaudeReviewerSession,
}).catch(() => undefined); shouldPersistSession,
currentSessionId,
provider: isClaudeCodeAgent ? 'claude' : 'codex',
};
}
const tasks = getAllTasks(roleAgentPlan.ownerAgentType); private async resolveMemoryBriefing(
currentSessionId: string | undefined,
): Promise<string | undefined> {
if (currentSessionId) {
return undefined;
}
return buildRoomMemoryBriefing({
groupFolder: this.args.group.folder,
groupName: this.args.group.name,
}).catch(() => undefined);
}
private writeAgentSnapshots(ownerAgentType: AgentType): void {
const tasks = getAllTasks(ownerAgentType);
writeTasksSnapshot( writeTasksSnapshot(
group.folder, this.args.group.folder,
isMain, this.args.group.isMain === true,
tasks.map((task) => ({ tasks.map((task) => ({
id: task.id, id: task.id,
groupFolder: task.group_folder, groupFolder: task.group_folder,
@@ -160,196 +284,280 @@ export async function prepareMessageAgentExecutionTarget(
next_run: task.next_run, next_run: task.next_run,
})), })),
); );
writeGroupsSnapshot( writeGroupsSnapshot(
group.folder, this.args.group.folder,
isMain, this.args.group.isMain === true,
listAvailableGroups(deps.getRoomBindings()), listAvailableGroups(this.deps.getRoomBindings()),
); );
}
const claudeTokenCount = isClaudeCodeAgent ? getTokenCount() : 0; private canRetryClaudeCredentials(isClaudeCodeAgent: boolean): boolean {
const canRetryClaudeCredentials = isClaudeCodeAgent && claudeTokenCount > 0; return isClaudeCodeAgent && getTokenCount() > 0;
const roomRoleContext = buildRoomRoleContext( }
currentLease,
effectiveServiceId, private preparePairedContext(
activeRole, roomRoleContext: RoomRoleContext | undefined,
); ): PreparedPairedExecutionContext | undefined {
const pairedExecutionContext = preparePairedExecutionContext({ return preparePairedExecutionContext({
group, group: this.args.group,
chatJid, chatJid: this.args.chatJid,
runId, runId: this.args.runId,
roomRoleContext, roomRoleContext,
hasHumanMessage: args.hasHumanMessage, hasHumanMessage: this.args.hasHumanMessage,
pairedTurnIdentity: args.pairedTurnIdentity, pairedTurnIdentity: this.args.pairedTurnIdentity,
}); });
const preparedTurnTaskUpdatedAt = pairedExecutionContext }
? (pairedExecutionContext.claimedTaskUpdatedAt ??
pairedExecutionContext.task.updated_at) private resolveRuntimePairedTurnIdentity(args: {
pairedTask: LatestOpenPairedTask | null;
pairedExecutionContext: PreparedPairedExecutionContext | undefined;
activeRole: PairedRoomRole;
}): RuntimePairedTurnResolution {
const preparedTurnTaskUpdatedAt = args.pairedExecutionContext
? (args.pairedExecutionContext.claimedTaskUpdatedAt ??
args.pairedExecutionContext.task.updated_at)
: undefined; : undefined;
const runtimePairedTurnIdentity = const runtimePairedTurnIdentity =
args.pairedTurnIdentity ?? this.args.pairedTurnIdentity ??
(pairedExecutionContext this.resolveCurrentRuntimePairedTurnIdentity({
? resolveRuntimePairedTurnIdentity({ ...args,
taskId: pairedExecutionContext.task.id, preparedTurnTaskUpdatedAt,
});
return { preparedTurnTaskUpdatedAt, runtimePairedTurnIdentity };
}
private resolveCurrentRuntimePairedTurnIdentity(args: {
pairedTask: LatestOpenPairedTask | null;
pairedExecutionContext: PreparedPairedExecutionContext | undefined;
activeRole: PairedRoomRole;
preparedTurnTaskUpdatedAt: string | undefined;
}): PairedTurnIdentity | undefined {
if (args.pairedExecutionContext) {
return resolveRuntimePairedTurnIdentity({
taskId: args.pairedExecutionContext.task.id,
taskUpdatedAt: taskUpdatedAt:
preparedTurnTaskUpdatedAt ?? pairedExecutionContext.task.updated_at, args.preparedTurnTaskUpdatedAt ??
role: activeRole, args.pairedExecutionContext.task.updated_at,
taskStatus: pairedExecutionContext.task.status, role: args.activeRole,
hasHumanMessage: args.hasHumanMessage, taskStatus: args.pairedExecutionContext.task.status,
}) hasHumanMessage: this.args.hasHumanMessage,
: pairedTask });
? resolveRuntimePairedTurnIdentity({
taskId: pairedTask.id,
taskUpdatedAt: pairedTask.updated_at,
role: activeRole,
taskStatus: pairedTask.status,
hasHumanMessage: args.hasHumanMessage,
})
: undefined);
if (runtimePairedTurnIdentity) {
if (runtimePairedTurnIdentity.role !== activeRole) {
throw new Error(
`Paired turn ${runtimePairedTurnIdentity.turnId} cannot execute as ${activeRole}`,
);
} }
if ( if (!args.pairedTask) {
pairedExecutionContext && return undefined;
runtimePairedTurnIdentity.taskId !== pairedExecutionContext.task.id
) {
throw new Error(
`Paired turn ${runtimePairedTurnIdentity.turnId} task_id does not match the prepared execution context`,
);
} }
if ( return resolveRuntimePairedTurnIdentity({
pairedExecutionContext && taskId: args.pairedTask.id,
runtimePairedTurnIdentity.taskUpdatedAt !== preparedTurnTaskUpdatedAt taskUpdatedAt: args.pairedTask.updated_at,
) { role: args.activeRole,
throw new Error( taskStatus: args.pairedTask.status,
`Paired turn ${runtimePairedTurnIdentity.turnId} task_updated_at does not match the prepared execution context`, hasHumanMessage: this.args.hasHumanMessage,
);
}
if (
!pairedExecutionContext &&
pairedTask &&
runtimePairedTurnIdentity.taskId !== pairedTask.id
) {
throw new Error(
`Paired turn ${runtimePairedTurnIdentity.turnId} task_id does not match the latest paired task`,
);
}
if (
!pairedExecutionContext &&
pairedTask &&
runtimePairedTurnIdentity.taskUpdatedAt !== pairedTask.updated_at
) {
throw new Error(
`Paired turn ${runtimePairedTurnIdentity.turnId} task_updated_at does not match the latest paired task`,
);
}
}
if (runtimePairedTurnIdentity) {
markPairedTurnRunning({
turnIdentity: runtimePairedTurnIdentity,
executorServiceId: effectiveServiceId,
executorAgentType: effectiveAgentType,
runId,
}); });
} }
if (pairedExecutionContext && !args.forcedAgentType) { private validateRuntimePairedTurnIdentity(args: {
const roleConfig = getRoleModelConfig(activeRole); pairedTask: LatestOpenPairedTask | null;
if (roleConfig.model) { pairedExecutionContext: PreparedPairedExecutionContext | undefined;
const modelKey = isClaudeCodeAgent ? 'CLAUDE_MODEL' : 'CODEX_MODEL'; activeRole: PairedRoomRole;
pairedExecutionContext.envOverrides[modelKey] = roleConfig.model; runtimeTurn: RuntimePairedTurnResolution;
}): void {
const { runtimePairedTurnIdentity, preparedTurnTaskUpdatedAt } =
args.runtimeTurn;
if (!runtimePairedTurnIdentity) {
return;
} }
if (roleConfig.effort) { if (runtimePairedTurnIdentity.role !== args.activeRole) {
const effortKey = isClaudeCodeAgent ? 'CLAUDE_EFFORT' : 'CODEX_EFFORT'; throw new Error(
pairedExecutionContext.envOverrides[effortKey] = roleConfig.effort; `Paired turn ${runtimePairedTurnIdentity.turnId} cannot execute as ${args.activeRole}`,
);
} }
} this.validatePreparedContextTurnIdentity({
if (pairedExecutionContext && runtimePairedTurnIdentity) { pairedExecutionContext: args.pairedExecutionContext,
pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TURN_ID = runtimePairedTurnIdentity,
runtimePairedTurnIdentity.turnId; preparedTurnTaskUpdatedAt,
pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TURN_ROLE = });
runtimePairedTurnIdentity.role; this.validateLatestTaskTurnIdentity({
pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TURN_INTENT = pairedTask: args.pairedTask,
runtimePairedTurnIdentity.intentKind; pairedExecutionContext: args.pairedExecutionContext,
pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TASK_UPDATED_AT = runtimePairedTurnIdentity,
runtimePairedTurnIdentity.taskUpdatedAt; });
} }
private validatePreparedContextTurnIdentity(args: {
pairedExecutionContext: PreparedPairedExecutionContext | undefined;
runtimePairedTurnIdentity: PairedTurnIdentity;
preparedTurnTaskUpdatedAt: string | undefined;
}): void {
if (!args.pairedExecutionContext) {
return;
}
if (
args.runtimePairedTurnIdentity.taskId !==
args.pairedExecutionContext.task.id
) {
throw new Error(
`Paired turn ${args.runtimePairedTurnIdentity.turnId} task_id does not match the prepared execution context`,
);
}
if (
args.runtimePairedTurnIdentity.taskUpdatedAt !==
args.preparedTurnTaskUpdatedAt
) {
throw new Error(
`Paired turn ${args.runtimePairedTurnIdentity.turnId} task_updated_at does not match the prepared execution context`,
);
}
}
private validateLatestTaskTurnIdentity(args: {
pairedTask: LatestOpenPairedTask | null;
pairedExecutionContext: PreparedPairedExecutionContext | undefined;
runtimePairedTurnIdentity: PairedTurnIdentity;
}): void {
if (args.pairedExecutionContext || !args.pairedTask) {
return;
}
if (args.runtimePairedTurnIdentity.taskId !== args.pairedTask.id) {
throw new Error(
`Paired turn ${args.runtimePairedTurnIdentity.turnId} task_id does not match the latest paired task`,
);
}
if (
args.runtimePairedTurnIdentity.taskUpdatedAt !==
args.pairedTask.updated_at
) {
throw new Error(
`Paired turn ${args.runtimePairedTurnIdentity.turnId} task_updated_at does not match the latest paired task`,
);
}
}
private markRuntimePairedTurnRunning(
runtimePairedTurnIdentity: PairedTurnIdentity | undefined,
executionTarget: ResolvedExecutionTarget,
): void {
if (!runtimePairedTurnIdentity) {
return;
}
markPairedTurnRunning({
turnIdentity: runtimePairedTurnIdentity,
executorServiceId: executionTarget.effectiveServiceId,
executorAgentType: executionTarget.effectiveAgentType,
runId: this.args.runId,
});
}
private applyPairedEnvOverrides(args: {
pairedExecutionContext: PreparedPairedExecutionContext | undefined;
runtimePairedTurnIdentity: PairedTurnIdentity | undefined;
activeRole: PairedRoomRole;
isClaudeCodeAgent: boolean;
}): void {
this.applyRoleModelEnvOverrides(args);
this.applyRuntimePairedTurnEnvOverrides(args);
}
private applyRoleModelEnvOverrides(args: {
pairedExecutionContext: PreparedPairedExecutionContext | undefined;
activeRole: PairedRoomRole;
isClaudeCodeAgent: boolean;
}): void {
if (!args.pairedExecutionContext || this.args.forcedAgentType) {
return;
}
const roleConfig = getRoleModelConfig(args.activeRole);
if (roleConfig.model) {
const modelKey = args.isClaudeCodeAgent ? 'CLAUDE_MODEL' : 'CODEX_MODEL';
args.pairedExecutionContext.envOverrides[modelKey] = roleConfig.model;
}
if (roleConfig.effort) {
const effortKey = args.isClaudeCodeAgent
? 'CLAUDE_EFFORT'
: 'CODEX_EFFORT';
args.pairedExecutionContext.envOverrides[effortKey] = roleConfig.effort;
}
}
private applyRuntimePairedTurnEnvOverrides(args: {
pairedExecutionContext: PreparedPairedExecutionContext | undefined;
runtimePairedTurnIdentity: PairedTurnIdentity | undefined;
}): void {
if (!args.pairedExecutionContext || !args.runtimePairedTurnIdentity) {
return;
}
args.pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TURN_ID =
args.runtimePairedTurnIdentity.turnId;
args.pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TURN_ROLE =
args.runtimePairedTurnIdentity.role;
args.pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TURN_INTENT =
args.runtimePairedTurnIdentity.intentKind;
args.pairedExecutionContext.envOverrides.EJCLAW_PAIRED_TASK_UPDATED_AT =
args.runtimePairedTurnIdentity.taskUpdatedAt;
}
private createExecutionLogger(args: {
currentLease: CurrentChannelLease;
pairedTask: LatestOpenPairedTask | null;
executionTarget: ResolvedExecutionTarget;
roleState: ResolvedRoleExecutionState;
runtimePairedTurnIdentity: PairedTurnIdentity | undefined;
}): ReturnType<typeof createScopedLogger> {
const log = createScopedLogger({ const log = createScopedLogger({
chatJid, chatJid: this.args.chatJid,
groupName: group.name, groupName: this.args.group.name,
groupFolder: group.folder, groupFolder: this.args.group.folder,
runId, runId: this.args.runId,
messageSeqStart: startSeq ?? undefined, messageSeqStart: this.args.startSeq ?? undefined,
messageSeqEnd: endSeq ?? undefined, messageSeqEnd: this.args.endSeq ?? undefined,
role: activeRole, role: args.executionTarget.activeRole,
serviceId: effectiveServiceId, serviceId: args.executionTarget.effectiveServiceId,
turnId: runtimePairedTurnIdentity?.turnId, turnId: args.runtimePairedTurnIdentity?.turnId,
}); });
log.info( log.info(
{ {
forcedRole: args.forcedRole, forcedRole: this.args.forcedRole,
forcedAgentType: args.forcedAgentType ?? null, forcedAgentType: this.args.forcedAgentType ?? null,
inferredRole, inferredRole: args.executionTarget.inferredRole,
canHonorForcedRole, canHonorForcedRole: args.executionTarget.canHonorForcedRole,
pairedTaskId: pairedTask?.id, pairedTaskId: args.pairedTask?.id,
pairedTaskStatus: pairedTask?.status, pairedTaskStatus: args.pairedTask?.status,
configuredAgentType, configuredAgentType: args.executionTarget.configuredAgentType,
effectiveServiceId, effectiveServiceId: args.executionTarget.effectiveServiceId,
effectiveAgentType, effectiveAgentType: args.executionTarget.effectiveAgentType,
groupAgentType: group.agentType, groupAgentType: this.args.group.agentType,
configuredReviewerAgentType: REVIEWER_AGENT_TYPE, configuredReviewerAgentType: REVIEWER_AGENT_TYPE,
configuredArbiterAgentType: ARBITER_AGENT_TYPE, configuredArbiterAgentType: ARBITER_AGENT_TYPE,
reviewerServiceId, reviewerServiceId: args.executionTarget.reviewerServiceId,
arbiterServiceId, arbiterServiceId: args.executionTarget.arbiterServiceId,
reviewerAgentType: currentLease.reviewer_agent_type, reviewerAgentType: args.currentLease.reviewer_agent_type,
arbiterAgentType: currentLease.arbiter_agent_type, arbiterAgentType: args.currentLease.arbiter_agent_type,
reviewerMode, reviewerMode: args.roleState.reviewerMode,
arbiterMode, arbiterMode: args.roleState.arbiterMode,
sessionFolder, sessionFolder: args.executionTarget.sessionFolder,
resumedSession: currentSessionId ?? null, resumedSession: args.roleState.currentSessionId ?? null,
}, },
'Resolved execution target for agent turn', 'Resolved execution target for agent turn',
); );
return log;
}
const clearRoleSdkSessions = (): void => { private createClearRoleSdkSessions(
pairedExecutionContext: PreparedPairedExecutionContext | undefined,
log: ReturnType<typeof createScopedLogger>,
): () => void {
return () => {
const configDir = pairedExecutionContext?.envOverrides?.CLAUDE_CONFIG_DIR; const configDir = pairedExecutionContext?.envOverrides?.CLAUDE_CONFIG_DIR;
if (!configDir) return; if (!configDir) return;
for (const sdkDir of ['.claude', '.codex']) { for (const sdkDir of ['.claude', '.codex']) {
const sessionsDir = path.join(configDir, sdkDir, 'sessions'); const sessionsDir = path.join(configDir, sdkDir, 'sessions');
if (fs.existsSync(sessionsDir)) { if (fs.existsSync(sessionsDir)) {
fs.rmSync(sessionsDir, { recursive: true, force: true }); fs.rmSync(sessionsDir, { recursive: true, force: true });
log.info({ sessionsDir }, 'Cleared SDK sessions for fresh Claude turn'); log.info(
{ sessionsDir },
'Cleared SDK sessions for fresh Claude turn',
);
} }
} }
}; };
}
return {
currentLease,
pairedTask,
activeRole,
effectiveServiceId,
effectiveAgentType,
sessionFolder,
reviewerMode,
arbiterMode,
effectiveGroup,
isClaudeCodeAgent,
forceFreshClaudeReviewerSession,
shouldPersistSession,
currentSessionId,
provider,
memoryBriefing,
canRetryClaudeCredentials,
roomRoleContext,
pairedExecutionContext,
runtimePairedTurnIdentity,
log,
clearRoleSdkSessions,
};
} }