import type { CharacterSummary } from "../config/character-card.js"; import { ERROR_MAX_MESSAGES_INVALID } from "../shared/messages.js"; interface GroupChatInfo { groupChatId: string; name: string | null; createdAt: string; groupMaxMessages: number; } export interface RoundState { roundMaxMessages: number; usedMessages: number; } interface OnlineCharacterState { sessionId: string; character: CharacterSummary; isStreaming: boolean; handRaised: boolean; } export interface GroupChatState { groupChat: GroupChatInfo; round: RoundState | null; nextSequence: number; characterReservations: Map; onlineCharacters: Map; } interface CreateGroupChatStateOptions { groupChatId: string; createdAt: string; groupMaxMessages: number; } export function createGroupChatState(options: CreateGroupChatStateOptions): GroupChatState { assertValidMaxMessages(options.groupMaxMessages); return { groupChat: { groupChatId: options.groupChatId, name: null, createdAt: options.createdAt, groupMaxMessages: options.groupMaxMessages, }, round: null, nextSequence: 0, characterReservations: new Map(), onlineCharacters: new Map(), }; } export function normalizeGroupChatName(name: string): string | null { return name.replace(/[\r\n]+/g, " ").trim() || null; } export function setGroupChatName(state: GroupChatState, name: string): string | null { const normalizedName = normalizeGroupChatName(name); state.groupChat.name = normalizedName; return normalizedName; } export function setGroupMaxMessages(state: GroupChatState, maxMessages: number): void { assertValidMaxMessages(maxMessages); state.groupChat.groupMaxMessages = maxMessages; } export function setHandRaised(state: GroupChatState, sessionId: string, raised: boolean): void { const character = state.onlineCharacters.get(sessionId); if (character) { character.handRaised = raised; } } export function assertValidMaxMessages(maxMessages: number): void { if (!Number.isSafeInteger(maxMessages) || maxMessages < 0) { throw new Error(ERROR_MAX_MESSAGES_INVALID); } }