@@ -2656,7 +2656,43 @@ describe("chatDirector spacer echo", () => {
26562656// them AFTER super(), so the base director kept sending the original and
26572657// the feature was a silent no-op.
26582658describe ( "tool-discipline rules on the wire" , ( ) => {
2659- async function promptSentFor ( model : string ) : Promise < string | undefined > {
2659+ async function subAgentPromptSentFor (
2660+ model : string ,
2661+ orchestrator = false ,
2662+ ) : Promise < string | undefined > {
2663+ const { SubAgentDirector } = await import ( "../subagent/nudge-director.js" ) ;
2664+ const { resolveModelFamilyPolicy } =
2665+ await import ( "./model-family-policy.js" ) ;
2666+ const policy = resolveModelFamilyPolicy ( {
2667+ providerName : "opencode-go" ,
2668+ model,
2669+ orchestrator,
2670+ } ) ;
2671+ const director = new SubAgentDirector (
2672+ "BASE PROMPT" ,
2673+ [ ] ,
2674+ undefined ,
2675+ undefined ,
2676+ Date . now ,
2677+ false ,
2678+ false ,
2679+ undefined ,
2680+ policy . toolDisciplineRules ,
2681+ ) ;
2682+ const event = {
2683+ type : "message.received" ,
2684+ message : { role : "user" , content : "hi" } ,
2685+ } as unknown as ReactorInboundEvent ;
2686+ const actions = actionsArray (
2687+ await director . decide ( event , mockState , stubReactorCapabilities ) ,
2688+ ) ;
2689+ const infer = actions . find ( ( a ) => a . type === "infer" ) as
2690+ | { options ?: ExtendedInferenceOptions }
2691+ | undefined ;
2692+ return infer ?. options ?. systemPrompt ;
2693+ }
2694+
2695+ async function chatPromptSentFor ( model : string ) : Promise < string | undefined > {
26602696 const director = createChatDirector ( "BASE PROMPT" , [ ] , {
26612697 provider : { providerName : "opencode-go" , model } ,
26622698 } ) ;
@@ -2665,21 +2701,31 @@ describe("tool-discipline rules on the wire", () => {
26652701 message : { role : "user" , content : "hi" } ,
26662702 } as unknown as ReactorInboundEvent ;
26672703 const actions = actionsArray (
2668- await director . decide ( event , stubReactorState , stubReactorCapabilities ) ,
2704+ await director . decide ( event , mockState , stubReactorCapabilities ) ,
26692705 ) ;
26702706 const infer = actions . find ( ( a ) => a . type === "infer" ) as
26712707 | { options ?: ExtendedInferenceOptions }
26722708 | undefined ;
26732709 return infer ?. options ?. systemPrompt ;
26742710 }
26752711
2676- test ( "a Muse Spark session appends rules at the tail, leaving the base prefix intact" , async ( ) => {
2677- const prompt = await promptSentFor ( "muse-spark-1.3-contributor" ) ;
2678- expect ( prompt ?. startsWith ( "BASE PROMPT" ) ) . toBe ( true ) ;
2679- expect ( prompt ?. length ?? 0 ) . toBeGreaterThan ( "BASE PROMPT" . length ) ;
2712+ test ( "a Muse leaf appends rules at the tail, leaving the base prefix intact" , async ( ) => {
2713+ for ( const model of [ "muse-spark-1.3-contributor" , "muse-wonder-1.0" ] ) {
2714+ const prompt = await subAgentPromptSentFor ( model , false ) ;
2715+ expect ( prompt ?. startsWith ( "BASE PROMPT" ) ) . toBe ( true ) ;
2716+ expect ( prompt ?. length ?? 0 ) . toBeGreaterThan ( "BASE PROMPT" . length ) ;
2717+ }
2718+ } ) ;
2719+
2720+ test ( "a Muse orchestrator and primary ChatDirector withhold leaf tool-discipline rules" , async ( ) => {
2721+ for ( const model of [ "muse-spark-1.3-contributor" , "muse-wonder-1.0" ] ) {
2722+ expect ( await subAgentPromptSentFor ( model , true ) ) . toBe ( "BASE PROMPT" ) ;
2723+ expect ( await chatPromptSentFor ( model ) ) . toBe ( "BASE PROMPT" ) ;
2724+ }
26802725 } ) ;
26812726
26822727 test ( "a family with no rules sends the prompt untouched" , async ( ) => {
2683- expect ( await promptSentFor ( "claude-sonnet-4" ) ) . toBe ( "BASE PROMPT" ) ;
2728+ expect ( await subAgentPromptSentFor ( "claude-sonnet-4" ) ) . toBe ( "BASE PROMPT" ) ;
2729+ expect ( await chatPromptSentFor ( "claude-sonnet-4" ) ) . toBe ( "BASE PROMPT" ) ;
26842730 } ) ;
26852731} ) ;
0 commit comments