forked from open-multi-agent/open-multi-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmulti-perspective-code-review.ts
More file actions
188 lines (163 loc) · 6.55 KB
/
multi-perspective-code-review.ts
File metadata and controls
188 lines (163 loc) · 6.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**
* Multi-Perspective Code Review
*
* Demonstrates:
* - Dependency chain: generator produces code, three reviewers depend on it
* - Parallel execution: security, performance, and style reviewers run concurrently
* - Shared memory: each agent's output is automatically stored and injected
* into downstream agents' prompts by the framework
*
* Flow:
* generator → [security-reviewer, performance-reviewer, style-reviewer] (parallel) → synthesizer
*
* Run:
* npx tsx examples/patterns/multi-perspective-code-review.ts
*
* Prerequisites:
* ANTHROPIC_API_KEY env var must be set.
*/
import { OpenMultiAgent } from '../../src/index.js'
import type { AgentConfig, OrchestratorEvent } from '../../src/types.js'
// ---------------------------------------------------------------------------
// API spec to implement
// ---------------------------------------------------------------------------
const API_SPEC = `POST /users endpoint that:
- Accepts JSON body with name (string, required), email (string, required), age (number, optional)
- Validates all fields
- Inserts into a PostgreSQL database
- Returns 201 with the created user or 400/500 on error`
// ---------------------------------------------------------------------------
// Agents
// ---------------------------------------------------------------------------
const generator: AgentConfig = {
name: 'generator',
model: 'claude-sonnet-4-6',
systemPrompt: `You are a Node.js backend developer. Given an API spec, write a complete
Express route handler. Include imports, validation, database query, and error handling.
Output only the code, no explanation. Keep it under 80 lines.`,
maxTurns: 2,
}
const securityReviewer: AgentConfig = {
name: 'security-reviewer',
model: 'claude-sonnet-4-6',
systemPrompt: `You are a security reviewer. Review the code provided in context and check
for OWASP top 10 vulnerabilities: SQL injection, XSS, broken authentication,
sensitive data exposure, etc. Write your findings as a markdown checklist.
Keep it to 150-200 words.`,
maxTurns: 2,
}
const performanceReviewer: AgentConfig = {
name: 'performance-reviewer',
model: 'claude-sonnet-4-6',
systemPrompt: `You are a performance reviewer. Review the code provided in context and check
for N+1 queries, memory leaks, blocking calls, missing connection pooling, and
inefficient patterns. Write your findings as a markdown checklist.
Keep it to 150-200 words.`,
maxTurns: 2,
}
const styleReviewer: AgentConfig = {
name: 'style-reviewer',
model: 'claude-sonnet-4-6',
systemPrompt: `You are a code style reviewer. Review the code provided in context and check
naming conventions, function structure, readability, error message clarity, and
consistency. Write your findings as a markdown checklist.
Keep it to 150-200 words.`,
maxTurns: 2,
}
const synthesizer: AgentConfig = {
name: 'synthesizer',
model: 'claude-sonnet-4-6',
systemPrompt: `You are a lead engineer synthesizing code review feedback. Review all
the feedback and original code provided in context. Produce a unified report with:
1. Critical issues (must fix before merge)
2. Recommended improvements (should fix)
3. Minor suggestions (nice to have)
Deduplicate overlapping feedback. Keep the report to 200-300 words.`,
maxTurns: 2,
}
// ---------------------------------------------------------------------------
// Orchestrator + team
// ---------------------------------------------------------------------------
function handleProgress(event: OrchestratorEvent): void {
if (event.type === 'task_start') {
console.log(` [START] ${event.task ?? '?'} → ${event.agent ?? '?'}`)
}
if (event.type === 'task_complete') {
const success = (event.data as { success?: boolean })?.success ?? true
console.log(` [DONE] ${event.task ?? '?'} (${success ? 'OK' : 'FAIL'})`)
}
}
const orchestrator = new OpenMultiAgent({
defaultModel: 'claude-sonnet-4-6',
onProgress: handleProgress,
})
const team = orchestrator.createTeam('code-review-team', {
name: 'code-review-team',
agents: [generator, securityReviewer, performanceReviewer, styleReviewer, synthesizer],
sharedMemory: true,
})
// ---------------------------------------------------------------------------
// Tasks
// ---------------------------------------------------------------------------
const tasks = [
{
title: 'Generate code',
description: `Write a Node.js Express route handler for this API spec:\n\n${API_SPEC}`,
assignee: 'generator',
},
{
title: 'Security review',
description: 'Review the generated code for security vulnerabilities.',
assignee: 'security-reviewer',
dependsOn: ['Generate code'],
},
{
title: 'Performance review',
description: 'Review the generated code for performance issues.',
assignee: 'performance-reviewer',
dependsOn: ['Generate code'],
},
{
title: 'Style review',
description: 'Review the generated code for style and readability.',
assignee: 'style-reviewer',
dependsOn: ['Generate code'],
},
{
title: 'Synthesize feedback',
description: 'Synthesize all review feedback and the original code into a unified, prioritized action item report.',
assignee: 'synthesizer',
dependsOn: ['Security review', 'Performance review', 'Style review'],
},
]
// ---------------------------------------------------------------------------
// Run
// ---------------------------------------------------------------------------
console.log('Multi-Perspective Code Review')
console.log('='.repeat(60))
console.log(`Spec: ${API_SPEC.split('\n')[0]}`)
console.log('Pipeline: generator → 3 reviewers (parallel) → synthesizer')
console.log('='.repeat(60))
console.log()
const result = await orchestrator.runTasks(team, tasks)
// ---------------------------------------------------------------------------
// Output
// ---------------------------------------------------------------------------
console.log('\n' + '='.repeat(60))
console.log(`Overall success: ${result.success}`)
console.log(`Tokens — input: ${result.totalTokenUsage.input_tokens}, output: ${result.totalTokenUsage.output_tokens}`)
console.log()
for (const [name, r] of result.agentResults) {
const icon = r.success ? 'OK ' : 'FAIL'
const tokens = `in:${r.tokenUsage.input_tokens} out:${r.tokenUsage.output_tokens}`
console.log(` [${icon}] ${name.padEnd(22)} ${tokens}`)
}
const synthResult = result.agentResults.get('synthesizer')
if (synthResult?.success) {
console.log('\n' + '='.repeat(60))
console.log('UNIFIED REVIEW REPORT')
console.log('='.repeat(60))
console.log()
console.log(synthResult.output)
}
console.log('\nDone.')