Repository navigation
🗂️ refactor: Artifacts via Model Specs & Scope Badge Persistence by Spec Context - #11796
Merged
Merged
Conversation
- Removed redundant useEffect for setting ephemeral agent when MCP values change. - Integrated ephemeral agent update directly into the MCP value change handler, improving code clarity and reducing unnecessary re-renders. - Updated dependencies in the effect hook to ensure proper state management. Why Effect 2 Was Added (PR #9528) PR #9528 was a refactor that migrated MCP state from useLocalStorage hooks to Jotai atomWithStorage. Before that PR, useLocalStorage handled bidirectional sync between localStorage and Recoil in one abstraction. After the migration, the two useEffect hooks were introduced to bridge Jotai ↔ Recoil: - Effect 1 (Recoil → Jotai): When ephemeralAgent.mcp changes externally, update the Jotai atom (which drives the UI dropdown) - Effect 2 (Jotai → Recoil): When mcpValues changes, push it back to ephemeralAgent.mcp (which is read at submission time) Effect 2 was needed because in that PR's design, setMCPValues only wrote to Jotai — it never touched Recoil. Effect 2 was the bridge to propagate user selections into the ephemeral agent. Why Removing It Is Correct All user-initiated MCP changes go through setMCPValues. The callers are in useMCPServerManager: toggleServerSelection, batchToggleServers, OAuth success callbacks, and access revocation. Our change puts the Recoil write directly in that callback, so all these paths are covered. All external changes go through Recoil, handled by Effect 1 (kept). Model spec application (applyModelSpecEphemeralAgent), agent template application after submission, and BadgeRowContext initialization all write directly to ephemeralAgentByConvoId. Effect 1 watches ephemeralAgent?.mcp and syncs those into the Jotai atom for the UI. There is no code path where mcpValues changes without going through setMCPValues or Effect 1. The only other source is atomWithStorage's getOnInit reading from localStorage on mount — that's just restoring persisted state and is harmless (overwritten by Effect 1 if the ephemeral agent has values). Additional Benefits - Eliminates the race condition. Effect 2 fired on mount with Jotai's stale default ([]), overwriting ephemeralAgent.mcp that had been set by a model spec. Our change prevents that because the imperative sync only fires on explicit user action. - Eliminates infinite loop risk. The old bidirectional two-effect approach relied on isEqual/JSON.stringify checks to break cycles. The new unidirectional-reactive (Effect 1) + imperative (setMCPValues) approach has no such risk. - Effect 1's enhancements are preserved. The mcp_clear sentinel handling and configuredServers filtering (both added after PR #9528) continue to work correctly.
…gents - Introduced `artifacts` property in the model specification and ephemeral agent types, allowing for string or boolean values. - Updated `applyModelSpecEphemeralAgent` to handle artifacts, defaulting to 'default' if true or an empty string if not specified. - Enhanced localStorage handling to store artifacts alongside other agent properties, improving state management for ephemeral agents.
- Modified the logic to only apply values from localStorage that were actually stored, preventing unnecessary overrides of the ephemeral agent. - Simplified the setting of ephemeral agent values by directly using initialValues, enhancing code clarity and maintainability.
…odel spec application - Updated BadgeRowContext to apply localStorage values only for tools not already set in ephemeralAgent, improving state management. - Modified useApplyModelSpecEffects to reset the ephemeral agent when no spec is provided but specs are configured, ensuring localStorage defaults are applied correctly. - Streamlined the logic for applying model spec properties, enhancing clarity and maintainability.
…eyed storage Spec tool state (badges, MCP) and non-spec user preferences previously shared conversation-keyed localStorage, causing cross-pollination when switching between spec and non-spec models. This introduces environment-keyed storage so each context maintains independent persisted state. Key changes: - Spec active: no localStorage persistence — admin config always applied fresh - Non-spec (with specs configured): tool/MCP state persisted to __defaults__ key - No specs configured: zero behavior change (conversation-keyed storage) - Per-conversation isolation preserved for existing conversations - Dual-write on user interaction updates both conversation and environment keys - Remove mcp_clear sentinel in favor of null ephemeral agent reset
…BadgeRowContext and useMCPSelect - Updated BadgeRowContext to clarify the handling of localStorage values for ephemeral agents, ensuring proper initialization based on conversation state. - Improved useMCPSelect tests to accurately reflect behavior when setting empty MCP values, ensuring the visual selection clears as expected. - Introduced environment-keyed storage logic to maintain independent state for spec and non-spec contexts, enhancing user experience during context switching.
…emeralAgent hooks - Introduced unit tests for the useToolToggle hook, covering dual-write behavior in non-spec mode and per-conversation isolation. - Added tests for applyModelSpecEphemeralAgent, ensuring correct application of model specifications and user overrides from localStorage. - Enhanced test coverage for ephemeral agent state management during conversation transitions, validating expected behaviors for both new and existing conversations.
danny-avila
added a commit
that referenced
this pull request
Feb 14, 2026
…pec Context (#11796) * 🔧 refactor: Simplify MCP selection logic in useMCPSelect hook - Removed redundant useEffect for setting ephemeral agent when MCP values change. - Integrated ephemeral agent update directly into the MCP value change handler, improving code clarity and reducing unnecessary re-renders. - Updated dependencies in the effect hook to ensure proper state management. Why Effect 2 Was Added (PR #9528) PR #9528 was a refactor that migrated MCP state from useLocalStorage hooks to Jotai atomWithStorage. Before that PR, useLocalStorage handled bidirectional sync between localStorage and Recoil in one abstraction. After the migration, the two useEffect hooks were introduced to bridge Jotai ↔ Recoil: - Effect 1 (Recoil → Jotai): When ephemeralAgent.mcp changes externally, update the Jotai atom (which drives the UI dropdown) - Effect 2 (Jotai → Recoil): When mcpValues changes, push it back to ephemeralAgent.mcp (which is read at submission time) Effect 2 was needed because in that PR's design, setMCPValues only wrote to Jotai — it never touched Recoil. Effect 2 was the bridge to propagate user selections into the ephemeral agent. Why Removing It Is Correct All user-initiated MCP changes go through setMCPValues. The callers are in useMCPServerManager: toggleServerSelection, batchToggleServers, OAuth success callbacks, and access revocation. Our change puts the Recoil write directly in that callback, so all these paths are covered. All external changes go through Recoil, handled by Effect 1 (kept). Model spec application (applyModelSpecEphemeralAgent), agent template application after submission, and BadgeRowContext initialization all write directly to ephemeralAgentByConvoId. Effect 1 watches ephemeralAgent?.mcp and syncs those into the Jotai atom for the UI. There is no code path where mcpValues changes without going through setMCPValues or Effect 1. The only other source is atomWithStorage's getOnInit reading from localStorage on mount — that's just restoring persisted state and is harmless (overwritten by Effect 1 if the ephemeral agent has values). Additional Benefits - Eliminates the race condition. Effect 2 fired on mount with Jotai's stale default ([]), overwriting ephemeralAgent.mcp that had been set by a model spec. Our change prevents that because the imperative sync only fires on explicit user action. - Eliminates infinite loop risk. The old bidirectional two-effect approach relied on isEqual/JSON.stringify checks to break cycles. The new unidirectional-reactive (Effect 1) + imperative (setMCPValues) approach has no such risk. - Effect 1's enhancements are preserved. The mcp_clear sentinel handling and configuredServers filtering (both added after PR #9528) continue to work correctly. * ✨ feat: Add artifacts support to model specifications and ephemeral agents - Introduced `artifacts` property in the model specification and ephemeral agent types, allowing for string or boolean values. - Updated `applyModelSpecEphemeralAgent` to handle artifacts, defaulting to 'default' if true or an empty string if not specified. - Enhanced localStorage handling to store artifacts alongside other agent properties, improving state management for ephemeral agents. * 🔧 refactor: Update BadgeRowContext to improve localStorage handling - Modified the logic to only apply values from localStorage that were actually stored, preventing unnecessary overrides of the ephemeral agent. - Simplified the setting of ephemeral agent values by directly using initialValues, enhancing code clarity and maintainability. * 🔧 refactor: Enhance ephemeral agent handling in BadgeRowContext and model spec application - Updated BadgeRowContext to apply localStorage values only for tools not already set in ephemeralAgent, improving state management. - Modified useApplyModelSpecEffects to reset the ephemeral agent when no spec is provided but specs are configured, ensuring localStorage defaults are applied correctly. - Streamlined the logic for applying model spec properties, enhancing clarity and maintainability. * refactor: Isolate spec and non-spec tool/MCP state with environment-keyed storage Spec tool state (badges, MCP) and non-spec user preferences previously shared conversation-keyed localStorage, causing cross-pollination when switching between spec and non-spec models. This introduces environment-keyed storage so each context maintains independent persisted state. Key changes: - Spec active: no localStorage persistence — admin config always applied fresh - Non-spec (with specs configured): tool/MCP state persisted to __defaults__ key - No specs configured: zero behavior change (conversation-keyed storage) - Per-conversation isolation preserved for existing conversations - Dual-write on user interaction updates both conversation and environment keys - Remove mcp_clear sentinel in favor of null ephemeral agent reset * refactor: Enhance ephemeral agent initialization and MCP handling in BadgeRowContext and useMCPSelect - Updated BadgeRowContext to clarify the handling of localStorage values for ephemeral agents, ensuring proper initialization based on conversation state. - Improved useMCPSelect tests to accurately reflect behavior when setting empty MCP values, ensuring the visual selection clears as expected. - Introduced environment-keyed storage logic to maintain independent state for spec and non-spec contexts, enhancing user experience during context switching. * test: Add comprehensive tests for useToolToggle and applyModelSpecEphemeralAgent hooks - Introduced unit tests for the useToolToggle hook, covering dual-write behavior in non-spec mode and per-conversation isolation. - Added tests for applyModelSpecEphemeralAgent, ensuring correct application of model specifications and user overrides from localStorage. - Enhanced test coverage for ephemeral agent state management during conversation transitions, validating expected behaviors for both new and existing conversations.
JumpLink
pushed a commit
to faktenforum/LibreChat
that referenced
this pull request
Feb 14, 2026
…pec Context (LibreChat-AI#11796) * 🔧 refactor: Simplify MCP selection logic in useMCPSelect hook - Removed redundant useEffect for setting ephemeral agent when MCP values change. - Integrated ephemeral agent update directly into the MCP value change handler, improving code clarity and reducing unnecessary re-renders. - Updated dependencies in the effect hook to ensure proper state management. Why Effect 2 Was Added (PR LibreChat-AI#9528) PR LibreChat-AI#9528 was a refactor that migrated MCP state from useLocalStorage hooks to Jotai atomWithStorage. Before that PR, useLocalStorage handled bidirectional sync between localStorage and Recoil in one abstraction. After the migration, the two useEffect hooks were introduced to bridge Jotai ↔ Recoil: - Effect 1 (Recoil → Jotai): When ephemeralAgent.mcp changes externally, update the Jotai atom (which drives the UI dropdown) - Effect 2 (Jotai → Recoil): When mcpValues changes, push it back to ephemeralAgent.mcp (which is read at submission time) Effect 2 was needed because in that PR's design, setMCPValues only wrote to Jotai — it never touched Recoil. Effect 2 was the bridge to propagate user selections into the ephemeral agent. Why Removing It Is Correct All user-initiated MCP changes go through setMCPValues. The callers are in useMCPServerManager: toggleServerSelection, batchToggleServers, OAuth success callbacks, and access revocation. Our change puts the Recoil write directly in that callback, so all these paths are covered. All external changes go through Recoil, handled by Effect 1 (kept). Model spec application (applyModelSpecEphemeralAgent), agent template application after submission, and BadgeRowContext initialization all write directly to ephemeralAgentByConvoId. Effect 1 watches ephemeralAgent?.mcp and syncs those into the Jotai atom for the UI. There is no code path where mcpValues changes without going through setMCPValues or Effect 1. The only other source is atomWithStorage's getOnInit reading from localStorage on mount — that's just restoring persisted state and is harmless (overwritten by Effect 1 if the ephemeral agent has values). Additional Benefits - Eliminates the race condition. Effect 2 fired on mount with Jotai's stale default ([]), overwriting ephemeralAgent.mcp that had been set by a model spec. Our change prevents that because the imperative sync only fires on explicit user action. - Eliminates infinite loop risk. The old bidirectional two-effect approach relied on isEqual/JSON.stringify checks to break cycles. The new unidirectional-reactive (Effect 1) + imperative (setMCPValues) approach has no such risk. - Effect 1's enhancements are preserved. The mcp_clear sentinel handling and configuredServers filtering (both added after PR LibreChat-AI#9528) continue to work correctly. * ✨ feat: Add artifacts support to model specifications and ephemeral agents - Introduced `artifacts` property in the model specification and ephemeral agent types, allowing for string or boolean values. - Updated `applyModelSpecEphemeralAgent` to handle artifacts, defaulting to 'default' if true or an empty string if not specified. - Enhanced localStorage handling to store artifacts alongside other agent properties, improving state management for ephemeral agents. * 🔧 refactor: Update BadgeRowContext to improve localStorage handling - Modified the logic to only apply values from localStorage that were actually stored, preventing unnecessary overrides of the ephemeral agent. - Simplified the setting of ephemeral agent values by directly using initialValues, enhancing code clarity and maintainability. * 🔧 refactor: Enhance ephemeral agent handling in BadgeRowContext and model spec application - Updated BadgeRowContext to apply localStorage values only for tools not already set in ephemeralAgent, improving state management. - Modified useApplyModelSpecEffects to reset the ephemeral agent when no spec is provided but specs are configured, ensuring localStorage defaults are applied correctly. - Streamlined the logic for applying model spec properties, enhancing clarity and maintainability. * refactor: Isolate spec and non-spec tool/MCP state with environment-keyed storage Spec tool state (badges, MCP) and non-spec user preferences previously shared conversation-keyed localStorage, causing cross-pollination when switching between spec and non-spec models. This introduces environment-keyed storage so each context maintains independent persisted state. Key changes: - Spec active: no localStorage persistence — admin config always applied fresh - Non-spec (with specs configured): tool/MCP state persisted to __defaults__ key - No specs configured: zero behavior change (conversation-keyed storage) - Per-conversation isolation preserved for existing conversations - Dual-write on user interaction updates both conversation and environment keys - Remove mcp_clear sentinel in favor of null ephemeral agent reset * refactor: Enhance ephemeral agent initialization and MCP handling in BadgeRowContext and useMCPSelect - Updated BadgeRowContext to clarify the handling of localStorage values for ephemeral agents, ensuring proper initialization based on conversation state. - Improved useMCPSelect tests to accurately reflect behavior when setting empty MCP values, ensuring the visual selection clears as expected. - Introduced environment-keyed storage logic to maintain independent state for spec and non-spec contexts, enhancing user experience during context switching. * test: Add comprehensive tests for useToolToggle and applyModelSpecEphemeralAgent hooks - Introduced unit tests for the useToolToggle hook, covering dual-write behavior in non-spec mode and per-conversation isolation. - Added tests for applyModelSpecEphemeralAgent, ensuring correct application of model specifications and user overrides from localStorage. - Enhanced test coverage for ephemeral agent state management during conversation transitions, validating expected behaviors for both new and existing conversations.
JumpLink
pushed a commit
to faktenforum/LibreChat
that referenced
this pull request
Feb 14, 2026
…pec Context (LibreChat-AI#11796) * 🔧 refactor: Simplify MCP selection logic in useMCPSelect hook - Removed redundant useEffect for setting ephemeral agent when MCP values change. - Integrated ephemeral agent update directly into the MCP value change handler, improving code clarity and reducing unnecessary re-renders. - Updated dependencies in the effect hook to ensure proper state management. Why Effect 2 Was Added (PR LibreChat-AI#9528) PR LibreChat-AI#9528 was a refactor that migrated MCP state from useLocalStorage hooks to Jotai atomWithStorage. Before that PR, useLocalStorage handled bidirectional sync between localStorage and Recoil in one abstraction. After the migration, the two useEffect hooks were introduced to bridge Jotai ↔ Recoil: - Effect 1 (Recoil → Jotai): When ephemeralAgent.mcp changes externally, update the Jotai atom (which drives the UI dropdown) - Effect 2 (Jotai → Recoil): When mcpValues changes, push it back to ephemeralAgent.mcp (which is read at submission time) Effect 2 was needed because in that PR's design, setMCPValues only wrote to Jotai — it never touched Recoil. Effect 2 was the bridge to propagate user selections into the ephemeral agent. Why Removing It Is Correct All user-initiated MCP changes go through setMCPValues. The callers are in useMCPServerManager: toggleServerSelection, batchToggleServers, OAuth success callbacks, and access revocation. Our change puts the Recoil write directly in that callback, so all these paths are covered. All external changes go through Recoil, handled by Effect 1 (kept). Model spec application (applyModelSpecEphemeralAgent), agent template application after submission, and BadgeRowContext initialization all write directly to ephemeralAgentByConvoId. Effect 1 watches ephemeralAgent?.mcp and syncs those into the Jotai atom for the UI. There is no code path where mcpValues changes without going through setMCPValues or Effect 1. The only other source is atomWithStorage's getOnInit reading from localStorage on mount — that's just restoring persisted state and is harmless (overwritten by Effect 1 if the ephemeral agent has values). Additional Benefits - Eliminates the race condition. Effect 2 fired on mount with Jotai's stale default ([]), overwriting ephemeralAgent.mcp that had been set by a model spec. Our change prevents that because the imperative sync only fires on explicit user action. - Eliminates infinite loop risk. The old bidirectional two-effect approach relied on isEqual/JSON.stringify checks to break cycles. The new unidirectional-reactive (Effect 1) + imperative (setMCPValues) approach has no such risk. - Effect 1's enhancements are preserved. The mcp_clear sentinel handling and configuredServers filtering (both added after PR LibreChat-AI#9528) continue to work correctly. * ✨ feat: Add artifacts support to model specifications and ephemeral agents - Introduced `artifacts` property in the model specification and ephemeral agent types, allowing for string or boolean values. - Updated `applyModelSpecEphemeralAgent` to handle artifacts, defaulting to 'default' if true or an empty string if not specified. - Enhanced localStorage handling to store artifacts alongside other agent properties, improving state management for ephemeral agents. * 🔧 refactor: Update BadgeRowContext to improve localStorage handling - Modified the logic to only apply values from localStorage that were actually stored, preventing unnecessary overrides of the ephemeral agent. - Simplified the setting of ephemeral agent values by directly using initialValues, enhancing code clarity and maintainability. * 🔧 refactor: Enhance ephemeral agent handling in BadgeRowContext and model spec application - Updated BadgeRowContext to apply localStorage values only for tools not already set in ephemeralAgent, improving state management. - Modified useApplyModelSpecEffects to reset the ephemeral agent when no spec is provided but specs are configured, ensuring localStorage defaults are applied correctly. - Streamlined the logic for applying model spec properties, enhancing clarity and maintainability. * refactor: Isolate spec and non-spec tool/MCP state with environment-keyed storage Spec tool state (badges, MCP) and non-spec user preferences previously shared conversation-keyed localStorage, causing cross-pollination when switching between spec and non-spec models. This introduces environment-keyed storage so each context maintains independent persisted state. Key changes: - Spec active: no localStorage persistence — admin config always applied fresh - Non-spec (with specs configured): tool/MCP state persisted to __defaults__ key - No specs configured: zero behavior change (conversation-keyed storage) - Per-conversation isolation preserved for existing conversations - Dual-write on user interaction updates both conversation and environment keys - Remove mcp_clear sentinel in favor of null ephemeral agent reset * refactor: Enhance ephemeral agent initialization and MCP handling in BadgeRowContext and useMCPSelect - Updated BadgeRowContext to clarify the handling of localStorage values for ephemeral agents, ensuring proper initialization based on conversation state. - Improved useMCPSelect tests to accurately reflect behavior when setting empty MCP values, ensuring the visual selection clears as expected. - Introduced environment-keyed storage logic to maintain independent state for spec and non-spec contexts, enhancing user experience during context switching. * test: Add comprehensive tests for useToolToggle and applyModelSpecEphemeralAgent hooks - Introduced unit tests for the useToolToggle hook, covering dual-write behavior in non-spec mode and per-conversation isolation. - Added tests for applyModelSpecEphemeralAgent, ensuring correct application of model specifications and user overrides from localStorage. - Enhanced test coverage for ephemeral agent state management during conversation transitions, validating expected behaviors for both new and existing conversations.
paychex-joser
added a commit
to paychex/LibreChat-oss-archive
that referenced
this pull request
Apr 17, 2026
* 🆔 fix: Atomic File Dedupe, Bedrock Tokens Fix, and Allowed MIME Types (#11675)
* feat: Add support for Apache Parquet MIME types
- Introduced 'application/x-parquet' to the full MIME types list and code interpreter MIME types list.
- Updated application MIME types regex to include 'x-parquet' and 'vnd.apache.parquet'.
- Added mapping for '.parquet' files to 'application/x-parquet' in code type mapping, enhancing file format support.
* feat: Implement atomic file claiming for code execution outputs
- Added a new `claimCodeFile` function to atomically claim a file_id for code execution outputs, preventing duplicates by using a compound key of filename and conversationId.
- Updated `processCodeOutput` to utilize the new claiming mechanism, ensuring that concurrent calls for the same filename converge on a single record.
- Refactored related tests to validate the new atomic claiming behavior and its impact on file usage tracking and versioning.
* fix: Update image file handling to use cache-busting filepath
- Modified the `processCodeOutput` function to generate a cache-busting filepath for updated image files, improving browser caching behavior.
- Adjusted related tests to reflect the change from versioned filenames to cache-busted filepaths, ensuring accurate validation of image updates.
* fix: Update step handler to prevent undefined content for non-tool call types
- Modified the condition in useStepHandler to ensure that undefined content is only assigned for specific content types, enhancing the robustness of content handling.
* fix: Update bedrockOutputParser to handle maxTokens for adaptive models
- Modified the bedrockOutputParser logic to ensure that maxTokens is not set for adaptive models when neither maxTokens nor maxOutputTokens are provided, improving the handling of adaptive thinking configurations.
- Updated related tests to reflect these changes, ensuring accurate validation of the output for adaptive models.
* chore: Update @librechat/agents to version 3.1.38 in package.json and package-lock.json
* fix: Enhance file claiming and error handling in code processing
- Updated the `processCodeOutput` function to use a consistent file ID for claiming files, preventing duplicates and improving concurrency handling.
- Refactored the `createFileMethods` to include error handling for failed file claims, ensuring robust behavior when claiming files for conversations.
- These changes enhance the reliability of file management in the application.
* fix: Update adaptive thinking test for Opus 4.6 model
- Modified the test for configuring adaptive thinking to reflect that no default maxTokens should be set for the Opus 4.6 model.
- Updated assertions to ensure that maxTokens is undefined, aligning with the expected behavior for adaptive models.
* 🌊 fix: Prevent Truncations When Redis Resumable Streams Are Enabled (#11710)
* fix: prevent truncated responses when Redis resumable streams are enabled
Race condition in RedisEventTransport.subscribe() caused early events
(seq 0+) to be lost. The Redis SUBSCRIBE command was fired as
fire-and-forget, but GenerationJobManager immediately set
hasSubscriber=true, disabling the earlyEventBuffer. Events published
during the gap between subscribe() returning and the Redis subscription
actually taking effect were neither buffered nor received — they were
silently dropped by Pub/Sub.
This manifested as "timeout waiting for seq 0, force-flushing N messages"
warnings followed by truncated or missing response text in the UI.
The fix:
- IEventTransport.subscribe() now returns an optional `ready` promise
that resolves once the transport can actually receive messages
- RedisEventTransport returns the Redis SUBSCRIBE acknowledgment as the
`ready` promise instead of firing it as fire-and-forget
- GenerationJobManager.subscribe() awaits `ready` before setting
hasSubscriber=true, keeping the earlyEventBuffer active during the
subscription window so no events are lost
- GenerationJobManager.emitChunk() early-returns after buffering when no
subscriber is connected, avoiding wasteful Redis PUBLISHes that nobody
would receive
Adds 5 regression tests covering the race condition for both in-memory
and Redis transports, verifying that events emitted before subscribe are
buffered and replayed, that the ready promise contract is correct for
both transport implementations, and that no events are lost across the
subscribe boundary.
* refactor: Update import paths in GenerationJobManager integration tests
- Refactored import statements in the GenerationJobManager integration test file to use absolute paths instead of relative paths, improving code readability and maintainability.
- Removed redundant imports and ensured consistent usage of the updated import structure across the test cases.
* chore: Remove redundant await from GenerationJobManager initialization in tests
- Updated multiple test cases to call GenerationJobManager.initialize() without awaiting, improving test performance and clarity.
- Ensured consistent initialization across various scenarios in the CollectedUsage and AbortJob test suites.
* refactor: Enhance GenerationJobManager integration tests and RedisEventTransport cleanup
- Updated GenerationJobManager integration tests to utilize dynamic Redis clients and removed unnecessary awaits from initialization calls, improving test performance.
- Refactored RedisEventTransport's destroy method to safely disconnect the subscriber, enhancing resource management and preventing potential errors during cleanup.
* feat: Enhance GenerationJobManager and RedisEventTransport for improved event handling
- Added a resetSequence method to IEventTransport and implemented it in RedisEventTransport to manage publish sequence counters effectively.
- Updated GenerationJobManager to utilize the new resetSequence method, ensuring proper event handling during stream operations.
- Introduced integration tests for GenerationJobManager to validate cross-replica event publishing and subscriber readiness in Redis, enhancing test coverage and reliability.
* test: Add integration tests for GenerationJobManager sequence reset and error recovery with Redis
- Introduced new tests to validate the behavior of GenerationJobManager during sequence resets, ensuring no stale events are received after a reset.
- Added tests to confirm that the sequence is not reset when a second subscriber joins mid-stream, maintaining event integrity.
- Implemented a test for resubscription after a Redis subscribe failure, verifying that events can still be received post-error.
- Enhanced overall test coverage for Redis-related functionalities in GenerationJobManager.
* fix: Update GenerationJobManager and RedisEventTransport for improved event synchronization
- Replaced the resetSequence method with syncReorderBuffer in GenerationJobManager to enhance cross-replica event handling without resetting the publisher sequence.
- Added a new syncReorderBuffer method in RedisEventTransport to advance the subscriber reorder buffer safely, ensuring no data loss during subscriber transitions.
- Introduced a new integration test to validate that local subscribers joining do not cause data loss for cross-replica subscribers, enhancing the reliability of event delivery.
- Updated existing tests to reflect changes in event handling logic, improving overall test coverage and robustness.
* fix: Clear flushTimeout in RedisEventTransport to prevent potential memory leaks
- Added logic to clear the flushTimeout in the reorderBuffer when resetting the sequence counters, ensuring proper resource management and preventing memory leaks during state transitions in RedisEventTransport.
* 🪟 fix: Update Link Target to Open in Separate Tabs (#11669)
`_new` is not a recognized keyword for the `target` attribute. While
browsers treat it as a named window, `_blank` is the standard value
for opening links in a new tab/window.
* 🔧 fix: Update z-index for ImagePreview modal components (#11714)
- Increased z-index values for the DialogPrimitive overlay and content in ImagePreview.tsx to ensure proper stacking order and visibility of modal elements. This change enhances the user experience by preventing modal content from being obscured by other UI elements.
* 📦 chore: Bump `@librechat/agents` & `axios`, Bedrock Prompt Caching fix (#11723)
* 🔧 chore: Update @librechat/agents to version 3.1.39 in package.json and package-lock.json
* 🔧 chore: Update axios to version 1.13.5 in package.json and package-lock.json across multiple packages
* ♿ style(MCP): Enhance dialog accessibility and styling consistency (#11585)
* style: update input IDs in BasicInfoSection for consistency and improve accessibility
* style: add border-destructive variable for improved design consistency
* style: update error border color for title input in BasicInfoSection
* style: update delete confirmation dialog title and description for MCP Server
* style: add text-destructive variable for improved design consistency
* style: update error message and border color for URL and trust fields for consistency
* style: reorder imports and update error message styling for consistency across sections
* style: enhance MCPServerDialog with copy link functionality and UI improvements
* style: enhance MCPServerDialog with improved accessibility and loading indicators
* style: bump @librechat/client to 0.4.51 and enhance OGDialogTemplate for improved selection handling
* a11y: enhance accessibility and error handling in MCPServerDialog sections
* style: enhance MCPServerDialog accessibility and improve resource name handling
* style: improve accessibility in MCPServerDialog and AuthSection, update translation for delete confirmation
* style: update aria-invalid attributes to use string values for improved accessibility in form sections
* style: enhance accessibility in AuthSection by updating aria attributes and adding error messages
* style: remove unnecessary aria-hidden attributes from Spinner components in MCPServerDialog
* style: simplify legacy selection check in OGDialogTemplate
* 🛡️ fix: Implement TOCTOU-Safe SSRF Protection for Actions and MCP (#11722)
* refactor: better SSRF Protection in Action and Tool Services
- Added `createSSRFSafeAgents` function to create HTTP/HTTPS agents that block connections to private/reserved IP addresses, enhancing security against SSRF attacks.
- Updated `createActionTool` to accept a `useSSRFProtection` parameter, allowing the use of SSRF-safe agents during tool execution.
- Modified `processRequiredActions` and `loadAgentTools` to utilize the new SSRF protection feature based on allowed domains configuration.
- Introduced `resolveHostnameSSRF` function to validate resolved IPs against private ranges, preventing potential SSRF vulnerabilities.
- Enhanced tests for domain resolution and private IP detection to ensure robust SSRF protection mechanisms are in place.
* feat: Implement SSRF protection in MCP connections
- Added `createSSRFSafeUndiciConnect` function to provide SSRF-safe DNS lookup options for undici agents.
- Updated `MCPConnection`, `MCPConnectionFactory`, and `ConnectionsRepository` to include `useSSRFProtection` parameter, enabling SSRF protection based on server configuration.
- Enhanced `MCPManager` and `UserConnectionManager` to utilize SSRF protection when establishing connections.
- Updated tests to validate the integration of SSRF protection across various components, ensuring robust security measures are in place.
* refactor: WS MCPConnection with SSRF protection and async transport construction
- Added `resolveHostnameSSRF` to validate WebSocket hostnames against private IP addresses, enhancing SSRF protection.
- Updated `constructTransport` method to be asynchronous, ensuring proper handling of SSRF checks before establishing connections.
- Improved error handling for WebSocket transport to prevent connections to potentially unsafe addresses.
* test: Enhance ActionRequest tests for SSRF-safe agent passthrough
- Added tests to verify that httpAgent and httpsAgent are correctly passed to axios.create when provided in ActionRequest.
- Included scenarios to ensure agents are not included when no options are specified.
- Enhanced coverage for POST requests to confirm agent passthrough functionality.
- Improved overall test robustness for SSRF protection in ActionRequest execution.
* 🏢 fix: Handle Group Overage for Azure Entra Authentication (#11557)
small fix
add tests
reorder
Update api/strategies/openidStrategy.spec.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Update api/strategies/openidStrategy.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
some fixes
and fix
fix
more fixes
fix
* 🕵️♂️ fix: Handle 404 errors on agent queries for favorites (#11587)
* 🗃️ refactor: Separate Tool Cache Namespace for Blue/Green Deployments (#11738)
* 🔧 refactor: Introduce TOOL_CACHE for isolated caching of tools
- Added TOOL_CACHE key to CacheKeys enum for managing tool-related cache.
- Updated various services and controllers to utilize TOOL_CACHE instead of CONFIG_STORE for better separation of concerns in caching logic.
- Enhanced .env.example with comments on using in-memory cache for blue/green deployments.
* 🔧 refactor: Update cache configuration for in-memory storage handling
- Enhanced the handling of `FORCED_IN_MEMORY_CACHE_NAMESPACES` in `cacheConfig.ts` to default to `CONFIG_STORE` and `APP_CONFIG`, ensuring safer blue/green deployments.
- Updated `.env.example` with clearer comments regarding the usage of in-memory cache namespaces.
- Improved unit tests to validate the new default behavior and handling of empty strings for cache namespaces.
* 💡 fix: System Theme Picker Selection (#11220)
* fix: theme picker selection
* refactor: remove problematic Jotai use and replace with React state and localStorage implementation
* chore: address comments from Copilot + LibreChat Agent assisted reviewers
* chore: remove unnecessary edit
* chore: remove space
* 🌍 i18n: Update translation.json with latest translations (#11739)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* 🛡️ fix: Secure MCP/Actions OAuth Flows, Resolve Race Condition & Tool Cache Cleanup (#11756)
* 🔧 fix: Update OAuth error message for clarity
- Changed the default error message in the OAuth error route from 'Unknown error' to 'Unknown OAuth error' to provide clearer context during authentication failures.
* 🔒 feat: Enhance OAuth flow with CSRF protection and session management
- Implemented CSRF protection for OAuth flows by introducing `generateOAuthCsrfToken`, `setOAuthCsrfCookie`, and `validateOAuthCsrf` functions.
- Added session management for OAuth with `setOAuthSession` and `validateOAuthSession` middleware.
- Updated routes to bind CSRF tokens for MCP and action OAuth flows, ensuring secure authentication.
- Enhanced tests to validate CSRF handling and session management in OAuth processes.
* 🔧 refactor: Invalidate cached tools after user plugin disconnection
- Added a call to `invalidateCachedTools` in the `updateUserPluginsController` to ensure that cached tools are refreshed when a user disconnects from an MCP server after a plugin authentication update. This change improves the accuracy of tool data for users.
* chore: imports order
* fix: domain separator regex usage in ToolService
- Moved the declaration of `domainSeparatorRegex` to avoid redundancy in the `loadActionToolsForExecution` function, improving code clarity and performance.
* chore: OAuth flow error handling and CSRF token generation
- Enhanced the OAuth callback route to validate the flow ID format, ensuring proper error handling for invalid states.
- Updated the CSRF token generation function to require a JWT secret, throwing an error if not provided, which improves security and clarity in token generation.
- Adjusted tests to reflect changes in flow ID handling and ensure robust validation across various scenarios.
* 🏁 fix: Resolve Content Aggregation Race Condition in Agent Event Handlers (#11757)
* 🔧 refactor: Consolidate aggregateContent calls in agent handlers
- Moved aggregateContent function calls to the beginning of the event handling functions in the agent callbacks to ensure consistent data aggregation before processing events. This change improves code clarity and maintains the intended functionality without redundancy.
* 🔧 chore: Update @librechat/agents to version 3.1.40 in package.json and package-lock.json across multiple packages
* 🔧 fix: Increase default recursion limit in AgentClient from 25 to 50 for improved processing capability
* 📦 chore: @librechat/agents to v3.1.41 (#11759)
* 🔎 fix: Include Legacy Documents With Undefined `_meiliIndex` in Search Sync (#11745)
* fix: document with undefined _meiliIndex not synced
missing property _meiliIndex is not being synced into meilisearch
* fix: updated comments to reflect changes to fix_meiliSearch property usage
* 🔱 chore: Harden API Routes Against IDOR and DoS Attacks (#11760)
* 🔧 feat: Update user key handling in keys route and add comprehensive tests
- Enhanced the PUT /api/keys route to destructure request body for better clarity and maintainability.
- Introduced a new test suite for keys route, covering key update, deletion, and retrieval functionalities, ensuring robust validation and IDOR prevention.
- Added tests to verify handling of extraneous fields and missing optional parameters in requests.
* 🔧 fix: Enhance conversation deletion route with parameter validation
- Updated the DELETE /api/convos route to handle cases where the request body is empty or the 'arg' parameter is null/undefined, returning a 400 status with an appropriate error message for DoS prevention.
- Added corresponding tests to ensure proper validation and error handling for these scenarios, enhancing the robustness of the API.
* 🔧 fix: Improve request body validation in keys and convos routes
- Updated the DELETE /api/convos and PUT /api/keys routes to validate the request body, returning a 400 status for null or invalid bodies to enhance security and prevent potential DoS attacks.
- Added corresponding tests to ensure proper error handling for these scenarios, improving the robustness of the API.
* 🔒 fix: Prevent Race Condition in RedisJobStore (#11764)
* 🔧 fix: Optimize job update logic in RedisJobStore
- Refactored the updateJob method to use a Lua script for atomic updates, ensuring that jobs are only updated if they exist in Redis.
- Removed redundant existence check and streamlined the serialization process for better performance and clarity.
* 🔧 test: Add race condition tests for RedisJobStore
- Introduced tests to verify behavior of updateJob after deleteJob, ensuring no job hash is recreated post-deletion.
- Added checks for orphan keys when concurrent deleteJob and updateJob operations occur, enhancing reliability in job management.
* 🔧 test: Refactor Redis client readiness checks in violationCache tests
- Introduced a new helper function `waitForRedisClients` to streamline the readiness checks for Redis clients in the violationCache integration tests.
- Removed redundant Redis client readiness checks from individual test cases, improving code clarity and maintainability.
* 🔧 fix: Update RedisJobStore to use hset instead of hmset
- Replaced instances of `hmset` with `hset` in the RedisJobStore implementation to align with the latest Redis command updates.
- Updated Lua script in the eval method to reflect the change, ensuring consistent job handling in both cluster and non-cluster modes.
* ⛵ feat: Expose enableServiceLinks in Helm Deployment Templates (#11741)
* 🐳 feat: Expose enableServiceLinks in Helm Deployment templates (#11740)
Allow users to disable Kubernetes service link injection via enableServiceLinks
in both LibreChat and RAG API Helm charts. This prevents pod startup failures
caused by "argument list too long" errors in namespaces with many services.
* Update helm/librechat/templates/deployment.yaml
* Update helm/librechat-rag-api/templates/rag-deployment.yaml
* set enableServiceLinks default to true
---------
Co-authored-by: Ganesh Bhat <ganesh.bhat@fullscript.com>
* 🔒 fix: Secure Cookie Localhost Bypass and OpenID Token Selection in AuthService (#11782)
* 🔒 fix: Secure Cookie Localhost Bypass and OpenID Token Selection in AuthService
Two independent bugs in `api/server/services/AuthService.js` cause complete
authentication failure when using `OPENID_REUSE_TOKENS=true` with Microsoft
Entra ID (or Auth0) on `http://localhost` with `NODE_ENV=production`:
Bug 1: `secure: isProduction` prevents auth cookies on localhost
PR #11518 introduced `shouldUseSecureCookie()` in `socialLogins.js` to handle
the case where `NODE_ENV=production` but the server runs on `http://localhost`.
However, `AuthService.js` was not updated — it still used `secure: isProduction`
in 6 cookie locations across `setAuthTokens()` and `setOpenIDAuthTokens()`.
The `token_provider` cookie being dropped is critical: without it,
`requireJwtAuth` middleware defaults to the `jwt` strategy instead of
`openidJwt`, causing all authenticated requests to return 401.
Bug 2: `setOpenIDAuthTokens()` returns `access_token` instead of `id_token`
The `openIdJwtStrategy` validates the Bearer token via JWKS. For Entra ID
without `OPENID_AUDIENCE`, the `access_token` is a Microsoft Graph API token
(opaque or signed for a different audience), which fails JWKS validation.
The `id_token` is always a standard JWT signed by the IdP's JWKS keys with
the app's `client_id` as audience — which is what the strategy expects.
This is the same root cause as issue #8796 (Auth0 encrypted access tokens).
Changes:
- Consolidate `shouldUseSecureCookie()` into `packages/api/src/oauth/csrf.ts`
as a shared, typed utility exported from `@librechat/api`, replacing the
duplicate definitions in `AuthService.js` and `socialLogins.js`
- Move `isProduction` check inside the function body so it is evaluated at
call time rather than module load time
- Fix `packages/api/src/oauth/csrf.ts` which also used bare
`secure: isProduction` for CSRF and session cookies (same localhost bug)
- Return `tokenset.id_token || tokenset.access_token` from
`setOpenIDAuthTokens()` so JWKS validation works with standard OIDC
providers; falls back to `access_token` for backward compatibility
- Add 15 tests for `shouldUseSecureCookie()` covering production/dev modes,
localhost variants, edge cases, and a documented IPv6 bracket limitation
- Add 13 tests for `setOpenIDAuthTokens()` covering token selection,
session storage, cookie secure flag delegation, and edge cases
Refs: #8796, #11518, #11236, #9931
* chore: Adjust Import Order and Type Definitions in AgentPanel Component
- Reordered imports in `AgentPanel.tsx` for better organization and clarity.
- Updated type imports to ensure proper usage of `FieldNamesMarkedBoolean` and `TranslationKeys`.
- Removed redundant imports to streamline the codebase.
* 🦙 fix: Memory Agent Fails to Initialize with Ollama Provider (#11680)
Fixed an issue where memory agents would fail with 'Provider Ollama not supported'
error when using Ollama as a custom endpoint. The getCustomEndpointConfig function
was only normalizing the endpoint config name but not the endpoint parameter
during comparison.
Changes:
- Modified getCustomEndpointConfig to normalize both sides of the endpoint comparison
- Added comprehensive test coverage for getCustomEndpointConfig including:
- Test for case-insensitive Ollama endpoint matching (main fix)
- Tests for various edge cases and error handling
This ensures that endpoint name matching works correctly for Ollama regardless
of case sensitivity in the configuration.
* 🪙 refactor: Distinguish ID Tokens from Access Tokens in OIDC Federated Auth (#11711)
* fix(openid): distinguish ID tokens from access tokens in federated auth
Fix OpenID Connect token handling to properly distinguish ID tokens from access tokens. ID tokens and access tokens are now stored and propagated separately, preventing token placeholders from resolving to identical values.
- AuthService.js: Added idToken field to session storage
- openIdJwtStrategy.js: Updated to read idToken from session
- openidStrategy.js: Explicitly included id_token in federatedTokens
- Test suites: Added comprehensive test coverage for token distinction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(openid): add separate openid_id_token cookie for ID token storage
Store the OIDC ID token in its own cookie rather than relying solely on
the access token, ensuring correct token type is used for identity
verification vs API authorization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test(openid): add JWT strategy cookie fallback tests
Cover the token source resolution logic in openIdJwtStrategy:
session-only, cookie-only, partial session fallback, raw Bearer
fallback, and distinct id_token/access_token from cookies.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* 🛰️ feat: Add Bedrock Parameter Settings for MoonshotAI and Z.AI Models (#11783)
- Introduced new model entries for 'moonshotai.kimi' and 'moonshotai.kimi-k2.5' in tokens.ts.
- Updated parameterSettings.ts to include configurations for MoonshotAI and ZAI providers.
- Enhanced schemas.ts by adding MoonshotAI and ZAI to the BedrockProviders enum for better integration.
* 🧰 fix: Convert `const` to `enum` in MCP Schemas for Gemini Compatibility (#11784)
* fix: Convert `const` to `enum` in MCP tool schemas for Gemini/Vertex AI compatibility
Gemini/Vertex AI rejects the JSON Schema `const` keyword in function declarations
with a 400 error. Previously, the Zod conversion layer accidentally stripped `const`,
but after migrating to pass raw JSON schemas directly to providers, the unsupported
keyword now reaches Gemini verbatim.
Add `normalizeJsonSchema` to recursively convert `const: X` → `enum: [X]`, which is
semantically equivalent per the JSON Schema spec and supported by all providers.
* fix: Update secure cookie handling in AuthService to use dynamic secure flag
Replaced the static `secure: isProduction` with a call to `shouldUseSecureCookie()` in the `setOpenIDAuthTokens` function. This change ensures that the secure cookie setting is evaluated at runtime, improving cookie handling in development environments while maintaining security in production.
* refactor: Simplify MCP tool key formatting and remove unused mocks in tests
- Updated MCP test suite to replace static tool key formatting with a dynamic delimiter from Constants, enhancing consistency and maintainability.
- Removed unused mock implementations for `@langchain/core/tools` and `@librechat/agents`, streamlining the test setup.
- Adjusted related test cases to reflect the new tool key format, ensuring all tests remain functional.
* chore: import order
* 🏎️ feat: Smart Reinstall with Turborepo Caching for Better DX (#11785)
* chore: Add Turborepo support and smart reinstall script
- Updated .gitignore to include Turborepo cache directory.
- Added Turbo as a dependency in package.json and package-lock.json.
- Introduced turbo.json configuration for build tasks.
- Created smart-reinstall.js script to optimize dependency installation and package builds using Turborepo caching.
* fix: Address PR review feedback for smart reinstall
- Fix Windows compatibility in hasTurbo() by checking for .cmd/.ps1 shims
- Remove Unix-specific shell syntax (> /dev/null 2>&1) from cache clearing
- Split try/catch blocks so daemon stop failure doesn't block cache clear
- Add actionable tips in error output pointing to --force and --verbose
* 🪟 fix: Tab Isolation for Agent Favorites + MCP Selections (#11786)
* 🔧 refactor: Implement tab-isolated storage for favorites and MCP selections
- Replaced `createStorageAtom` with `createTabIsolatedAtom` in favorites store to prevent cross-tab synchronization of favorites.
- Introduced `createTabIsolatedStorage` and `createTabIsolatedAtom` in `jotai-utils` to facilitate tab-specific state management.
- Updated MCP values atom family to utilize tab-isolated storage, ensuring independent MCP server selections across tabs.
* 🔧 fix: Update MCP selection logic to ensure active MCPs are only set when configured servers are available
- Modified the condition in `useMCPSelect` to check for both available MCPs and configured servers before setting MCP values. This change prevents potential issues when no servers are configured, enhancing the reliability of MCP selections.
* 📳 refactor: Optimize Model Selector (#11787)
- Introduced a new `EndpointMenuContent` component to lazily render endpoint submenu content, improving performance by deferring expensive model-list rendering until the submenu is mounted.
- Refactored `EndpointItem` to utilize the new component, simplifying the code and enhancing readability.
- Removed redundant filtering logic and model specifications handling from `EndpointItem`, centralizing it within `EndpointMenuContent` for better maintainability.
* 🎭 feat: Override Custom Endpoint Schema with Specified Params Endpoint (#11788)
* 🔧 refactor: Simplify payload parsing and enhance getSaveOptions logic
- Removed unused bedrockInputSchema from payloadParser, streamlining the function.
- Updated payloadParser to handle optional chaining for model parameters.
- Enhanced getSaveOptions to ensure runOptions defaults to an empty object if parsing fails, improving robustness.
- Adjusted the assignment of maxContextTokens to use the instance variable for consistency.
* 🔧 fix: Update maxContextTokens assignment logic in initializeAgent function
- Enhanced the maxContextTokens assignment to allow for user-defined values, ensuring it defaults to a calculated value only when not provided or invalid. This change improves flexibility in agent initialization.
* 🧪 test: Add unit tests for initializeAgent function
- Introduced comprehensive unit tests for the initializeAgent function, focusing on maxContextTokens behavior.
- Tests cover scenarios for user-defined values, fallback calculations, and edge cases such as zero and negative values, enhancing overall test coverage and reliability of agent initialization logic.
* refactor: default params Endpoint Configuration Handling
- Integrated `getEndpointsConfig` to fetch endpoint configurations, allowing for dynamic handling of `defaultParamsEndpoint`.
- Updated `buildEndpointOption` to pass `defaultParamsEndpoint` to `parseCompactConvo`, ensuring correct parameter handling based on endpoint type.
- Added comprehensive unit tests for `buildDefaultConvo` and `cleanupPreset` to validate behavior with `defaultParamsEndpoint`, covering various scenarios and edge cases.
- Refactored related hooks and utility functions to support the new configuration structure, improving overall flexibility and maintainability.
* refactor: Centralize defaultParamsEndpoint retrieval
- Introduced `getDefaultParamsEndpoint` function to streamline the retrieval of `defaultParamsEndpoint` across various hooks and middleware.
- Updated multiple files to utilize the new function, enhancing code consistency and maintainability.
- Removed redundant logic for fetching `defaultParamsEndpoint`, simplifying the codebase.
* 🧩 chore: Extract Agent Client Utilities to `/packages/api` (#11789)
Extract 7 standalone utilities from api/server/controllers/agents/client.js
into packages/api/src/agents/client.ts for TypeScript support and to
declutter the 1400-line controller module:
- omitTitleOptions: Set of keys to exclude from title generation options
- payloadParser: Extracts model_parameters from request body for non-agent endpoints
- createTokenCounter: Factory for langchain-compatible token counting functions
- logToolError: Callback handler for agent tool execution errors
- findPrimaryAgentId: Resolves primary agent from suffixed parallel agent IDs
- createMultiAgentMapper: Message content processor that filters parallel agent
output to primary agents and applies agent labels for handoff/multi-agent flows
Supporting changes:
- Add endpointOption and endpointType to RequestBody type (packages/api/src/types/http.ts)
so payloadParser can access middleware-attached fields without type casts
- Add @typescript-eslint/no-unused-vars with underscore ignore patterns to the
packages/api eslint config block, matching the convention used by client/ and
data-provider/ blocks
- Update agent controller imports to consume the moved functions from @librechat/api
and remove now-unused direct imports (logAxiosError, labelContentByAgent,
getTokenCountForMessage)
* 📦 chore: `@librechat/agents` to v3.1.42 (#11790)
* 🗨️ refactor: Better Whitespace handling in Chat Message rendering (#11791)
- Updated the rendering logic in the Part component to handle whitespace-only text more effectively.
- Introduced a placeholder for whitespace-only last parts during streaming to enhance user experience.
- Ensured non-last whitespace-only parts are skipped to avoid rendering empty containers, improving layout stability.
* 🗂️ refactor: Artifacts via Model Specs & Scope Badge Persistence by Spec Context (#11796)
* 🔧 refactor: Simplify MCP selection logic in useMCPSelect hook
- Removed redundant useEffect for setting ephemeral agent when MCP values change.
- Integrated ephemeral agent update directly into the MCP value change handler, improving code clarity and reducing unnecessary re-renders.
- Updated dependencies in the effect hook to ensure proper state management.
Why Effect 2 Was Added (PR #9528)
PR #9528 was a refactor that migrated MCP state from useLocalStorage hooks to Jotai atomWithStorage. Before that PR, useLocalStorage
handled bidirectional sync between localStorage and Recoil in one abstraction. After the migration, the two useEffect hooks were
introduced to bridge Jotai ↔ Recoil:
- Effect 1 (Recoil → Jotai): When ephemeralAgent.mcp changes externally, update the Jotai atom (which drives the UI dropdown)
- Effect 2 (Jotai → Recoil): When mcpValues changes, push it back to ephemeralAgent.mcp (which is read at submission time)
Effect 2 was needed because in that PR's design, setMCPValues only wrote to Jotai — it never touched Recoil. Effect 2 was the bridge to
propagate user selections into the ephemeral agent.
Why Removing It Is Correct
All user-initiated MCP changes go through setMCPValues. The callers are in useMCPServerManager: toggleServerSelection,
batchToggleServers, OAuth success callbacks, and access revocation. Our change puts the Recoil write directly in that callback, so all
these paths are covered.
All external changes go through Recoil, handled by Effect 1 (kept). Model spec application (applyModelSpecEphemeralAgent), agent
template application after submission, and BadgeRowContext initialization all write directly to ephemeralAgentByConvoId. Effect 1
watches ephemeralAgent?.mcp and syncs those into the Jotai atom for the UI.
There is no code path where mcpValues changes without going through setMCPValues or Effect 1. The only other source is
atomWithStorage's getOnInit reading from localStorage on mount — that's just restoring persisted state and is harmless (overwritten by
Effect 1 if the ephemeral agent has values).
Additional Benefits
- Eliminates the race condition. Effect 2 fired on mount with Jotai's stale default ([]), overwriting ephemeralAgent.mcp that had been
set by a model spec. Our change prevents that because the imperative sync only fires on explicit user action.
- Eliminates infinite loop risk. The old bidirectional two-effect approach relied on isEqual/JSON.stringify checks to break cycles. The
new unidirectional-reactive (Effect 1) + imperative (setMCPValues) approach has no such risk.
- Effect 1's enhancements are preserved. The mcp_clear sentinel handling and configuredServers filtering (both added after PR #9528)
continue to work correctly.
* ✨ feat: Add artifacts support to model specifications and ephemeral agents
- Introduced `artifacts` property in the model specification and ephemeral agent types, allowing for string or boolean values.
- Updated `applyModelSpecEphemeralAgent` to handle artifacts, defaulting to 'default' if true or an empty string if not specified.
- Enhanced localStorage handling to store artifacts alongside other agent properties, improving state management for ephemeral agents.
* 🔧 refactor: Update BadgeRowContext to improve localStorage handling
- Modified the logic to only apply values from localStorage that were actually stored, preventing unnecessary overrides of the ephemeral agent.
- Simplified the setting of ephemeral agent values by directly using initialValues, enhancing code clarity and maintainability.
* 🔧 refactor: Enhance ephemeral agent handling in BadgeRowContext and model spec application
- Updated BadgeRowContext to apply localStorage values only for tools not already set in ephemeralAgent, improving state management.
- Modified useApplyModelSpecEffects to reset the ephemeral agent when no spec is provided but specs are configured, ensuring localStorage defaults are applied correctly.
- Streamlined the logic for applying model spec properties, enhancing clarity and maintainability.
* refactor: Isolate spec and non-spec tool/MCP state with environment-keyed storage
Spec tool state (badges, MCP) and non-spec user preferences previously shared
conversation-keyed localStorage, causing cross-pollination when switching between
spec and non-spec models. This introduces environment-keyed storage so each
context maintains independent persisted state.
Key changes:
- Spec active: no localStorage persistence — admin config always applied fresh
- Non-spec (with specs configured): tool/MCP state persisted to __defaults__ key
- No specs configured: zero behavior change (conversation-keyed storage)
- Per-conversation isolation preserved for existing conversations
- Dual-write on user interaction updates both conversation and environment keys
- Remove mcp_clear sentinel in favor of null ephemeral agent reset
* refactor: Enhance ephemeral agent initialization and MCP handling in BadgeRowContext and useMCPSelect
- Updated BadgeRowContext to clarify the handling of localStorage values for ephemeral agents, ensuring proper initialization based on conversation state.
- Improved useMCPSelect tests to accurately reflect behavior when setting empty MCP values, ensuring the visual selection clears as expected.
- Introduced environment-keyed storage logic to maintain independent state for spec and non-spec contexts, enhancing user experience during context switching.
* test: Add comprehensive tests for useToolToggle and applyModelSpecEphemeralAgent hooks
- Introduced unit tests for the useToolToggle hook, covering dual-write behavior in non-spec mode and per-conversation isolation.
- Added tests for applyModelSpecEphemeralAgent, ensuring correct application of model specifications and user overrides from localStorage.
- Enhanced test coverage for ephemeral agent state management during conversation transitions, validating expected behaviors for both new and existing conversations.
* 👻 fix: Prevent Async Title Generation From Recreating Deleted Conversations (#11797)
* 🐛 fix: Prevent deleted conversations from being recreated by async title generation
When a user deletes a chat while auto-generated title is still in progress,
`saveConvo` with `upsert: true` recreates the deleted conversation as a ghost
entry with only a title and no messages. This adds a `noUpsert` metadata option
to `saveConvo` and uses it in both agent and assistant title generation paths,
so the title save is skipped if the conversation no longer exists.
* test: conversation creation logic with noUpsert option
Added new tests to validate the behavior of the `saveConvo` function with the `noUpsert` option. This includes scenarios where a conversation should not be created if it doesn't exist, updating an existing conversation when `noUpsert` is true, and ensuring that upsert behavior remains the default when `noUpsert` is not provided. These changes improve the flexibility and reliability of conversation management.
* test: Clean up Conversation.spec.js by removing commented-out code
Removed unnecessary comments from the Conversation.spec.js test file to improve readability and maintainability. This includes comments related to database verification and temporary conversation handling, streamlining the test cases for better clarity.
* 🌙 fix: Accessible Contrast for Theme Switcher Icons (#11795)
* fix: proper colors for contrast in theme switcher icons
* fix: use themed font colors
* 🔧 feat: `deleteRagFile` utility for Consistent RAG API document deletion (#11493)
* 🔧 feat: Implement deleteRagFile utility for RAG API document deletion across storage strategies
* chore: import order
* chore: import order & remove unnecessary comments
---------
Co-authored-by: Danny Avila <danacordially@gmail.com>
* 💎 feat: Add Redis as Optional Sub-chart Dependency in Helm Chart (#11664)
Add Bitnami Redis as an optional Helm sub-chart dependency, following the
same pattern used by MongoDB and Meilisearch. When enabled, USE_REDIS and
REDIS_URI are auto-wired into the LibreChat ConfigMap.
- Add redis dependency (Bitnami 24.1.3, Redis 8.4) to Chart.yaml
- Add redis config section to values.yaml (disabled by default)
- Auto-wire USE_REDIS and REDIS_URI in configmap-env.yaml with dig
checks to allow user overrides via configEnv
- Bump chart version to 1.10.0
Co-authored-by: Feng Lu <feng.lu@kindredgroup.com>
Co-authored-by: Danny Avila <danny@librechat.ai>
* 🎮 feat: Bedrock Parameters for OpenAI GPT-OSS models (#11798)
Add OpenAI as a Bedrock provider so that selecting openai.gpt-oss-*
models in the Bedrock agent UI renders the general parameter settings
(temperature, top_p, max_tokens) instead of a blank panel. Also add
token context lengths (128K) for gpt-oss-20b and gpt-oss-120b.
* 🎛️ fix: Google JSON Schema Normalization/Resolution Logic (#11804)
- Updated `resolveJsonSchemaRefs` to prevent `` and `definitions` from appearing in the resolved output, ensuring compatibility with LLM APIs.
- Improved `normalizeJsonSchema` to strip vendor extension fields (e.g., `x-*` prefixed keys) and leftover ``/`definitions` blocks, enhancing schema normalization for Google/Gemini API.
- Added comprehensive tests to validate the stripping of ``, vendor extensions, and proper normalization across various schema structures.
* 📦 chore: `@librechat/agents` to v3.1.43 (#11805)
* 🪪 fix: Pass Scope in OpenID Refresh Token Grant for Azure Custom API (#11770)
* fix(auth): pass scope parameter in OpenID refresh token grant
When using Azure Entra ID with a custom API scope (e.g., api://app-id/access_user)
and OPENID_REUSE_TOKENS=true, the refresh token exchange fails with AADSTS90009
because the scope parameter is not included in the refresh request.
Azure AD v2.0 requires the scope parameter when refreshing tokens issued for
custom API audiences. Without it, Azure interprets the request as the app
requesting a token for itself and rejects it.
This fix passes OPENID_SCOPE as the scope parameter to refreshTokenGrant(),
maintaining backward compatibility (no scope sent if OPENID_SCOPE is not set).
Fixes: refresh token 400 error with Azure custom API scopes
Tested: Azure Entra ID + Token Reuse + SharePoint integration
* style(auth): fix ESLint multiline arguments formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* 🥠 refactor: Always set OIDC refresh token cookie to survive session expiry (#11810)
The express session cookie maxAge (SESSION_EXPIRY, default 15 min) is
shorter than the OIDC token lifetime (~1 hour). When OPENID_REUSE_TOKENS
is enabled, the refresh token was stored only in the express session
(req.session.openidTokens). After the session expired, the refresh token
was lost, causing "Refresh token not provided" on the next refresh
attempt and signing the user out. Re-login via OIDC would succeed
immediately (provider session still active), masking the root cause.
The session-only storage was introduced in #11236 to avoid HTTP/2 header
size limits from large access_token/id_token JWTs (especially Azure
Entra ID with many group claims). The refresh token is a small opaque
string and does not contribute to that problem.
Move the refreshToken cookie out of the no-session fallback branch so it
is always set alongside the session storage. The refreshController
already has the fallback logic (req.session?.openidTokens?.refreshToken
|| parsedCookies.refreshToken) but previously never had a cookie to fall
back to.
Timeline before fix:
T=0 Login, session created (15 min maxAge), id_token valid ~1 hr
T=15min Session cookie expires, refresh token lost
T=15min+ Page refresh or id_token expiry triggers refresh, fails with
"Refresh token not provided", user redirected to /login
Timeline after fix:
T=0 Login, session created + refreshToken cookie (7 day expiry)
T=15min Session cookie expires
T=15min+ Refresh reads refreshToken from cookie fallback, succeeds,
restores session with fresh tokens
* 🪂 fix: Handle MongoDB Connection Errors to Prevent Process Crashes (#11809)
* fix: handle MongoDB connection errors to prevent process crashes
Add mongoose.connection.on('error') listener in connect.js to catch
connection-level errors emitted by MongoDB driver's SDAM monitoring.
Without this listener, these errors become uncaught exceptions per
Node.js EventEmitter behavior.
Also add MongoDB error patterns to the uncaughtException handler in
server/index.js as defense-in-depth, following the same pattern used
for GoogleGenerativeAI, Meilisearch, and OpenAI errors.
Fixes #11808
* style: fix prettier formatting in uncaughtException handler
* refactor: move error listener to module level
* fix: use precise MongoDB error matching in uncaughtException handler
* fix: replace process.exit(1) with graceful error logging
Instead of maintaining a growing list of error patterns that should
not crash the process, invert the default behavior: log all unhandled
errors and keep running. The existing specific handlers are preserved
for their contextual log messages.
This prevents process crashes from any transient error (MongoDB timeouts,
network issues, third-party library bugs) without needing to add new
patterns each time a new error type is encountered. Unnecessary restarts
are expensive as they trigger full Meilisearch re-syncs under load.
* fix: address review feedback
- connect.js: pass full error object to logger instead of just message
- server/index.js: add optional chaining for nullish err
- server/index.js: make crash-on-unknown-error opt-in via
CRASH_ON_UNCAUGHT_EXCEPTION env var (defaults to graceful logging)
* fix: rename to CONTINUE_ON_UNCAUGHT_EXCEPTION, default to exit
---------
Co-authored-by: Feng Lu <feng.lu@kindredgroup.com>
* 📦 chore: `@librechat/agents` to v3.1.44 (#11811)
* 📋 chore: Document Uncaught Exception Config and Fix Empty Text Export (#11812)
* chore: Prevent empty text parts in conversation export function
Added a check to return an empty array if the text part of the conversation is empty or consists only of whitespace, ensuring cleaner data handling in the export process.
* chore: Update .env.example to include CONTINUE_ON_UNCAUGHT_EXCEPTION variable
Added documentation for the CONTINUE_ON_UNCAUGHT_EXCEPTION environment variable, which allows the app to continue running after encountering uncaught exceptions. This change is not recommended for production environments unless necessary.
* 📦 chore: Update `@librechat/agents` to v3.1.45 (#11815)
* 🌍 i18n: Update translation.json with latest translations (#11813)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* 🪆 refactor: Internalize Producer Event Handling into Agent Graph Context (#11816)
* 🔧 refactor: Simplify Event Handling with Consumer Callbacks only
Removed direct handling of tool calls from the ModelEndHandler and using ChatModelStreamHandler outside of graph contexts, as are now managed within the graph execution context to maintain it as a producer of events, and the model end handler as a consumer. This change eliminates potential race conditions and streamlines the processing of model end events.
/**
* handleToolCalls is now called from within the graph execution context
* (Graph.createCallModel, after attemptInvoke) rather than here in the
* stream consumer. This eliminates the race condition where ToolNode
* could read toolCallStepIds before this handler had populated it,
* since the stream consumer and graph execution run concurrently.
*/
* 📦 chore: Update `@librechat/agents` to v3.1.50
* 🤖 feat: Claude Sonnet 4.6 support (#11829)
* 🤖 feat: Claude Sonnet 4.6 support
- Updated .env.example to include claude-sonnet-4-6 in the list of available models.
- Enhanced token value assignments in api/models/tx.js and packages/api/src/utils/tokens.ts to accommodate claude-sonnet-4-6.
- Added tests in packages/data-provider/specs/bedrock.spec.ts to verify support for claude-sonnet-4-6 in adaptive thinking and context-1m functionalities.
- Modified bedrock.ts to correctly parse and identify the version of claude-sonnet-4-6 for adaptive thinking checks.
- Included claude-sonnet-4-6 in sharedAnthropicModels and bedrockModels for consistent model availability.
* chore: additional Claude Sonnet 4.6 tests
- Added unit tests for Claude Sonnet 4.6 in `tokens.spec.js` to verify context length and max output tokens.
- Updated `helpers.ts` documentation to reflect adaptive thinking support for Sonnet 4.6.
- Enhanced `llm.spec.ts` with tests for context headers and adaptive thinking configurations for Claude Sonnet 4.6.
- Improved `bedrock.spec.ts` to ensure correct parsing and handling of Claude Sonnet 4.6 model variations with adaptive thinking.
* 🌍 i18n: Update translation.json with latest translations (#11831)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* 📦 chore: Bump Dependabot Packages (#11836)
* 📦 chore: Update axios and form-data dependencies in react-query/package.json and lockfile
- Upgraded axios from version 1.12.1 to 1.13.5.
- Updated form-data from version 4.0.4 to 4.0.5.
- Adjusted follow-redirects dependency version in package-lock.json.
* 📦 chore: Update mermaid and chevrotain dependencies in package.json and package-lock.json
- Upgraded mermaid from version 11.12.2 to 11.12.3.
- Updated chevrotain and its related packages to version 11.1.1.
- Adjusted lodash-es version to 4.17.23 and langium dependency in @mermaid-js/parser to ^4.0.0.
* 📦 chore: Update langsmith dependency to version 0.4.12 in package.json and package-lock.json
* 🪹 fix: Prevent whitespace-only Chat input Submissions (#11838)
fix(input): normalize chat input text before submit
Trim input text before checking if empty to show submit button as disabled
* ♻️ refactor: On-demand MCP connections: remove proactive reconnect, default to available (#11839)
* feat: Implement reconnection staggering and backoff jitter for MCP connections
- Enhanced the reconnection logic in OAuthReconnectionManager to stagger reconnection attempts for multiple servers, reducing the risk of connection storms.
- Introduced a backoff delay with random jitter in MCPConnection to improve reconnection behavior during network issues.
- Updated the ConnectionsRepository to handle multiple server connections concurrently with a defined concurrency limit.
Added tests to ensure the new reconnection strategy works as intended.
* refactor: Update MCP server query configuration for improved data freshness
- Reduced stale time from 5 minutes to 30 seconds to ensure quicker updates on server initialization.
- Enabled refetching on window focus and mount to enhance data accuracy during user interactions.
* ♻️ refactor: On-demand MCP connections; remove proactive reconnection, default to available
- Remove reconnectServers() from refresh controller (connection storm root cause)
- Stop gating server selection on connection status; add to selection immediately
- Render agent panel tools from DB cache, not live connection status
- Proceed to cached tools on init failure (only gate on OAuth)
- Remove unused batchToggleServers()
- Reduce useMCPServersQuery staleTime from 5min to 30s, enable refetchOnMount/WindowFocus
* refactor: Optimize MCP tool initialization and server connection logic
- Adjusted tool initialization to only occur if no cached tools are available, improving efficiency.
- Updated comments for clarity on server connection and tool fetching processes.
- Removed unnecessary connection status checks during server selection to streamline the user experience.
* 🐛 fix: Normalize `output_text` blocks in Responses API input conversion (#11835)
* 🐛 fix: Normalize `output_text` blocks in Responses API input conversion
Treat `output_text` content blocks the same as `input_text` when
converting Responses API input to internal message format. Previously,
assistant messages containing `output_text` blocks fell through to the
default handler, producing `{ type: 'output_text' }` without a `text`
field, which caused downstream provider adapters (e.g. Bedrock) to fail
with "Unsupported content block type: output_text".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: Remove ChatModelStreamHandler from OpenAI and Responses controllers
Eliminated the ChatModelStreamHandler from both OpenAIChatCompletionController and createResponse functions to streamline event handling. This change simplifies the code by relying on existing handlers for message deltas and reasoning deltas, enhancing maintainability and reducing complexity in the agent's event processing logic.
* feat: Enhance input conversion in Responses API
Updated the `convertInputToMessages` function to handle additional content types, including `input_file` and `refusal` blocks, ensuring they are converted to appropriate message formats. Implemented null filtering for content arrays and default values for missing fields, improving robustness. Added comprehensive unit tests to validate these changes and ensure correct behavior across various input scenarios.
* fix: Forward upstream provider status codes in error responses
Updated error handling in OpenAIChatCompletionController and createResponse functions to forward upstream provider status codes (e.g., Anthropic 400s) instead of masking them as 500. This change improves error reporting by providing more accurate status codes and error types, enhancing the clarity of error responses for clients.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* ⚛️ refactor: Redis Scalability Improvements for High-Throughput Deployments (#11840)
* fix: Redis scalability improvements for high-throughput deployments
Replace INCR+check+DECR race in concurrency middleware with atomic Lua
scripts. The old approach allowed 3-4 concurrent requests through a
limit of 2 at 300 req/s because another request could slip between the
INCR returning and the DECR executing. The Lua scripts run atomically
on the Redis server, eliminating the race window entirely.
Add exponential backoff with jitter to all three Redis retry strategies
(ioredis single-node, cluster, keyv). Previously all instances retried
at the same millisecond after an outage, causing a connection storm.
Batch the RedisJobStore cleanup loop into parallel chunks of 50. With
1000 stale jobs, this reduces cleanup from ~20s of sequential calls to
~2s. Also pipeline appendChunk (xadd + expire) into a single round-trip
and refresh TTL on every chunk instead of only the first, preventing
TTL expiry during long-running streams.
Propagate publish errors in RedisEventTransport.emitDone and emitError
so callers can detect dropped completion/error events. emitChunk is left
as swallow-and-log because its callers fire-and-forget without await.
Add jest.config.js for the API package with babel TypeScript support and
path alias resolution. Fix existing stream integration tests that were
silently broken due to missing USE_REDIS_CLUSTER=false env var.
* chore: Migrate Jest configuration from jest.config.js to jest.config.mjs
Removed the old jest.config.js file and integrated the Jest configuration into jest.config.mjs, adding Babel TypeScript support and path alias resolution. This change streamlines the configuration for the API package.
* fix: Ensure Redis retry delays do not exceed maximum configured delay
Updated the delay calculation in Redis retry strategies to enforce a maximum delay defined in the configuration. This change prevents excessive delays during reconnection attempts, improving overall connection stability and performance.
* fix: Update RedisJobStore cleanup to handle job failures gracefully
Changed the cleanup process in RedisJobStore to use Promise.allSettled instead of Promise.all, allowing for individual job failures to be logged without interrupting the entire cleanup operation. This enhances error handling and provides better visibility into issues during job cleanup.
* 📦 chore: Bump `fast-xml-parser` to v5.3.6 (#11841)
* 🔗 fix: Preserve Stream State Across Reconnects to Prevent Reorder Buffer Desync (#11842)
When all subscribers left a stream, both RedisEventTransport and
InMemoryEventTransport deleted the entire stream state, destroying
the allSubscribersLeftCallbacks and abortCallbacks registered by
GenerationJobManager.createJob(). On the next subscribe/unsubscribe
cycle, the callback that resets hasSubscriber was gone, causing
syncReorderBuffer to be skipped on subsequent reconnects. This led
to the reorder buffer expecting seq 0 while the publisher was at
seq 300+, triggering a 500ms force-flush timeout and "skipping N
missing messages" warnings.
Fix: preserve stream state (callbacks, abort handlers) when the last
subscriber leaves instead of deleting it. State is fully cleaned up
by cleanup() when the job completes, aborts, or is collected by
periodic orphan cleanup.
* 🧭 fix: Robust 404 Conversation Not Found Redirect (#11853)
* fix: route to new conversation when conversation not found
* Addressed PR feedback
* fix: Robust 404 conversation redirect handling
- Extract `isNotFoundError` utility to `utils/errors.ts` so axios stays
contained in one place rather than leaking into route/query layers
- Add `initialConvoQuery.isError` to the useEffect dependency array so
the redirect actually fires when the 404 response arrives after other
deps have already settled (was the root cause of the blank screen)
- Show a warning toast so users understand why they were redirected
- Add `com_ui_conversation_not_found` i18n key
* fix: Enhance error handling in getResponseStatus function
- Update the getResponseStatus function to ensure it correctly returns the status from error objects only if the status is a number. This improves robustness in error handling by preventing potential type issues.
* fix: Improve conversation not found handling in ChatRoute
- Enhance error handling when a conversation is not found by checking additional conditions before showing a warning toast.
- Update the newConversation function to include model data and preset options, improving user experience during error scenarios.
* fix: Log error details for conversation not found in ChatRoute
- Added logging for the initial conversation query error when a conversation is not found, improving debugging capabilities and error tracking in the ChatRoute component.
---------
Co-authored-by: Dan Lew <daniel@mightyacorn.com>
* 🧬 fix: Backfill Missing SHARE Permissions and Migrate Legacy SHARED_GLOBAL Fields (#11854)
* chore: Migrate legacy SHARED_GLOBAL permissions to SHARE and clean up orphaned fields
- Implemented migration logic to convert legacy SHARED_GLOBAL permissions to SHARE for PROMPTS and AGENTS, preserving user intent.
- Added cleanup process to remove orphaned SHARED_GLOBAL fields from the database after the schema change.
- Enhanced unit tests to verify migration and cleanup functionality, ensuring correct behavior for existing roles and permissions.
* fix: Enhance migration of SHARED_GLOBAL to SHARE permissions
- Updated the `updateAccessPermissions` function to ensure that SHARED_GLOBAL values are inherited into SHARE when SHARE is absent from both the database and the update payload.
- Implemented logic to prevent overwriting explicit SHARE values provided in the update, preserving user intent.
- Enhanced unit tests to cover various scenarios, including migration from SHARED_GLOBAL to SHARE and ensuring orphaned SHARED_GLOBAL fields are cleaned up appropriately.
* ✨ v0.8.3-rc1 (#11856)
* 🔧 chore: Update configuration version to 1.3.4 in librechat.example.yaml and data-provider config.ts
- Bumped the configuration version in both librechat.example.yaml and data-provider/src/config.ts to 1.3.4.
- Added new options for creating prompts and agents in the interface section of the YAML configuration.
- Updated capabilities list in the endpoints section to include 'deferred_tools'.
* 🔧 chore: Bump version to 0.8.3-rc1 across multiple packages and update related configurations
- Updated version to 0.8.3-rc1 in bun.lock, package.json, and various package.json files for frontend, backend, and data provider.
- Adjusted Dockerfile and Dockerfile.multi to reflect the new version.
- Incremented version for @librechat/api from 1.7.22 to 1.7.23 and for @librechat/client from 0.4.51 to 0.4.52.
- Updated appVersion in helm Chart.yaml to 0.8.3-rc1.
- Enhanced test configuration to align with the new version.
* 🔧 chore: Update version to 0.8.300 across multiple packages
- Bumped version to 0.8.300 in bun.lock, package-lock.json, and package.json for the data provider.
- Ensured consistency in versioning across the frontend, backend, and data provider packages.
* 🔧 chore: Bump package versions in bun.lock
- Updated version for @librechat/api from 1.7.22 to 1.7.23.
- Incremented version for @librechat/client from 0.4.51 to 0.4.52.
- Bumped version for @librechat/data-schemas from 0.0.35 to 0.0.36.
* 📝 docs: Add AGENTS.md for Project Structure and Coding Standards (#11866)
* 📝 docs: Add AGENTS.md for project structure and coding standards
- Introduced AGENTS.md to outline project workspaces, coding standards, and development commands.
- Defined workspace boundaries for backend and frontend development, emphasizing TypeScript usage.
- Established guidelines for code style, iteration performance, type safety, and import order.
- Updated CONTRIBUTING.md to reference AGENTS.md for coding standards and project conventions.
- Modified package.json to streamline build commands, consolidating frontend and backend build processes.
* chore: Update build commands and improve smart reinstall process
- Modified AGENTS.md to clarify the purpose of `npm run smart-reinstall` and other build commands, emphasizing Turborepo's role in dependency management and builds.
- Updated package.json to streamline build commands, replacing the legacy frontend build with a Turborepo-based approach for improved performance.
- Enhanced the smart reinstall script to fully delegate build processes to Turborepo, including cache management and dependency checks, ensuring a more efficient build workflow.
* 🔍 chore: Update MeiliSearch version (#11873)
- Bumped MeiliSearch image version from v1.12.3 to v1.35.1 in both deploy-compose.yml and docker-compose.yml
- Updated volume paths to reflect the new version for data storage consistency.
* 🤖 feat: Gemini 3.1 Pricing and Context Window (#11884)
- Added support for the new Gemini 3.1 models, including 'gemini-3.1-pro-preview' and 'gemini-3.1-pro-preview-customtools'.
- Updated pricing logic to apply standard and premium rates based on token usage thresholds for the new models.
- Enhanced tests to validate pricing behavior for both standard and premium scenarios.
- Modified configuration files to include Gemini 3.1 models in the default model lists and token value mappings.
- Updated environment example file to reflect the new model options.
* ✳️ docs: Point CLAUDE.md to AGENTS.md (#11886)
* 🪣 fix: Proper Key Extraction from S3 URL (#11241)
* ✨ feat: Enhance S3 URL handling and add comprehensive tests for CRUD …
jcbartle
pushed a commit
to jcbartle/LibreChat
that referenced
this pull request
May 11, 2026
…pec Context (LibreChat-AI#11796) * 🔧 refactor: Simplify MCP selection logic in useMCPSelect hook - Removed redundant useEffect for setting ephemeral agent when MCP values change. - Integrated ephemeral agent update directly into the MCP value change handler, improving code clarity and reducing unnecessary re-renders. - Updated dependencies in the effect hook to ensure proper state management. Why Effect 2 Was Added (PR LibreChat-AI#9528) PR LibreChat-AI#9528 was a refactor that migrated MCP state from useLocalStorage hooks to Jotai atomWithStorage. Before that PR, useLocalStorage handled bidirectional sync between localStorage and Recoil in one abstraction. After the migration, the two useEffect hooks were introduced to bridge Jotai ↔ Recoil: - Effect 1 (Recoil → Jotai): When ephemeralAgent.mcp changes externally, update the Jotai atom (which drives the UI dropdown) - Effect 2 (Jotai → Recoil): When mcpValues changes, push it back to ephemeralAgent.mcp (which is read at submission time) Effect 2 was needed because in that PR's design, setMCPValues only wrote to Jotai — it never touched Recoil. Effect 2 was the bridge to propagate user selections into the ephemeral agent. Why Removing It Is Correct All user-initiated MCP changes go through setMCPValues. The callers are in useMCPServerManager: toggleServerSelection, batchToggleServers, OAuth success callbacks, and access revocation. Our change puts the Recoil write directly in that callback, so all these paths are covered. All external changes go through Recoil, handled by Effect 1 (kept). Model spec application (applyModelSpecEphemeralAgent), agent template application after submission, and BadgeRowContext initialization all write directly to ephemeralAgentByConvoId. Effect 1 watches ephemeralAgent?.mcp and syncs those into the Jotai atom for the UI. There is no code path where mcpValues changes without going through setMCPValues or Effect 1. The only other source is atomWithStorage's getOnInit reading from localStorage on mount — that's just restoring persisted state and is harmless (overwritten by Effect 1 if the ephemeral agent has values). Additional Benefits - Eliminates the race condition. Effect 2 fired on mount with Jotai's stale default ([]), overwriting ephemeralAgent.mcp that had been set by a model spec. Our change prevents that because the imperative sync only fires on explicit user action. - Eliminates infinite loop risk. The old bidirectional two-effect approach relied on isEqual/JSON.stringify checks to break cycles. The new unidirectional-reactive (Effect 1) + imperative (setMCPValues) approach has no such risk. - Effect 1's enhancements are preserved. The mcp_clear sentinel handling and configuredServers filtering (both added after PR LibreChat-AI#9528) continue to work correctly. * ✨ feat: Add artifacts support to model specifications and ephemeral agents - Introduced `artifacts` property in the model specification and ephemeral agent types, allowing for string or boolean values. - Updated `applyModelSpecEphemeralAgent` to handle artifacts, defaulting to 'default' if true or an empty string if not specified. - Enhanced localStorage handling to store artifacts alongside other agent properties, improving state management for ephemeral agents. * 🔧 refactor: Update BadgeRowContext to improve localStorage handling - Modified the logic to only apply values from localStorage that were actually stored, preventing unnecessary overrides of the ephemeral agent. - Simplified the setting of ephemeral agent values by directly using initialValues, enhancing code clarity and maintainability. * 🔧 refactor: Enhance ephemeral agent handling in BadgeRowContext and model spec application - Updated BadgeRowContext to apply localStorage values only for tools not already set in ephemeralAgent, improving state management. - Modified useApplyModelSpecEffects to reset the ephemeral agent when no spec is provided but specs are configured, ensuring localStorage defaults are applied correctly. - Streamlined the logic for applying model spec properties, enhancing clarity and maintainability. * refactor: Isolate spec and non-spec tool/MCP state with environment-keyed storage Spec tool state (badges, MCP) and non-spec user preferences previously shared conversation-keyed localStorage, causing cross-pollination when switching between spec and non-spec models. This introduces environment-keyed storage so each context maintains independent persisted state. Key changes: - Spec active: no localStorage persistence — admin config always applied fresh - Non-spec (with specs configured): tool/MCP state persisted to __defaults__ key - No specs configured: zero behavior change (conversation-keyed storage) - Per-conversation isolation preserved for existing conversations - Dual-write on user interaction updates both conversation and environment keys - Remove mcp_clear sentinel in favor of null ephemeral agent reset * refactor: Enhance ephemeral agent initialization and MCP handling in BadgeRowContext and useMCPSelect - Updated BadgeRowContext to clarify the handling of localStorage values for ephemeral agents, ensuring proper initialization based on conversation state. - Improved useMCPSelect tests to accurately reflect behavior when setting empty MCP values, ensuring the visual selection clears as expected. - Introduced environment-keyed storage logic to maintain independent state for spec and non-spec contexts, enhancing user experience during context switching. * test: Add comprehensive tests for useToolToggle and applyModelSpecEphemeralAgent hooks - Introduced unit tests for the useToolToggle hook, covering dual-write behavior in non-spec mode and per-conversation isolation. - Added tests for applyModelSpecEphemeralAgent, ensuring correct application of model specifications and user overrides from localStorage. - Enhanced test coverage for ephemeral agent state management during conversation transitions, validating expected behaviors for both new and existing conversations.
7 tasks done
danny-avila
added a commit
that referenced
this pull request
Jun 11, 2026
The no-spec branch of `useApplyModelSpecEffects` (added in #11796) reset `ephemeralAgentByConvoId` to null on every `newConversation` call when model specs are configured. On in-place model/endpoint switches (modular chat, same conversation or new-chat draft), BadgeRowContext never refills from localStorage — its init effect only re-runs when the storage suffix or spec changes — so the MCP selection (and tool toggles) were silently dropped from subsequent request payloads while the MCP badge kept displaying them. Reset now only happens on context transitions (leaving a spec, or moving to a different conversation key), where a BadgeRowContext refill is guaranteed; in-place non-spec switches preserve the ephemeral agent. - Gate the no-spec reset on `prevSpecName` / `prevConvoId`, passed from `newConversation` via a snapshot read of the pre-switch conversation - Add jest coverage for all five branches of the no-spec path - Add e2e spec asserting `ephemeralAgent.mcp` stays in the chat payload after a new-chat model switch and after regenerate on a switched conversation (verified failing before the fix, passing after) - Add non-spec "Mock Provider D" endpoint to the e2e config so tests can switch between two real ephemeral endpoints; widen `MockEndpoint` type
fuuuzzy
pushed a commit
to fuuuzzy/LibreChat
that referenced
this pull request
Jun 18, 2026
…Chat-AI#13697) The no-spec branch of `useApplyModelSpecEffects` (added in LibreChat-AI#11796) reset `ephemeralAgentByConvoId` to null on every `newConversation` call when model specs are configured. On in-place model/endpoint switches (modular chat, same conversation or new-chat draft), BadgeRowContext never refills from localStorage — its init effect only re-runs when the storage suffix or spec changes — so the MCP selection (and tool toggles) were silently dropped from subsequent request payloads while the MCP badge kept displaying them. Reset now only happens on context transitions (leaving a spec, or moving to a different conversation key), where a BadgeRowContext refill is guaranteed; in-place non-spec switches preserve the ephemeral agent. - Gate the no-spec reset on `prevSpecName` / `prevConvoId`, passed from `newConversation` via a snapshot read of the pre-switch conversation - Add jest coverage for all five branches of the no-spec path - Add e2e spec asserting `ephemeralAgent.mcp` stays in the chat payload after a new-chat model switch and after regenerate on a switched conversation (verified failing before the fix, passing after) - Add non-spec "Mock Provider D" endpoint to the e2e config so tests can switch between two real ephemeral endpoints; widen `MockEndpoint` type
ThomasVuNguyen
pushed a commit
to ThomasVuNguyen/LibreChat
that referenced
this pull request
Jul 15, 2026
…pec Context (LibreChat-AI#11796) * 🔧 refactor: Simplify MCP selection logic in useMCPSelect hook - Removed redundant useEffect for setting ephemeral agent when MCP values change. - Integrated ephemeral agent update directly into the MCP value change handler, improving code clarity and reducing unnecessary re-renders. - Updated dependencies in the effect hook to ensure proper state management. Why Effect 2 Was Added (PR LibreChat-AI#9528) PR LibreChat-AI#9528 was a refactor that migrated MCP state from useLocalStorage hooks to Jotai atomWithStorage. Before that PR, useLocalStorage handled bidirectional sync between localStorage and Recoil in one abstraction. After the migration, the two useEffect hooks were introduced to bridge Jotai ↔ Recoil: - Effect 1 (Recoil → Jotai): When ephemeralAgent.mcp changes externally, update the Jotai atom (which drives the UI dropdown) - Effect 2 (Jotai → Recoil): When mcpValues changes, push it back to ephemeralAgent.mcp (which is read at submission time) Effect 2 was needed because in that PR's design, setMCPValues only wrote to Jotai — it never touched Recoil. Effect 2 was the bridge to propagate user selections into the ephemeral agent. Why Removing It Is Correct All user-initiated MCP changes go through setMCPValues. The callers are in useMCPServerManager: toggleServerSelection, batchToggleServers, OAuth success callbacks, and access revocation. Our change puts the Recoil write directly in that callback, so all these paths are covered. All external changes go through Recoil, handled by Effect 1 (kept). Model spec application (applyModelSpecEphemeralAgent), agent template application after submission, and BadgeRowContext initialization all write directly to ephemeralAgentByConvoId. Effect 1 watches ephemeralAgent?.mcp and syncs those into the Jotai atom for the UI. There is no code path where mcpValues changes without going through setMCPValues or Effect 1. The only other source is atomWithStorage's getOnInit reading from localStorage on mount — that's just restoring persisted state and is harmless (overwritten by Effect 1 if the ephemeral agent has values). Additional Benefits - Eliminates the race condition. Effect 2 fired on mount with Jotai's stale default ([]), overwriting ephemeralAgent.mcp that had been set by a model spec. Our change prevents that because the imperative sync only fires on explicit user action. - Eliminates infinite loop risk. The old bidirectional two-effect approach relied on isEqual/JSON.stringify checks to break cycles. The new unidirectional-reactive (Effect 1) + imperative (setMCPValues) approach has no such risk. - Effect 1's enhancements are preserved. The mcp_clear sentinel handling and configuredServers filtering (both added after PR LibreChat-AI#9528) continue to work correctly. * ✨ feat: Add artifacts support to model specifications and ephemeral agents - Introduced `artifacts` property in the model specification and ephemeral agent types, allowing for string or boolean values. - Updated `applyModelSpecEphemeralAgent` to handle artifacts, defaulting to 'default' if true or an empty string if not specified. - Enhanced localStorage handling to store artifacts alongside other agent properties, improving state management for ephemeral agents. * 🔧 refactor: Update BadgeRowContext to improve localStorage handling - Modified the logic to only apply values from localStorage that were actually stored, preventing unnecessary overrides of the ephemeral agent. - Simplified the setting of ephemeral agent values by directly using initialValues, enhancing code clarity and maintainability. * 🔧 refactor: Enhance ephemeral agent handling in BadgeRowContext and model spec application - Updated BadgeRowContext to apply localStorage values only for tools not already set in ephemeralAgent, improving state management. - Modified useApplyModelSpecEffects to reset the ephemeral agent when no spec is provided but specs are configured, ensuring localStorage defaults are applied correctly. - Streamlined the logic for applying model spec properties, enhancing clarity and maintainability. * refactor: Isolate spec and non-spec tool/MCP state with environment-keyed storage Spec tool state (badges, MCP) and non-spec user preferences previously shared conversation-keyed localStorage, causing cross-pollination when switching between spec and non-spec models. This introduces environment-keyed storage so each context maintains independent persisted state. Key changes: - Spec active: no localStorage persistence — admin config always applied fresh - Non-spec (with specs configured): tool/MCP state persisted to __defaults__ key - No specs configured: zero behavior change (conversation-keyed storage) - Per-conversation isolation preserved for existing conversations - Dual-write on user interaction updates both conversation and environment keys - Remove mcp_clear sentinel in favor of null ephemeral agent reset * refactor: Enhance ephemeral agent initialization and MCP handling in BadgeRowContext and useMCPSelect - Updated BadgeRowContext to clarify the handling of localStorage values for ephemeral agents, ensuring proper initialization based on conversation state. - Improved useMCPSelect tests to accurately reflect behavior when setting empty MCP values, ensuring the visual selection clears as expected. - Introduced environment-keyed storage logic to maintain independent state for spec and non-spec contexts, enhancing user experience during context switching. * test: Add comprehensive tests for useToolToggle and applyModelSpecEphemeralAgent hooks - Introduced unit tests for the useToolToggle hook, covering dual-write behavior in non-spec mode and per-conversation isolation. - Added tests for applyModelSpecEphemeralAgent, ensuring correct application of model specifications and user overrides from localStorage. - Enhanced test coverage for ephemeral agent state management during conversation transitions, validating expected behaviors for both new and existing conversations.
ThomasVuNguyen
pushed a commit
to ThomasVuNguyen/LibreChat
that referenced
this pull request
Jul 15, 2026
…Chat-AI#13697) The no-spec branch of `useApplyModelSpecEffects` (added in LibreChat-AI#11796) reset `ephemeralAgentByConvoId` to null on every `newConversation` call when model specs are configured. On in-place model/endpoint switches (modular chat, same conversation or new-chat draft), BadgeRowContext never refills from localStorage — its init effect only re-runs when the storage suffix or spec changes — so the MCP selection (and tool toggles) were silently dropped from subsequent request payloads while the MCP badge kept displaying them. Reset now only happens on context transitions (leaving a spec, or moving to a different conversation key), where a BadgeRowContext refill is guaranteed; in-place non-spec switches preserve the ephemeral agent. - Gate the no-spec reset on `prevSpecName` / `prevConvoId`, passed from `newConversation` via a snapshot read of the pre-switch conversation - Add jest coverage for all five branches of the no-spec path - Add e2e spec asserting `ephemeralAgent.mcp` stays in the chat payload after a new-chat model switch and after regenerate on a switched conversation (verified failing before the fix, passing after) - Add non-spec "Mock Provider D" endpoint to the e2e config so tests can switch between two real ephemeral endpoints; widen `MockEndpoint` type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Problem
When model specs are configured, tool badge state (code execution, web search, file search, artifacts) and MCP server selections shared the same
localStoragekeys regardless of whether a spec was active. This caused:Design
Two-layer persistence model:
localStorage)localStorageoverrides__defaults__localStoragekeylocalStorageKey mechanisms:
storageContextKey(__defaults__orundefined) threads throughBadgeRowProvider→useToolToggle/useMCPSelectto control which environment writes go to.__defaults__key (future new conversation defaults).storageContextKeyso spec and non-spec each get their own atom; existing conversations always use conversation-keyed atoms.applyModelSpecEphemeralAgentmergeslocalStorage: For existing conversations, reads per-conversationlocalStorageoverrides and layers them on top of spec defaults. IflocalStorageis cleared, spec values stand alone (fresh admin config).null, lettingBadgeRowContexthydrate from__defaults__localStorage.Changes
Data layer
packages/data-provider/src/config.ts: Addspec_defaults_keyconstant.packages/data-provider/src/models.ts: Addartifactsfield toTModelSpecschema.packages/data-provider/src/types.ts: AddartifactstoTEphemeralAgenttype.Core logic
client/src/utils/endpoints.ts:applyModelSpecEphemeralAgentnow merges per-conversationlocalStorageoverrides for existing conversations; add artifacts mapping (true→'default').client/src/Providers/BadgeRowContext.tsx: ComputestorageContextKeyandstorageSuffix; init effect skips for all spec conversations (handled byapplyModelSpecEphemeralAgent); read MCP overrides fromlocalStorage; threadstorageContextKeyto all hooks.client/src/hooks/Plugins/useToolToggle.ts: AcceptstorageContextKey; dual-write to environment key inhandleChange.client/src/hooks/MCP/useMCPSelect.ts: Environment-keyed Jotai atom for new conversations; dual-write insetMCPValues; clear atom when ephemeral agent has explicit empty MCP.client/src/hooks/Agents/useApplyModelSpecAgents.ts: Reset ephemeral agent tonull(notmcp_clear) for non-spec; add artifacts merging inuseApplyAgentTemplate.Plumbing
ChatForm.tsx→BadgeRow.tsx→BadgeRowProvider: ThreadspecName={conversation?.spec}.useMCPServerManager.ts→useMCPSelect: ForwardstorageContextKey.MCPSelect,MCPSubMenu,MCPConfigDialog,ServerInitializationSection): ThreadstorageContextKey.Tests (58 total)
applyModelSpecEphemeralAgent.test.ts(14 tests): New conversation fresh config, existing conversationlocalStoragemerge, clearedlocalStoragefallback, artifacts mapping, guard clauses.useToolToggle.test.tsx(10 tests): Dual-write behavior, spec-mode no-dual-write, per-conversation isolation, ephemeral agent sync,isToolEnabledcomputation.useMCPSelect.test.tsx(34 tests): Environment-keyed atoms, dual-write, empty MCP clearing, spec/non-spec switching, per-conversation isolation.Test plan
executeCode: true,mcpServers: ["clickhouse"]. New chat → badges and MCP should show selected.executeCodewithin a spec conversation, submit a message. Navigate away and back →executeCodeshould still be off.executeCodeshould be on (fresh admin config).localStorage: ClearlocalStorage, navigate to the existing spec conversation → should show fresh admin config.webSearch. New chat (non-spec) →webSearchshould persist.