[Web] Enable Quota System for AI Features (#31544)

* feat: migrate from aiErrorAssist naming for disabling AI features to aiFeatures.enabled to avoid confusion

feat: keep aiErrorAssistant as setting on user object until migration is run

* feat: migrate writefull.enabled unset to instead use promotionSet false

* feat: updating to use quota based system for AI usage

* feat: hide relevant sections of quota system behind split test

* feat: ship onAiFreeTrial instead of free quota amount to project meta

* fix: renaming splitTestEnabledForUser to featureFlagEnabledForUser

* fix: v1_personal should have free trial amount of ai quota

* fix: onAiFreeTrial in projectController should account for anonymous users with no features

* feat: fixing marketing exports for ai quotas

* feat: update features epoch

* feat: move to quota tiers, and map tier to numeric allowance within rateLimiters

GitOrigin-RevId: 17763447965aae5777053b783d2601517bfe6b12
This commit is contained in:
Jimmy Domagala-Tang
2026-02-23 09:23:38 -05:00
committed by Copybot
parent 8fb5b0ed05
commit 92463fb3e2
18 changed files with 112 additions and 14 deletions
@@ -510,8 +510,10 @@ async function projectListPage(req, res, next) {
logger.error({ err: error }, 'Failed to get individual subscription')
}
const aiBlocked = !(await _canUseAIAssist(user))
const hasAiAssist = await _userHasAIAssist(user)
const aiBlocked =
Features.hasFeature('saas') && !(await _canUseAIAssist(user))
const hasAiAssist =
Features.hasFeature('saas') && (await _userHasAIAssist(user))
await SplitTestHandler.promises.getAssignment(
req,
@@ -899,11 +901,13 @@ function _hasActiveFilter(filters) {
)
}
// todo: quota clean-up: rename function and vars
async function _userHasAIAssist(user) {
// Check if the user has AI Assist enabled via Overleaf
if (user.features?.aiErrorAssistant) {
// Check if the user has a non free trial version of our AI features
if (user.features?.aiUsageQuota === Settings.aiFeatures.unlimitedQuota) {
return true
}
// Check if the user has AI Assist enabled via Writefull
const { isPremium: hasAiAssistViaWritefull } =
await UserGetter.promises.getWritefullData(user._id)
@@ -918,6 +922,7 @@ async function _userHasAIAssist(user) {
// It does NOT determine if the user has AI Assist enabled
async function _canUseAIAssist(user) {
// Check if the assistant has been manually disabled by the user
// post https://github.com/overleaf/internal/pull/31273 we can rely on user.aiFeatures being populated
if (user.aiFeatures?.enabled === false) {
return false
}