From f273d734084bb6e086457cfc42a10db51c50db97 Mon Sep 17 00:00:00 2001 From: JeremyDev87 Date: Sat, 4 Apr 2026 03:14:52 +0900 Subject: [PATCH] fix(mcp): enrich agent prompt builder with mandatory_checklist, skills, and language (#1246) buildAgentSystemPrompt() now includes rich agent metadata from passthrough fields: mandatory_checklist, communication.language, skills (required/recommended), agent-specific mode instructions (overriding generic when present), and verification_guide. Added 7 tests covering each new section and graceful fallback. --- .../src/agent/agent-prompt.builder.spec.ts | 103 ++++++++++++++++++ .../src/agent/agent-prompt.builder.ts | 65 ++++++++++- 2 files changed, 165 insertions(+), 3 deletions(-) diff --git a/apps/mcp-server/src/agent/agent-prompt.builder.spec.ts b/apps/mcp-server/src/agent/agent-prompt.builder.spec.ts index 67a83271..1544df8e 100644 --- a/apps/mcp-server/src/agent/agent-prompt.builder.spec.ts +++ b/apps/mcp-server/src/agent/agent-prompt.builder.spec.ts @@ -118,6 +118,109 @@ describe('agent-prompt.builder', () => { expect(result).toMatch(/output|format|json|structured/i); }); + + it('should include mandatory_checklist when present', () => { + const profileWithChecklist: AgentProfile = { + ...mockAgentProfile, + mandatory_checklist: [ + 'Type safety: no any usage', + 'Test coverage 90%+', + 'SOLID principles applied', + ], + }; + const result = buildAgentSystemPrompt(profileWithChecklist, mockContext); + + expect(result).toContain('## Mandatory Checklist'); + expect(result).toContain('- [ ] Type safety: no any usage'); + expect(result).toContain('- [ ] Test coverage 90%+'); + expect(result).toContain('- [ ] SOLID principles applied'); + }); + + it('should include communication language when present', () => { + const profileWithLang: AgentProfile = { + ...mockAgentProfile, + communication: { language: 'Korean' }, + }; + const result = buildAgentSystemPrompt(profileWithLang, mockContext); + + expect(result).toContain('## Communication'); + expect(result).toContain('IMPORTANT: Always respond in Korean.'); + }); + + it('should use agent-specific mode instructions when modes field present', () => { + const profileWithModes: AgentProfile = { + ...mockAgentProfile, + modes: { + eval: { + focus: ['code quality', 'security'], + output_format: 'structured review', + }, + }, + }; + const result = buildAgentSystemPrompt(profileWithModes, mockContext); + + expect(result).toContain('## Mode-Specific Instructions'); + expect(result).toContain('code quality'); + expect(result).toContain('structured review'); + // Should NOT contain generic EVAL instructions + expect(result).not.toContain('Evaluate and assess the implementation quality'); + }); + + it('should fall back to generic mode instructions when agent modes not present', () => { + const result = buildAgentSystemPrompt(mockAgentProfile, mockContext); + + expect(result).toContain('Evaluate and assess the implementation quality'); + expect(result).not.toContain('## Mode-Specific Instructions'); + }); + + it('should include required skills when present', () => { + const profileWithSkills: AgentProfile = { + ...mockAgentProfile, + skills: { + required: [ + { name: 'todo_write', purpose: 'Track implementation', when: 'Creating plans' }, + ], + recommended: [ + { name: 'web_search', purpose: 'Validate recommendations', when: 'Evaluating' }, + ], + }, + }; + const result = buildAgentSystemPrompt(profileWithSkills, mockContext); + + expect(result).toContain('## Required Skills'); + expect(result).toContain('**todo_write**: Track implementation (when: Creating plans)'); + expect(result).toContain('## Recommended Skills'); + expect(result).toContain('**web_search**: Validate recommendations (when: Evaluating)'); + }); + + it('should include verification_guide when present', () => { + const profileWithVerification: AgentProfile = { + ...mockAgentProfile, + verification_guide: { + steps: ['Check type safety', 'Run tests', 'Review coverage'], + }, + }; + const result = buildAgentSystemPrompt(profileWithVerification, mockContext); + + expect(result).toContain('## Verification Guide'); + expect(result).toContain('Check type safety'); + expect(result).toContain('Run tests'); + }); + + it('should handle agent without optional rich metadata gracefully', () => { + // mockAgentProfile has no mandatory_checklist, modes, skills, etc. + const result = buildAgentSystemPrompt(mockAgentProfile, mockContext); + + expect(result).toBeDefined(); + expect(result).not.toContain('## Mandatory Checklist'); + expect(result).not.toContain('## Communication'); + expect(result).not.toContain('## Required Skills'); + expect(result).not.toContain('## Recommended Skills'); + expect(result).not.toContain('## Verification Guide'); + expect(result).not.toContain('## Mode-Specific Instructions'); + // Should still have generic mode instructions + expect(result).toContain('Evaluate and assess the implementation quality'); + }); }); describe('buildTaskDescription', () => { diff --git a/apps/mcp-server/src/agent/agent-prompt.builder.ts b/apps/mcp-server/src/agent/agent-prompt.builder.ts index 64c51aaa..6ca476e4 100644 --- a/apps/mcp-server/src/agent/agent-prompt.builder.ts +++ b/apps/mcp-server/src/agent/agent-prompt.builder.ts @@ -74,12 +74,71 @@ export function buildAgentSystemPrompt(agentProfile: AgentProfile, context: Agen sections.push(''); } - // Mode-specific instructions + // Rich metadata from passthrough fields + const rawProfile = agentProfile as Record; + + // Mandatory Checklist + if (Array.isArray(rawProfile.mandatory_checklist) && rawProfile.mandatory_checklist.length) { + sections.push('## Mandatory Checklist'); + for (const item of rawProfile.mandatory_checklist) { + sections.push(`- [ ] ${item}`); + } + sections.push(''); + } + + // Communication language + const comm = rawProfile.communication as Record | undefined; + if (comm?.language) { + sections.push('## Communication'); + sections.push(`IMPORTANT: Always respond in ${comm.language}.`); + sections.push(''); + } + + // Required / Recommended Skills + const skills = rawProfile.skills as + | { + required?: Array<{ name: string; purpose: string; when: string }>; + recommended?: Array<{ name: string; purpose: string; when: string }>; + } + | undefined; + if (skills?.required?.length) { + sections.push('## Required Skills'); + for (const s of skills.required) { + sections.push(`- **${s.name}**: ${s.purpose} (when: ${s.when})`); + } + sections.push(''); + } + if (skills?.recommended?.length) { + sections.push('## Recommended Skills'); + for (const s of skills.recommended) { + sections.push(`- **${s.name}**: ${s.purpose} (when: ${s.when})`); + } + sections.push(''); + } + + // Mode-specific instructions (agent-defined modes override generic) sections.push('## Current Mode'); sections.push(`Mode: ${context.mode}`); sections.push(''); - sections.push(MODE_INSTRUCTIONS[context.mode]); - sections.push(''); + + const modesObj = rawProfile.modes as Record | undefined; + const modeKey = context.mode.toLowerCase(); + const agentModeConfig = modesObj?.[modeKey]; + if (agentModeConfig && typeof agentModeConfig === 'object') { + sections.push('## Mode-Specific Instructions'); + sections.push(JSON.stringify(agentModeConfig, null, 2)); + sections.push(''); + } else { + sections.push(MODE_INSTRUCTIONS[context.mode]); + sections.push(''); + } + + // Verification Guide + if (rawProfile.verification_guide) { + sections.push('## Verification Guide'); + sections.push(JSON.stringify(rawProfile.verification_guide, null, 2)); + sections.push(''); + } // Context information sections.push('## Task Context');