📇 refactor: Improve State mgmt. for File uploads and Tool Auth (#9359)

* 🔧 fix: Ensure loading state is correctly set when files are empty or in progress

* 🔧 fix: Update ephemeral agent state on file upload error for execute code tool resource

* 🔧 fix: Reset ephemeral agent state for tool when authentication fails

* refactor: Pass conversation prop to FileFormChat and AttachFileChat components
This commit is contained in:
Danny Avila 2025-08-28 23:11:16 -04:00 committed by GitHub
parent 8772b04d1d
commit a26597a696
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 33 additions and 8 deletions

View file

@ -253,7 +253,7 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
handleSaveBadges={handleSaveBadges}
setBadges={setBadges}
/>
<FileFormChat disableInputs={disableInputs} />
<FileFormChat conversation={conversation} />
{endpoint && (
<div className={cn('flex', isRTL ? 'flex-row-reverse' : 'flex-row')}>
<TextareaAutosize
@ -301,7 +301,7 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
)}
>
<div className={`${isRTL ? 'mr-2' : 'ml-2'}`}>
<AttachFileChat disableInputs={disableInputs} />
<AttachFileChat conversation={conversation} disableInputs={disableInputs} />
</div>
<BadgeRow
showEphemeralBadges={!isAgentsEndpoint(endpoint) && !isAssistantsEndpoint(endpoint)}

View file

@ -7,14 +7,18 @@ import {
isAssistantsEndpoint,
fileConfig as defaultFileConfig,
} from 'librechat-data-provider';
import type { EndpointFileConfig } from 'librechat-data-provider';
import type { EndpointFileConfig, TConversation } from 'librechat-data-provider';
import { useGetFileConfig } from '~/data-provider';
import AttachFileMenu from './AttachFileMenu';
import { useChatContext } from '~/Providers';
import AttachFile from './AttachFile';
function AttachFileChat({ disableInputs }: { disableInputs: boolean }) {
const { conversation } = useChatContext();
function AttachFileChat({
disableInputs,
conversation,
}: {
disableInputs: boolean;
conversation: TConversation | null;
}) {
const conversationId = conversation?.conversationId ?? Constants.NEW_CONVO;
const { endpoint, endpointType } = conversation ?? { endpoint: null };
const isAgents = useMemo(() => isAgentsEndpoint(endpoint), [endpoint]);

View file

@ -1,13 +1,14 @@
import { memo } from 'react';
import { useRecoilValue } from 'recoil';
import type { TConversation } from 'librechat-data-provider';
import { useChatContext } from '~/Providers';
import { useFileHandling } from '~/hooks';
import FileRow from './FileRow';
import store from '~/store';
function FileFormChat({ disableInputs }: { disableInputs: boolean }) {
function FileFormChat({ conversation }: { conversation: TConversation | null }) {
const { files, setFiles, setFilesLoading } = useChatContext();
const chatDirection = useRecoilValue(store.chatDirection).toLowerCase();
const { files, setFiles, conversation, setFilesLoading } = useChatContext();
const { endpoint: _endpoint } = conversation ?? { endpoint: null };
const { abortUpload } = useFileHandling();

View file

@ -59,10 +59,12 @@ export default function FileRow({
useEffect(() => {
if (files.length === 0) {
setFilesLoading(false);
return;
}
if (files.some((file) => file.progress < 1)) {
setFilesLoading(true);
return;
}

View file

@ -1,10 +1,13 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { v4 } from 'uuid';
import { useSetRecoilState } from 'recoil';
import { useToastContext } from '@librechat/client';
import { useQueryClient } from '@tanstack/react-query';
import {
QueryKeys,
Constants,
EModelEndpoint,
EToolResources,
mergeFileConfig,
isAgentsEndpoint,
isAssistantsEndpoint,
@ -19,6 +22,7 @@ import useLocalize, { TranslationKeys } from '~/hooks/useLocalize';
import { useDelayedUploadToast } from './useDelayedUploadToast';
import { processFileForUpload } from '~/utils/heicConverter';
import { useChatContext } from '~/Providers/ChatContext';
import { ephemeralAgentByConvoId } from '~/store';
import { logger, validateFiles } from '~/utils';
import useClientResize from './useClientResize';
import useUpdateFiles from './useUpdateFiles';
@ -39,6 +43,9 @@ const useFileHandling = (params?: UseFileHandling) => {
const abortControllerRef = useRef<AbortController | null>(null);
const { startUploadTimer, clearUploadTimer } = useDelayedUploadToast();
const { files, setFiles, setFilesLoading, conversation } = useChatContext();
const setEphemeralAgent = useSetRecoilState(
ephemeralAgentByConvoId(conversation?.conversationId ?? Constants.NEW_CONVO),
);
const setError = (error: string) => setErrors((prevErrors) => [...prevErrors, error]);
const { addFile, replaceFile, updateFileById, deleteFileById } = useUpdateFiles(
params?.fileSetter ?? setFiles,
@ -133,6 +140,13 @@ const useFileHandling = (params?: UseFileHandling) => {
const error = _error as TError | undefined;
console.log('upload error', error);
const file_id = body.get('file_id');
const tool_resource = body.get('tool_resource');
if (tool_resource === EToolResources.execute_code) {
setEphemeralAgent((prev) => ({
...prev,
[EToolResources.execute_code]: false,
}));
}
clearUploadTimer(file_id as string);
deleteFileById(file_id as string);

View file

@ -98,6 +98,10 @@ export function useToolToggle({
if (isAuthenticated !== undefined && !isAuthenticated && setIsDialogOpen) {
setIsDialogOpen(true);
e?.preventDefault?.();
setEphemeralAgent((prev) => ({
...(prev || {}),
[toolKey]: false,
}));
return;
}