import { AGENT_MODEL_MAX_LENGTH, AGENT_STATUS_MAX_SUBAGENTS, AGENT_TYPE_MAX_LENGTH, type AgentSubagentSnapshot } from './agent-status-types' import { normalizeOptionalField } from './agent-status-field-normalization' const CODEX_SUBAGENT_ID_MAX_LENGTH = 64 export type CodexSubagentRoster = Map type TrackedCodexSubagent = { agentType?: string model?: string state: 'working' | 'waiting' startedAt: number } export function upsertCodexSubagent( roster: CodexSubagentRoster, id: string, fields: { agentType?: string model?: string state: 'working' | 'waiting' }, now: number ): void { const normalizedId = id.trim() if (normalizedId.length === 0 || normalizedId.length > CODEX_SUBAGENT_ID_MAX_LENGTH) { return } const agentType = normalizeOptionalField(fields.agentType, AGENT_TYPE_MAX_LENGTH) const model = normalizeOptionalField(fields.model, AGENT_MODEL_MAX_LENGTH) const existing = roster.get(normalizedId) if (existing) { existing.agentType = agentType ?? existing.agentType existing.model = model ?? existing.model existing.state = fields.state return } if (roster.size >= AGENT_STATUS_MAX_SUBAGENTS) { return } roster.set(normalizedId, { agentType, model, state: fields.state, startedAt: now }) } export function finishCodexSubagent(roster: CodexSubagentRoster, id: string): void { roster.delete(id.trim()) } export function seedCodexSubagentRoster( roster: CodexSubagentRoster, snapshots: readonly AgentSubagentSnapshot[] ): void { for (const snapshot of snapshots) { if (snapshot.state !== 'working' && snapshot.state !== 'waiting') { continue } upsertCodexSubagent( roster, snapshot.id, { agentType: snapshot.agentType, model: snapshot.model, state: snapshot.state }, snapshot.startedAt ) } } export function codexRosterToSnapshots( roster: CodexSubagentRoster | undefined ): AgentSubagentSnapshot[] | undefined { if (!roster || roster.size === 0) { return undefined } const snapshots = Array.from(roster, ([id, tracked]) => ({ id, agentType: tracked.agentType, model: tracked.model, state: tracked.state, startedAt: tracked.startedAt })) snapshots.sort((a, b) => a.startedAt - b.startedAt || a.id.localeCompare(b.id)) return snapshots } export function codexRosterEffectiveState( roster: CodexSubagentRoster | undefined, leadState: 'working' | 'waiting' | 'done' ): 'working' | 'waiting' | 'done' { if (!roster || roster.size === 0) { return leadState } for (const tracked of roster.values()) { if (tracked.state === 'waiting') { return 'waiting' } } return leadState === 'done' ? 'working' : leadState }