perf: Optimize First Load of Large Conversations (#14901)

*  perf: Index the Conversation Fetch and Trim the Client Message Projection

*  perf: Memoize the Message Tree per Cache Write

*  perf: Serve Message Reads via the Trimmed Projection and an Ownership Probe

*  perf: Defer Collapsed Disclosure Bodies Until First Expansion

*  perf: Progressively Mount Long Threads from the Scroll Anchor

* 🩹 fix: Address Codex Findings on Retention, Anchoring, and Cache Bounds

* 🩹 fix: Poll the Oversized Export Precondition Through the Progressive Mount

* 🩹 fix: Keep Video Results in the Client Message Projection
This commit is contained in:
Danny Avila 2026-08-16 19:45:21 -04:00 committed by GitHub
parent df5abbb377
commit 1b7e2a4e6a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 1192 additions and 138 deletions

View file

@ -1,5 +1,5 @@
jest.mock('~/models', () => ({
getConvo: jest.fn(),
getConvoOwnership: jest.fn(),
}));
jest.mock('@librechat/api', () => ({
@ -18,7 +18,7 @@ jest.mock('@librechat/data-schemas', () => ({
}));
const validateMessageReq = require('../validateMessageReq');
const { getConvo } = require('~/models');
const { getConvoOwnership } = require('~/models');
const { GenerationJobManager } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
@ -52,7 +52,7 @@ describe('validateMessageReq', () => {
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith({ error: 'Conversation ID mismatch' });
expect(getConvo).not.toHaveBeenCalled();
expect(getConvoOwnership).not.toHaveBeenCalled();
expect(next).not.toHaveBeenCalled();
});
@ -69,7 +69,7 @@ describe('validateMessageReq', () => {
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith({ error: 'Conversation ID mismatch' });
expect(getConvo).not.toHaveBeenCalled();
expect(getConvoOwnership).not.toHaveBeenCalled();
expect(next).not.toHaveBeenCalled();
});
@ -81,11 +81,11 @@ describe('validateMessageReq', () => {
};
const res = createResponse();
const next = jest.fn();
getConvo.mockResolvedValue({ conversationId: 'convo-owned', user: userId });
getConvoOwnership.mockResolvedValue({ conversationId: 'convo-owned', user: userId });
await validateMessageReq(req, res, next);
expect(getConvo).toHaveBeenCalledWith(userId, 'convo-owned');
expect(getConvoOwnership).toHaveBeenCalledWith(userId, 'convo-owned');
expect(next).toHaveBeenCalledTimes(1);
});
@ -98,7 +98,7 @@ describe('validateMessageReq', () => {
};
const res = createResponse();
const next = jest.fn();
getConvo.mockResolvedValue(null);
getConvoOwnership.mockResolvedValue(null);
GenerationJobManager.getJob.mockResolvedValue({
status: 'running',
metadata: { userId, tenantId: 'tenant-a' },
@ -120,7 +120,7 @@ describe('validateMessageReq', () => {
};
const res = createResponse();
const next = jest.fn();
getConvo.mockResolvedValue(null);
getConvoOwnership.mockResolvedValue(null);
GenerationJobManager.getJob.mockResolvedValue({
status: 'running',
metadata: { userId },
@ -141,7 +141,7 @@ describe('validateMessageReq', () => {
};
const res = createResponse();
const next = jest.fn();
getConvo.mockResolvedValue(null);
getConvoOwnership.mockResolvedValue(null);
GenerationJobManager.getJob.mockResolvedValue({
status: 'running',
metadata: { userId: 'another-user' },
@ -163,7 +163,7 @@ describe('validateMessageReq', () => {
};
const res = createResponse();
const next = jest.fn();
getConvo.mockResolvedValue(null);
getConvoOwnership.mockResolvedValue(null);
GenerationJobManager.getJob.mockResolvedValue({
status: 'running',
metadata: { userId, tenantId: 'tenant-b' },
@ -185,7 +185,7 @@ describe('validateMessageReq', () => {
};
const res = createResponse();
const next = jest.fn();
getConvo.mockResolvedValue(null);
getConvoOwnership.mockResolvedValue(null);
await validateMessageReq(req, res, next);
@ -205,7 +205,7 @@ describe('validateMessageReq', () => {
const res = createResponse();
const next = jest.fn();
const error = new Error('job store unavailable');
getConvo.mockResolvedValue(null);
getConvoOwnership.mockResolvedValue(null);
GenerationJobManager.getJob.mockRejectedValue(error);
await validateMessageReq(req, res, next);
@ -229,7 +229,7 @@ describe('validateMessageReq', () => {
};
const res = createResponse();
const next = jest.fn();
getConvo.mockResolvedValue(null);
getConvoOwnership.mockResolvedValue(null);
await validateMessageReq(req, res, next);

View file

@ -4,10 +4,10 @@ const {
isPendingActionStale,
} = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { getConvo } = require('~/models');
const { getConvoOwnership } = require('~/models');
module.exports = createMessageRequestMiddleware({
getConvo,
getConvo: getConvoOwnership,
getJob: (conversationId) => GenerationJobManager.getJob(conversationId),
isPendingActionStale,
logger,

View file

@ -1,3 +1,4 @@
const { CLIENT_MESSAGE_SELECT } = require('@librechat/data-schemas');
const express = require('express');
const request = require('supertest');
@ -49,7 +50,7 @@ jest.mock('librechat-data-provider', () => ({
jest.mock('~/models', () => ({
saveConvo: jest.fn(),
getConvo: jest.fn(),
getConvoOwnership: jest.fn(),
getMessage: jest.fn(),
saveMessage: jest.fn(),
getMessages: jest.fn(),
@ -90,7 +91,7 @@ jest.mock('~/db/models', () => ({
describe('GET /api/messages/:conversationId with real validation middleware', () => {
let app;
const { getConvo, getMessages } = require('~/models');
const { getConvoOwnership, getMessages } = require('~/models');
const authenticatedUserId = 'user-owner-123';
beforeAll(() => {
@ -114,7 +115,7 @@ describe('GET /api/messages/:conversationId with real validation middleware', ()
expect(response.status).toBe(200);
expect(response.body).toEqual([]);
expect(getConvo).not.toHaveBeenCalled();
expect(getConvoOwnership).not.toHaveBeenCalled();
expect(getMessages).not.toHaveBeenCalled();
});
@ -125,7 +126,7 @@ describe('GET /api/messages/:conversationId with real validation middleware', ()
resolveConvo = resolve;
});
getConvo.mockImplementation(() => {
getConvoOwnership.mockImplementation(() => {
events.push('convo-started');
return convoPromise;
});
@ -156,10 +157,10 @@ describe('GET /api/messages/:conversationId with real validation middleware', ()
const response = await responsePromise;
expect(eventsBeforeValidation).toEqual(['convo-started', 'messages-started']);
expect(getConvo).toHaveBeenCalledWith(authenticatedUserId, 'convo-1');
expect(getConvoOwnership).toHaveBeenCalledWith(authenticatedUserId, 'convo-1');
expect(getMessages).toHaveBeenCalledWith(
{ conversationId: 'convo-1', user: authenticatedUserId },
'-_id -__v -user',
CLIENT_MESSAGE_SELECT,
);
expect(response.status).toBe(200);
expect(response.body).toEqual([{ messageId: 'message-1', conversationId: 'convo-1' }]);

View file

@ -1,3 +1,4 @@
const { CLIENT_MESSAGE_SELECT } = require('@librechat/data-schemas');
const express = require('express');
const request = require('supertest');
@ -171,7 +172,7 @@ describe('message route conversation ownership filters', () => {
expect(response.status).toBe(200);
expect(getMessages).toHaveBeenCalledWith(
{ conversationId: 'convo-1', user: authenticatedUserId },
'-_id -__v -user',
CLIENT_MESSAGE_SELECT,
);
});
@ -216,7 +217,7 @@ describe('message route conversation ownership filters', () => {
expect(eventsBeforeValidation).toEqual(['messages-started']);
expect(getMessages).toHaveBeenCalledWith(
{ conversationId: 'convo-1', user: authenticatedUserId },
'-_id -__v -user',
CLIENT_MESSAGE_SELECT,
);
expect(response.status).toBe(200);
@ -242,7 +243,7 @@ describe('message route conversation ownership filters', () => {
expect(getMessages).toHaveBeenCalledWith(
{ conversationId: 'convo-1', user: authenticatedUserId },
'-_id -__v -user',
CLIENT_MESSAGE_SELECT,
);
expect(response.status).toBe(404);
expect(response.body).toEqual({ error: 'Conversation not found' });
@ -256,7 +257,7 @@ describe('message route conversation ownership filters', () => {
expect(response.status).toBe(200);
expect(getMessages).toHaveBeenCalledWith(
{ conversationId: 'convo-1', messageId: 'message-1', user: authenticatedUserId },
'-_id -__v -user',
CLIENT_MESSAGE_SELECT,
);
});
});

View file

@ -1,6 +1,6 @@
const express = require('express');
const { v4: uuidv4 } = require('uuid');
const { logger } = require('@librechat/data-schemas');
const { logger, CLIENT_MESSAGE_SELECT } = require('@librechat/data-schemas');
const {
ContentTypes,
feedbackSchema,
@ -289,7 +289,7 @@ router.get('/:conversationId', prepareMessageRequestValidation, async (req, res)
// This intentionally starts a user-scoped read before validation resolves;
// the response remains gated on validation success below.
const messagesPromise = validation.shouldFetchMessages
? db.getMessages({ conversationId, user: req.user.id }, '-_id -__v -user').then(
? db.getMessages({ conversationId, user: req.user.id }, CLIENT_MESSAGE_SELECT).then(
(messages) => ({ messages }),
(error) => ({ error }),
)
@ -350,7 +350,7 @@ router.get('/:conversationId/:messageId', validateMessageReq, async (req, res) =
const { conversationId, messageId } = req.params;
const message = await db.getMessages(
{ conversationId, messageId, user: req.user.id },
'-_id -__v -user',
CLIENT_MESSAGE_SELECT,
);
if (!message) {
return res.status(404).json({ error: 'Message not found' });