@@ -11,7 +11,7 @@ jest.mock("../../core/prompts/sections/custom-instructions", () => ({
1111 addCustomInstructions : mockAddCustomInstructions ,
1212} ) )
1313
14- import { isToolAllowedForMode , FileRestrictionError , getFullModeDetails , modes } from "../modes"
14+ import { isToolAllowedForMode , FileRestrictionError , getFullModeDetails , modes , getModeSelection } from "../modes"
1515import { addCustomInstructions } from "../../core/prompts/sections/custom-instructions"
1616
1717describe ( "isToolAllowedForMode" , ( ) => {
@@ -371,3 +371,178 @@ describe("FileRestrictionError", () => {
371371 expect ( error . name ) . toBe ( "FileRestrictionError" )
372372 } )
373373} )
374+
375+ describe ( "getModeSelection" , ( ) => {
376+ const builtInAskMode = modes . find ( ( m ) => m . slug === "ask" ) !
377+
378+ const customModesList : ModeConfig [ ] = [
379+ {
380+ slug : "code" , // Override
381+ name : "Custom Code Mode" ,
382+ roleDefinition : "Custom Code Role" ,
383+ customInstructions : "Custom Code Instructions" ,
384+ groups : [ "read" ] ,
385+ } ,
386+ {
387+ slug : "new-custom" ,
388+ name : "New Custom Mode" ,
389+ roleDefinition : "New Custom Role" ,
390+ customInstructions : "New Custom Instructions" ,
391+ groups : [ "edit" ] ,
392+ } ,
393+ ]
394+
395+ const promptComponentCode : PromptComponent = {
396+ roleDefinition : "Prompt Component Code Role" ,
397+ customInstructions : "Prompt Component Code Instructions" ,
398+ }
399+
400+ const promptComponentAsk : PromptComponent = {
401+ roleDefinition : "Prompt Component Ask Role" ,
402+ customInstructions : "Prompt Component Ask Instructions" ,
403+ }
404+
405+ test ( "should return built-in mode details if no overrides" , ( ) => {
406+ const selection = getModeSelection ( "ask" )
407+ expect ( selection . roleDefinition ) . toBe ( builtInAskMode . roleDefinition )
408+ expect ( selection . baseInstructions ) . toBe ( builtInAskMode . customInstructions || "" )
409+ } )
410+
411+ test ( "should prioritize promptComponent for built-in mode" , ( ) => {
412+ const selection = getModeSelection ( "ask" , promptComponentAsk )
413+ expect ( selection . roleDefinition ) . toBe ( promptComponentAsk . roleDefinition )
414+ expect ( selection . baseInstructions ) . toBe ( promptComponentAsk . customInstructions )
415+ } )
416+
417+ test ( "should prioritize customMode over built-in mode" , ( ) => {
418+ const selection = getModeSelection ( "code" , undefined , customModesList )
419+ const customCode = customModesList . find ( ( m ) => m . slug === "code" ) !
420+ expect ( selection . roleDefinition ) . toBe ( customCode . roleDefinition )
421+ expect ( selection . baseInstructions ) . toBe ( customCode . customInstructions )
422+ } )
423+
424+ test ( "should prioritize customMode over promptComponent and built-in mode when all define properties" , ( ) => {
425+ const selection = getModeSelection ( "code" , promptComponentCode , customModesList )
426+ const customCode = customModesList . find ( ( m ) => m . slug === "code" ) !
427+ expect ( selection . roleDefinition ) . toBe ( customCode . roleDefinition )
428+ expect ( selection . baseInstructions ) . toBe ( customCode . customInstructions )
429+ } )
430+
431+ test ( "should return new custom mode details" , ( ) => {
432+ const selection = getModeSelection ( "new-custom" , undefined , customModesList )
433+ const newCustom = customModesList . find ( ( m ) => m . slug === "new-custom" ) !
434+ expect ( selection . roleDefinition ) . toBe ( newCustom . roleDefinition )
435+ expect ( selection . baseInstructions ) . toBe ( newCustom . customInstructions )
436+ } )
437+
438+ test ( "customMode properties take precedence for new custom mode even with promptComponent" , ( ) => {
439+ const promptComponentNew : PromptComponent = {
440+ roleDefinition : "Prompt New Custom Role" ,
441+ customInstructions : "Prompt New Custom Instructions" ,
442+ }
443+ const selection = getModeSelection ( "new-custom" , promptComponentNew , customModesList )
444+ const newCustomMode = customModesList . find ( ( m ) => m . slug === "new-custom" ) !
445+ expect ( selection . roleDefinition ) . toBe ( newCustomMode . roleDefinition )
446+ expect ( selection . baseInstructions ) . toBe ( newCustomMode . customInstructions )
447+ } )
448+
449+ test ( "should fallback to default (first) mode if slug does not exist" , ( ) => {
450+ const selection = getModeSelection ( "non-existent-mode" , undefined , customModesList )
451+ expect ( selection . roleDefinition ) . toBe ( modes [ 0 ] . roleDefinition )
452+ expect ( selection . baseInstructions ) . toBe ( modes [ 0 ] . customInstructions || "" )
453+ } )
454+
455+ test ( "customMode.roleDefinition is used if defined, ignoring promptComponent's; customMode.customInstructions also from customMode" , ( ) => {
456+ const selection = getModeSelection ( "code" , { roleDefinition : "Prompt Role Only" } , customModesList )
457+ const customCodeMode = customModesList . find ( ( m ) => m . slug === "code" ) !
458+ expect ( selection . roleDefinition ) . toBe ( customCodeMode . roleDefinition )
459+ expect ( selection . baseInstructions ) . toBe ( customCodeMode . customInstructions )
460+ } )
461+
462+ test ( "customMode.customInstructions is used if defined, ignoring promptComponent's; customMode.roleDefinition also from customMode" , ( ) => {
463+ const selection = getModeSelection ( "code" , { customInstructions : "Prompt Instructions Only" } , customModesList )
464+ const customCodeMode = customModesList . find ( ( m ) => m . slug === "code" ) !
465+ expect ( selection . roleDefinition ) . toBe ( customCodeMode . roleDefinition )
466+ expect ( selection . baseInstructions ) . toBe ( customCodeMode . customInstructions )
467+ } )
468+
469+ test ( "customMode takes precedence over built-in when no promptComponent" , ( ) => {
470+ const selection = getModeSelection ( "code" , undefined , customModesList )
471+ expect ( selection . roleDefinition ) . toBe ( customModesList . find ( ( m ) => m . slug === "code" ) ! . roleDefinition )
472+ expect ( selection . baseInstructions ) . toBe ( customModesList . find ( ( m ) => m . slug === "code" ) ! . customInstructions )
473+ } )
474+
475+ test ( "handles undefined customInstructions in modes gracefully" , ( ) => {
476+ const modesWithoutCustomInstructions : ModeConfig [ ] = [
477+ {
478+ slug : "no-instr" ,
479+ name : "No Instructions Mode" ,
480+ roleDefinition : "Role for no instructions" ,
481+ groups : [ "read" ] ,
482+ // customInstructions is undefined
483+ } ,
484+ ]
485+ const selection = getModeSelection ( "no-instr" , undefined , modesWithoutCustomInstructions )
486+ expect ( selection . roleDefinition ) . toBe ( "Role for no instructions" )
487+ expect ( selection . baseInstructions ) . toBe ( "" ) // Should default to empty string
488+ } )
489+
490+ test ( "handles undefined roleDefinition in modes gracefully by falling back" , ( ) => {
491+ const modesWithoutRoleDef : ModeConfig [ ] = [
492+ {
493+ slug : "no-role" ,
494+ name : "No Role Mode" ,
495+ roleDefinition : "" , // Ensure roleDefinition is present
496+ customInstructions : "Instructions for no role" ,
497+ groups : [ "read" ] ,
498+ } ,
499+ ]
500+ // Since 'no-role' is a custom mode not overriding a built-in, and it lacks a role,
501+ // the logic in getModeSelection might fall back if not handled.
502+ // The current getModeBySlug logic in getModeSelection will fetch this mode.
503+ // Then, isCustom will be true.
504+ // roleDefinition = modeConfig?.roleDefinition (undefined) || promptComponent?.roleDefinition (undefined) || ""
505+ // So it should become ""
506+ const selection = getModeSelection ( "no-role" , undefined , modesWithoutRoleDef )
507+ expect ( selection . roleDefinition ) . toBe ( "" )
508+ expect ( selection . baseInstructions ) . toBe ( "Instructions for no role" )
509+ } )
510+
511+ test ( "promptComponent fills customInstructions if customMode's is undefined" , ( ) => {
512+ const customModeRoleOnly : ModeConfig [ ] = [
513+ { slug : "role-custom" , name : "Role Custom" , roleDefinition : "Custom Role Only" , groups : [ "read" ] } ,
514+ ]
515+ const promptComponentInstrOnly : PromptComponent = { customInstructions : "Prompt Instructions Only" }
516+ const selection = getModeSelection ( "role-custom" , promptComponentInstrOnly , customModeRoleOnly )
517+ expect ( selection . roleDefinition ) . toBe ( "Custom Role Only" )
518+ expect ( selection . baseInstructions ) . toBe ( "Prompt Instructions Only" )
519+ } )
520+
521+ test ( "promptComponent fills roleDefinition if customMode's is undefined" , ( ) => {
522+ const customModeInstrOnly : ModeConfig [ ] = [
523+ {
524+ slug : "instr-custom" ,
525+ name : "Instr Custom" ,
526+ roleDefinition : "" , // Added to satisfy ModeConfig type
527+ customInstructions : "Custom Instructions Only" ,
528+ groups : [ "read" ] ,
529+ } ,
530+ ]
531+ const promptComponentRoleOnly : PromptComponent = { roleDefinition : "Prompt Role Only" }
532+ const selection = getModeSelection ( "instr-custom" , promptComponentRoleOnly , customModeInstrOnly )
533+ expect ( selection . roleDefinition ) . toBe ( "Prompt Role Only" )
534+ expect ( selection . baseInstructions ) . toBe ( "Custom Instructions Only" )
535+ } )
536+
537+ test ( "builtInMode fills properties if customMode and promptComponent's are undefined" , ( ) => {
538+ const customModeMinimal : ModeConfig [ ] = [
539+ { slug : "ask" , name : "Custom Ask Minimal" , roleDefinition : "" , groups : [ "read" ] } , // No roleDef or customInstr
540+ ]
541+ const promptComponentMinimal : PromptComponent = { } // No roleDef or customInstr
542+ const selection = getModeSelection ( "ask" , promptComponentMinimal , customModeMinimal )
543+
544+ // According to original logic, if customMode provides "", that takes precedence.
545+ expect ( selection . roleDefinition ) . toBe ( "" ) // Was builtInAskMode.roleDefinition
546+ expect ( selection . baseInstructions ) . toBe ( "" ) // Was builtInAskMode.customInstructions || ""
547+ } )
548+ } )
0 commit comments