Skip to content

πŸ—‚οΈ perf: Index Hot Lookups and Fix the Message Cursor - #17464

Merged
berry-13 merged 14 commits into
devfrom
berry-13/devin-perf-indexes
Oct 27, 2026
Merged

berry-13 merged 14 commits into
devfrom
berry-13/devin-perf-indexes

Conversation

@berry-13

Copy link
Copy Markdown
Collaborator

Summary

Adds the indexes the 2026-10-19 Devin performance scan found missing on request paths, fixes the message cursor, and caps GET /api/messages page size. deleteSession({ refreshToken }), user-only deleteToolCalls, queued-turn delivery retirement and reconciliation claims, and Agent.exists on code environment ids all ran collection scans; each gets the narrowest index for its query shape (partial where the field is optional). The KeyvMongo logs collection gets a TTL index on expiresAt, so expired ban/violation entries no longer accumulate.

getMessagesByCursor sorted on updatedAt with no index and paged with a cursor that dropped milliseconds and skipped rows sharing a timestamp. The sort now ends with _id, the cursor is <iso>|<_id> with a compound predicate (bare legacy cursors still parse), and a {conversationId, user, updatedAt, _id} index serves the default sort. pageSize is parsed by parseMessagesPageSize in packages/api and capped at 1000, the same as MEILI_SEARCH_LIMIT.

Type of change

  • Bug fix
  • Performance improvement

Testing

Tested environments/configuration: mongodb-memory-server.

Automated tests:

  • message.cursor.spec.ts: ties across asc/desc on both sort fields, ms precision, legacy cursor, and explain() showing IXSCAN with no SORT stage.
  • schema/lookupIndexes.spec.ts: explain() confirms each new index is chosen.
  • keyvMongo.spec.ts, messages/page.spec.ts, message.spec.ts, queuedTurn/session specs, and the messages* route specs: all pass.
  • eslint, prettier clean; tsc --noEmit in packages/data-schemas and packages/api clean.

Screenshots / recordings

No user-facing change.

Risk / compatibility

New indexes build on startup when auto-index is enabled; the message index adds some write cost on a busy collection. The TTL index deletes logs entries Keyv already treats as expired (entries without a ttl store null and are ignored). No current client sends pageSize above 1000. The people-picker regex, hasFiles filter, trigger delivery claim sort and unbounded conversation reads need a design decision and are not in this PR.

Checklist

  • I reviewed my own changes
  • Relevant tests have been added or updated
  • Existing relevant tests pass
  • The change does not introduce new warnings or errors

Copilot AI balanced review requested due to automatic review settings October 26, 2026 17:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
πŸ“ Code Review βœ… Completed 2026-10-27T22:43:55.293234Z c5488b3 New commits
πŸ”’ Security Review βœ… Completed 2026-10-26T17:03:21.861894Z e3ab937 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with πŸ‘€ while any review is running, comments if it has suggestions, and reacts with πŸ‘ once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3ab937fd5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const cursorValue =
sortField === 'createdAt' ? last.createdAt : last[sortField as keyof IMessage];
nextCursor = String(cursorValue ?? '');
nextCursor = formatMessageCursor(last[sortField as keyof IMessage], last._id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Retain the cursor ID when applying the public projection

For the production GET /api/messages path, api/server/routes/messages.js passes select: CLIENT_MESSAGE_SELECT, which explicitly excludes _id (packages/data-schemas/src/methods/message.ts:528–529). Consequently, last._id is always undefined here and formatMessageCursor returns only the timestamp, so the new tie-breaking predicate never runs and messages sharing the page boundary's timestamp are still skipped. The added tests omit this projection and therefore miss the actual route behavior. Retain _id internally until the cursor is constructed, then remove it from the returned messages.

Useful? React with πŸ‘Β / πŸ‘Ž.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0eff604 (select typing in 7f70c1c). The cursor now reads _id before the -_id projection is applied and strips it from returned rows; a spec pages tied rows under CLIENT_MESSAGE_SELECT.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0eff604 (rebased); the cursor keeps _id under the client projection.

@@ -0,0 +1,13 @@
export const DEFAULT_MESSAGES_PAGE_SIZE = 25;
/** Matches the search page ceiling, so no previously honored search page size changes. */
export const MAX_MESSAGES_PAGE_SIZE = 1000;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Expose the new message page limit through configuration

The new ceiling unconditionally clamps conversation message requests to 1000, with no configSchema field or caller-supplied setting for deployments that need a different limit. Root AGENTS.md requires newly introduced limits to be configurable through librechat.yaml, with a compatibility-preserving default. Matching the existing search ceiling does not preserve the previously uncapped conversation-read behavior. Add the configuration field and pass its resolved value into the parser rather than imposing a fixed constant.

AGENTS.md reference: AGENTS.md:L91-L93

Useful? React with πŸ‘Β / πŸ‘Ž.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 99c325b and f9751d7. Added messages.maxPageSize to configSchema (default 1000), passed from req.config into parseMessagesPageSize, and the default page size is clamped to it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: messages.maxPageSize in configSchema, resolved per request.

@codegraph-librechat codegraph-librechat Bot added the πŸ—ΊοΈ DB Schemas codegraph: the taxonomy area this belongs to (classifier, confidence β‰₯ 0.9) label Oct 26, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b0312bdf2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/server/routes/messages.js Outdated
}

