LibreChat/api/server/controllers/ContextProjectionController.js
Danny Avila 5701a9da9c
🩹 fix: Codex review on context projection (G1 guard, IDOR, recount, summary)
- Guard `currentActive` against a stale window: a model/window switch on the
  current branch left the live snapshot outranking the projection (G1 didn't
  fire). Now defers to the projection unless streaming or the window matches.
- Scope branch lookups to the authenticated user (`getMessages` filter +
  injected `userId`) — was loading any conversation by id (IDOR).
- Recount messages with no stored `tokenCount` via the tokenizer instead of
  charging 0, so snapshot-less/imported histories don't under-report.
- Fall back (null) for already-summarized branches rather than projecting from
  the full raw parent chain (the next call would send summary + tail); the
  client's summary-baseline-aware estimate handles them until a follow-up
  replays the summary boundary.
2026-06-16 16:52:02 -04:00

31 lines
1.1 KiB
JavaScript

const { logger } = require('@librechat/data-schemas');
const { resolveContextProjection } = require('@librechat/api');
const db = require('~/models');
/**
* Returns a server-side context-usage projection for the viewed branch + config
* (agents SDK, no model call) — powers the gauge for snapshot-less branches and
* after a model/window switch. Resolution lives in `@librechat/api`; this
* controller only injects request-scoped model accessors.
* @param {ServerRequest} req
* @param {ServerResponse} res
*/
async function contextProjectionController(req, res) {
try {
const params = req.body ?? {};
if (!params.conversationId || !params.messageId) {
res.json(null);
return;
}
const projection = await resolveContextProjection(
{ userId: req.user?.id, getMessages: db.getMessages, getAgent: db.getAgent },
params,
);
res.json(projection ?? null);
} catch (error) {
logger.error('[contextProjectionController]', error);
res.status(500).json({ error: 'Failed to resolve context projection' });
}
}
module.exports = contextProjectionController;