🪣 fix: Cap Context Projection Workload Before Tokenization (#13910)

* fix: bound context projection workload

* fix: Address context projection CI failures

* fix: Bound context projection database reads

* fix: Sort projection spec imports

* fix: Cap projection body reads with stats
This commit is contained in:
Danny Avila 2026-06-23 08:43:09 -04:00 committed by GitHub
parent 2f800c5b52
commit 77854decdf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 606 additions and 18 deletions

View file

@ -18,7 +18,11 @@ async function contextProjectionController(req, res) {
return;
}
const projection = await resolveContextProjection(
{ userId: req.user?.id, getMessages: db.getMessages },
{
userId: req.user?.id,
getMessages: db.getMessages,
getMessageTextStats: db.getMessageTextStats,
},
params,
);
res.json(projection ?? null);

View file

@ -0,0 +1,19 @@
const rateLimit = require('express-rate-limit');
const { limiterCache } = require('@librechat/api');
const { CONTEXT_PROJECTION_WINDOW = 1, CONTEXT_PROJECTION_MAX = 20 } = process.env;
const windowMs = (parseInt(CONTEXT_PROJECTION_WINDOW, 10) || 1) * 60 * 1000;
const max = parseInt(CONTEXT_PROJECTION_MAX, 10) || 20;
const contextProjectionLimiter = rateLimit({
windowMs,
max,
handler: (_req, res) => {
res.status(429).json({ message: 'Too many context projection requests. Try again later' });
},
keyGenerator: (req) => req.user?.id,
store: limiterCache('context_projection_limiter'),
});
module.exports = contextProjectionLimiter;

View file

@ -9,6 +9,7 @@ const registerLimiter = require('./registerLimiter');
const toolCallLimiter = require('./toolCallLimiter');
const messageLimiters = require('./messageLimiters');
const promptUsageLimiter = require('./promptUsageLimiter');
const contextProjectionLimiter = require('./contextProjectionLimiter');
const verifyEmailLimiter = require('./verifyEmailLimiter');
const resetPasswordLimiter = require('./resetPasswordLimiter');
const twoFactorTempLimiter = require('./twoFactorTempLimiter');
@ -22,6 +23,7 @@ module.exports = {
loginLimiter,
registerLimiter,
toolCallLimiter,
contextProjectionLimiter,
createTTSLimiters,
createSTTLimiters,
verifyEmailLimiter,

View file

@ -4,11 +4,18 @@ const configMiddleware = require('~/server/middleware/config/app');
const endpointController = require('~/server/controllers/EndpointController');
const tokenConfigController = require('~/server/controllers/TokenConfigController');
const contextProjectionController = require('~/server/controllers/ContextProjectionController');
const { contextProjectionLimiter } = require('~/server/middleware/limiters');
const router = express.Router();
/** Auth required for role/tenant-scoped endpoint config resolution. */
router.get('/', requireJwtAuth, endpointController);
router.get('/token-config', requireJwtAuth, configMiddleware, tokenConfigController);
router.post('/context-projection', requireJwtAuth, configMiddleware, contextProjectionController);
router.post(
'/context-projection',
requireJwtAuth,
contextProjectionLimiter,
configMiddleware,
contextProjectionController,
);
module.exports = router;