🚏 chore: Remove Resumable Stream Toggle (#11258)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions

* 🚏 chore: Remove Resumable Stream Toggle

- Removed the `useResumableStreamToggle` hook and its associated logic from the ChatView component.
- Updated Conversations and useAdaptiveSSE hooks to determine resumable stream status based on the endpoint type.
- Cleaned up settings by removing the `resumableStreams` state from the store and its related localization strings.

* 🔧 refactor: Simplify Active Jobs Logic in Conversations Component

- Removed the endpoint type checks and associated logic for resumable streams in the Conversations component.
- Updated the `useActiveJobs` hook call to no longer depend on resumable stream status, streamlining the data fetching process.
This commit is contained in:
Danny Avila 2026-01-07 20:37:35 -05:00 committed by GitHub
parent 24e8a258cd
commit c30afb8b68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 32 additions and 89 deletions

View file

@ -5,4 +5,3 @@ export { default as useResumeOnLoad } from './useResumeOnLoad';
export { default as useStepHandler } from './useStepHandler';
export { default as useContentHandler } from './useContentHandler';
export { default as useAttachmentHandler } from './useAttachmentHandler';
export { default as useResumableStreamToggle } from './useResumableStreamToggle';

View file

@ -1,9 +1,8 @@
import { useRecoilValue } from 'recoil';
import { isAssistantsEndpoint } from 'librechat-data-provider';
import type { TSubmission } from 'librechat-data-provider';
import type { EventHandlerParams } from './useEventHandlers';
import useSSE from './useSSE';
import useResumableSSE from './useResumableSSE';
import store from '~/store';
import useSSE from './useSSE';
type ChatHelpers = Pick<
EventHandlerParams,
@ -17,7 +16,7 @@ type ChatHelpers = Pick<
/**
* Adaptive SSE hook that switches between standard and resumable modes.
* Uses Recoil state to determine which mode to use.
* Uses resumable streams by default, falls back to standard SSE for assistants endpoints.
*
* Note: Both hooks are always called to comply with React's Rules of Hooks.
* We pass null submission to the inactive one.
@ -28,7 +27,11 @@ export default function useAdaptiveSSE(
isAddedRequest = false,
runIndex = 0,
) {
const resumableEnabled = useRecoilValue(store.resumableStreams);
const endpoint = submission?.conversation?.endpoint;
const endpointType = submission?.conversation?.endpointType;
const actualEndpoint = endpointType ?? endpoint;
const isAssistants = isAssistantsEndpoint(actualEndpoint);
const resumableEnabled = !isAssistants;
useSSE(resumableEnabled ? null : submission, chatHelpers, isAddedRequest, runIndex);

View file

@ -1,41 +0,0 @@
import { useEffect, useRef } from 'react';
import { useRecoilState } from 'recoil';
import { isAssistantsEndpoint } from 'librechat-data-provider';
import type { EModelEndpoint } from 'librechat-data-provider';
import store from '~/store';
/**
* Automatically toggles resumable streams off for assistants endpoints
* and restores the previous value when switching away.
*
* Assistants endpoints have their own streaming mechanism and don't support resumable streams.
*/
export default function useResumableStreamToggle(
endpoint: EModelEndpoint | string | null | undefined,
endpointType?: EModelEndpoint | string | null,
) {
const [resumableStreams, setResumableStreams] = useRecoilState(store.resumableStreams);
const savedValueRef = useRef<boolean | null>(null);
const wasAssistantsRef = useRef(false);
useEffect(() => {
const actualEndpoint = endpointType ?? endpoint;
const isAssistants = isAssistantsEndpoint(actualEndpoint);
if (isAssistants && !wasAssistantsRef.current) {
// Switching TO assistants: save current value and disable
savedValueRef.current = resumableStreams;
if (resumableStreams) {
setResumableStreams(false);
}
wasAssistantsRef.current = true;
} else if (!isAssistants && wasAssistantsRef.current) {
// Switching AWAY from assistants: restore saved value
if (savedValueRef.current !== null) {
setResumableStreams(savedValueRef.current);
savedValueRef.current = null;
}
wasAssistantsRef.current = false;
}
}, [endpoint, endpointType, resumableStreams, setResumableStreams]);
}

View file

@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react';
import { useSetRecoilState, useRecoilValue } from 'recoil';
import { Constants, tMessageSchema } from 'librechat-data-provider';
import { Constants, tMessageSchema, isAssistantsEndpoint } from 'librechat-data-provider';
import type { TMessage, TConversation, TSubmission, Agents } from 'librechat-data-provider';
import { useStreamStatus } from '~/data-provider';
import store from '~/store';
@ -102,9 +102,13 @@ export default function useResumeOnLoad(
runIndex = 0,
messagesLoaded = true,
) {
const resumableEnabled = useRecoilValue(store.resumableStreams);
const setSubmission = useSetRecoilState(store.submissionByIndex(runIndex));
const currentSubmission = useRecoilValue(store.submissionByIndex(runIndex));
const currentConversation = useRecoilValue(store.conversationByIndex(runIndex));
const endpoint = currentConversation?.endpoint;
const endpointType = currentConversation?.endpointType;
const actualEndpoint = endpointType ?? endpoint;
const resumableEnabled = !isAssistantsEndpoint(actualEndpoint);
// Track conversations we've already processed (either resumed or skipped)
const processedConvoRef = useRef<string | null>(null);