router.get('/', async (req, res) => {
router.get('/', configMiddleware, async (req, res) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve message configuration alongside the database reads

On conversation loads with cold principal/config caches, adding configMiddleware here makes configuration database reads finish before either the ownership or message query starts. It also invokes code-environment authorization when stateful code sessions are configured, although this route only needs message limits. Previously, prepareToolCallPreviews resolved configuration concurrently with those reads using skipRuntimeAugmentation: true; it still performs its own resolution afterward because it does not consume req.config. This adds serial database latency to the visible conversation-loading path. Resolve the required configuration concurrently with ownership checking, skip unrelated runtime augmentation, and reuse that result for preview limits.

AGENTS.md reference: AGENTS.md:L59-L61

Useful? React with πŸ‘Β / πŸ‘Ž.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c5488b3: configMiddleware removed; the page size resolves beside the ownership read with skipRuntimeAugmentation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8d1f089c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/server/routes/messages.js Outdated
Comment on lines +149 to +151
/** Observed here so a rejection while the page size resolves is not unhandled; it is rethrown at the await below. */
ownershipRead.catch(() => {});
const pageSize = await pageSizeRead;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move the new read orchestration into packages/api

The conversation-read path now adds promise-rejection handling and config-dependent query scheduling directly to the legacy CJS route. Root AGENTS.md explicitly requires newly added behaviorβ€”including edits to existing CJSβ€”to live in packages/api, leaving /api as wiring. Moving only the page-size parser does not satisfy that boundary: extract the new read orchestration into a TypeScript handler/helper with injected database and configuration dependencies, and delegate to it from this route.

AGENTS.md reference: AGENTS.md:L78-L82

Useful? React with πŸ‘Β / πŸ‘Ž.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c5488b3: the page size resolution and rejection observation live in packages/api; the route only calls them.

@berry-13 berry-13 added ⚑ performance Speed and efficiency improvements πŸ› bug Something isn't working πŸ”§ fix Bug fixes and code patches labels Oct 27, 2026
@berry-13
berry-13 force-pushed the berry-13/devin-perf-indexes branch from 6a85994 to c5488b3 Compare October 27, 2026 22:42
@berry-13
berry-13 merged commit c81e244 into dev Oct 27, 2026
50 checks passed
@berry-13
berry-13 deleted the berry-13/devin-perf-indexes branch October 27, 2026 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

πŸ› bug Something isn't working πŸ—ΊοΈ DB Schemas codegraph: the taxonomy area this belongs to (classifier, confidence β‰₯ 0.9) πŸ”§ fix Bug fixes and code patches ⚑ performance Speed and efficiency improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants