Skip to content

Commit a532e40

Browse files
committed
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.
1 parent 207e4b6 commit a532e40

2 files changed

Lines changed: 165 additions & 3 deletions

File tree

apps/mcp-server/src/agent/agent-prompt.builder.spec.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,109 @@ describe('agent-prompt.builder', () => {
118118

119119
expect(result).toMatch(/output|format|json|structured/i);
120120
});
121+
122+
it('should include mandatory_checklist when present', () => {
123+
const profileWithChecklist: AgentProfile = {
124+
...mockAgentProfile,
125+
mandatory_checklist: [
126+
'Type safety: no any usage',
127+
'Test coverage 90%+',
128+
'SOLID principles applied',
129+
],
130+
};
131+
const result = buildAgentSystemPrompt(profileWithChecklist, mockContext);
132+
133+
expect(result).toContain('## Mandatory Checklist');
134+
expect(result).toContain('- [ ] Type safety: no any usage');
135+
expect(result).toContain('- [ ] Test coverage 90%+');
136+
expect(result).toContain('- [ ] SOLID principles applied');
137+
});
138+
139+
it('should include communication language when present', () => {
140+
const profileWithLang: AgentProfile = {
141+
...mockAgentProfile,
142+
communication: { language: 'Korean' },
143+
};
144+
const result = buildAgentSystemPrompt(profileWithLang, mockContext);
145+
146+
expect(result).toContain('## Communication');
147+
expect(result).toContain('IMPORTANT: Always respond in Korean.');
148+
});
149+
150+
it('should use agent-specific mode instructions when modes field present', () => {
151+
const profileWithModes: AgentProfile = {
152+
...mockAgentProfile,
153+
modes: {
154+
eval: {
155+
focus: ['code quality', 'security'],
156+
output_format: 'structured review',
157+
},
158+
},
159+
};
160+
const result = buildAgentSystemPrompt(profileWithModes, mockContext);
161+
162+
expect(result).toContain('## Mode-Specific Instructions');
163+
expect(result).toContain('code quality');
164+
expect(result).toContain('structured review');
165+
// Should NOT contain generic EVAL instructions
166+
expect(result).not.toContain('Evaluate and assess the implementation quality');
167+
});
168+
169+
it('should fall back to generic mode instructions when agent modes not present', () => {
170+
const result = buildAgentSystemPrompt(mockAgentProfile, mockContext);
171+
172+
expect(result).toContain('Evaluate and assess the implementation quality');
173+
expect(result).not.toContain('## Mode-Specific Instructions');
174+
});
175+
176+
it('should include required skills when present', () => {
177+
const profileWithSkills: AgentProfile = {
178+
...mockAgentProfile,
179+
skills: {
180+
required: [
181+
{ name: 'todo_write', purpose: 'Track implementation', when: 'Creating plans' },
182+
],
183+
recommended: [
184+
{ name: 'web_search', purpose: 'Validate recommendations', when: 'Evaluating' },
185+
],
186+
},
187+
};
188+
const result = buildAgentSystemPrompt(profileWithSkills, mockContext);
189+
190+
expect(result).toContain('## Required Skills');
191+
expect(result).toContain('**todo_write**: Track implementation (when: Creating plans)');
192+
expect(result).toContain('## Recommended Skills');
193+
expect(result).toContain('**web_search**: Validate recommendations (when: Evaluating)');
194+
});
195+
196+
it('should include verification_guide when present', () => {
197+
const profileWithVerification: AgentProfile = {
198+
...mockAgentProfile,
199+
verification_guide: {
200+
steps: ['Check type safety', 'Run tests', 'Review coverage'],
201+
},
202+
};
203+
const result = buildAgentSystemPrompt(profileWithVerification, mockContext);
204+
205+
expect(result).toContain('## Verification Guide');
206+
expect(result).toContain('Check type safety');
207+
expect(result).toContain('Run tests');
208+
});
209+
210+
it('should handle agent without optional rich metadata gracefully', () => {
211+
// mockAgentProfile has no mandatory_checklist, modes, skills, etc.
212+
const result = buildAgentSystemPrompt(mockAgentProfile, mockContext);
213+
214+
expect(result).toBeDefined();
215+
expect(result).not.toContain('## Mandatory Checklist');
216+
expect(result).not.toContain('## Communication');
217+
expect(result).not.toContain('## Required Skills');
218+
expect(result).not.toContain('## Recommended Skills');
219+
expect(result).not.toContain('## Verification Guide');
220+
expect(result).not.toContain('## Mode-Specific Instructions');
221+
// Should still have generic mode instructions
222+
expect(result).toContain('Evaluate and assess the implementation quality');
223+
});
121224
});
122225

