From 60408cc1faded7cbe1344a3209c7664ad6928d6c Mon Sep 17 00:00:00 2001 From: Eyejoker Date: Tue, 31 Mar 2026 04:26:48 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20arbiter=20session=20collision=20?= =?UTF-8?q?=E2=80=94=20separate=20session=20folder=20+=20always=20fresh=20?= =?UTF-8?q?session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolveSessionFolder now always returns unique folder for arbiter (prevents sharing session with owner when both use same agent type) - Arbiter sessionId forced to undefined to prevent resume attempts --- src/db.ts | 12 ++++++++++++ src/message-agent-executor.ts | 5 ++++- src/message-runtime-rules.ts | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/db.ts b/src/db.ts index 4647fa7..7b3aeaa 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1137,6 +1137,18 @@ export function getLastHumanMessageTimestamp(chatJid: string): string | null { return row?.timestamp ?? null; } +export function getLastHumanMessageSender(chatJid: string): string | null { + const row = db + .prepare( + `SELECT sender FROM messages + WHERE chat_jid = ? AND is_bot_message = 0 AND is_from_me = 0 + AND content != '' AND content IS NOT NULL + ORDER BY timestamp DESC, seq DESC LIMIT 1`, + ) + .get(chatJid) as { sender: string } | undefined; + return row?.sender ?? null; +} + export function getLastHumanMessageContent(chatJid: string): string | null { const row = db .prepare( diff --git a/src/message-agent-executor.ts b/src/message-agent-executor.ts index 2db193b..a9f5a29 100644 --- a/src/message-agent-executor.ts +++ b/src/message-agent-executor.ts @@ -14,8 +14,10 @@ import { listAvailableGroups } from './available-groups.js'; import { createServiceHandoff, getAllTasks, + getLastHumanMessageSender, getLatestOpenPairedTaskForChat, getLatestTurnNumber, + getPairedTaskById, insertPairedTurnOutput, } from './db.js'; import { GroupQueue } from './group-queue.js'; @@ -128,7 +130,8 @@ export async function runAgentForGroup( activeRole, group.agentType, ); - const sessionId = sessions[sessionFolder]; + // Arbiter always starts fresh — never resume a previous session + const sessionId = activeRole === 'arbiter' ? undefined : sessions[sessionFolder]; const memoryBriefing = sessionId ? undefined : await buildRoomMemoryBriefing({ diff --git a/src/message-runtime-rules.ts b/src/message-runtime-rules.ts index 201c0c3..e52ef1a 100644 --- a/src/message-runtime-rules.ts +++ b/src/message-runtime-rules.ts @@ -89,6 +89,8 @@ export function resolveSessionFolder( role: 'owner' | 'reviewer' | 'arbiter', groupAgentType: AgentType | undefined, ): string { + // Arbiter always gets a separate session — must never share with owner/reviewer + if (role === 'arbiter') return `${groupFolder}:arbiter`; const effectiveType = resolveEffectiveAgentType(role, groupAgentType); const groupDefault: AgentType = groupAgentType || 'claude-code'; if (effectiveType === groupDefault) return groupFolder;