Code Review Workflow
medium15 minbasic-workflow.ts
A review should always run the same steps — static checks, an LLM review, fixes only when there are enough issues, then a report.
What it shows
- Wrap a tool, agents and a function as nodes with
toolNode,agentNodeandfunctionNode - Branch with
addConditional()and join both branches - Run it with
WorkflowExecutorand per-node callbacks
The code
basic-workflow.ts
import { Agent, Cogitator, tool } from '@cogitator-ai/core';
import { WorkflowBuilder, WorkflowExecutor, agentNode, functionNode, toolNode } from '@cogitator-ai/workflows';
import { z } from 'zod';
const apiKey = process.env.GOOGLE_API_KEY;
if (!apiKey) throw new Error('Set GOOGLE_API_KEY');
interface ReviewState {
[key: string]: unknown;
code: string;
issues: string[];
analysis: string;
fixes: string;
report: string;
}
const analyzeCode = tool({
name: 'analyze_code',
description: 'Find common issues in source code',
parameters: z.object({ code: z.string() }),
execute: async ({ code }) => {
const issues: string[] = [];
if (/for.*\n.*for/.test(code)) issues.push('Nested loops');
if (/TODO|FIXME/.test(code)) issues.push('Unresolved TODO');
if (/console\.log/.test(code)) issues.push('Console logging in production code');
return { issues };
},
});
const cog = new Cogitator({ llm: { providers: { google: { apiKey } } } });
const model = 'google/gemini-3.5-flash-lite';
const reviewer = new Agent({
name: 'code-reviewer',
model,
instructions: 'You are a code reviewer. Explain why the found issues matter. Be concise.',
temperature: 0.3,
});
const fixAdvisor = new Agent({
name: 'fix-advisor',
model,
instructions: 'Suggest a concrete fix with a short code snippet for each issue.',
temperature: 0.3,
});
const analyze = toolNode<ReviewState, { code: string }>(analyzeCode, {
argsMapper: (state) => ({ code: state.code }),
stateMapper: (result) => ({ issues: (result as { issues: string[] }).issues }),
});
const review = agentNode<ReviewState>(reviewer, {
inputMapper: (state) => `Issues: ${state.issues.join(', ')}\n\nCode:\n${state.code}`,
stateMapper: (result) => ({ analysis: result.output }),
});
const advise = agentNode<ReviewState>(fixAdvisor, {
inputMapper: (state) => `${state.analysis}\n\nCode:\n${state.code}`,
stateMapper: (result) => ({ fixes: result.output }),
});
const report = functionNode<ReviewState, string>(
'report',
async (state) => `Issues: ${state.issues.length}\n\n${state.analysis}\n\nFixes:\n${state.fixes}`,
{ stateMapper: (output) => ({ report: output as string }) }
);
const workflow = new WorkflowBuilder<ReviewState>('code-review')
.initialState({ code: '', issues: [], analysis: '', fixes: '', report: '' })
.addNode(analyze.name, analyze.fn)
.addNode(review.name, review.fn, { after: [analyze.name] })
.addConditional('severity', (state) => (state.issues.length > 1 ? advise.name : 'minor'), {
after: [review.name],
})
.addNode(advise.name, advise.fn, { after: ['severity'] })
.addNode('minor', async () => ({ state: { fixes: 'No significant fixes needed.' } }), {
after: ['severity'],
})
.addNode(report.name, report.fn, { after: [advise.name, 'minor'] })
.entryPoint(analyze.name)
.build();
const code = `function process(orders) {
for (const order of orders) {
// TODO: validate
for (const item of order.items) console.log(item);
}
}`;
const result = await new WorkflowExecutor(cog).execute(workflow, { code }, {
onNodeComplete: (node, _output, duration) => console.log(`done: ${node} (${duration}ms)`),
});
console.log(result.state.report);
await cog.close();Run it
install · bash
pnpm add @cogitator-ai/core @cogitator-ai/workflows zodEnvironment
GOOGLE_API_KEYrun · bash
GOOGLE_API_KEY=your-key npx tsx basic-workflow.tsOr run the full example from a clone of the repository (keys in .env):
repository · bash
npx tsx examples/workflows/01-basic-workflow.ts