123226
describe('buildTaskDescription', () => {

apps/mcp-server/src/agent/agent-prompt.builder.ts

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,71 @@ export function buildAgentSystemPrompt(agentProfile: AgentProfile, context: Agen
7474
sections.push('');
7575
}
7676

77-
// Mode-specific instructions
77+
// Rich metadata from passthrough fields
78+
const rawProfile = agentProfile as Record<string, unknown>;
79+
80+
// Mandatory Checklist
81+
if (Array.isArray(rawProfile.mandatory_checklist) && rawProfile.mandatory_checklist.length) {
82+
sections.push('## Mandatory Checklist');
83+
for (const item of rawProfile.mandatory_checklist) {
84+
sections.push(`- [ ] ${item}`);
85+
}
86+
sections.push('');
87+
}
88+
89+
// Communication language
90+
const comm = rawProfile.communication as Record<string, string> | undefined;
91+
if (comm?.language) {
92+
sections.push('## Communication');
93+
sections.push(`IMPORTANT: Always respond in ${comm.language}.`);
94+
sections.push('');
95+
}
96+
97+
// Required / Recommended Skills
98+
const skills = rawProfile.skills as
99+
| {
100+
required?: Array<{ name: string; purpose: string; when: string }>;
101+
recommended?: Array<{ name: string; purpose: string; when: string }>;
102+
}
103+
| undefined;
104+
if (skills?.required?.length) {
105+
sections.push('## Required Skills');
106+
for (const s of skills.required) {
107+
sections.push(`- **${s.name}**: ${s.purpose} (when: ${s.when})`);
108+
}
109+
sections.push('');
110+
}
111+
if (skills?.recommended?.length) {
112+
sections.push('## Recommended Skills');
113+
for (const s of skills.recommended) {
114+
sections.push(`- **${s.name}**: ${s.purpose} (when: ${s.when})`);
115+
}
116+
sections.push('');
117+
}
118+
119+
// Mode-specific instructions (agent-defined modes override generic)
78120
sections.push('## Current Mode');
79121
sections.push(`Mode: ${context.mode}`);
80122
sections.push('');
81-
sections.push(MODE_INSTRUCTIONS[context.mode]);
82-
sections.push('');
123+
124+
const modesObj = rawProfile.modes as Record<string, unknown> | undefined;
125+
const modeKey = context.mode.toLowerCase();
126+
const agentModeConfig = modesObj?.[modeKey];
127+
if (agentModeConfig && typeof agentModeConfig === 'object') {
128+
sections.push('## Mode-Specific Instructions');
129+
sections.push(JSON.stringify(agentModeConfig, null, 2));
130+
sections.push('');
131+
} else {
132+
sections.push(MODE_INSTRUCTIONS[context.mode]);
133+
sections.push('');
134+
}
135+
136+
// Verification Guide
137+
if (rawProfile.verification_guide) {
138+
sections.push('## Verification Guide');
139+
sections.push(JSON.stringify(rawProfile.verification_guide, null, 2));
140+
sections.push('');
141+
}
83142

84143
// Context information
85144
sections.push('## Task Context');

0 commit comments

Comments
 (0)