import { prisma } from "./db"; // ── Platform limits ──────────────────────────────────────────────────────────── /** Max change requests an agent may create per rolling hour. */ export const MAX_REQUESTS_PER_HOUR = 15; /** Max agents a single human account may own. */ export const MAX_AGENTS_PER_USER = 5; /** Pending-request cap bounds (human-configurable per agent). */ export const MIN_PENDING_LIMIT = 1; export const MAX_PENDING_LIMIT = 10; export const DEFAULT_PENDING_LIMIT = 5; /** Request expiry bounds, in seconds. */ export const DEFAULT_EXPIRY_SECONDS = 30 * 60; // 30 minutes export const MIN_EXPIRY_SECONDS = 60; // 1 minute export const MAX_EXPIRY_SECONDS = 12 * 60 * 60; // 12 hours /** Auto-delete retention bounds, in days. */ export const MIN_AUTO_DELETE_DAYS = 7; export const DEFAULT_AUTO_DELETE_DAYS = 30; // ── Pure clamps ──────────────────────────────────────────────────────────────── export function clampPendingLimit(value: number): number { if (!Number.isFinite(value)) return DEFAULT_PENDING_LIMIT; return Math.min(MAX_PENDING_LIMIT, Math.max(MIN_PENDING_LIMIT, Math.trunc(value))); } export function clampExpirySeconds(value: number | undefined | null): number { if (value === undefined || value === null || !Number.isFinite(value)) { return DEFAULT_EXPIRY_SECONDS; } return Math.min(MAX_EXPIRY_SECONDS, Math.max(MIN_EXPIRY_SECONDS, Math.trunc(value))); } export function clampAutoDeleteDays(value: number): number { if (!Number.isFinite(value)) return DEFAULT_AUTO_DELETE_DAYS; return Math.max(MIN_AUTO_DELETE_DAYS, Math.trunc(value)); } // ── Limit checks (DB-backed) ──────────────────────────────────────────────────── export type LimitResult = { allowed: true } | { allowed: false; reason: string }; /** An agent may create at most MAX_REQUESTS_PER_HOUR requests per rolling hour. */ export async function checkAgentHourlyLimit(agentId: number): Promise { const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000); const count = await prisma.changeRequest.count({ where: { agentId, createdAt: { gte: oneHourAgo } }, }); if (count >= MAX_REQUESTS_PER_HOUR) { return { allowed: false, reason: `Rate limit reached: an agent may create at most ${MAX_REQUESTS_PER_HOUR} requests per hour`, }; } return { allowed: true }; } /** An agent may have at most `maxPendingRequests` requests in PENDING state. */ export async function checkAgentPendingLimit( agentId: number, maxPendingRequests: number, ): Promise { const count = await prisma.changeRequest.count({ where: { agentId, state: "PENDING" }, }); if (count >= maxPendingRequests) { return { allowed: false, reason: `Pending limit reached: this agent may have at most ${maxPendingRequests} pending requests at a time`, }; } return { allowed: true }; } /** A human may own at most MAX_AGENTS_PER_USER agents. */ export async function checkAgentCountLimit(userId: number): Promise { const count = await prisma.agent.count({ where: { ownerId: userId } }); if (count >= MAX_AGENTS_PER_USER) { return { allowed: false, reason: `Agent limit reached: a human may own at most ${MAX_AGENTS_PER_USER} agents`, }; } return { allowed: true }; }