Skip to content

Commit 926a98c

Browse files
committed
Move agent config validation to the server
1 parent f48e2e7 commit 926a98c

File tree

6 files changed

+156
-98
lines changed

6 files changed

+156
-98
lines changed

common/src/__tests__/agent-validation.test.ts

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ describe('Agent Validation', () => {
9797
systemPrompt: 'You are a creative brainstormer.',
9898
instructionsPrompt: 'Help brainstorm ideas.',
9999
stepPrompt: 'Continue brainstorming.',
100-
toolNames: ['end_turn'],
100+
toolNames: ['end_turn', 'spawn_agents'],
101101
subagents: ['thinker', 'researcher'],
102102
outputMode: 'last_message',
103103
includeMessageHistory: true,
@@ -107,6 +107,7 @@ describe('Agent Validation', () => {
107107

108108
const result = validateAgents(fileContext.agentTemplates || {})
109109

110+
110111
expect(result.validationErrors).toHaveLength(0)
111112
expect(result.templates).toHaveProperty('brainstormer')
112113
expect(result.templates.brainstormer.displayName).toBe('Brainy')
@@ -147,7 +148,7 @@ describe('Agent Validation', () => {
147148
...mockFileContext,
148149
agentTemplates: {
149150
'custom.ts': {
150-
id: 'custom_agent',
151+
id: 'custom-agent',
151152
version: '1.0.0',
152153
displayName: 'Custom',
153154
parentPrompt: 'Custom agent',
@@ -166,15 +167,15 @@ describe('Agent Validation', () => {
166167
const result = validateAgents(fileContext.agentTemplates || {})
167168

168169
// Should have dynamic templates
169-
expect(result.templates).toHaveProperty('custom_agent') // Dynamic
170+
expect(result.templates).toHaveProperty('custom-agent') // Dynamic
170171
})
171172

172173
it('should handle agents with JSON schemas', async () => {
173174
const fileContext: ProjectFileContext = {
174175
...mockFileContext,
175176
agentTemplates: {
176177
'schema-agent.ts': {
177-
id: 'schema_agent',
178+
id: 'schema-agent',
178179
version: '1.0.0',
179180
displayName: 'Schema Agent',
180181
parentPrompt: 'Agent with JSON schemas',
@@ -204,18 +205,19 @@ describe('Agent Validation', () => {
204205

205206
const result = validateAgents(fileContext.agentTemplates || {})
206207

208+
207209
expect(result.validationErrors).toHaveLength(0)
208-
expect(result.templates).toHaveProperty('schema_agent')
209-
expect(result.templates.schema_agent.inputSchema.prompt).toBeDefined()
210-
expect(result.templates.schema_agent.inputSchema.params).toBeDefined()
210+
expect(result.templates).toHaveProperty('schema-agent')
211+
expect(result.templates['schema-agent'].inputSchema.prompt).toBeDefined()
212+
expect(result.templates['schema-agent'].inputSchema.params).toBeDefined()
211213
})
212214

213215
it('should return validation errors for invalid schemas', async () => {
214216
const fileContext: ProjectFileContext = {
215217
...mockFileContext,
216218
agentTemplates: {
217219
'invalid-schema-agent.ts': {
218-
id: 'invalid_schema_agent',
220+
id: 'invalid-schema-agent',
219221
version: '1.0.0',
220222
displayName: 'Invalid Schema Agent',
221223
parentPrompt: 'Agent with invalid schemas',
@@ -238,17 +240,17 @@ describe('Agent Validation', () => {
238240

239241
expect(result.validationErrors).toHaveLength(1)
240242
expect(result.validationErrors[0].message).toContain(
241-
'Invalid inputSchema.prompt in invalid-schema-agent.ts',
243+
'Schema validation failed',
242244
)
243-
expect(result.templates).not.toHaveProperty('invalid_schema_agent')
245+
expect(result.templates).not.toHaveProperty('invalid-schema-agent')
244246
})
245247

246248
it('should handle missing override field as non-override template', async () => {
247249
const fileContext: ProjectFileContext = {
248250
...mockFileContext,
249251
agentTemplates: {
250252
'no-override-field.ts': {
251-
id: 'no_override_agent',
253+
id: 'no-override-agent',
252254
version: '1.0.0',
253255
// No override field - should be treated as non-override
254256
displayName: 'No Override Agent',
@@ -267,16 +269,17 @@ describe('Agent Validation', () => {
267269

268270
const result = validateAgents(fileContext.agentTemplates || {})
269271

272+
270273
expect(result.validationErrors).toHaveLength(0)
271-
expect(result.templates).toHaveProperty('no_override_agent')
274+
expect(result.templates).toHaveProperty('no-override-agent')
272275
})
273276

274277
it('should validate spawnable agents including dynamic agents from first pass', async () => {
275278
const fileContext: ProjectFileContext = {
276279
...mockFileContext,
277280
agentTemplates: {
278281
'git-committer.ts': {
279-
id: 'CodebuffAI/git-committer',
282+
id: 'codebuffai-git-committer',
280283
version: '0.0.1',
281284
displayName: 'Git Committer',
282285
parentPrompt: 'A git committer agent',
@@ -290,29 +293,30 @@ describe('Agent Validation', () => {
290293
toolNames: ['end_turn'],
291294
},
292295
'spawner.ts': {
293-
id: 'spawner_agent',
296+
id: 'spawner-agent',
294297
version: '1.0.0',
295298
displayName: 'Spawner Agent',
296299
parentPrompt: 'Agent that can spawn git-committer',
297300
model: 'anthropic/claude-4-sonnet-20250522',
298301
systemPrompt: 'Test system prompt',
299302
instructionsPrompt: 'Test user prompt',
300303
stepPrompt: 'Test step prompt',
301-
subagents: ['CodebuffAI/git-committer'], // Should be valid after first pass
304+
subagents: ['codebuffai-git-committer'], // Should be valid after first pass
302305
outputMode: 'last_message',
303306
includeMessageHistory: true,
304-
toolNames: ['end_turn'],
307+
toolNames: ['end_turn', 'spawn_agents'],
305308
},
306309
},
307310
}
308311

309312
const result = validateAgents(fileContext.agentTemplates || {})
310313

314+
311315
expect(result.validationErrors).toHaveLength(0)
312-
expect(result.templates).toHaveProperty('CodebuffAI/git-committer')
313-
expect(result.templates).toHaveProperty('spawner_agent')
314-
expect(result.templates.spawner_agent.subagents).toContain(
315-
'CodebuffAI/git-committer', // Full agent ID with prefix
316+
expect(result.templates).toHaveProperty('codebuffai-git-committer')
317+
expect(result.templates).toHaveProperty('spawner-agent')
318+
expect(result.templates['spawner-agent'].subagents).toContain(
319+
'codebuffai-git-committer', // Full agent ID with prefix
316320
)
317321
})
318322
})
@@ -324,7 +328,7 @@ describe('Agent Validation', () => {
324328
...mockFileContext,
325329
agentTemplates: {
326330
'no-prompt-schema.ts': {
327-
id: 'no_prompt_schema_agent',
331+
id: 'no-prompt-schema-agent',
328332
version: '1.0.0',
329333
displayName: 'No Prompt Schema Agent',
330334
parentPrompt: 'Test agent without prompt schema',
@@ -344,9 +348,9 @@ describe('Agent Validation', () => {
344348
const result = validateAgents(fileContext.agentTemplates || {})
345349

346350
expect(result.validationErrors).toHaveLength(0)
347-
expect(result.templates).toHaveProperty('no_prompt_schema_agent')
351+
expect(result.templates).toHaveProperty('no-prompt-schema-agent')
348352
expect(
349-
result.templates.no_prompt_schema_agent.inputSchema.prompt,
353+
result.templates['no-prompt-schema-agent'].inputSchema.prompt,
350354
).toBeUndefined()
351355
})
352356

@@ -355,7 +359,7 @@ describe('Agent Validation', () => {
355359
...mockFileContext,
356360
agentTemplates: {
357361
'no-params-schema.ts': {
358-
id: 'no_params_schema_agent',
362+
id: 'no-params-schema-agent',
359363
version: '1.0.0',
360364
displayName: 'No Params Schema Agent',
361365
parentPrompt: 'Test agent without params schema',
@@ -375,9 +379,9 @@ describe('Agent Validation', () => {
375379
const result = validateAgents(fileContext.agentTemplates || {})
376380

377381
expect(result.validationErrors).toHaveLength(0)
378-
expect(result.templates).toHaveProperty('no_params_schema_agent')
382+
expect(result.templates).toHaveProperty('no-params-schema-agent')
379383
expect(
380-
result.templates.no_params_schema_agent.inputSchema.params,
384+
result.templates['no-params-schema-agent'].inputSchema.params,
381385
).toBeUndefined()
382386
})
383387
})
@@ -388,7 +392,7 @@ describe('Agent Validation', () => {
388392
...mockFileContext,
389393
agentTemplates: {
390394
'both-schemas.ts': {
391-
id: 'both_schemas_agent',
395+
id: 'both-schemas-agent',
392396
version: '1.0.0',
393397
displayName: 'Both Schemas Agent',
394398
parentPrompt: 'Test agent with both schemas',
@@ -430,9 +434,9 @@ describe('Agent Validation', () => {
430434
const result = validateAgents(fileContext.agentTemplates || {})
431435

432436
expect(result.validationErrors).toHaveLength(0)
433-
expect(result.templates).toHaveProperty('both_schemas_agent')
437+
expect(result.templates).toHaveProperty('both-schemas-agent')
434438

435-
const template = result.templates.both_schemas_agent
439+
const template = result.templates['both-schemas-agent']
436440
expect(template.inputSchema.prompt).toBeDefined()
437441
expect(template.inputSchema.params).toBeDefined()
438442

@@ -456,7 +460,7 @@ describe('Agent Validation', () => {
456460
...mockFileContext,
457461
agentTemplates: {
458462
'complex-schema.ts': {
459-
id: 'complex_schema_agent',
463+
id: 'complex-schema-agent',
460464
version: '1.0.0',
461465
displayName: 'Complex Schema Agent',
462466
parentPrompt: 'Test agent with complex nested schema',
@@ -501,10 +505,10 @@ describe('Agent Validation', () => {
501505
const result = validateAgents(fileContext.agentTemplates || {})
502506

503507
expect(result.validationErrors).toHaveLength(0)
504-
expect(result.templates).toHaveProperty('complex_schema_agent')
508+
expect(result.templates).toHaveProperty('complex-schema-agent')
505509

506510
const paramsSchema =
507-
result.templates.complex_schema_agent.inputSchema.params!
511+
result.templates['complex-schema-agent'].inputSchema.params!
508512

509513
// Test valid complex object
510514
const validParams = {
@@ -537,7 +541,7 @@ describe('Agent Validation', () => {
537541
...mockFileContext,
538542
agentTemplates: {
539543
'error-context.ts': {
540-
id: 'error_context_agent',
544+
id: 'error-context-agent',
541545
version: '1.0.0',
542546
displayName: 'Error Context Agent',
543547
parentPrompt: 'Test agent for error context',
@@ -559,7 +563,7 @@ describe('Agent Validation', () => {
559563
const result = validateAgents(fileContext.agentTemplates || {})
560564

561565
expect(result.validationErrors).toHaveLength(1)
562-
expect(result.validationErrors[0].message).toContain('in error-context')
566+
expect(result.validationErrors[0].message).toContain('Schema validation failed')
563567
expect(result.validationErrors[0].filePath).toBe('error-context.ts')
564568
})
565569
})
@@ -570,7 +574,7 @@ describe('Agent Validation', () => {
570574
...mockFileContext,
571575
agentTemplates: {
572576
'git-committer.ts': {
573-
id: 'CodebuffAI/git-committer',
577+
id: 'codebuffai-git-committer',
574578
version: '0.0.1',
575579
displayName: 'Git Committer',
576580
parentPrompt:
@@ -605,9 +609,9 @@ describe('Agent Validation', () => {
605609
const result = validateAgents(fileContext.agentTemplates || {})
606610

607611
expect(result.validationErrors).toHaveLength(0)
608-
expect(result.templates).toHaveProperty('CodebuffAI/git-committer')
612+
expect(result.templates).toHaveProperty('codebuffai-git-committer')
609613

610-
const template = result.templates['CodebuffAI/git-committer']
614+
const template = result.templates['codebuffai-git-committer']
611615
const paramsSchema = template.inputSchema.params!
612616

613617
expect(paramsSchema.safeParse('').success).toBe(false) // Too short
@@ -629,14 +633,14 @@ describe('Agent Validation', () => {
629633
...mockFileContext,
630634
agentTemplates: {
631635
'empty-schema.ts': {
632-
id: 'empty_schema_agent',
636+
id: 'empty-schema-agent',
633637
version: '1.0.0',
634638
displayName: 'Empty Schema Agent',
635-
parentPrompt: 'Test agent with empty schema',
636639
model: 'anthropic/claude-4-sonnet-20250522',
637640
systemPrompt: 'Test system prompt',
638641
instructionsPrompt: 'Test user prompt',
639642
stepPrompt: 'Test step prompt',
643+
parentPrompt: 'Test agent with empty schema',
640644
inputSchema: {},
641645
outputMode: 'last_message',
642646
includeMessageHistory: true,
@@ -649,11 +653,11 @@ describe('Agent Validation', () => {
649653
const result = validateAgents(fileContext.agentTemplates || {})
650654

651655
expect(result.validationErrors).toHaveLength(0)
652-
expect(result.templates).toHaveProperty('empty_schema_agent')
656+
expect(result.templates).toHaveProperty('empty-schema-agent')
653657

654658
// Empty schemas should have no prompt schema
655659
expect(
656-
result.templates.empty_schema_agent.inputSchema.prompt,
660+
result.templates['empty-schema-agent'].inputSchema.prompt,
657661
).toBeUndefined()
658662
})
659663
})
@@ -808,7 +812,6 @@ describe('Agent Validation', () => {
808812
expect(result.validationErrors[0].message).toContain('generator function')
809813
expect(result.validationErrors[0].message).toContain('function*')
810814
})
811-
812815
test('should verify loaded template handleSteps matches original function toString', async () => {
813816
// Create a generator function
814817
const originalFunction = function* ({

0 commit comments

Comments
 (0)