package repo import ( "context" "time" "github.com/agentmail/gateway/internal/db" ) // ---------- 新建会话速率限制 ---------- // // Agent 可以用 name@path.new 开一串新会话,每条都是全新预算 —— // 速率限制只压住「短时间内暴开」这个滥用形态,过一个窗口自动恢复。 // ErrSessionRateLimited 表示该 Agent 短时间内新建会话过多。 // (目前未使用,直接返回 retryAfter 由 handler 构造 429 响应) const ( sessionRateWindow = time.Hour sessionRateLimit = 20 ) // AllowNewSession 供 handler 调用:Agent 新建会话前先过速率限制。 // 人类用户不走这条路径(手工点「新建邮件」的频率天然受限)。 // 返回 (allowed, retryAfter)。DB 不可用时放行。 func AllowNewSession(ctx context.Context, agentName string) (bool, int) { if agentName == "" { return true, 0 } return RateLimitCheckAndRecord(ctx, "session:"+agentName, sessionRateWindow, sessionRateLimit) } // ReleaseNewSession 建会话失败后归还名额。 // DB-backed 方式下记账在 AllowNewSession 里已完成,失败时需手动删除最近一条。 func ReleaseNewSession(ctx context.Context, agentName string) { if agentName == "" { return } bucket := "session:" + agentName // 删掉最近一条(建会话失败,那次不该占名额) _, _ = db.DB.ExecContext(ctx, `DELETE FROM rate_limits WHERE bucket = $1 AND ts = ( SELECT MAX(ts) FROM rate_limits WHERE bucket = $1 )`, bucket) } // SessionRateLimit 暴露窗口内的新建上限,供错误文案使用。 func SessionRateLimit() int { return sessionRateLimit }