refactor: read default room owner from room settings
This commit is contained in:
16
src/db.ts
16
src/db.ts
@@ -913,6 +913,22 @@ export function _initTestDatabaseFromFile(dbPath: string): void {
|
|||||||
createSchema(db);
|
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).
|
* Store chat metadata only (no message content).
|
||||||
* Used for all chats to enable group discovery without storing sensitive content.
|
* Used for all chats to enable group discovery without storing sensitive content.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { beforeEach, describe, expect, it } from 'vitest';
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
_setStoredRoomOwnerAgentTypeForTests,
|
||||||
_initTestDatabase,
|
_initTestDatabase,
|
||||||
setExplicitRoomMode,
|
setExplicitRoomMode,
|
||||||
setRegisteredGroup,
|
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', () => {
|
it('creates a same-service reviewer lease when explicit tribunal is runnable on a solo registration', () => {
|
||||||
setRegisteredGroup('dc:explicit-tribunal', {
|
setRegisteredGroup('dc:explicit-tribunal', {
|
||||||
name: 'Explicit Tribunal Claude',
|
name: 'Explicit Tribunal Claude',
|
||||||
@@ -145,4 +193,13 @@ describe('service-routing global failover', () => {
|
|||||||
explicit: false,
|
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,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ import {
|
|||||||
getAllChannelOwnerLeases,
|
getAllChannelOwnerLeases,
|
||||||
getEffectiveRuntimeRoomMode,
|
getEffectiveRuntimeRoomMode,
|
||||||
getRegisteredAgentTypesForJid,
|
getRegisteredAgentTypesForJid,
|
||||||
|
getStoredRoomSettings,
|
||||||
setChannelOwnerLease,
|
setChannelOwnerLease,
|
||||||
type ChannelOwnerLeaseRow,
|
type ChannelOwnerLeaseRow,
|
||||||
} from './db.js';
|
} from './db.js';
|
||||||
import { logger } from './logger.js';
|
import { logger } from './logger.js';
|
||||||
|
import type { AgentType } from './types.js';
|
||||||
|
|
||||||
export interface EffectiveChannelLease {
|
export interface EffectiveChannelLease {
|
||||||
chat_jid: string;
|
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 types = getRegisteredAgentTypesForJid(chatJid);
|
||||||
const hasClaude = types.includes('claude-code');
|
const hasClaude = types.includes('claude-code');
|
||||||
const hasCodex = types.includes('codex');
|
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 roomMode = getEffectiveRuntimeRoomMode(chatJid);
|
||||||
|
const ownerAgentType = resolveDefaultOwnerAgentType(chatJid);
|
||||||
|
const ownerServiceId = ownerAgentType
|
||||||
|
? getServiceIdForAgentType(ownerAgentType)
|
||||||
|
: CLAUDE_SERVICE_ID;
|
||||||
|
|
||||||
if (roomMode === 'tribunal') {
|
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 {
|
return {
|
||||||
chat_jid: chatJid,
|
chat_jid: chatJid,
|
||||||
owner_service_id: ownerServiceId,
|
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 {
|
return {
|
||||||
chat_jid: chatJid,
|
chat_jid: chatJid,
|
||||||
owner_service_id: CLAUDE_SERVICE_ID,
|
owner_service_id: ownerServiceId,
|
||||||
reviewer_service_id: null,
|
reviewer_service_id: null,
|
||||||
arbiter_service_id: null,
|
arbiter_service_id: null,
|
||||||
activated_at: null,
|
activated_at: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user