@@ -651,6 +651,96 @@ describe('resolveAgentConfig', () => {
651651 ) ;
652652 } ) ;
653653
654+ describe ( 'supervisor with own slug (priority check)' , ( ) => {
655+ // This tests the fix for LOBE-4127: When supervisor agent has its own slug,
656+ // it should still use 'group-supervisor' slug when in group scope
657+
658+ it ( 'should use group-supervisor slug even when agent has its own slug in group scope' , ( ) => {
659+ // Supervisor agent has its own slug (e.g., from being a builtin agent)
660+ vi . spyOn ( agentSelectors . agentSelectors , 'getAgentSlugById' ) . mockReturnValue (
661+ ( ) => 'some-agent-slug' ,
662+ ) ;
663+
664+ // Mock: groupById returns the group
665+ vi . spyOn ( agentGroupSelectors . agentGroupByIdSelectors , 'groupById' ) . mockReturnValue (
666+ ( ) => mockGroupWithSupervisor as any ,
667+ ) ;
668+
669+ vi . spyOn ( agentGroupSelectors . agentGroupSelectors , 'getGroupMembers' ) . mockReturnValue (
670+ ( ) =>
671+ [
672+ { id : 'member-agent-1' , title : 'Agent 1' } ,
673+ { id : 'member-agent-2' , title : 'Agent 2' } ,
674+ ] as any ,
675+ ) ;
676+
677+ vi . spyOn ( builtinAgents , 'getAgentRuntimeConfig' ) . mockReturnValue ( {
678+ chatConfig : { enableHistoryCount : false } ,
679+ plugins : [ GroupManagementIdentifier , GTDIdentifier ] ,
680+ systemRole : 'You are a group supervisor...' ,
681+ } ) ;
682+
683+ const result = resolveAgentConfig ( {
684+ agentId : 'supervisor-agent-id' ,
685+ groupId : 'group-123' ,
686+ scope : 'group' , // Key: must be 'group' scope
687+ } ) ;
688+
689+ // Should use group-supervisor, NOT the agent's own slug
690+ expect ( result . isBuiltinAgent ) . toBe ( true ) ;
691+ expect ( result . slug ) . toBe ( 'group-supervisor' ) ;
692+ expect ( result . plugins ) . toContain ( GroupManagementIdentifier ) ;
693+ } ) ;
694+
695+ it ( 'should use agent own slug when scope is not group' , ( ) => {
696+ // Supervisor agent has its own slug
697+ vi . spyOn ( agentSelectors . agentSelectors , 'getAgentSlugById' ) . mockReturnValue (
698+ ( ) => 'some-agent-slug' ,
699+ ) ;
700+
701+ // Mock: groupById returns the group
702+ vi . spyOn ( agentGroupSelectors . agentGroupByIdSelectors , 'groupById' ) . mockReturnValue (
703+ ( ) => mockGroupWithSupervisor as any ,
704+ ) ;
705+
706+ vi . spyOn ( builtinAgents , 'getAgentRuntimeConfig' ) . mockReturnValue ( {
707+ plugins : [ 'agent-specific-plugin' ] ,
708+ systemRole : 'Agent specific system role' ,
709+ } ) ;
710+
711+ const result = resolveAgentConfig ( {
712+ agentId : 'supervisor-agent-id' ,
713+ groupId : 'group-123' ,
714+ scope : 'main' , // Not 'group' scope
715+ } ) ;
716+
717+ // Should use agent's own slug since scope is not 'group'
718+ expect ( result . isBuiltinAgent ) . toBe ( true ) ;
719+ expect ( result . slug ) . toBe ( 'some-agent-slug' ) ;
720+ } ) ;
721+
722+ it ( 'should use agent own slug when groupId is not provided' , ( ) => {
723+ // Supervisor agent has its own slug
724+ vi . spyOn ( agentSelectors . agentSelectors , 'getAgentSlugById' ) . mockReturnValue (
725+ ( ) => 'some-agent-slug' ,
726+ ) ;
727+
728+ vi . spyOn ( builtinAgents , 'getAgentRuntimeConfig' ) . mockReturnValue ( {
729+ plugins : [ 'agent-specific-plugin' ] ,
730+ systemRole : 'Agent specific system role' ,
731+ } ) ;
732+
733+ const result = resolveAgentConfig ( {
734+ agentId : 'supervisor-agent-id' ,
735+ scope : 'group' , // Even with group scope, no groupId
736+ } ) ;
737+
738+ // Should use agent's own slug since no groupId
739+ expect ( result . isBuiltinAgent ) . toBe ( true ) ;
740+ expect ( result . slug ) . toBe ( 'some-agent-slug' ) ;
741+ } ) ;
742+ } ) ;
743+
654744 it ( 'should detect supervisor agent using groupId for direct lookup' , ( ) => {
655745 // Mock: groupById returns the group
656746 vi . spyOn ( agentGroupSelectors . agentGroupByIdSelectors , 'groupById' ) . mockReturnValue (
@@ -676,6 +766,7 @@ describe('resolveAgentConfig', () => {
676766 const result = resolveAgentConfig ( {
677767 agentId : 'supervisor-agent-id' ,
678768 groupId : 'group-123' ,
769+ scope : 'group' , // Required: supervisor detection only works in group scope
679770 } ) ;
680771
681772 expect ( result . isBuiltinAgent ) . toBe ( true ) ;
@@ -710,6 +801,7 @@ describe('resolveAgentConfig', () => {
710801 resolveAgentConfig ( {
711802 agentId : 'supervisor-agent-id' ,
712803 groupId : 'group-123' ,
804+ scope : 'group' , // Required: supervisor detection only works in group scope
713805 } ) ;
714806
715807 expect ( getAgentRuntimeConfigSpy ) . toHaveBeenCalledWith (
@@ -789,6 +881,7 @@ describe('resolveAgentConfig', () => {
789881 const result = resolveAgentConfig ( {
790882 agentId : 'supervisor-agent-id' ,
791883 groupId : 'group-123' ,
884+ scope : 'group' , // Required: supervisor detection only works in group scope
792885 } ) ;
793886
794887 // Should correctly identify as builtin supervisor agent
@@ -913,4 +1006,108 @@ describe('resolveAgentConfig', () => {
9131006 expect ( result . plugins ) . toContain ( 'lobe-gtd' ) ;
9141007 } ) ;
9151008 } ) ;
1009+
1010+ describe ( 'disableTools (broadcast scenario)' , ( ) => {
1011+ beforeEach ( ( ) => {
1012+ vi . spyOn ( agentSelectors . agentSelectors , 'getAgentSlugById' ) . mockReturnValue ( ( ) => undefined ) ;
1013+ } ) ;
1014+
1015+ it ( 'should return empty plugins when disableTools is true for regular agent' , ( ) => {
1016+ vi . spyOn ( agentSelectors . agentSelectors , 'getAgentConfigById' ) . mockReturnValue (
1017+ ( ) =>
1018+ ( {
1019+ ...mockAgentConfig ,
1020+ plugins : [ 'plugin-a' , 'plugin-b' , 'lobe-gtd' ] ,
1021+ } ) as any ,
1022+ ) ;
1023+
1024+ const result = resolveAgentConfig ( {
1025+ agentId : 'test-agent' ,
1026+ disableTools : true ,
1027+ } ) ;
1028+
1029+ expect ( result . plugins ) . toEqual ( [ ] ) ;
1030+ } ) ;
1031+
1032+ it ( 'should keep plugins when disableTools is false' , ( ) => {
1033+ const result = resolveAgentConfig ( {
1034+ agentId : 'test-agent' ,
1035+ disableTools : false ,
1036+ } ) ;
1037+
1038+ expect ( result . plugins ) . toEqual ( [ 'plugin-a' , 'plugin-b' ] ) ;
1039+ } ) ;
1040+
1041+ it ( 'should keep plugins when disableTools is undefined' , ( ) => {
1042+ const result = resolveAgentConfig ( { agentId : 'test-agent' } ) ;
1043+
1044+ expect ( result . plugins ) . toEqual ( [ 'plugin-a' , 'plugin-b' ] ) ;
1045+ } ) ;
1046+
1047+ it ( 'should return empty plugins for builtin agent when disableTools is true' , ( ) => {
1048+ vi . spyOn ( agentSelectors . agentSelectors , 'getAgentSlugById' ) . mockReturnValue (
1049+ ( ) => 'some-builtin-slug' ,
1050+ ) ;
1051+ vi . spyOn ( builtinAgents , 'getAgentRuntimeConfig' ) . mockReturnValue ( {
1052+ plugins : [ 'runtime-plugin-1' , 'runtime-plugin-2' ] ,
1053+ systemRole : 'Runtime system role' ,
1054+ } ) ;
1055+
1056+ const result = resolveAgentConfig ( {
1057+ agentId : 'builtin-agent' ,
1058+ disableTools : true ,
1059+ } ) ;
1060+
1061+ expect ( result . plugins ) . toEqual ( [ ] ) ;
1062+ expect ( result . isBuiltinAgent ) . toBe ( true ) ;
1063+ } ) ;
1064+
1065+ it ( 'should return empty plugins in page scope when disableTools is true' , ( ) => {
1066+ vi . spyOn ( builtinAgents , 'getAgentRuntimeConfig' ) . mockReturnValue ( {
1067+ plugins : [ PageAgentIdentifier ] ,
1068+ systemRole : 'Page agent system role' ,
1069+ } ) ;
1070+
1071+ const result = resolveAgentConfig ( {
1072+ agentId : 'test-agent' ,
1073+ disableTools : true ,
1074+ scope : 'page' ,
1075+ } ) ;
1076+
1077+ // disableTools should override page scope injection
1078+ expect ( result . plugins ) . toEqual ( [ ] ) ;
1079+ } ) ;
1080+
1081+ it ( 'should take precedence over isSubTask filtering' , ( ) => {
1082+ vi . spyOn ( agentSelectors . agentSelectors , 'getAgentConfigById' ) . mockReturnValue (
1083+ ( ) =>
1084+ ( {
1085+ ...mockAgentConfig ,
1086+ plugins : [ 'lobe-gtd' , 'plugin-a' ] ,
1087+ } ) as any ,
1088+ ) ;
1089+
1090+ const result = resolveAgentConfig ( {
1091+ agentId : 'test-agent' ,
1092+ disableTools : true ,
1093+ isSubTask : true ,
1094+ } ) ;
1095+
1096+ // disableTools should result in empty plugins regardless of isSubTask
1097+ expect ( result . plugins ) . toEqual ( [ ] ) ;
1098+ } ) ;
1099+
1100+ it ( 'should preserve agentConfig and chatConfig when disableTools is true' , ( ) => {
1101+ const result = resolveAgentConfig ( {
1102+ agentId : 'test-agent' ,
1103+ disableTools : true ,
1104+ } ) ;
1105+
1106+ // Only plugins should be empty, other config should be preserved
1107+ expect ( result . plugins ) . toEqual ( [ ] ) ;
1108+ expect ( result . agentConfig ) . toEqual ( mockAgentConfig ) ;
1109+ expect ( result . chatConfig ) . toEqual ( mockChatConfig ) ;
1110+ expect ( result . isBuiltinAgent ) . toBe ( false ) ;
1111+ } ) ;
1112+ } ) ;
9161113} ) ;
0 commit comments