Feat: add duplicate action to agent list (#14769) (#14856)

closes #14769 


### What problem does this PR solve?

_Briefly describe what this PR aims to solve. Include background context
that will help reviewers understand the purpose of the PR._

### Type of change

- [ ] Bug Fix (non-breaking change which fixes an issue)
- [x] New Feature (non-breaking change which adds functionality)
- [ ] Documentation Update
- [ ] Refactoring
- [ ] Performance Improvement
- [ ] Other (please describe):

---------

Co-authored-by: Zhichang Yu <yuzhichang@gmail.com>
This commit is contained in:
Rene Arredondo
2026-06-28 18:17:44 -07:00
committed by yzc
parent 9f6f0c5582
commit dc07b6ca8f
4 changed files with 59 additions and 2 deletions

View File

@@ -251,6 +251,59 @@ export const useUpdateAgentSetting = () => {
return { data, loading, updateAgentSetting: mutateAsync };
};
export const useDuplicateAgent = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [AgentApiAction.SetAgent, 'duplicate'],
mutationFn: async (agent: Pick<IFlow, 'id' | 'title'>) => {
try {
const { data: detail } = await agentService.getAgent(agent.id);
const source = detail?.data;
if (!source) {
message.error(i18n.t('message.requestError'));
return null;
}
const sourceTitle = agent.title ?? source.title ?? '';
const { data } = await agentService.createAgent({
title: i18n.t('flow.copyOfAgentName', {
name: sourceTitle,
defaultValue: `${sourceTitle} (Copy)`,
}),
dsl: source.dsl,
avatar: source.avatar,
description: source.description,
canvas_category: source.canvas_category,
});
if (data?.code === 0) {
message.success(i18n.t('message.created'));
queryClient.invalidateQueries({
queryKey: [AgentApiAction.FetchAgentListByPage],
});
return data;
}
message.error(data?.message ?? i18n.t('message.requestError'));
return null;
} catch (error) {
console.error('useDuplicateAgent failed:', error);
message.error(
(error as { message?: string })?.message ??
i18n.t('message.requestError'),
);
return null;
}
},
});
return { data, loading, duplicateAgent: mutateAsync };
};
export const useDeleteAgent = () => {
const queryClient = useQueryClient();
const {

View File

@@ -2697,6 +2697,8 @@ This process aggregates variables from multiple branches into a single variable
createFromBlank: 'Create from blank',
createFromTemplate: 'Create from template',
importJsonFile: 'Import JSON file',
duplicate: 'Duplicate',
copyOfAgentName: '{{name}} (copy)',
ceateAgent: 'Workflow',
createPipeline: 'Ingestion pipeline',
chooseAgentType: 'Choose agent type',

View File

@@ -2334,6 +2334,8 @@ NER使用 spaCy NER 和基于规则的关键词提取来抽取实体和关系
createFromBlank: '从空白创建',
createFromTemplate: '从模板创建',
importJsonFile: '导入 JSON 文件',
duplicate: '复制',
copyOfAgentName: '{{name}} (副本)',
chooseAgentType: '选择智能体类型',
parser: '解析器',
parserDescription: '从文件中提取原始文本和结构以供下游处理。',

View File

@@ -9,10 +9,10 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { useDeleteAgent } from '@/hooks/use-agent-request';
import { useDeleteAgent, useDuplicateAgent } from '@/hooks/use-agent-request';
import { IFlow } from '@/interfaces/database/agent';
import { PenLine, Tag, Trash2 } from 'lucide-react';
import { MouseEventHandler, PropsWithChildren, useCallback, useState } from 'react';
import { PenLine, Tag, Trash2 } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { AgentTagEditor } from './agent-tag-editor';
import { useRenameAgent } from './use-rename-agent';