🛠️ Fix: Update Agent Cache and Improve Actions UI (#5020)

* style: improve a11y, localization, and styling consistency of actions input form

* refactor: move agent mutations to dedicated module

* fix: update agent cache on agent deletion + delete and update actions
This commit is contained in:
Danny Avila 2024-12-17 12:45:58 -05:00 committed by GitHub
parent 6ef05dd2e6
commit 0a97ad3915
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 337 additions and 320 deletions

View file

@ -16,10 +16,10 @@ import type { ActionAuthForm } from '~/common';
import type { Spec } from './ActionsTable';
import { ActionsTable, columns } from './ActionsTable';
import { useUpdateAgentAction } from '~/data-provider';
import { cn, removeFocusOutlines } from '~/utils';
import { useToastContext } from '~/Providers';
import useLocalize from '~/hooks/useLocalize';
import { Spinner } from '~/components/svg';
import { logger } from '~/utils';
const debouncedValidation = debounce(
(input: string, callback: (result: ValidationResult) => void) => {
@ -56,12 +56,13 @@ export default function ActionsInput({
const [functions, setFunctions] = useState<FunctionTool[] | null>(null);
useEffect(() => {
if (!action?.metadata?.raw_spec) {
const rawSpec = action?.metadata.raw_spec ?? '';
if (!rawSpec) {
return;
}
setInputValue(action.metadata.raw_spec);
debouncedValidation(action.metadata.raw_spec, handleResult);
}, [action?.metadata?.raw_spec]);
setInputValue(rawSpec);
debouncedValidation(rawSpec, handleResult);
}, [action?.metadata.raw_spec]);
useEffect(() => {
if (!validationResult || !validationResult.status || !validationResult.spec) {
@ -94,15 +95,16 @@ export default function ActionsInput({
},
onError(error) {
showToast({
message: (error as Error)?.message ?? localize('com_assistants_update_actions_error'),
message: (error as Error).message || localize('com_assistants_update_actions_error'),
status: 'error',
});
},
});
const saveAction = handleSubmit((authFormData) => {
console.log('authFormData', authFormData);
if (!agent_id) {
logger.log('actions', 'saving action', authFormData);
const currentAgentId = agent_id ?? '';
if (!currentAgentId) {
// alert user?
return;
}
@ -171,7 +173,7 @@ export default function ActionsInput({
action_id,
metadata,
functions,
agent_id,
agent_id: currentAgentId,
});
});
@ -186,17 +188,34 @@ export default function ActionsInput({
debouncedValidation(newValue, handleResult);
};
const getButtonContent = () => {
if (updateAgentAction.isLoading) {
return <Spinner className="icon-md" />;
}
if (action?.action_id != null && action.action_id) {
return localize('com_ui_update');
}
return localize('com_ui_create');
};
return (
<>
<div className="">
<div className="mb-1 flex flex-wrap items-center justify-between gap-4">
<label className="text-token-text-primary whitespace-nowrap font-medium">Schema</label>
<label
htmlFor="schemaInput"
className="text-token-text-primary whitespace-nowrap font-medium"
>
Schema
</label>
<div className="flex items-center gap-2">
{/* <button className="btn btn-neutral border-token-border-light relative h-8 min-w-[100px] rounded-lg font-medium">
<div className="flex w-full items-center justify-center text-xs">Import from URL</div>
</button> */}
<select
onChange={(e) => console.log(e.target.value)}
onChange={(e) => logger.log('actions', 'selecting example action', e.target.value)}
className="border-token-border-medium h-8 min-w-[100px] rounded-lg border bg-transparent px-2 py-0 text-sm"
>
<option value="label">{localize('com_ui_examples')}</option>
@ -207,17 +226,15 @@ export default function ActionsInput({
</select>
</div>
</div>
<div className="border-token-border-light mb-4 overflow-hidden rounded-lg border">
<div className="border-token-border-medium bg-token-surface-primary hover:border-token-border-hover mb-4 w-full overflow-hidden rounded-lg border ring-0">
<div className="relative">
<textarea
id="schemaInput"
value={inputValue}
onChange={handleInputChange}
spellCheck="false"
placeholder="Enter your OpenAPI schema here"
className={cn(
'text-token-text-primary block h-96 w-full border-none bg-transparent p-2 font-mono text-xs',
removeFocusOutlines,
)}
placeholder={localize('com_ui_enter_openapi_schema')}
className="text-token-text-primary block h-96 w-full bg-transparent p-2 font-mono text-xs outline-none focus:ring-1 focus:ring-border-light"
/>
{/* TODO: format input button */}
</div>
@ -240,28 +257,18 @@ export default function ActionsInput({
<ActionsTable columns={columns} data={data} />
</div>
)}
<div className="mt-4">
<div className="relative my-1">
<div className="mb-1.5 flex items-center">
<span className="" data-state="closed">
<label className="text-token-text-primary block font-medium">
{localize('com_ui_privacy_policy')}
</label>
</span>
<label className="text-token-text-primary block font-medium">
{localize('com_ui_privacy_policy_url')}
</label>
</div>
<div className="rounded-md border border-gray-300 px-3 py-2 shadow-none focus-within:border-gray-800 focus-within:ring-1 focus-within:ring-gray-800 dark:border-gray-700 dark:bg-gray-700 dark:focus-within:border-gray-500 dark:focus-within:ring-gray-500">
<label
htmlFor="privacyPolicyUrl"
className="block text-xs font-medium text-gray-900 dark:text-gray-100"
<div className="border-token-border-medium bg-token-surface-primary hover:border-token-border-hover flex h-9 w-full rounded-lg border">
<input
type="text"
placeholder="https://api.example-weather-app.com/privacy"
className="flex-1 rounded-lg bg-transparent px-3 py-1.5 text-sm outline-none focus:ring-1 focus:ring-border-light"
/>
<div className="relative">
<input
name="privacyPolicyUrl"
id="privacyPolicyUrl"
className="block w-full border-0 p-0 text-gray-900 placeholder-gray-500 shadow-none outline-none focus-within:shadow-none focus-within:outline-none focus-within:ring-0 focus:border-none focus:ring-0 dark:bg-gray-700 dark:text-gray-100 sm:text-sm"
placeholder="https://api.example-weather-app.com/privacy"
// value=""
/>
</div>
</div>
</div>
<div className="flex items-center justify-end">
@ -271,13 +278,7 @@ export default function ActionsInput({
className="focus:shadow-outline mt-1 flex min-w-[100px] items-center justify-center rounded bg-green-500 px-4 py-2 font-semibold text-white hover:bg-green-400 focus:border-green-500 focus:outline-none focus:ring-0 disabled:bg-green-400"
type="button"
>
{updateAgentAction.isLoading ? (
<Spinner className="icon-md" />
) : action?.action_id ? (
localize('com_ui_update')
) : (
localize('com_ui_create')
)}
{getButtonContent()}
</button>
</div>
</>

View file

@ -39,7 +39,7 @@ export default function ActionsPanel({
},
onError(error) {
showToast({
message: (error as Error)?.message ?? localize('com_assistants_delete_actions_error'),
message: (error as Error).message ?? localize('com_assistants_delete_actions_error'),
status: 'error',
});
},
@ -68,7 +68,7 @@ export default function ActionsPanel({
const type = watch('type');
useEffect(() => {
if (action?.metadata?.auth) {
if (action?.metadata.auth) {
reset({
type: action.metadata.auth.type || AuthTypeEnum.None,
saved_auth_fields: false,
@ -149,16 +149,16 @@ export default function ActionsPanel({
)}
<div className="text-xl font-medium">{(action ? 'Edit' : 'Add') + ' ' + 'actions'}</div>
<div className="text-token-text-tertiary text-sm">
<div className="text-xs text-text-secondary">
{localize('com_assistants_actions_info')}
</div>
{/* <div className="text-sm text-token-text-tertiary">
{/* <div className="text-sm text-text-secondary">
<a href="https://help.openai.com/en/articles/8554397-creating-a-gpt" target="_blank" rel="noreferrer" className="font-medium">Learn more.</a>
</div> */}
</div>
<Dialog open={openAuthDialog} onOpenChange={setOpenAuthDialog}>
<DialogTrigger asChild>
<div className="relative mb-6">
<div className="relative mb-4">
<div className="mb-1.5 flex items-center">
<label className="text-token-text-primary block font-medium">
{localize('com_ui_authentication')}

View file

@ -18,7 +18,6 @@ import type { Spec } from './ActionsTable';
import { useAssistantsMapContext, useToastContext } from '~/Providers';
import { ActionsTable, columns } from './ActionsTable';
import { useUpdateAction } from '~/data-provider';
import { cn, removeFocusOutlines } from '~/utils';
import useLocalize from '~/hooks/useLocalize';
import { Spinner } from '~/components/svg';
@ -219,7 +218,7 @@ export default function ActionsInput({
htmlFor="example-schema"
className="text-token-text-primary whitespace-nowrap font-medium"
>
Schema
{localize('com_ui_schema')}
</label>
<div className="flex items-center gap-2">
{/* <button className="btn btn-neutral border-token-border-light relative h-8 min-w-[100px] rounded-lg font-medium">
@ -238,17 +237,15 @@ export default function ActionsInput({
</select>
</div>
</div>
<div className="border-token-border-light mb-4 overflow-hidden rounded-lg border">
<div className="border-token-border-medium bg-token-surface-primary hover:border-token-border-hover mb-4 w-full overflow-hidden rounded-lg border ring-0">
<div className="relative">
<textarea
id="schemaInput"
value={inputValue}
onChange={handleInputChange}
spellCheck="false"
placeholder="Enter your OpenAPI schema here"
className={cn(
'text-token-text-primary block h-96 w-full border-none bg-transparent p-2 font-mono text-xs',
removeFocusOutlines,
)}
placeholder={localize('com_ui_enter_openapi_schema')}
className="text-token-text-primary block h-96 w-full bg-transparent p-2 font-mono text-xs outline-none focus:ring-1 focus:ring-border-light"
/>
{/* TODO: format input button */}
</div>
@ -271,20 +268,18 @@ export default function ActionsInput({
<ActionsTable columns={columns} data={data} />
</div>
)}
<div className="mt-4">
<div className="rounded-md border border-gray-300 px-3 py-2 shadow-none focus-within:border-gray-800 focus-within:ring-1 focus-within:ring-gray-800 dark:border-gray-700 dark:bg-gray-700 dark:focus-within:border-gray-500 dark:focus-within:ring-gray-500">
<label htmlFor="privacyPolicyUrl" className="block text-xs text-text-secondary">
Privacy Policy URL
<div className="relative my-1">
<div className="mb-1.5 flex items-center">
<label className="text-token-text-primary block font-medium">
{localize('com_ui_privacy_policy_url')}
</label>
<div className="relative">
<input
name="privacyPolicyUrl"
id="privacyPolicyUrl"
className="block w-full border-0 bg-transparent p-0 placeholder-text-secondary shadow-none outline-none focus-within:shadow-none focus-within:outline-none focus-within:ring-0 focus:border-none focus:ring-0 sm:text-sm"
placeholder="https://api.example-weather-app.com/privacy"
// value=""
/>
</div>
</div>
<div className="border-token-border-medium bg-token-surface-primary hover:border-token-border-hover flex h-9 w-full rounded-lg border">
<input
type="text"
placeholder="https://api.example-weather-app.com/privacy"
className="flex-1 rounded-lg bg-transparent px-3 py-1.5 text-sm outline-none focus:ring-1 focus:ring-border-light"
/>
</div>
</div>
<div className="flex items-center justify-end">

View file

@ -155,16 +155,16 @@ export default function ActionsPanel({
)}
<div className="text-xl font-medium">{(action ? 'Edit' : 'Add') + ' ' + 'actions'}</div>
<div className="text-token-text-tertiary text-sm">
<div className="text-xs text-text-secondary">
{localize('com_assistants_actions_info')}
</div>
{/* <div className="text-sm text-token-text-tertiary">
{/* <div className="text-sm text-text-secondary">
<a href="https://help.openai.com/en/articles/8554397-creating-a-gpt" target="_blank" rel="noreferrer" className="font-medium">Learn more.</a>
</div> */}
</div>
<Dialog open={openAuthDialog} onOpenChange={setOpenAuthDialog}>
<DialogTrigger asChild>
<div className="relative mb-6">
<div className="relative mb-4">
<div className="mb-1.5 flex items-center">
<label className="text-token-text-primary block font-medium">
{localize('com_ui_authentication')}

View file

@ -1 +1,2 @@
export * from './queries';
export * from './mutations';

View file

@ -0,0 +1,265 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { dataService, MutationKeys, QueryKeys, defaultOrderQuery } from 'librechat-data-provider';
import type * as t from 'librechat-data-provider';
import type { UseMutationResult } from '@tanstack/react-query';
/**
* AGENTS
*/
/**
* Create a new agent
*/
export const useCreateAgentMutation = (
options?: t.CreateAgentMutationOptions,
): UseMutationResult<t.Agent, Error, t.AgentCreateParams> => {
const queryClient = useQueryClient();
return useMutation((newAgentData: t.AgentCreateParams) => dataService.createAgent(newAgentData), {
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (newAgent, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(newAgent, variables, context);
}
const currentAgents = [newAgent, ...JSON.parse(JSON.stringify(listRes.data))];
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data: currentAgents,
});
return options?.onSuccess?.(newAgent, variables, context);
},
});
};
/**
* Hook for updating an agent
*/
export const useUpdateAgentMutation = (
options?: t.UpdateAgentMutationOptions,
): UseMutationResult<t.Agent, Error, { agent_id: string; data: t.AgentUpdateParams }> => {
const queryClient = useQueryClient();
return useMutation(
({ agent_id, data }: { agent_id: string; data: t.AgentUpdateParams }) => {
return dataService.updateAgent({
data,
agent_id,
});
},
{
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (updatedAgent, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(updatedAgent, variables, context);
}
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data: listRes.data.map((agent) => {
if (agent.id === variables.agent_id) {
return updatedAgent;
}
return agent;
}),
});
queryClient.setQueryData<t.Agent>([QueryKeys.agent, variables.agent_id], updatedAgent);
return options?.onSuccess?.(updatedAgent, variables, context);
},
},
);
};
/**
* Hook for deleting an agent
*/
export const useDeleteAgentMutation = (
options?: t.DeleteAgentMutationOptions,
): UseMutationResult<void, Error, t.DeleteAgentBody> => {
const queryClient = useQueryClient();
return useMutation(
({ agent_id }: t.DeleteAgentBody) => {
return dataService.deleteAgent({ agent_id });
},
{
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (_data, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(_data, variables, context);
}
const data = listRes.data.filter((agent) => agent.id !== variables.agent_id);
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data,
});
queryClient.removeQueries([QueryKeys.agent, variables.agent_id]);
return options?.onSuccess?.(_data, variables, data);
},
},
);
};
/**
* Hook for uploading an agent avatar
*/
export const useUploadAgentAvatarMutation = (
options?: t.UploadAgentAvatarOptions,
): UseMutationResult<
t.Agent, // response data
unknown, // error
t.AgentAvatarVariables, // request
unknown // context
> => {
return useMutation([MutationKeys.agentAvatarUpload], {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
mutationFn: ({ postCreation, ...variables }: t.AgentAvatarVariables) =>
dataService.uploadAgentAvatar(variables),
...(options || {}),
});
};
/**
* Hook for updating Agent Actions
*/
export const useUpdateAgentAction = (
options?: t.UpdateAgentActionOptions,
): UseMutationResult<
t.UpdateAgentActionResponse, // response data
unknown, // error
t.UpdateAgentActionVariables, // request
unknown // context
> => {
const queryClient = useQueryClient();
return useMutation([MutationKeys.updateAgentAction], {
mutationFn: (variables: t.UpdateAgentActionVariables) =>
dataService.updateAgentAction(variables),
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (updateAgentActionResponse, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(updateAgentActionResponse, variables, context);
}
const updatedAgent = updateAgentActionResponse[0];
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data: listRes.data.map((agent) => {
if (agent.id === variables.agent_id) {
return updatedAgent;
}
return agent;
}),
});
queryClient.setQueryData<t.Action[]>([QueryKeys.actions], (prev) => {
return prev
?.map((action) => {
if (action.action_id === variables.action_id) {
return updateAgentActionResponse[1];
}
return action;
})
.concat(
variables.action_id != null && variables.action_id
? []
: [updateAgentActionResponse[1]],
);
});
queryClient.setQueryData<t.Agent>([QueryKeys.agent, variables.agent_id], updatedAgent);
return options?.onSuccess?.(updateAgentActionResponse, variables, context);
},
});
};
/**
* Hook for deleting an Agent Action
*/
export const useDeleteAgentAction = (
options?: t.DeleteAgentActionOptions,
): UseMutationResult<void, Error, t.DeleteAgentActionVariables, unknown> => {
const queryClient = useQueryClient();
return useMutation([MutationKeys.deleteAgentAction], {
mutationFn: (variables: t.DeleteAgentActionVariables) => {
return dataService.deleteAgentAction({
...variables,
});
},
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (_data, variables, context) => {
let domain: string | undefined = '';
queryClient.setQueryData<t.Action[]>([QueryKeys.actions], (prev) => {
return prev?.filter((action) => {
domain = action.metadata.domain;
return action.action_id !== variables.action_id;
});
});
queryClient.setQueryData<t.AgentListResponse>(
[QueryKeys.agents, defaultOrderQuery],
(prev) => {
if (!prev) {
return prev;
}
return {
...prev,
data: prev.data.map((agent) => {
if (agent.id === variables.agent_id) {
return {
...agent,
tools: agent.tools?.filter((tool) => !tool.includes(domain ?? '')),
};
}
return agent;
}),
};
},
);
queryClient.setQueryData<t.Agent>([QueryKeys.agent, variables.agent_id], (prev) => {
if (!prev) {
return prev;
}
return {
...prev,
tools: prev.tools?.filter((tool) => !tool.includes(domain ?? '')),
};
});
return options?.onSuccess?.(_data, variables, context);
},
});
};

View file

@ -1056,254 +1056,6 @@ export const useDeleteAction = (
});
};
/**
* AGENTS
*/
/**
* Create a new agent
*/
export const useCreateAgentMutation = (
options?: t.CreateAgentMutationOptions,
): UseMutationResult<t.Agent, Error, t.AgentCreateParams> => {
const queryClient = useQueryClient();
return useMutation((newAgentData: t.AgentCreateParams) => dataService.createAgent(newAgentData), {
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (newAgent, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(newAgent, variables, context);
}
const currentAgents = [newAgent, ...JSON.parse(JSON.stringify(listRes.data))];
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data: currentAgents,
});
return options?.onSuccess?.(newAgent, variables, context);
},
});
};
/**
* Hook for updating an agent
*/
export const useUpdateAgentMutation = (
options?: t.UpdateAgentMutationOptions,
): UseMutationResult<t.Agent, Error, { agent_id: string; data: t.AgentUpdateParams }> => {
const queryClient = useQueryClient();
return useMutation(
({ agent_id, data }: { agent_id: string; data: t.AgentUpdateParams }) => {
return dataService.updateAgent({
data,
agent_id,
});
},
{
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (updatedAgent, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(updatedAgent, variables, context);
}
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data: listRes.data.map((agent) => {
if (agent.id === variables.agent_id) {
return updatedAgent;
}
return agent;
}),
});
queryClient.setQueryData<t.Agent>([QueryKeys.agent, variables.agent_id], updatedAgent);
return options?.onSuccess?.(updatedAgent, variables, context);
},
},
);
};
/**
* Hook for deleting an agent
*/
export const useDeleteAgentMutation = (
options?: t.DeleteAgentMutationOptions,
): UseMutationResult<void, Error, t.DeleteAgentBody> => {
const queryClient = useQueryClient();
return useMutation(
({ agent_id }: t.DeleteAgentBody) => {
return dataService.deleteAgent({ agent_id });
},
{
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (_data, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(_data, variables, context);
}
const data = listRes.data.filter((agent) => agent.id !== variables.agent_id);
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data,
});
return options?.onSuccess?.(_data, variables, data);
},
},
);
};
/**
* Hook for uploading an agent avatar
*/
export const useUploadAgentAvatarMutation = (
options?: t.UploadAgentAvatarOptions,
): UseMutationResult<
t.Agent, // response data
unknown, // error
t.AgentAvatarVariables, // request
unknown // context
> => {
return useMutation([MutationKeys.agentAvatarUpload], {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
mutationFn: ({ postCreation, ...variables }: t.AgentAvatarVariables) =>
dataService.uploadAgentAvatar(variables),
...(options || {}),
});
};
/**
* Hook for updating Agent Actions
*/
export const useUpdateAgentAction = (
options?: t.UpdateAgentActionOptions,
): UseMutationResult<
t.UpdateAgentActionResponse, // response data
unknown, // error
t.UpdateAgentActionVariables, // request
unknown // context
> => {
const queryClient = useQueryClient();
return useMutation([MutationKeys.updateAgentAction], {
mutationFn: (variables: t.UpdateAgentActionVariables) =>
dataService.updateAgentAction(variables),
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (updateAgentActionResponse, variables, context) => {
const listRes = queryClient.getQueryData<t.AgentListResponse>([
QueryKeys.agents,
defaultOrderQuery,
]);
if (!listRes) {
return options?.onSuccess?.(updateAgentActionResponse, variables, context);
}
const updatedAgent = updateAgentActionResponse[0];
queryClient.setQueryData<t.AgentListResponse>([QueryKeys.agents, defaultOrderQuery], {
...listRes,
data: listRes.data.map((agent) => {
if (agent.id === variables.agent_id) {
return updatedAgent;
}
return agent;
}),
});
queryClient.setQueryData<t.Action[]>([QueryKeys.actions], (prev) => {
return prev
?.map((action) => {
if (action.action_id === variables.action_id) {
return updateAgentActionResponse[1];
}
return action;
})
.concat(
variables.action_id != null && variables.action_id
? []
: [updateAgentActionResponse[1]],
);
});
return options?.onSuccess?.(updateAgentActionResponse, variables, context);
},
});
};
/**
* Hook for deleting an Agent Action
*/
export const useDeleteAgentAction = (
options?: t.DeleteAgentActionOptions,
): UseMutationResult<void, Error, t.DeleteAgentActionVariables, unknown> => {
const queryClient = useQueryClient();
return useMutation([MutationKeys.deleteAgentAction], {
mutationFn: (variables: t.DeleteAgentActionVariables) => {
return dataService.deleteAgentAction({
...variables,
});
},
onMutate: (variables) => options?.onMutate?.(variables),
onError: (error, variables, context) => options?.onError?.(error, variables, context),
onSuccess: (_data, variables, context) => {
let domain: string | undefined = '';
queryClient.setQueryData<t.Action[]>([QueryKeys.actions], (prev) => {
return prev?.filter((action) => {
domain = action.metadata.domain;
return action.action_id !== variables.action_id;
});
});
queryClient.setQueryData<t.AgentListResponse>(
[QueryKeys.agents, defaultOrderQuery],
(prev) => {
if (!prev) {
return prev;
}
return {
...prev,
data: prev.data.map((agent) => {
if (agent.id === variables.agent_id) {
return {
...agent,
tools: agent.tools?.filter((tool) => !tool.includes(domain ?? '')),
};
}
return agent;
}),
};
},
);
return options?.onSuccess?.(_data, variables, context);
},
});
};
/**
* Hook for verifying email address
*/

View file

@ -401,7 +401,10 @@ export default {
com_ui_locked: 'Locked',
com_ui_upload_delay:
'Uploading "{0}" is taking more time than anticipated. Please wait while the file finishes indexing for retrieval.',
com_ui_schema: 'Schema',
com_ui_enter_openapi_schema: 'Enter your OpenAPI schema here',
com_ui_privacy_policy: 'Privacy policy',
com_ui_privacy_policy_url: 'Privacy Policy URL',
com_ui_terms_of_service: 'Terms of service',
com_ui_use_micrphone: 'Use microphone',
com_ui_min_tags: 'Cannot remove more values, a minimum of {0} are required.',