/**
* Test Lambda/Transformer Workflow
*
* This script tests the full Lambda integration:
* 1. Three parallel agents write unit tests for different functions
* 2. A TypeScript Lambda transforms/summarizes their outputs
* 3. A final agent reviews the transformed summary
*/
const API_BASE = process.env.API_BASE || 'http://localhost:3000';
// TypeScript Lambda that transforms the outputs using the new unified input contract
const typescriptLambda = `
/**
* Transform function that summarizes unit test outputs from multiple workers
*
* Uses unified LambdaInput contract:
* - input.tasks: Array of upstream task results (agents or transformers)
* - input.meta: Metadata (transformerId, lambdaName, executionId)
*/
function transform(input: any): string {
console.log('Lambda received', input.tasks.length, 'task results');
console.log('Transformer ID:', input.meta.transformerId);
// Create a structured summary of all the test outputs
const summary = input.tasks.map((task: any, index: number) => {
// Get the output based on task type
const output = task.taskType === 'agent'
? task.workerOutput || ''
: task.transformerOutput || '';
// Extract just the first 500 chars of each output for the summary
const preview = output.substring(0, 500);
// Include QC feedback if available
let qcNote = '';
if (task.qcResult && task.qcResult.passed) {
qcNote = \`\\n**QC Status**: ✅ Passed (Score: \${task.qcResult.score})\`;
} else if (task.qcResult) {
qcNote = \`\\n**QC Status**: ⚠️ Issues: \${task.qcResult.feedback}\`;
}
return \`## Test Suite \${index + 1}: \${task.taskTitle}\${qcNote}\\n\\n\${preview}...\`;
}).join('\\n\\n---\\n\\n');
// Return a formatted prompt for the next agent
return \`# Unit Test Summary from Previous Phase
The following unit tests were generated by the worker agents. Please review them for:
1. Code coverage completeness
2. Edge case handling
3. Assertion quality
4. Test naming conventions
\${summary}
---
Please provide a brief code review summary highlighting any issues or improvements needed.\`;
}
`;
// The test workflow
const workflow = {
tasks: [
// Task 1: Write unit tests for calculateSum function
{
id: 'task-1',
taskType: 'agent',
title: 'Write Unit Tests for calculateSum',
agentRoleDescription: 'TypeScript Test Engineer specializing in Jest unit testing. Write concise, focused tests.',
recommendedModel: 'gpt-4.1',
prompt: `Write 3 simple Jest unit tests for a calculateSum function that adds two numbers. Keep tests minimal and focused. Output only the test code.
Example function signature:
\`\`\`typescript
function calculateSum(a: number, b: number): number
\`\`\``,
dependencies: [],
parallelGroup: 1,
estimatedDuration: '2 min',
estimatedToolCalls: 0,
successCriteria: ['Tests compile', 'Tests cover basic cases'],
qcRole: 'Test QC Agent - verify test quality and coverage',
verificationCriteria: ['Tests are valid Jest syntax', 'At least 2 test cases'],
maxRetries: 1,
},
// Task 2: Write unit tests for validateEmail function
{
id: 'task-2',
taskType: 'agent',
title: 'Write Unit Tests for validateEmail',
agentRoleDescription: 'TypeScript Test Engineer specializing in Jest unit testing. Write concise, focused tests.',
recommendedModel: 'gpt-4.1',
prompt: `Write 3 simple Jest unit tests for a validateEmail function that returns true if email is valid. Keep tests minimal. Output only the test code.
Example function signature:
\`\`\`typescript
function validateEmail(email: string): boolean
\`\`\``,
dependencies: [],
parallelGroup: 1,
estimatedDuration: '2 min',
estimatedToolCalls: 0,
successCriteria: ['Tests compile', 'Tests cover basic cases'],
qcRole: 'Test QC Agent - verify test quality and coverage',
verificationCriteria: ['Tests are valid Jest syntax', 'At least 2 test cases'],
maxRetries: 1,
},
// Task 3: Write unit tests for formatDate function
{
id: 'task-3',
taskType: 'agent',
title: 'Write Unit Tests for formatDate',
agentRoleDescription: 'TypeScript Test Engineer specializing in Jest unit testing. Write concise, focused tests.',
recommendedModel: 'gpt-4.1',
prompt: `Write 3 simple Jest unit tests for a formatDate function that formats dates as YYYY-MM-DD. Keep tests minimal. Output only the test code.
Example function signature:
\`\`\`typescript
function formatDate(date: Date): string
\`\`\``,
dependencies: [],
parallelGroup: 1,
estimatedDuration: '2 min',
estimatedToolCalls: 0,
successCriteria: ['Tests compile', 'Tests cover basic cases'],
qcRole: 'Test QC Agent - verify test quality and coverage',
verificationCriteria: ['Tests are valid Jest syntax', 'At least 2 test cases'],
maxRetries: 1,
},
// Task 4: Lambda Transformer - summarizes all test outputs
{
id: 'transformer-1',
taskType: 'transformer',
title: 'Summarize Test Outputs',
dependencies: ['task-1', 'task-2', 'task-3'],
parallelGroup: null,
// Resolved Lambda fields (normally done by frontend)
lambdaScript: typescriptLambda,
lambdaLanguage: 'typescript',
lambdaName: 'TestSummarizer',
},
// Task 5: Final Review Agent - receives transformed summary
{
id: 'task-4',
taskType: 'agent',
title: 'Final Test Review',
agentRoleDescription: 'Senior Code Reviewer specializing in test quality. Provide brief, actionable feedback.',
recommendedModel: 'gpt-4.1',
prompt: '', // Will be populated from Lambda output
dependencies: ['transformer-1'],
parallelGroup: null,
estimatedDuration: '2 min',
estimatedToolCalls: 0,
successCriteria: ['Review completed'],
qcRole: 'Review QC Agent - verify review quality',
verificationCriteria: ['Actionable feedback provided'],
maxRetries: 1,
},
],
parallelGroups: [
{ id: 1, name: 'Unit Test Writers', taskIds: ['task-1', 'task-2', 'task-3'], color: '#3b82f6' },
],
agentTemplates: [],
projectPlan: {
overview: {
goal: 'Test Lambda/Transformer workflow integration',
complexity: 'Medium',
totalTasks: 5,
estimatedDuration: '10 min',
estimatedToolCalls: 0,
},
},
};
async function runTest() {
console.log('🧪 Testing Lambda/Transformer Workflow');
console.log('=====================================\n');
// Step 1: Validate the Lambda first
console.log('📝 Step 1: Validating TypeScript Lambda...');
try {
const validateResponse = await fetch(`${API_BASE}/api/validate-lambda`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
script: typescriptLambda,
language: 'typescript',
}),
});
const validateResult = await validateResponse.json();
console.log('Validation result:', validateResult.valid ? '✅ PASSED' : '❌ FAILED');
if (!validateResult.valid) {
console.error('Validation errors:', validateResult.errors);
process.exit(1);
}
console.log('');
} catch (error) {
console.error('Failed to validate Lambda:', error.message);
process.exit(1);
}
// Step 2: Execute the workflow
console.log('🚀 Step 2: Executing workflow...');
console.log(` - ${workflow.tasks.length} total tasks`);
console.log(` - 3 parallel agents (unit test writers)`);
console.log(` - 1 TypeScript transformer`);
console.log(` - 1 final review agent\n`);
try {
const executeResponse = await fetch(`${API_BASE}/api/execute-workflow`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(workflow),
});
const executeResult = await executeResponse.json();
if (!executeResult.success) {
console.error('❌ Failed to start workflow:', executeResult.error);
process.exit(1);
}
console.log(`✅ Workflow started: ${executeResult.executionId}`);
console.log('\n📡 Connecting to SSE stream for real-time updates...\n');
// Connect to SSE for updates using native EventSource polyfill
const eventsource = await import('eventsource');
const EventSource = eventsource.default || eventsource.EventSource || eventsource;
const es = new EventSource(`${API_BASE}/api/execution-stream/${executeResult.executionId}`);
es.addEventListener('task-start', (event) => {
const data = JSON.parse(event.data);
const taskType = data.taskType || 'agent';
const icon = taskType === 'transformer' ? '🔮' : '👷';
console.log(`${icon} [${data.progress}/${data.total}] Started: ${data.taskTitle} (${taskType})`);
});
es.addEventListener('task-complete', (event) => {
const data = JSON.parse(event.data);
const taskType = data.taskType || 'agent';
const icon = taskType === 'transformer' ? '🔮' : '✅';
console.log(`${icon} [${data.progress}/${data.total}] Completed: ${data.taskTitle} (${data.duration}ms)`);
});
es.addEventListener('task-fail', (event) => {
const data = JSON.parse(event.data);
console.log(`❌ [${data.progress}/${data.total}] Failed: ${data.taskTitle}`);
});
es.addEventListener('agent-chatter', (event) => {
const data = JSON.parse(event.data);
if (data.output) {
console.log(` 📝 Output preview: ${data.output.substring(0, 100)}...`);
}
});
es.addEventListener('execution-complete', (event) => {
const data = JSON.parse(event.data);
console.log('\n' + '='.repeat(60));
console.log('🎉 WORKFLOW EXECUTION COMPLETE');
console.log('='.repeat(60));
console.log(`Status: ${data.status}`);
console.log(`Successful: ${data.successful}/${data.total}`);
console.log(`Failed: ${data.failed}/${data.total}`);
console.log(`Duration: ${(data.totalDuration / 1000).toFixed(2)}s`);
console.log(`Deliverables: ${data.deliverables?.length || 0}`);
console.log('');
es.close();
process.exit(data.status === 'completed' ? 0 : 1);
});
es.addEventListener('execution-cancelled', (event) => {
console.log('\n⛔ Workflow was cancelled');
es.close();
process.exit(1);
});
es.onerror = (error) => {
console.error('SSE error:', error);
};
} catch (error) {
console.error('Failed to execute workflow:', error.message);
process.exit(1);
}
}
// Run the test
runTest().catch(console.error);