feat: support room-level reviewer and arbiter agent selection
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import { Database } from 'bun:sqlite';
|
||||
|
||||
import { OWNER_AGENT_TYPE, REVIEWER_AGENT_TYPE } from '../config.js';
|
||||
import {
|
||||
ARBITER_AGENT_TYPE,
|
||||
OWNER_AGENT_TYPE,
|
||||
REVIEWER_AGENT_TYPE,
|
||||
} from '../config.js';
|
||||
import { isValidGroupFolder } from '../group-folder.js';
|
||||
import { logger } from '../logger.js';
|
||||
import { type RoleAgentPlan, resolveRoleAgentPlan } from '../role-agent-plan.js';
|
||||
import type { AgentType, RegisteredGroup, RoomMode } from '../types.js';
|
||||
|
||||
export type RoomModeSource = 'explicit' | 'inferred';
|
||||
@@ -58,8 +63,12 @@ export interface LegacyRoomMigrationPlan {
|
||||
export interface SyncRoomRoleOverridesOptions {
|
||||
ownerAgentConfig?: RegisteredGroup['agentConfig'];
|
||||
ownerCreatedAt?: string;
|
||||
reviewerAgentType?: AgentType;
|
||||
reviewerAgentConfig?: RegisteredGroup['agentConfig'];
|
||||
reviewerCreatedAt?: string;
|
||||
arbiterAgentType?: AgentType | null;
|
||||
arbiterAgentConfig?: RegisteredGroup['agentConfig'];
|
||||
arbiterCreatedAt?: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
@@ -207,14 +216,32 @@ export function getStoredRoomRowsFromDatabase(
|
||||
.filter((row): row is StoredRoomSettings => Boolean(row));
|
||||
}
|
||||
|
||||
export function resolveStoredRoomRoleAgentPlan(
|
||||
database: Database,
|
||||
stored: StoredRoomSettings,
|
||||
): RoleAgentPlan {
|
||||
const overrides = getStoredRoomRoleOverrideRows(database, stored.chatJid);
|
||||
const ownerAgentType =
|
||||
stored.ownerAgentType ?? overrides.get('owner')?.agentType ?? OWNER_AGENT_TYPE;
|
||||
|
||||
return resolveRoleAgentPlan({
|
||||
paired: stored.roomMode === 'tribunal',
|
||||
groupAgentType: ownerAgentType,
|
||||
configuredReviewer:
|
||||
overrides.get('reviewer')?.agentType ?? REVIEWER_AGENT_TYPE,
|
||||
configuredArbiter: overrides.get('arbiter')?.agentType ?? ARBITER_AGENT_TYPE,
|
||||
});
|
||||
}
|
||||
|
||||
export function buildRegisteredGroupFromStoredSettings(
|
||||
database: Database,
|
||||
stored: StoredRoomSettings,
|
||||
requestedAgentType?: AgentType,
|
||||
): (RegisteredGroup & { jid: string }) | undefined {
|
||||
const capabilityTypes = resolveStoredRoomCapabilityTypes(database, stored);
|
||||
const rolePlan = resolveStoredRoomRoleAgentPlan(database, stored);
|
||||
const ownerAgentType =
|
||||
stored.ownerAgentType ||
|
||||
rolePlan.ownerAgentType ||
|
||||
(capabilityTypes.length > 0
|
||||
? inferOwnerAgentTypeFromRegisteredAgentTypes(capabilityTypes)
|
||||
: undefined);
|
||||
@@ -233,8 +260,12 @@ export function buildRegisteredGroupFromStoredSettings(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const role: 'owner' | 'reviewer' =
|
||||
ownerAgentType === resolvedAgentType ? 'owner' : 'reviewer';
|
||||
const role: 'owner' | 'reviewer' | 'arbiter' =
|
||||
ownerAgentType === resolvedAgentType
|
||||
? 'owner'
|
||||
: rolePlan.reviewerAgentType === resolvedAgentType
|
||||
? 'reviewer'
|
||||
: 'arbiter';
|
||||
const capabilityMetadata = getStoredRoomRoleOverrideRows(
|
||||
database,
|
||||
stored.chatJid,
|
||||
@@ -273,24 +304,17 @@ export function resolveStoredRoomCapabilityTypes(
|
||||
database: Database,
|
||||
stored: StoredRoomSettings,
|
||||
): AgentType[] {
|
||||
const overrides = getStoredRoomRoleOverrideRows(database, stored.chatJid);
|
||||
const ownerAgentType =
|
||||
stored.ownerAgentType ??
|
||||
overrides.get('owner')?.agentType ??
|
||||
OWNER_AGENT_TYPE;
|
||||
|
||||
if (stored.modeSource !== 'explicit') {
|
||||
return inferStoredRoomCapabilityTypes(database, stored);
|
||||
}
|
||||
|
||||
const types = new Set<AgentType>([ownerAgentType]);
|
||||
if (stored.roomMode === 'tribunal') {
|
||||
const reviewerAgentType =
|
||||
overrides.get('reviewer')?.agentType ??
|
||||
(ownerAgentType === REVIEWER_AGENT_TYPE
|
||||
? OWNER_AGENT_TYPE
|
||||
: REVIEWER_AGENT_TYPE);
|
||||
types.add(reviewerAgentType);
|
||||
const rolePlan = resolveStoredRoomRoleAgentPlan(database, stored);
|
||||
const types = new Set<AgentType>([rolePlan.ownerAgentType]);
|
||||
if (stored.roomMode === 'tribunal' && rolePlan.reviewerAgentType) {
|
||||
types.add(rolePlan.reviewerAgentType);
|
||||
}
|
||||
if (stored.roomMode === 'tribunal' && rolePlan.arbiterAgentType) {
|
||||
types.add(rolePlan.arbiterAgentType);
|
||||
}
|
||||
return [...types];
|
||||
}
|
||||
@@ -526,11 +550,19 @@ export function syncRoomRoleOverridesForRoom(
|
||||
});
|
||||
|
||||
if (roomMode === 'tribunal') {
|
||||
const reviewerAgentType =
|
||||
ownerAgentType === REVIEWER_AGENT_TYPE
|
||||
const existingReviewerOverride = existingOverrides.get('reviewer');
|
||||
const previousDefaultReviewerAgentType =
|
||||
existingOwnerOverride?.agentType === REVIEWER_AGENT_TYPE
|
||||
? OWNER_AGENT_TYPE
|
||||
: REVIEWER_AGENT_TYPE;
|
||||
const existingReviewerOverride = existingOverrides.get('reviewer');
|
||||
const computedReviewerAgentType =
|
||||
ownerAgentType === REVIEWER_AGENT_TYPE ? OWNER_AGENT_TYPE : REVIEWER_AGENT_TYPE;
|
||||
const reviewerAgentType =
|
||||
options.reviewerAgentType ??
|
||||
(existingReviewerOverride &&
|
||||
existingReviewerOverride.agentType !== previousDefaultReviewerAgentType
|
||||
? existingReviewerOverride.agentType
|
||||
: computedReviewerAgentType);
|
||||
upsertRoomRoleOverride(database, chatJid, {
|
||||
role: 'reviewer',
|
||||
agentType: reviewerAgentType,
|
||||
@@ -547,6 +579,40 @@ export function syncRoomRoleOverridesForRoom(
|
||||
now,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
||||
const existingArbiterOverride = existingOverrides.get('arbiter');
|
||||
const arbiterAgentType =
|
||||
options.arbiterAgentType ??
|
||||
existingArbiterOverride?.agentType ??
|
||||
ARBITER_AGENT_TYPE ??
|
||||
null;
|
||||
|
||||
if (arbiterAgentType) {
|
||||
upsertRoomRoleOverride(database, chatJid, {
|
||||
role: 'arbiter',
|
||||
agentType: arbiterAgentType,
|
||||
agentConfig:
|
||||
options.arbiterAgentConfig ??
|
||||
(existingArbiterOverride?.agentType === arbiterAgentType
|
||||
? existingArbiterOverride.agentConfig
|
||||
: undefined),
|
||||
createdAt:
|
||||
(existingArbiterOverride?.agentType === arbiterAgentType
|
||||
? existingArbiterOverride.createdAt
|
||||
: undefined) ??
|
||||
options.arbiterCreatedAt ??
|
||||
now,
|
||||
updatedAt: now,
|
||||
});
|
||||
} else {
|
||||
database
|
||||
.prepare(
|
||||
`DELETE FROM room_role_overrides
|
||||
WHERE chat_jid = ?
|
||||
AND role = 'arbiter'`,
|
||||
)
|
||||
.run(chatJid);
|
||||
}
|
||||
} else {
|
||||
database
|
||||
.prepare(
|
||||
@@ -555,6 +621,13 @@ export function syncRoomRoleOverridesForRoom(
|
||||
AND role = 'reviewer'`,
|
||||
)
|
||||
.run(chatJid);
|
||||
database
|
||||
.prepare(
|
||||
`DELETE FROM room_role_overrides
|
||||
WHERE chat_jid = ?
|
||||
AND role = 'arbiter'`,
|
||||
)
|
||||
.run(chatJid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
normalizeStoredAgentType,
|
||||
resolveAssignedRoomFolder,
|
||||
resolveStoredRoomCapabilityTypes,
|
||||
resolveStoredRoomRoleAgentPlan,
|
||||
syncRoomRoleOverridesForRoom,
|
||||
updateStoredRoomMetadata,
|
||||
upsertRoomRoleOverride,
|
||||
@@ -31,6 +32,8 @@ export interface AssignRoomInput {
|
||||
name: string;
|
||||
roomMode?: RoomMode;
|
||||
ownerAgentType?: AgentType;
|
||||
reviewerAgentType?: AgentType;
|
||||
arbiterAgentType?: AgentType | null;
|
||||
folder?: string;
|
||||
isMain?: boolean;
|
||||
workDir?: string;
|
||||
@@ -233,6 +236,8 @@ export function assignRoomInDatabase(
|
||||
syncRoomRoleOverridesForRoom(database, chatJid, roomMode, ownerAgentType, {
|
||||
ownerAgentConfig: input.ownerAgentConfig,
|
||||
ownerCreatedAt: input.addedAt ?? now,
|
||||
reviewerAgentType: input.reviewerAgentType,
|
||||
arbiterAgentType: input.arbiterAgentType,
|
||||
updatedAt: input.addedAt ?? now,
|
||||
});
|
||||
})();
|
||||
@@ -294,6 +299,14 @@ export function getStoredRoomSettingsFromDatabase(
|
||||
return getStoredRoomSettingsRowFromDatabase(database, chatJid);
|
||||
}
|
||||
|
||||
export function getStoredRoomRoleAgentPlanFromDatabase(
|
||||
database: Database,
|
||||
chatJid: string,
|
||||
): ReturnType<typeof resolveStoredRoomRoleAgentPlan> | undefined {
|
||||
const stored = getStoredRoomSettingsRowFromDatabase(database, chatJid);
|
||||
return stored ? resolveStoredRoomRoleAgentPlan(database, stored) : undefined;
|
||||
}
|
||||
|
||||
function getStoredRoomModeRowFromDatabase(
|
||||
database: Database,
|
||||
chatJid: string,
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
getExplicitRoomModeFromDatabase,
|
||||
getRegisteredAgentTypesForJidFromDatabase,
|
||||
getRegisteredGroupFromDatabase,
|
||||
getStoredRoomRoleAgentPlanFromDatabase,
|
||||
getStoredRoomSettingsFromDatabase,
|
||||
setExplicitRoomModeInDatabase,
|
||||
setRegisteredGroupForTestsInDatabase,
|
||||
@@ -354,6 +355,14 @@ export function getStoredRoomSettings(
|
||||
return getStoredRoomSettingsFromDatabase(db, chatJid);
|
||||
}
|
||||
|
||||
export function getStoredRoomRoleAgentPlan(
|
||||
chatJid: string,
|
||||
): ReturnType<typeof getStoredRoomRoleAgentPlanFromDatabase> {
|
||||
const db = getDatabaseIfInitialized();
|
||||
if (!db) return undefined;
|
||||
return getStoredRoomRoleAgentPlanFromDatabase(db, chatJid);
|
||||
}
|
||||
|
||||
export function getExplicitRoomMode(chatJid: string): RoomMode | undefined {
|
||||
return getExplicitRoomModeFromDatabase(requireDatabase(), chatJid);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user