@@ -26,6 +26,7 @@ import {
2626} from "@/types/agentConfig" ;
2727import AgentImportWizard from "@/components/agent/AgentImportWizard" ;
2828import log from "@/lib/logger" ;
29+ import { useConfirmModal } from "@/hooks/useConfirmModal" ;
2930
3031import SubAgentPool from "./agent/SubAgentPool" ;
3132import CollaborativeAgentDisplay from "./agent/CollaborativeAgentDisplay" ;
@@ -150,7 +151,9 @@ export default function AgentSetupOrchestrator({
150151 detailReasons . length > 0 ? detailReasons : fallbackReasons ;
151152
152153 const normalizedAvailability =
153- typeof detail ?. is_available === "boolean"
154+ normalizedReasons . length > 0
155+ ? false
156+ : typeof detail ?. is_available === "boolean"
154157 ? detail . is_available
155158 : typeof fallback ?. is_available === "boolean"
156159 ? fallback . is_available
@@ -196,6 +199,7 @@ export default function AgentSetupOrchestrator({
196199
197200 const { t } = useTranslation ( "common" ) ;
198201 const { message } = App . useApp ( ) ;
202+ const { confirm } = useConfirmModal ( ) ;
199203
200204 // Common refresh agent list function, moved to the front to avoid hoisting issues
201205 const refreshAgentList = async ( t : TFunction , clearTools : boolean = true ) => {
@@ -1858,6 +1862,138 @@ export default function AgentSetupOrchestrator({
18581862 }
18591863 } ;
18601864
1865+ // Handle copy agent from list
1866+ const handleCopyAgentFromList = async ( agent : Agent ) => {
1867+ try {
1868+ // Fetch source agent detail before duplicating
1869+ const detailResult = await searchAgentInfo ( Number ( agent . id ) ) ;
1870+ if ( ! detailResult . success || ! detailResult . data ) {
1871+ message . error ( detailResult . message ) ;
1872+ return ;
1873+ }
1874+ const detail = detailResult . data ;
1875+
1876+ // Prepare copy names
1877+ const copyName = `${ detail . name || "agent" } _copy` ;
1878+ const copyDisplayName = `${
1879+ detail . display_name || t ( "agentConfig.agents.defaultDisplayName" )
1880+ } ${ t ( "agent.copySuffix" ) } `;
1881+
1882+ // Gather tool and sub-agent identifiers from the source agent
1883+ const tools = Array . isArray ( detail . tools ) ? detail . tools : [ ] ;
1884+ const unavailableTools = tools . filter (
1885+ ( tool : any ) => tool && tool . is_available === false
1886+ ) ;
1887+ const unavailableToolNames = unavailableTools
1888+ . map (
1889+ ( tool : any ) =>
1890+ tool ?. display_name || tool ?. name || tool ?. tool_name || ""
1891+ )
1892+ . filter ( ( name : string ) => Boolean ( name ) ) ;
1893+
1894+ const enabledToolIds = tools
1895+ . filter ( ( tool : any ) => tool && tool . is_available !== false )
1896+ . map ( ( tool : any ) => Number ( tool . id ) )
1897+ . filter ( ( id : number ) => Number . isFinite ( id ) ) ;
1898+ const subAgentIds = ( Array . isArray ( detail . sub_agent_id_list )
1899+ ? detail . sub_agent_id_list
1900+ : [ ]
1901+ )
1902+ . map ( ( id : any ) => Number ( id ) )
1903+ . filter ( ( id : number ) => Number . isFinite ( id ) ) ;
1904+
1905+ // Create a new agent using the source agent fields
1906+ const createResult = await updateAgent (
1907+ undefined ,
1908+ copyName ,
1909+ detail . description ,
1910+ detail . model ,
1911+ detail . max_step ,
1912+ detail . provide_run_summary ,
1913+ detail . enabled ,
1914+ detail . business_description ,
1915+ detail . duty_prompt ,
1916+ detail . constraint_prompt ,
1917+ detail . few_shots_prompt ,
1918+ copyDisplayName ,
1919+ detail . model_id ?? undefined ,
1920+ detail . business_logic_model_name ?? undefined ,
1921+ detail . business_logic_model_id ?? undefined ,
1922+ enabledToolIds ,
1923+ subAgentIds
1924+ ) ;
1925+ if ( ! createResult . success || ! createResult . data ?. agent_id ) {
1926+ message . error (
1927+ createResult . message ||
1928+ t ( "agentConfig.agents.copyFailed" )
1929+ ) ;
1930+ return ;
1931+ }
1932+ const newAgentId = Number ( createResult . data . agent_id ) ;
1933+ const copiedAgentFallback : Agent = {
1934+ ...detail ,
1935+ id : String ( newAgentId ) ,
1936+ name : copyName ,
1937+ display_name : copyDisplayName ,
1938+ sub_agent_id_list : subAgentIds ,
1939+ } ;
1940+
1941+ // Copy tool configuration to the new agent
1942+ for ( const tool of tools ) {
1943+ if ( ! tool || tool . is_available === false ) {
1944+ continue ;
1945+ }
1946+ const params =
1947+ tool . initParams ?. reduce ( ( acc : Record < string , any > , param : any ) => {
1948+ acc [ param . name ] = param . value ;
1949+ return acc ;
1950+ } , { } ) || { } ;
1951+ try {
1952+ await updateToolConfig ( Number ( tool . id ) , newAgentId , params , true ) ;
1953+ } catch ( error ) {
1954+ log . error ( "Failed to copy tool configuration while duplicating agent:" , error ) ;
1955+ message . error (
1956+ t ( "agentConfig.agents.copyFailed" )
1957+ ) ;
1958+ return ;
1959+ }
1960+ }
1961+
1962+ // Refresh UI state and notify user about copy result
1963+ await refreshAgentList ( t , false ) ;
1964+ message . success ( t ( "agentConfig.agents.copySuccess" ) ) ;
1965+ if ( unavailableTools . length > 0 ) {
1966+ const names =
1967+ unavailableToolNames . join ( ", " ) ||
1968+ unavailableTools
1969+ . map ( ( tool : any ) => Number ( tool ?. id ) )
1970+ . filter ( ( id : number ) => ! Number . isNaN ( id ) )
1971+ . join ( ", " ) ;
1972+ message . warning (
1973+ t ( "agentConfig.agents.copyUnavailableTools" , {
1974+ count : unavailableTools . length ,
1975+ names,
1976+ } )
1977+ ) ;
1978+ }
1979+ // Auto select the newly copied agent for editing
1980+ await handleEditAgent ( copiedAgentFallback , t ) ;
1981+ } catch ( error ) {
1982+ log . error ( "Failed to copy agent:" , error ) ;
1983+ message . error ( t ( "agentConfig.agents.copyFailed" ) ) ;
1984+ }
1985+ } ;
1986+
1987+ const handleCopyAgentWithConfirm = ( agent : Agent ) => {
1988+ confirm ( {
1989+ title : t ( "agentConfig.agents.copyConfirmTitle" ) ,
1990+ content : t ( "agentConfig.agents.copyConfirmContent" , {
1991+ name : agent ?. display_name || agent ?. name || "" ,
1992+ } ) ,
1993+ onConfirm : ( ) => handleCopyAgentFromList ( agent ) ,
1994+ } ) ;
1995+ } ;
1996+
18611997 // Handle delete agent from list
18621998 const handleDeleteAgentFromList = ( agent : Agent ) => {
18631999 setAgentToDelete ( agent ) ;
@@ -1977,6 +2113,7 @@ export default function AgentSetupOrchestrator({
19772113 isGeneratingAgent = { isGeneratingAgent }
19782114 editingAgent = { editingAgent }
19792115 isCreatingNewAgent = { isCreatingNewAgent }
2116+ onCopyAgent = { handleCopyAgentWithConfirm }
19802117 onExportAgent = { handleExportAgentFromList }
19812118 onDeleteAgent = { handleDeleteAgentFromList }
19822119 unsavedAgentId = {
0 commit comments