Integrate AI Agents into Next.js: Server Actions, Streaming & Route Handlers
Integrate AI Agents into Next.js: Server Actions, Streaming & Route Handlers: Designed as a zero-dependency, open-source TypeScript architecture under the MIT License with native Model Context Protocol (MCP) support and deterministic phase state machines.
- Route Handler + SSE for real-time agent event streaming to the browser
- Server Actions for fire-and-forget agent task invocation
- useAgentStream hook for live token streaming in React components
- Edge Runtime compatible agent configuration for global low-latency
Streaming Agent Events via Route Handler + SSE
Create a Next.js Route Handler that accepts a task instruction and streams agent events as Server-Sent Events:
import { NextRequest } from 'next/server';import { createAgent } from 'smoke-monkey-harness';export const runtime = 'nodejs'; // Required for file system accessexport async function POST(req: NextRequest) {const { instruction, workspacePath } = await req.json();const encoder = new TextEncoder();const stream = new TransformStream();const writer = stream.writable.getWriter();const agent = createAgent({provider: 'anthropic',model: 'claude-3-7-sonnet',workspacePath: workspacePath || process.cwd(),autoApprove: true,});// Stream events to client via SSEagent.on('model.streaming', (e) => {writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'chunk', text: e.data.chunk })}\n\n`));});agent.on('tool.started', (e) => {writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'tool', name: e.data.toolName })}\n\n`));});// Run agent and close stream when doneagent.run(instruction).then(() => {writer.write(encoder.encode('data: {"type":"done"}\n\n'));writer.close();});return new Response(stream.readable, {headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' },});}
useAgentStream React Hook
Create a custom hook to consume the SSE stream in your React components with live token streaming:
// hooks/useAgentStream.ts
export function useAgentStream() {
const [output, setOutput] = useState('');
const [isRunning, setIsRunning] = useState(false);
const run = async (instruction: string) => {
setIsRunning(true);
setOutput('');
const res = await fetch('/api/agent', {
method: 'POST',
body: JSON.stringify({ instruction }),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const events = decoder.decode(value).split('\\
\\
');
for (const event of events) {
if (event.startsWith('data:')) {
const data = JSON.parse(event.slice(5));
if (data.type === 'chunk') setOutput((p) => p + data.text);
if (data.type === 'done') setIsRunning(false);
}
}
}
};
return { output, isRunning, run };
}Frequently Asked Questions
Q:Can I use Smoke Monkey in Next.js Edge Runtime?
Edge Runtime lacks access to the Node.js file system APIs that Smoke Monkey's engineering tools require. Use the nodejs runtime for agent route handlers and edge runtime only for lightweight middleware.
Q:How do I prevent concurrent agent requests from conflicting on the same workspace?
Use a per-user or per-session workspacePath (e.g., /tmp/agent-workspaces/{userId}) and implement request queuing if multiple simultaneous agent runs are possible.
Related Alternatives & Comparisons
Build with Smoke Monkey Harness
Zero dependencies. 24 built-in tools. Human-in-the-loop safety. 100% open source under the MIT License.