feat: implement MAGI 3-agent arbiter system for deadlock resolution
Introduces a third agent role (arbiter) that is summoned on-demand when owner and reviewer reach a deadlock (same verdict 3+ rounds). Architecture: - 3 Discord bots: owner (codex), reviewer (claude), arbiter (claude/codex) - Arbiter is NOT always-on — only invoked when deadlock detected - Arbiter renders binding verdict: PROCEED/REVISE/RESET/ESCALATE - Non-escalate verdicts reset round_trip_count and resume ping-pong - Backward compatible: ARBITER_AGENT_TYPE unset = existing 2-agent mode Changes across 13 source files + 7 test files: - types.ts: PairedRoomRole += 'arbiter', new statuses, ArbiterVerdict type - config.ts: ARBITER_AGENT_TYPE, ARBITER_SERVICE_ID, ARBITER_DEADLOCK_THRESHOLD - db.ts: schema migration (arbiter columns in channel_owner + paired_tasks) - service-routing.ts: arbiter_service_id in lease - room-role-context.ts: arbiter role detection - paired-execution-context.ts: deadlock->arbiter, verdict handling - message-runtime.ts: arbiter turn routing, cursor, sender labeling - message-agent-executor.ts: arbiter mode, failover - agent-runner.ts + environment.ts: arbiter container mode - platform-prompts.ts: arbiter prompt loading New files: - prompts/arbiter-paired-room.md: arbiter system prompt - src/arbiter-context.ts: builds conversation context for arbiter judgment
This commit is contained in:
@@ -15,6 +15,8 @@ const PAIRED_ROOM_PROMPT_FILES: Record<AgentType, string> = {
|
||||
codex: 'claude-paired-room.md',
|
||||
};
|
||||
|
||||
const ARBITER_PROMPT_FILE = 'arbiter-paired-room.md';
|
||||
|
||||
export function getPlatformPromptsDir(projectRoot = process.cwd()): string {
|
||||
return path.join(projectRoot, 'prompts');
|
||||
}
|
||||
@@ -60,3 +62,22 @@ export function readPairedRoomPrompt(
|
||||
const prompt = fs.readFileSync(promptPath, 'utf-8').trim();
|
||||
return prompt || undefined;
|
||||
}
|
||||
|
||||
export function getArbiterPromptPath(
|
||||
projectRoot = process.cwd(),
|
||||
): string {
|
||||
return path.join(
|
||||
getPlatformPromptsDir(projectRoot),
|
||||
ARBITER_PROMPT_FILE,
|
||||
);
|
||||
}
|
||||
|
||||
export function readArbiterPrompt(
|
||||
projectRoot = process.cwd(),
|
||||
): string | undefined {
|
||||
const promptPath = getArbiterPromptPath(projectRoot);
|
||||
if (!fs.existsSync(promptPath)) return undefined;
|
||||
|
||||
const prompt = fs.readFileSync(promptPath, 'utf-8').trim();
|
||||
return prompt || undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user