@@ -563,7 +563,7 @@ impl Agents {
563563 } ;
564564
565565 let mut agents = Vec :: < Agent > :: new ( ) ;
566- let results = load_agents_from_entries ( files, os, & mut global_mcp_config, mcp_enabled, output) . await ;
566+ let results = load_agents_from_entries ( files, os, & mut global_mcp_config, mcp_enabled, false , output) . await ;
567567 for result in results {
568568 match result {
569569 Ok ( agent) => agents. push ( agent) ,
@@ -601,7 +601,7 @@ impl Agents {
601601 } ;
602602
603603 let mut agents = Vec :: < Agent > :: new ( ) ;
604- let results = load_agents_from_entries ( files, os, & mut global_mcp_config, mcp_enabled, output) . await ;
604+ let results = load_agents_from_entries ( files, os, & mut global_mcp_config, mcp_enabled, true , output) . await ;
605605 for result in results {
606606 match result {
607607 Ok ( agent) => agents. push ( agent) ,
@@ -886,6 +886,7 @@ async fn load_agents_from_entries(
886886 os : & Os ,
887887 global_mcp_config : & mut Option < McpServerConfig > ,
888888 mcp_enabled : bool ,
889+ is_from_global_dir : bool ,
889890 output : & mut impl Write ,
890891) -> Vec < Result < Agent , AgentConfigError > > {
891892 let mut res = Vec :: < Result < Agent , AgentConfigError > > :: new ( ) ;
@@ -897,7 +898,30 @@ async fn load_agents_from_entries(
897898 . and_then ( OsStr :: to_str)
898899 . is_some_and ( |s| s == "json" )
899900 {
900- res. push ( Agent :: load ( os, file_path, global_mcp_config, mcp_enabled, output) . await ) ;
901+ let agent_res = Agent :: load ( os, file_path, global_mcp_config, mcp_enabled, output) . await ;
902+ if let Ok ( agent) = & agent_res {
903+ if res. iter ( ) . any ( |res| match res {
904+ Ok ( a) => a. name == agent. name ,
905+ Err ( _) => false ,
906+ } ) {
907+ let _ = queue ! (
908+ output,
909+ StyledText :: warning_fg( ) ,
910+ style:: Print ( "WARNING: " ) ,
911+ StyledText :: reset( ) ,
912+ style:: Print ( "Duplicate agent with name " ) ,
913+ StyledText :: success_fg( ) ,
914+ style:: Print ( & agent. name) ,
915+ StyledText :: reset( ) ,
916+ style:: Print ( " was found in the " ) ,
917+ style:: Print ( if is_from_global_dir { "global" } else { "workspace" } ) ,
918+ style:: Print ( " directory.\n " ) ,
919+ StyledText :: reset( ) ,
920+ ) ;
921+ continue ;
922+ }
923+ }
924+ res. push ( agent_res) ;
901925 }
902926 }
903927
@@ -996,6 +1020,7 @@ fn validate_agent_name(name: &str) -> eyre::Result<()> {
9961020mod tests {
9971021 use std:: fs;
9981022
1023+ use bstr:: ByteSlice ;
9991024 use serde_json:: json;
10001025 use tempfile:: TempDir ;
10011026
@@ -1581,4 +1606,44 @@ mod tests {
15811606 let result = agent. resolve_prompt ( ) ;
15821607 assert ! ( result. is_err( ) ) ;
15831608 }
1609+
1610+ #[ tokio:: test]
1611+ async fn test_load_agents_from_entries_warns_duplicate ( ) {
1612+ // Given two agents with the same name
1613+ let os = Os :: new ( ) . await . unwrap ( ) ;
1614+ let agents = [
1615+ Agent {
1616+ name : "test-agent" . to_string ( ) ,
1617+ ..Default :: default ( )
1618+ } ,
1619+ Agent {
1620+ name : "test-agent" . to_string ( ) ,
1621+ ..Default :: default ( )
1622+ } ,
1623+ ] ;
1624+ for ( i, agent) in agents. iter ( ) . enumerate ( ) {
1625+ os. fs
1626+ . write ( format ! ( "{}_{}.json" , agent. name, i) , agent. to_str_pretty ( ) . unwrap ( ) )
1627+ . await
1628+ . unwrap ( ) ;
1629+ }
1630+
1631+ // When we load them
1632+ let mut output = Vec :: new ( ) ;
1633+ let results = load_agents_from_entries (
1634+ os. fs . read_dir ( "." ) . await . unwrap ( ) ,
1635+ & os,
1636+ & mut None ,
1637+ false ,
1638+ false ,
1639+ & mut output,
1640+ )
1641+ . await ;
1642+
1643+ // We should see a warning
1644+ assert ! ( output. contains_str( "WARNING" ) ) ;
1645+ assert ! ( output. contains_str( "test-agent" ) ) ;
1646+ assert ! ( output. contains_str( "workspace" ) ) ;
1647+ assert_eq ! ( results. len( ) , 1 ) ;
1648+ }
15841649}
0 commit comments