mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-23 20:00:15 +01:00
🎥 feat: YouTube Tool (#5582)
* adding youtube tool * refactor: use short `url` param instead of `videoUrl` * refactor: move API key retrieval to a separate credentials module * refactor: remove unnecessary `isEdited` message property * refactor: remove unnecessary `isEdited` message property pt. 2 * refactor: YouTube Tool with new `tool()` generator, handle tools already created by new `tool` generator * fix: only reset request data for multi-convo messages * refactor: enhance YouTube tool by adding transcript parsing and returning structured JSON responses * refactor: update transcript parsing to handle raw response and clean up text output * feat: support toolkits and refactor YouTube tool as a toolkit for better LLM usage * refactor: remove unused OpenAPI specs and streamline tools transformation in loadAsyncEndpoints * refactor: implement manifestToolMap for better tool management and streamline authentication handling * feat: support toolkits for assistants * refactor: rename loadedTools to toolDefinitions for clarity in PluginController and assistant controllers * feat: complete support of toolkits for assistants --------- Co-authored-by: Danilo Pejakovic <danilo.pejakovic@leoninestudios.com>
This commit is contained in:
parent
33f6093775
commit
352565c9a6
29 changed files with 456 additions and 102 deletions
|
|
@ -1,25 +1,27 @@
|
|||
import { useState, useMemo } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useForm, FormProvider, Controller, useWatch } from 'react-hook-form';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import {
|
||||
Tools,
|
||||
QueryKeys,
|
||||
Capabilities,
|
||||
actionDelimiter,
|
||||
ImageVisionTool,
|
||||
defaultAssistantFormValues,
|
||||
} from 'librechat-data-provider';
|
||||
import type { FunctionTool, TConfig, TPlugin } from 'librechat-data-provider';
|
||||
import type { FunctionTool, TConfig } from 'librechat-data-provider';
|
||||
import type { AssistantForm, AssistantPanelProps } from '~/common';
|
||||
import { useCreateAssistantMutation, useUpdateAssistantMutation } from '~/data-provider';
|
||||
import {
|
||||
useCreateAssistantMutation,
|
||||
useUpdateAssistantMutation,
|
||||
useAvailableAgentToolsQuery,
|
||||
} from '~/data-provider';
|
||||
import { cn, cardStyle, defaultTextProps, removeFocusOutlines } from '~/utils';
|
||||
import AssistantConversationStarters from './AssistantConversationStarters';
|
||||
import { useAssistantsMapContext, useToastContext } from '~/Providers';
|
||||
import { useSelectAssistant, useLocalize } from '~/hooks';
|
||||
import { ToolSelectDialog } from '~/components/Tools';
|
||||
import CapabilitiesForm from './CapabilitiesForm';
|
||||
import AppendDateCheckbox from './AppendDateCheckbox';
|
||||
import CapabilitiesForm from './CapabilitiesForm';
|
||||
import { SelectDropDown } from '~/components/ui';
|
||||
import AssistantAvatar from './AssistantAvatar';
|
||||
import AssistantSelect from './AssistantSelect';
|
||||
|
|
@ -49,11 +51,10 @@ export default function AssistantPanel({
|
|||
assistantsConfig,
|
||||
version,
|
||||
}: AssistantPanelProps & { assistantsConfig?: TConfig | null }) {
|
||||
const queryClient = useQueryClient();
|
||||
const modelsQuery = useGetModelsQuery();
|
||||
const assistantMap = useAssistantsMapContext();
|
||||
|
||||
const allTools = queryClient.getQueryData<TPlugin[]>([QueryKeys.tools]) ?? [];
|
||||
const { data: allTools = [] } = useAvailableAgentToolsQuery();
|
||||
const { onSelect: onSelectAssistant } = useSelectAssistant(endpoint);
|
||||
const { showToast } = useToastContext();
|
||||
const localize = useLocalize();
|
||||
|
|
@ -227,6 +228,7 @@ export default function AssistantPanel({
|
|||
value={field.value}
|
||||
endpoint={endpoint}
|
||||
documentsMap={documentsMap}
|
||||
allTools={allTools}
|
||||
setCurrentAssistantId={setCurrentAssistantId}
|
||||
selectedAssistant={current_assistant_id ?? null}
|
||||
createMutation={create}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Plus } from 'lucide-react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useMemo, useCallback, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Tools,
|
||||
FileSources,
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import type { UseFormReset } from 'react-hook-form';
|
||||
import type { UseMutationResult } from '@tanstack/react-query';
|
||||
import type {
|
||||
TPlugin,
|
||||
Assistant,
|
||||
AssistantDocument,
|
||||
AssistantsEndpoint,
|
||||
|
|
@ -48,6 +49,7 @@ export default function AssistantSelect({
|
|||
selectedAssistant,
|
||||
setCurrentAssistantId,
|
||||
createMutation,
|
||||
allTools,
|
||||
}: {
|
||||
reset: UseFormReset<AssistantForm>;
|
||||
value: TAssistantOption;
|
||||
|
|
@ -56,6 +58,7 @@ export default function AssistantSelect({
|
|||
documentsMap: Map<string, AssistantDocument> | null;
|
||||
setCurrentAssistantId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
createMutation: UseMutationResult<Assistant, Error, AssistantCreateParams>;
|
||||
allTools?: TPlugin[];
|
||||
}) {
|
||||
const localize = useLocalize();
|
||||
const fileMap = useFileMapContext();
|
||||
|
|
@ -65,6 +68,11 @@ export default function AssistantSelect({
|
|||
{} as LastSelectedModels,
|
||||
);
|
||||
|
||||
const toolkits = useMemo(
|
||||
() => new Set(allTools?.filter((tool) => tool.toolkit === true).map((tool) => tool.pluginKey)),
|
||||
[allTools],
|
||||
);
|
||||
|
||||
const query = useListAssistantsQuery(endpoint, undefined, {
|
||||
select: (res) =>
|
||||
res.data.map((_assistant) => {
|
||||
|
|
@ -153,7 +161,7 @@ export default function AssistantSelect({
|
|||
const update = {
|
||||
...assistant,
|
||||
label: assistant.name ?? '',
|
||||
value: assistant.id ?? '',
|
||||
value: assistant.id || '',
|
||||
};
|
||||
|
||||
const actions: Actions = {
|
||||
|
|
@ -164,7 +172,7 @@ export default function AssistantSelect({
|
|||
|
||||
(assistant.tools ?? [])
|
||||
.filter((tool) => tool.type !== 'function' || isImageVisionTool(tool))
|
||||
.map((tool) => tool.function?.name || tool.type)
|
||||
.map((tool) => (tool.function?.name ?? '') || tool.type)
|
||||
.forEach((tool) => {
|
||||
if (tool === Tools.file_search) {
|
||||
actions[Capabilities.retrieval] = true;
|
||||
|
|
@ -172,9 +180,22 @@ export default function AssistantSelect({
|
|||
actions[tool] = true;
|
||||
});
|
||||
|
||||
const seenToolkits = new Set<string>();
|
||||
const functions = (assistant.tools ?? [])
|
||||
.filter((tool) => tool.type === 'function' && !isImageVisionTool(tool))
|
||||
.map((tool) => tool.function?.name ?? '');
|
||||
.map((tool) => tool.function?.name ?? '')
|
||||
.filter((fnName) => {
|
||||
const fnPrefix = fnName.split('_')[0];
|
||||
const seenToolkit = toolkits.has(fnPrefix);
|
||||
if (seenToolkit) {
|
||||
seenToolkits.add(fnPrefix);
|
||||
}
|
||||
return !seenToolkit;
|
||||
});
|
||||
|
||||
if (seenToolkits.size > 0) {
|
||||
functions.push(...Array.from(seenToolkits));
|
||||
}
|
||||
|
||||
const formValues: Partial<AssistantForm & Actions> = {
|
||||
functions,
|
||||
|
|
@ -210,7 +231,15 @@ export default function AssistantSelect({
|
|||
reset(formValues);
|
||||
setCurrentAssistantId(assistant.id);
|
||||
},
|
||||
[query.data, reset, setCurrentAssistantId, createMutation, endpoint, lastSelectedModels],
|
||||
[
|
||||
query.data,
|
||||
reset,
|
||||
setCurrentAssistantId,
|
||||
createMutation,
|
||||
endpoint,
|
||||
lastSelectedModels,
|
||||
toolkits,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue