- Map the four NVIDIA Nemotron models on Bedrock to their AWS-documented context windows (256K for Nemotron 3 Super and Nano, 128K for the Nano v2 pair), so agents stop falling back to the 32K default that MCP tool schemas exhaust once a tool result arrives.
- Price the same models at their Bedrock on-demand rates so the context and pricing maps stay in parity.
* 🛌 perf: Defer Search Key Dialog Initialization Until First Open
* test: Reuse the Search Dialog Trigger Label in Lifecycle Tests
---------
Co-authored-by: Lia <lia@librechat.ai>
* fix: Move conversation project and PR icons to the leading edge
* fix: Preserve Conversation Focus With Leading PR Icons
* test: Check Icon Order After Leaving Pinned Section
* test: Enable Project Chats Before Checking Their Badges
Localize source pagination labels and the default sources error fallback. Add focused regression coverage and stabilize the oversized screenshot export test.
Bound model-facing Flux images to the 5 MiB base64 budget for standard and finetuned generation. Preserve original image data for attachment storage under the existing resolution policy.
Fixes#6954.
* fix: Read the Account and Session Together and Test Cancel on a Real Database
- Start the setup user and refresh session lookups together in the cancel controller instead of one after the other, as the opt-in confirmation already does
- Run the cancel controller spec on mongodb-memory-server with the real data-schemas methods, so the session and compare-and-swap predicates under test are the production ones, and add a negative case for each
- Keep only a module wiring test in the CJS controller spec, since the database behavior is now covered where it can run for real
* test: Pin the Cancel Response When the Session Lookup Fails
Both lookups now run before any cookie or write, so a failed session lookup answers 500 with the browser and the stored state untouched. Cover that on the real database.
* fix: Keep the Saved Files Draft Until the File List Loads
After a reload the live file map is empty until the server's file list arrives, and the restore that rebuilds it needs that list. The save effect rewrote the stored draft from the empty map in between, so a pasted-text chip or any other attachment was gone before it could be restored. It now waits for the list. This is what turned the composer-attachments restore scenario red on dev.
- Bump @floating-ui/utils from 0.2.8 to 0.2.9 in package-lock.json and bun.lock so isContainingBlock treats translate, scale and rotate as containing blocks
- Add schedule-time-popover scenarios: the Weekly time picker, the Hourly minute picker and a dialog scrolled by its own overflow each open against their field
* fix: Bound Generation Status Reads So a Silent Request Cannot Strand the Pane
* test: Cover Status Reads That Never Answer Across Terminal, Error and Foreground Paths
* test: Match Scenario Replies Exactly
* fix: Keep the Provider Message on Classified Rate Limit Errors
* fix: Honor maxProviderErrorChars for Classified Generation Errors
* test: Cover Classified Gateway Errors in the Mock Harness
* test: Cover a Zero Provider Detail Limit on Generation Errors
* refactor: Resolve Classified Provider Errors in the TypeScript Backend
* fix: Redact Provider Details Before Truncating Them
* fix: Wrap Label and Prose Text Between Words Instead of Mid-Word
* test: Cover Word Wrapping in the MCP Trust Disclosure and Bookmark Delete Dialog
* test: Reopen the MCP dialog per width and treat hyphens as break points
* test: Open the bookmark delete confirmation from the keyboard
* fix: Let the MCP Dialog Segmented Controls Wrap on Narrow Screens
* 📏 fix: Measure Usage Percent Against the Allowance Each Period Granted
Store the credits granted at the start of each balance period on the record and measure the usage percent against it, so changing refillAmount or startBalance no longer moves a user's percent until their next grant. Legacy records fall back to the configured amount.
* 🕰️ fix: Ignore a Stored Allotment a Later Refill Has Replaced
Stamp each stored allotment with the time of its grant and measure against it only while no refill is more recent, so a refill by a replica that predates the field falls back to the configured amount instead of reporting usage against the prior period's allowance.
* 🔒 fix: Write the Allotment Grant Atomically and Return Its Period Start
Insert lastRefill with the credit, allotment and grant time when a balance record is created, so a racing creator never moves another's period start past its grant. Return lastRefill even without auto-refill so the client can place a stored allotment in its period, and fall back when it cannot.
* 🔐 fix: Authorize Restored MCP Tools Before Agent Revert Writes Them
Reverting wrote the version snapshot, including its mcpServerNames, before
filterAuthorizedTools ran. Agent-scoped MCP access is granted from that index,
so a restored server vouched for itself and an editor without access to it
could re-attach it. A snapshot without mcpServerNames also left the current
index in place, keeping agent-scoped access to servers no tool used.
The handler now authorizes the restored tools against the agent as it stands,
treating only its current tools as existing, and passes the authorized tools
and rebuilt index to revertAgentVersion so the restore is one write pinned to
the revision it was checked against. revertAgentVersion always rewrites the
index for the restored tools.
* 🔐 fix: Exclude the Target Agent's Own Grant When Authorizing a Revert
Moves the restore authorization into authorizeAgentRestore in packages/api,
leaving the revert controller as wiring.
A newly restored MCP tool whose server the user reaches only through agents
must now be reachable through an agent other than the one being reverted,
checked fresh against the database. The target's current or cached index
(including one left stale by an earlier revert) no longer vouches for it.
Prior server names are matched through their normalized aliases, and only for
tools the agent already had. When nothing resolves, the pre-restore index is
kept instead of deriving names from tool keys.
A revision-filtered restore that misses is reported as a 409 conflict.
The route spec restores the real ~/config so the MCP registry is consulted
rather than reported unavailable.
* 🔐 fix: Check Newly Restored MCP Servers Against Live Grants
The restore gate now runs for every approved MCP tool, not only consumeOnly
ones. A tool the agent doesn't already have, on a DB-backed server, is
admitted when a current tool still uses that server, or on a live direct
server grant, or through another viewable agent. A grant the registry still
caches after revocation no longer becomes durable through the restored index.
Admission is memoized per server. A snapshot tools array that sanitizes to
nothing restores an explicit empty set. Active-server matching no longer
reuses the index fallback, so a stale entry is never read as in use.
* 🔐 fix: Treat Legacy Cached DB Configs as User-Sourced in the Restore Gate
A config cached before an upgrade may carry a dbId without source. The
restore gate now uses isUserSourced, so such configs get the live access
check instead of passing as operator-managed.
* 🔐 fix: Recheck Unindexed Existing MCP Tools in the Restore Gate
Holding a tool no longer exempts it from the live check. Only a current tool
whose server the agent's index already lists skips it. Otherwise an unindexed
tool on a legacy agent could pass on a revoked grant the registry still
caches, and the restore would add its server to the index.
* ⚡ perf: Run Restore Admission Checks for Distinct Servers Concurrently
filterAuthorizedTools now starts every admission check during its single pass
and awaits them together, so each distinct DB-backed server no longer adds a
serial lookup wave to the revert. Tool order is preserved and server names
are recorded only for admitted tools.
* perf: Prefetch Conversation Messages From the Chat Route
The messages request started only when ChatView mounted, after startup config, roles, endpoints, models and the conversation record resolved, although it needs only the route id. ChatRoute now starts it as soon as the id is known for a conversation the cache has never held, sharing the view's query function, and the view's first mount uses that payload instead of fetching it again.
* fix: Keep the Messages Prefetch Mark for the Observer That Uses It
Child observers of the same conversation mount first and cleared the mark before the conversation view subscribed, so the view loaded the messages a second time.
* fix: Show a Failed Messages Prefetch Instead of Requesting It Again
A prefetch that failed left no data, so the view loaded the messages again on mount, and a link to a missing conversation sent two requests. The view now shows a fresh prefetch failure, and the prefetch retries like the view's own load except on a 4xx.
* test: Cover Route-Level Messages Loading on Cold Load, Sidebar Switch and Missing Conversation
* fix: Retry Rate-Limited and Timed-Out Messages Prefetches
* fix: Prove Prefetched History by Reply Identity and Honor Invalidation
A URL load's prefetch starts before the conversation record is cached, so it captured no reply stamp and the seen check loaded an unread conversation's history a second time. Once the record lands, the prefetched history is proven when it holds the exact reply the record names. The mount guards also yield to an invalidation, and the failed-prefetch guard is the default for every observer of the conversation's messages.
* fix: Match Vendor Chunk Rules Against the Module Path, Not the Checkout
The vendor chunk rules tested the absolute module path, so a repository under a directory whose name contains a rule's text (fetch, ky, zod) sent every dependency to that chunk and the PWA precache limit failed the build. The rules now see the path from the first node_modules segment on.
* test: Cover Vendor Chunk Rules Under a Hostile Checkout Path
* refactor: Move Part Helpers and activityLabels Into the Chat Package
activityLabels moves to packages/chat/src/core/parts and exports from
@librechat/chat. useLazyCollapseBody, useProgress and useThrottledValue move
to packages/chat/src/react/parts (@librechat/chat/react). useExpandCollapse,
CopyButton, ActionButton, LangIcon and its icon paths move to
packages/chat/src/components/parts (@librechat/chat/components), since they
read @librechat/client. Specs move with them, client importers and mocks point
at the package entries, and design-lint suppressions follow the moved files.
The fold-type set in activityLabels is built on first use so the module reads
no data-provider enum at load, with a spec pinning its members.
* test: Point the About Spec's Localize Mock at the Package's Copy Button
* chore: Retest Against Current Dev
* fix: Only Hand Out OpenID Access Tokens the Bearer Verifier Accepts
The OpenID reuse path in refreshController and the post-refresh fallback in
getOpenIDAppAuthToken returned the cached access token as the app auth token
whenever its exp was in the future. Entra issues Microsoft Graph access tokens
to sign-in clients by default; their aud names Graph, so the bearer verifier
rejects them and every protected request answers 401 until the client loops.
Both paths now require the access token's aud to name the client id or an
OPENID_AUDIENCE entry, the same audiences the verifier accepts. The reuse path
refreshes with the IdP instead, and the post-refresh fallback keeps opaque
tokens as before. Audience parsing is shared with openIdJwtStrategy.
Related to #17791
* test: Exercise Real OpenID Audience Helpers in AuthService Spec
The AuthService spec stubbed the audience helpers as pass-throughs, so it
could not catch a foreign-audience access token escaping the post-refresh
fallback. Use the real exports and cover Graph-audience, configured-audience
and opaque access tokens through setOpenIDAuthTokens.