feat: support room-level reviewer and arbiter agent selection

This commit is contained in:
ejclaw
2026-04-15 23:47:46 +09:00
parent 1846d59d2f
commit a59813dee6
15 changed files with 618 additions and 52 deletions

View File

@@ -250,6 +250,32 @@ describe('paired execution context', () => {
});
});
it('uses room role context agent overrides when creating a paired task', () => {
preparePairedExecutionContext({
group,
chatJid: 'dc:test',
runId: 'run-room-overrides',
roomRoleContext: {
...ownerContext,
ownerAgentType: 'codex',
reviewerAgentType: 'codex',
reviewerServiceId: config.CODEX_REVIEW_SERVICE_ID,
arbiterAgentType: 'claude-code',
},
hasHumanMessage: true,
});
expect(db.createPairedTask).toHaveBeenCalledWith(
expect.objectContaining({
owner_service_id: config.CODEX_MAIN_SERVICE_ID,
reviewer_service_id: config.CODEX_REVIEW_SERVICE_ID,
owner_agent_type: 'codex',
reviewer_agent_type: 'codex',
arbiter_agent_type: 'claude-code',
}),
);
});
it('persists stable role-slot service shadow instead of the transient failover owner lease', () => {
preparePairedExecutionContext({
group,
@@ -562,6 +588,49 @@ describe('paired execution context', () => {
delete process.env.EJCLAW_UNSAFE_HOST_PAIRED_MODE;
});
it('honors room-level reviewer agent overrides for unsafe host reviewer runtime env', () => {
process.env.EJCLAW_UNSAFE_HOST_PAIRED_MODE = '1';
vi.mocked(db.getLatestOpenPairedTaskForChat).mockReturnValue(
buildPairedTask({
status: 'review_ready',
review_requested_at: '2026-03-28T00:00:00.000Z',
reviewer_agent_type: 'codex',
}),
);
vi.mocked(db.getPairedTaskById).mockReturnValue(
buildPairedTask({
status: 'review_ready',
review_requested_at: '2026-03-28T00:00:00.000Z',
reviewer_agent_type: 'codex',
}),
);
vi.mocked(
pairedWorkspaceManager.prepareReviewerWorkspaceForExecution,
).mockReturnValue({
workspace: buildWorkspace('reviewer', '/tmp/paired/task-1/reviewer'),
autoRefreshed: false,
});
const result = preparePairedExecutionContext({
group,
chatJid: 'dc:test',
runId: 'run-host-reviewer-room-override',
roomRoleContext: {
...reviewerContext,
reviewerAgentType: 'codex',
},
});
expect(result?.envOverrides).toMatchObject({
EJCLAW_WORK_DIR: '/tmp/paired/task-1/reviewer',
EJCLAW_PAIRED_ROLE: 'reviewer',
EJCLAW_UNSAFE_HOST_PAIRED_MODE: '1',
});
expect(result?.envOverrides.EJCLAW_CLAUDE_REVIEWER_READONLY).toBeUndefined();
expect(result?.envOverrides.EJCLAW_REVIEWER_RUNTIME).toBeUndefined();
delete process.env.EJCLAW_UNSAFE_HOST_PAIRED_MODE;
});
it('completePairedExecutionContext logs without error', () => {
completePairedExecutionContext({
taskId: 'task-1',