refactor: read default room owner from room settings

This commit is contained in:
Eyejoker
2026-03-31 20:48:30 +09:00
parent fc4eaefeda
commit 1fccc37fe8
3 changed files with 108 additions and 34 deletions

View File

@@ -913,6 +913,22 @@ export function _initTestDatabaseFromFile(dbPath: string): void {
createSchema(db);
}
/** @internal - for tests only. */
export function _setStoredRoomOwnerAgentTypeForTests(
chatJid: string,
ownerAgentType: AgentType | null,
): void {
if (!db) {
throw new Error('Database not initialized');
}
db.prepare(
`UPDATE room_settings
SET owner_agent_type = ?,
updated_at = ?
WHERE chat_jid = ?`,
).run(ownerAgentType, new Date().toISOString(), chatJid);
}
/**
* Store chat metadata only (no message content).
* Used for all chats to enable group discovery without storing sensitive content.

View File

@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it } from 'vitest';
import {
_setStoredRoomOwnerAgentTypeForTests,
_initTestDatabase,
setExplicitRoomMode,
setRegisteredGroup,
@@ -108,6 +109,53 @@ describe('service-routing global failover', () => {
});
});
it('uses stored owner agent type when room_settings selects a different owner', () => {
setRegisteredGroup('dc:stored-owner-claude', {
name: 'Stored Owner Claude',
folder: 'stored-owner-claude',
trigger: '@Andy',
added_at: '2024-01-01T00:00:00.000Z',
agentType: 'claude-code',
});
setRegisteredGroup('dc:stored-owner-claude', {
name: 'Stored Owner Claude',
folder: 'stored-owner-claude',
trigger: '@Codex',
added_at: '2024-01-01T00:00:00.000Z',
agentType: 'codex',
});
setExplicitRoomMode('dc:stored-owner-claude', 'single');
_setStoredRoomOwnerAgentTypeForTests(
'dc:stored-owner-claude',
'claude-code',
);
expect(getEffectiveChannelLease('dc:stored-owner-claude')).toMatchObject({
chat_jid: 'dc:stored-owner-claude',
owner_service_id: 'claude',
reviewer_service_id: null,
explicit: false,
});
});
it('falls back to the available service when stored owner agent type is unavailable', () => {
setRegisteredGroup('dc:stored-owner-fallback', {
name: 'Stored Owner Fallback',
folder: 'stored-owner-fallback',
trigger: '@Andy',
added_at: '2024-01-01T00:00:00.000Z',
agentType: 'claude-code',
});
_setStoredRoomOwnerAgentTypeForTests('dc:stored-owner-fallback', 'codex');
expect(getEffectiveChannelLease('dc:stored-owner-fallback')).toMatchObject({
chat_jid: 'dc:stored-owner-fallback',
owner_service_id: 'claude',
reviewer_service_id: null,
explicit: false,
});
});
it('creates a same-service reviewer lease when explicit tribunal is runnable on a solo registration', () => {
setRegisteredGroup('dc:explicit-tribunal', {
name: 'Explicit Tribunal Claude',
@@ -145,4 +193,13 @@ describe('service-routing global failover', () => {
explicit: false,
});
});
it('keeps the legacy claude fallback for chats without room settings', () => {
expect(getEffectiveChannelLease('dc:unregistered')).toMatchObject({
chat_jid: 'dc:unregistered',
owner_service_id: 'claude',
reviewer_service_id: null,
explicit: false,
});
});
});

View File

@@ -14,10 +14,12 @@ import {
getAllChannelOwnerLeases,
getEffectiveRuntimeRoomMode,
getRegisteredAgentTypesForJid,
getStoredRoomSettings,
setChannelOwnerLease,
type ChannelOwnerLeaseRow,
} from './db.js';
import { logger } from './logger.js';
import type { AgentType } from './types.js';
export interface EffectiveChannelLease {
chat_jid: string;
@@ -55,21 +57,44 @@ function normalizeLeaseRow(
};
}
function getDefaultLease(chatJid: string): EffectiveChannelLease {
function getServiceIdForAgentType(agentType: AgentType): string {
return agentType === 'codex' ? CODEX_MAIN_SERVICE_ID : CLAUDE_SERVICE_ID;
}
function inferFallbackOwnerAgentType(
hasClaude: boolean,
hasCodex: boolean,
): AgentType | undefined {
if (hasClaude && hasCodex) return OWNER_AGENT_TYPE;
if (hasCodex) return 'codex';
if (hasClaude) return 'claude-code';
return undefined;
}
function resolveDefaultOwnerAgentType(chatJid: string): AgentType | undefined {
const types = getRegisteredAgentTypesForJid(chatJid);
const hasClaude = types.includes('claude-code');
const hasCodex = types.includes('codex');
const storedOwnerAgentType = getStoredRoomSettings(chatJid)?.ownerAgentType;
if (storedOwnerAgentType === 'claude-code' && hasClaude) {
return 'claude-code';
}
if (storedOwnerAgentType === 'codex' && hasCodex) {
return 'codex';
}
return inferFallbackOwnerAgentType(hasClaude, hasCodex);
}
function getDefaultLease(chatJid: string): EffectiveChannelLease {
const roomMode = getEffectiveRuntimeRoomMode(chatJid);
const ownerAgentType = resolveDefaultOwnerAgentType(chatJid);
const ownerServiceId = ownerAgentType
? getServiceIdForAgentType(ownerAgentType)
: CLAUDE_SERVICE_ID;
if (roomMode === 'tribunal') {
const ownerServiceId =
hasClaude && hasCodex
? OWNER_AGENT_TYPE === 'codex'
? CODEX_MAIN_SERVICE_ID
: CLAUDE_SERVICE_ID
: hasCodex
? CODEX_MAIN_SERVICE_ID
: CLAUDE_SERVICE_ID;
return {
chat_jid: chatJid,
owner_service_id: ownerServiceId,
@@ -81,33 +106,9 @@ function getDefaultLease(chatJid: string): EffectiveChannelLease {
};
}
if (hasCodex) {
return {
chat_jid: chatJid,
owner_service_id: CODEX_MAIN_SERVICE_ID,
reviewer_service_id: null,
arbiter_service_id: null,
activated_at: null,
reason: null,
explicit: false,
};
}
if (hasClaude) {
return {
chat_jid: chatJid,
owner_service_id: CLAUDE_SERVICE_ID,
reviewer_service_id: null,
arbiter_service_id: null,
activated_at: null,
reason: null,
explicit: false,
};
}
return {
chat_jid: chatJid,
owner_service_id: CLAUDE_SERVICE_ID,
owner_service_id: ownerServiceId,
reviewer_service_id: null,
arbiter_service_id: null,
activated_at: null,