mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-19 00:48:08 +01:00
💻 feat: Deeper MCP UI integration in the Chat UI (#9669)
* 💻 feat: deeper MCP UI integration in the chat UI using plugins --------- Co-authored-by: Samuel Path <samuel.path@shopify.com> Co-authored-by: Pierre-Luc Godin <pierreluc.godin@shopify.com> * 💻 refactor: Migrate MCP UI resources from index-based to ID-based referencing - Replace index-based resource markers with stable resource IDs - Update plugin to parse \ui{resourceId} format instead of \ui0 - Refactor components to use useMessagesOperations instead of useSubmitMessage - Add ShareMessagesProvider for UI resources in share view - Add useConversationUIResources hook for cross-turn resource lookups - Update parsers to generate resource IDs from content hashes - Update all tests to use resource IDs instead of indices - Add sandbox permissions for iframe popups - Remove deprecated MCP tool context instructions --------- Co-authored-by: Pierre-Luc Godin <pierreluc.godin@shopify.com>
This commit is contained in:
parent
4a0fbb07bc
commit
304bba853c
27 changed files with 1545 additions and 122 deletions
55
client/src/hooks/Messages/useConversationUIResources.ts
Normal file
55
client/src/hooks/Messages/useConversationUIResources.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Tools } from 'librechat-data-provider';
|
||||
import type { TAttachment, UIResource } from 'librechat-data-provider';
|
||||
import { useMessagesOperations } from '~/Providers';
|
||||
import store from '~/store';
|
||||
|
||||
/**
|
||||
* Hook to collect all UI resources in a conversation, indexed by resource ID.
|
||||
* This enables cross-turn resource references in the conversation.
|
||||
* Works in both main app (using React Query cache) and share view (using context messages).
|
||||
*
|
||||
* @param conversationId - The ID of the conversation to collect resources from
|
||||
* @returns A Map of resource IDs to UIResource objects
|
||||
*/
|
||||
export function useConversationUIResources(
|
||||
conversationId: string | undefined,
|
||||
): Map<string, UIResource> {
|
||||
const { getMessages } = useMessagesOperations();
|
||||
|
||||
const conversationAttachmentsMap = useRecoilValue(
|
||||
store.conversationAttachmentsSelector(conversationId),
|
||||
);
|
||||
|
||||
return useMemo(() => {
|
||||
const map = new Map<string, UIResource>();
|
||||
|
||||
const collectResources = (attachments?: TAttachment[]) => {
|
||||
attachments
|
||||
?.filter((attachment) => attachment?.type === Tools.ui_resources)
|
||||
.forEach((attachment) => {
|
||||
const resources = attachment?.[Tools.ui_resources];
|
||||
if (Array.isArray(resources)) {
|
||||
resources.forEach((resource) => {
|
||||
if (resource?.resourceId) {
|
||||
map.set(resource.resourceId, resource);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Collect from messages (works in both main app and share view)
|
||||
getMessages()?.forEach((message) => {
|
||||
collectResources(message.attachments);
|
||||
});
|
||||
|
||||
// Collect from in-flight messages (Recoil state during streaming - only when we have a conversationId)
|
||||
if (conversationId) {
|
||||
Object.values(conversationAttachmentsMap).forEach(collectResources);
|
||||
}
|
||||
|
||||
return map;
|
||||
}, [conversationId, getMessages, conversationAttachmentsMap]);
|
||||
}
|
||||
|
|
@ -33,5 +33,5 @@ export { default as useDocumentTitle } from './useDocumentTitle';
|
|||
export { default as useSpeechToText } from './Input/useSpeechToText';
|
||||
export { default as useTextToSpeech } from './Input/useTextToSpeech';
|
||||
export { default as useGenerationsByLatest } from './useGenerationsByLatest';
|
||||
export { useResourcePermissions } from './useResourcePermissions';
|
||||
export { default as useLocalizedConfig } from './useLocalizedConfig';
|
||||
export { default as useResourcePermissions } from './useResourcePermissions';
|
||||
|
|
|
|||
|
|
@ -24,3 +24,5 @@ export const useResourcePermissions = (resourceType: ResourceType, resourceId: s
|
|||
permissionBits: data?.permissionBits || 0,
|
||||
};
|
||||
};
|
||||
|
||||
export default useResourcePermissions;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue