mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-20 10:20:15 +01:00
* 🪦 refactor: Remove Legacy Code (#10533) * 🗑️ chore: Remove unused Legacy Provider clients and related helpers * Deleted OpenAIClient and GoogleClient files along with their associated tests. * Removed references to these clients in the clients index file. * Cleaned up typedefs by removing the OpenAISpecClient export. * Updated chat controllers to use the OpenAI SDK directly instead of the removed client classes. * chore/remove-openapi-specs * 🗑️ chore: Remove unused mergeSort and misc utility functions * Deleted mergeSort.js and misc.js files as they are no longer needed. * Removed references to cleanUpPrimaryKeyValue in messages.js and adjusted related logic. * Updated mongoMeili.ts to eliminate local implementations of removed functions. * chore: remove legacy endpoints * chore: remove all plugins endpoint related code * chore: remove unused prompt handling code and clean up imports * Deleted handleInputs.js and instructions.js files as they are no longer needed. * Removed references to these files in the prompts index.js. * Updated docker-compose.yml to simplify reverse proxy configuration. * chore: remove unused LightningIcon import from Icons.tsx * chore: clean up translation.json by removing deprecated and unused keys * chore: update Jest configuration and remove unused mock file * Simplified the setupFiles array in jest.config.js by removing the fetchEventSource mock. * Deleted the fetchEventSource.js mock file as it is no longer needed. * fix: simplify endpoint type check in Landing and ConversationStarters components * Updated the endpoint type check to use strict equality for better clarity and performance. * Ensured consistency in the handling of the azureOpenAI endpoint across both components. * chore: remove unused dependencies from package.json and package-lock.json * chore: remove legacy EditController, associated routes and imports * chore: update banResponse logic to refine request handling for banned users * chore: remove unused validateEndpoint middleware and its references * chore: remove unused 'res' parameter from initializeClient in multiple endpoint files * chore: remove unused 'isSmallScreen' prop from BookmarkNav and NewChat components; clean up imports in ArchivedChatsTable and useSetIndexOptions hooks; enhance localization in PromptVersions * chore: remove unused import of Constants and TMessage from MobileNav; retain only necessary QueryKeys import * chore: remove unused TResPlugin type and related references; clean up imports in types and schemas * 🪦 refactor: Remove Legacy Code (#10533) * 🗑️ chore: Remove unused Legacy Provider clients and related helpers * Deleted OpenAIClient and GoogleClient files along with their associated tests. * Removed references to these clients in the clients index file. * Cleaned up typedefs by removing the OpenAISpecClient export. * Updated chat controllers to use the OpenAI SDK directly instead of the removed client classes. * chore/remove-openapi-specs * 🗑️ chore: Remove unused mergeSort and misc utility functions * Deleted mergeSort.js and misc.js files as they are no longer needed. * Removed references to cleanUpPrimaryKeyValue in messages.js and adjusted related logic. * Updated mongoMeili.ts to eliminate local implementations of removed functions. * chore: remove legacy endpoints * chore: remove all plugins endpoint related code * chore: remove unused prompt handling code and clean up imports * Deleted handleInputs.js and instructions.js files as they are no longer needed. * Removed references to these files in the prompts index.js. * Updated docker-compose.yml to simplify reverse proxy configuration. * chore: remove unused LightningIcon import from Icons.tsx * chore: clean up translation.json by removing deprecated and unused keys * chore: update Jest configuration and remove unused mock file * Simplified the setupFiles array in jest.config.js by removing the fetchEventSource mock. * Deleted the fetchEventSource.js mock file as it is no longer needed. * fix: simplify endpoint type check in Landing and ConversationStarters components * Updated the endpoint type check to use strict equality for better clarity and performance. * Ensured consistency in the handling of the azureOpenAI endpoint across both components. * chore: remove unused dependencies from package.json and package-lock.json * chore: remove legacy EditController, associated routes and imports * chore: update banResponse logic to refine request handling for banned users * chore: remove unused validateEndpoint middleware and its references * chore: remove unused 'res' parameter from initializeClient in multiple endpoint files * chore: remove unused 'isSmallScreen' prop from BookmarkNav and NewChat components; clean up imports in ArchivedChatsTable and useSetIndexOptions hooks; enhance localization in PromptVersions * chore: remove unused import of Constants and TMessage from MobileNav; retain only necessary QueryKeys import * chore: remove unused TResPlugin type and related references; clean up imports in types and schemas * 📦 chore: Bump Express.js to v5 (#10671) * chore: update express to version 5.1.0 in package.json * chore: update express-rate-limit to version 8.2.1 in package.json and package-lock.json * fix: Enhance server startup error handling in experimental and index files * Added error handling for server startup in both experimental.js and index.js to log errors and exit the process if the server fails to start. * Updated comments in openidStrategy.js to clarify the purpose of the CustomOpenIDStrategy class and its relation to Express version changes. * chore: Implement rate limiting for all POST routes excluding /speech, required for express v5 * Added middleware to apply IP and user rate limiters to all POST requests, ensuring that the /speech route remains unaffected. * Enhanced code clarity with comments explaining the new rate limiting logic. * chore: Enable writable req.query for mongoSanitize compatibility in Express 5 * chore: Ensure req.body exists in multiple middleware and route files for Express 5 compatibility * 🗣 feat: MCP Status Accessibility Improvements (#10738) * feat: make MultiSelect highlight same opacity as other focus highlights in app * feat: add better screenreader announcements for mcp server and variable states * feat: memoize fullTitle calculation * 🪨 feat: Add PROXY support for AWS Bedrock endpoints (#8871) * feat: added PROXY support for AWS Bedrock endpoint * chore: explicit install of new packages required for bedrock proxy --------- Co-authored-by: Danny Avila <danny@librechat.ai> * ✨ feat: Implement Favorites functionality with controllers, hooks, and UI components * ✨ feat: Refactor Favorites functionality to support new data structure and enhance UI interactions * ✨ feat: Add endpoint to new conversation for agent favorites * ✨ feat: Enhance Conversations and Favorites components with expanded functionality and improved UI interactions * ✨ feat: Remove 'Pinned' label from UI translations for cleaner interface * feat: clean up comments and improve code readability in favorites and agent components; bump @librechat/data-schemas to 0.0.24 * ✨ feat: Enhance favorites management with validation, update data structure, and improve UI interactions * ✨ feat: Simplify rendering logic in EndpointModelItem and optimize useEffect dependencies in Conversations component * ✨ test: Update favorites mock implementation and improve button focus styles in AgentDetail tests * ✨ feat: Enhance favorites management by adding loading and error states, and refactor related hooks and components * ✨ feat: Add loading skeletons for favorites while agents are being fetched * ✨ feat: Improve loading experience in FavoritesList by adding skeleton placeholders for favorites and marketplace * feat: Optimize cache handling in Conversations and enhance FavoritesList to notify height changes on loading completion * ✨ feat: Add loading skeleton for SearchBar in Nav component and update agent avatar fallback icon to Feather * feat: Refactor FavoritesController validation, streamline ModelSelector component, and enhance EndpointModelItem with selection state * feat: Adjust padding in Conversations and FavoritesList components for improved layout consistency * feat: Refactor FavoritesController to use model methods for user updates and retrieval * feat: Enhance Favorites functionality with validation, cleanup, and improved error handling * tests: Update AgentCard and agent utilities to use Feather icon fallback instead of Bot icon * refactor: Remove collapsible animation styles from CSS * feat: Migrate favorites state management from Recoil to Jotai * fix: Correct type definition in useGetFavoritesQuery and ensure useFavorites is exported * refactor: Simplify AuthField component by removing TooltipAnchor and directly rendering Label * fix: Ensure favorites are always an array and update references in FavoritesList * style: Update Conversation component styles for improved UI consistency * feat: re-integrate AuthContext to manage agent marketplace visibility based on authentication state * fix: Improve optimistic updates in favorites mutation handling * feat: Implement error handling for favorites limit and consolidate marketplace access logic * fix: package-lock --------- Co-authored-by: Danny Avila <danny@librechat.ai> Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Co-authored-by: Arthur Barrett <abarrett@fas.harvard.edu>
195 lines
5.9 KiB
TypeScript
195 lines
5.9 KiB
TypeScript
import React, { useRef } from 'react';
|
|
import { Link, Pin, PinOff } from 'lucide-react';
|
|
import { useQueryClient } from '@tanstack/react-query';
|
|
import { OGDialog, OGDialogContent, Button, useToastContext } from '@librechat/client';
|
|
import {
|
|
QueryKeys,
|
|
Constants,
|
|
EModelEndpoint,
|
|
PermissionBits,
|
|
LocalStorageKeys,
|
|
AgentListResponse,
|
|
} from 'librechat-data-provider';
|
|
import type t from 'librechat-data-provider';
|
|
import { useLocalize, useDefaultConvo, useFavorites } from '~/hooks';
|
|
import { renderAgentAvatar, clearMessagesCache } from '~/utils';
|
|
import { useChatContext } from '~/Providers';
|
|
|
|
interface SupportContact {
|
|
name?: string;
|
|
email?: string;
|
|
}
|
|
|
|
interface AgentWithSupport extends t.Agent {
|
|
support_contact?: SupportContact;
|
|
}
|
|
interface AgentDetailProps {
|
|
agent: AgentWithSupport; // The agent data to display
|
|
isOpen: boolean; // Whether the detail dialog is open
|
|
onClose: () => void; // Callback when dialog is closed
|
|
}
|
|
|
|
/**
|
|
* Dialog for displaying agent details
|
|
*/
|
|
const AgentDetail: React.FC<AgentDetailProps> = ({ agent, isOpen, onClose }) => {
|
|
const localize = useLocalize();
|
|
const queryClient = useQueryClient();
|
|
const { showToast } = useToastContext();
|
|
const dialogRef = useRef<HTMLDivElement>(null);
|
|
const getDefaultConversation = useDefaultConvo();
|
|
const { conversation, newConversation } = useChatContext();
|
|
const { isFavoriteAgent, toggleFavoriteAgent } = useFavorites();
|
|
const isFavorite = isFavoriteAgent(agent?.id);
|
|
|
|
const handleFavoriteClick = () => {
|
|
if (agent) {
|
|
toggleFavoriteAgent(agent.id);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Navigate to chat with the selected agent
|
|
*/
|
|
const handleStartChat = () => {
|
|
if (agent) {
|
|
const keys = [QueryKeys.agents, { requiredPermission: PermissionBits.EDIT }];
|
|
const listResp = queryClient.getQueryData<AgentListResponse>(keys);
|
|
if (listResp != null) {
|
|
if (!listResp.data.some((a) => a.id === agent.id)) {
|
|
const currentAgents = [agent, ...JSON.parse(JSON.stringify(listResp.data))];
|
|
queryClient.setQueryData<AgentListResponse>(keys, { ...listResp, data: currentAgents });
|
|
}
|
|
}
|
|
|
|
localStorage.setItem(`${LocalStorageKeys.AGENT_ID_PREFIX}0`, agent.id);
|
|
|
|
clearMessagesCache(queryClient, conversation?.conversationId);
|
|
queryClient.invalidateQueries([QueryKeys.messages]);
|
|
|
|
/** Template with agent configuration */
|
|
const template = {
|
|
conversationId: Constants.NEW_CONVO as string,
|
|
endpoint: EModelEndpoint.agents,
|
|
agent_id: agent.id,
|
|
title: localize('com_agents_chat_with', { name: agent.name || localize('com_ui_agent') }),
|
|
};
|
|
|
|
const currentConvo = getDefaultConversation({
|
|
conversation: { ...(conversation ?? {}), ...template },
|
|
preset: template,
|
|
});
|
|
|
|
newConversation({
|
|
template: currentConvo,
|
|
preset: template,
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Copy the agent's shareable link to clipboard
|
|
*/
|
|
const handleCopyLink = () => {
|
|
const baseUrl = new URL(window.location.origin);
|
|
const chatUrl = `${baseUrl.origin}/c/new?agent_id=${agent.id}`;
|
|
navigator.clipboard
|
|
.writeText(chatUrl)
|
|
.then(() => {
|
|
showToast({
|
|
message: localize('com_agents_link_copied'),
|
|
});
|
|
})
|
|
.catch(() => {
|
|
showToast({
|
|
message: localize('com_agents_link_copy_failed'),
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Format contact information with mailto links when appropriate
|
|
*/
|
|
const formatContact = () => {
|
|
if (!agent?.support_contact) return null;
|
|
|
|
const { name, email } = agent.support_contact;
|
|
|
|
if (name && email) {
|
|
return (
|
|
<a href={`mailto:${email}`} className="text-primary hover:underline">
|
|
{name}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
if (email) {
|
|
return (
|
|
<a href={`mailto:${email}`} className="text-primary hover:underline">
|
|
{email}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
if (name) {
|
|
return <span>{name}</span>;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
return (
|
|
<OGDialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
|
|
<OGDialogContent ref={dialogRef} className="max-h-[90vh] w-11/12 max-w-lg overflow-y-auto">
|
|
{/* Agent avatar */}
|
|
<div className="mt-6 flex justify-center">{renderAgentAvatar(agent, { size: 'xl' })}</div>
|
|
|
|
{/* Agent name */}
|
|
<div className="mt-3 text-center">
|
|
<h2 className="text-2xl font-bold text-text-primary">
|
|
{agent?.name || localize('com_agents_loading')}
|
|
</h2>
|
|
</div>
|
|
|
|
{/* Contact info */}
|
|
{agent?.support_contact && formatContact() && (
|
|
<div className="mt-1 text-center text-sm text-text-secondary">
|
|
{localize('com_agents_contact')}: {formatContact()}
|
|
</div>
|
|
)}
|
|
|
|
{/* Agent description */}
|
|
<div className="mt-4 whitespace-pre-wrap px-6 text-center text-base text-text-primary">
|
|
{agent?.description}
|
|
</div>
|
|
|
|
{/* Action button */}
|
|
<div className="mb-4 mt-6 flex justify-center gap-2">
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={handleFavoriteClick}
|
|
title={isFavorite ? localize('com_ui_unpin') : localize('com_ui_pin')}
|
|
aria-label={isFavorite ? localize('com_ui_unpin') : localize('com_ui_pin')}
|
|
>
|
|
{isFavorite ? <PinOff className="h-4 w-4" /> : <Pin className="h-4 w-4" />}
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={handleCopyLink}
|
|
title={localize('com_agents_copy_link')}
|
|
aria-label={localize('com_agents_copy_link')}
|
|
>
|
|
<Link className="h-4 w-4" aria-hidden="true" />
|
|
</Button>
|
|
<Button className="w-full max-w-xs" onClick={handleStartChat} disabled={!agent}>
|
|
{localize('com_agents_start_chat')}
|
|
</Button>
|
|
</div>
|
|
</OGDialogContent>
|
|
</OGDialog>
|
|
);
|
|
};
|
|
|
|
export default AgentDetail;
|