import { z } from 'zod' const id = z.string().min(1).max(128) const unique = (rows: string[]) => new Set(rows).size === rows.length const labelIds = z.array(id).max(20).refine(unique, 'Duplicate labels') export const agentLabelBodySchema = z.object({ name: z.string().trim().min(1).max(64), color: z.enum(['primary', 'success', 'warning', 'destructive', 'secondary', 'info']).nullable().optional() }).strict() export const patchAgentLabelSchema = agentLabelBodySchema.partial().refine((body) => Object.keys(body).length > 0, 'Supply a label change') export const putAgentLabelsSchema = z.object({ label_ids: labelIds }).strict() export const agentLabelFilterSchema = z.object({ label_ids: z.preprocess((value) => typeof value === 'string' ? value.split(',').filter(Boolean) : value, labelIds.optional()) }).passthrough() const selector = z.object({ agent_ids: z.array(id).min(1).max(100).refine(unique, 'Duplicate agents').optional(), label_ids: labelIds.refine((rows) => rows.length > 0).optional() }).strict() .refine((body) => Boolean(body.agent_ids) !== Boolean(body.label_ids), 'Choose agent IDs or label IDs') export const previewLabelAssignmentSchema = z.object({ selector, mode: z.enum(['add', 'replace']), set_ids: z.array(id).max(100).refine(unique, 'Duplicate sets') }).strict() export const applyLabelAssignmentSchema = previewLabelAssignmentSchema.extend({ expected: z.array(z.object({ agent_id: id, generation: z.number().int().positive().max(Number.MAX_SAFE_INTEGER) }).strict()).min(1).max(100).refine((rows) => unique(rows.map((row) => row.agent_id)), 'Duplicate expected agents') }) export type PreviewLabelAssignment = z.infer export type ApplyLabelAssignment = z.infer export type AgentLabel = { id: string; name: string; color: string | null; created_at: string } export type LabelAssignmentPreview = { mode: 'add' | 'replace'; items: { agent_id: string; generation: number; previous_set_ids: string[]; set_ids: string[]; changed: boolean }[]; total: number }