Skip to content

Commit 1bc3c9f

Browse files
sheikhcodersclaude
andcommitted
🔌 Add MCP ecosystem, API routes, and agent UI components
- MCP integration framework with custom and pre-built MCPs - Updated API routes for multi-agent system - Agent UI with task visualization - Task state management hooks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent b3453e3 commit 1bc3c9f

File tree

7 files changed

+1179
-0
lines changed

7 files changed

+1179
-0
lines changed

src/app/agent/page.tsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"use client";
2+
3+
import { useAgent } from "@/hooks/use-agent";
4+
import { TaskInput } from "@/components/agent/task-input";
5+
import { TaskProgress } from "@/components/agent/task-progress";
6+
import { Header } from "@/components/layout/header";
7+
import { Button } from "@/components/ui/button";
8+
import { RefreshCw } from "lucide-react";
9+
10+
export default function AgentPage() {
11+
const {
12+
task,
13+
isRunning,
14+
currentSubTask,
15+
progress,
16+
error,
17+
executeTask,
18+
reset,
19+
} = useAgent();
20+
21+
return (
22+
<div className="flex min-h-screen flex-col">
23+
<Header />
24+
<main
25+
id="main-content"
26+
className="flex-1 px-4 py-8 safe-area-inset"
27+
role="main"
28+
aria-label="Multi-Agent Task Execution"
29+
>
30+
<div className="mx-auto max-w-4xl space-y-6">
31+
{/* Page title */}
32+
<div className="text-center">
33+
<h1 className="text-3xl font-bold tracking-tight">Multi-Agent System</h1>
34+
<p className="mt-2 text-muted-foreground">
35+
Describe a complex task and let specialized AI agents work together to complete it.
36+
</p>
37+
</div>
38+
39+
{/* Show input or progress based on state */}
40+
{!task ? (
41+
<TaskInput
42+
onSubmit={executeTask}
43+
isLoading={isRunning}
44+
/>
45+
) : (
46+
<div className="space-y-4">
47+
<TaskProgress
48+
task={task}
49+
currentSubTask={currentSubTask}
50+
progress={progress}
51+
/>
52+
53+
{/* Actions */}
54+
{!isRunning && (
55+
<div className="flex justify-center">
56+
<Button onClick={reset} variant="outline">
57+
<RefreshCw className="mr-2 h-4 w-4" aria-hidden="true" />
58+
New Task
59+
</Button>
60+
</div>
61+
)}
62+
</div>
63+
)}
64+
65+
{/* Error display */}
66+
{error && (
67+
<div
68+
className="rounded-lg border border-destructive bg-destructive/10 p-4 text-destructive"
69+
role="alert"
70+
>
71+
<p className="font-medium">Error</p>
72+
<p className="text-sm">{error}</p>
73+
</div>
74+
)}
75+
76+
{/* Agent capabilities info */}
77+
{!task && (
78+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
79+
{[
80+
{
81+
title: "Code Agent",
82+
description: "Full-stack development with auth, database, and testing",
83+
color: "text-blue-500",
84+
},
85+
{
86+
title: "Research Agent",
87+
description: "Deep research with search, analysis, and charts",
88+
color: "text-green-500",
89+
},
90+
{
91+
title: "PPT Agent",
92+
description: "Beautiful presentations with flexible layouts",
93+
color: "text-orange-500",
94+
},
95+
{
96+
title: "Multimodal Agent",
97+
description: "Process and generate images, audio, and video",
98+
color: "text-purple-500",
99+
},
100+
].map((agent) => (
101+
<div
102+
key={agent.title}
103+
className="rounded-lg border bg-card p-4 text-card-foreground"
104+
>
105+
<h3 className={`font-medium ${agent.color}`}>{agent.title}</h3>
106+
<p className="mt-1 text-sm text-muted-foreground">
107+
{agent.description}
108+
</p>
109+
</div>
110+
))}
111+
</div>
112+
)}
113+
</div>
114+
</main>
115+
</div>
116+
);
117+
}

src/app/api/agent/route.ts

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/**
2+
* Multi-Agent API Route
3+
*
4+
* Handles complex tasks through the multi-agent orchestration system:
5+
* 1. Receives task description
6+
* 2. Decomposes into sub-tasks
7+
* 3. Routes to specialized agents
8+
* 4. Streams progress and results
9+
*/
10+
11+
import { NextRequest } from "next/server";
12+
import { executeTask, decomposeTask } from "@/lib/agents/orchestrator";
13+
import type { Task } from "@/lib/agents/types";
14+
15+
// Allow long-running agent tasks
16+
export const maxDuration = 120; // 2 minutes
17+
18+
/**
19+
* POST /api/agent
20+
* Execute a complex task through the multi-agent system
21+
*/
22+
export async function POST(req: NextRequest) {
23+
try {
24+
const { title, description, stream = true } = await req.json();
25+
26+
if (!title || !description) {
27+
return new Response(
28+
JSON.stringify({ error: "Title and description are required" }),
29+
{ status: 400, headers: { "Content-Type": "application/json" } }
30+
);
31+
}
32+
33+
// Create task
34+
const task: Task = {
35+
id: `task-${Date.now()}`,
36+
title,
37+
description,
38+
status: "pending",
39+
subTasks: [],
40+
messages: [],
41+
createdAt: new Date(),
42+
updatedAt: new Date(),
43+
};
44+
45+
if (stream) {
46+
// Stream progress using SSE
47+
const encoder = new TextEncoder();
48+
const stream = new ReadableStream({
49+
async start(controller) {
50+
const send = (data: Record<string, unknown>) => {
51+
controller.enqueue(
52+
encoder.encode(`data: ${JSON.stringify(data)}\n\n`)
53+
);
54+
};
55+
56+
try {
57+
// Send initial task
58+
send({ type: "task_created", task: { id: task.id, title, status: "pending" } });
59+
60+
// Execute with progress callback
61+
const result = await executeTask(task, ({ subTask, status }) => {
62+
send({
63+
type: "subtask_update",
64+
subTask: {
65+
id: subTask.id,
66+
title: subTask.title,
67+
agent: subTask.assignedAgent,
68+
status,
69+
},
70+
});
71+
});
72+
73+
// Send final result
74+
send({
75+
type: "task_complete",
76+
task: {
77+
id: result.id,
78+
status: result.status,
79+
result: result.result,
80+
subTasks: result.subTasks.map((st) => ({
81+
id: st.id,
82+
title: st.title,
83+
agent: st.assignedAgent,
84+
status: st.status,
85+
result: st.result,
86+
})),
87+
},
88+
});
89+
90+
controller.close();
91+
} catch (error) {
92+
send({
93+
type: "error",
94+
error: error instanceof Error ? error.message : "Unknown error",
95+
});
96+
controller.close();
97+
}
98+
},
99+
});
100+
101+
return new Response(stream, {
102+
headers: {
103+
"Content-Type": "text/event-stream",
104+
"Cache-Control": "no-cache",
105+
Connection: "keep-alive",
106+
},
107+
});
108+
} else {
109+
// Non-streaming response
110+
const result = await executeTask(task);
111+
112+
return new Response(JSON.stringify(result), {
113+
headers: { "Content-Type": "application/json" },
114+
});
115+
}
116+
} catch (error) {
117+
console.error("Agent API error:", error);
118+
119+
return new Response(
120+
JSON.stringify({
121+
error: error instanceof Error ? error.message : "An error occurred",
122+
}),
123+
{ status: 500, headers: { "Content-Type": "application/json" } }
124+
);
125+
}
126+
}
127+
128+
/**
129+
* POST /api/agent/decompose
130+
* Preview task decomposition without executing
131+
*/
132+
export async function PUT(req: NextRequest) {
133+
try {
134+
const { title, description } = await req.json();
135+
136+
if (!title || !description) {
137+
return new Response(
138+
JSON.stringify({ error: "Title and description are required" }),
139+
{ status: 400, headers: { "Content-Type": "application/json" } }
140+
);
141+
}
142+
143+
const task: Task = {
144+
id: `preview-${Date.now()}`,
145+
title,
146+
description,
147+
status: "pending",
148+
subTasks: [],
149+
messages: [],
150+
createdAt: new Date(),
151+
updatedAt: new Date(),
152+
};
153+
154+
const subTasks = await decomposeTask(task);
155+
156+
return new Response(
157+
JSON.stringify({
158+
task: { id: task.id, title, description },
159+
subTasks: subTasks.map((st) => ({
160+
title: st.title,
161+
description: st.description,
162+
agent: st.assignedAgent,
163+
priority: st.priority,
164+
dependencies: st.dependencies,
165+
})),
166+
}),
167+
{ headers: { "Content-Type": "application/json" } }
168+
);
169+
} catch (error) {
170+
console.error("Decompose API error:", error);
171+
172+
return new Response(
173+
JSON.stringify({
174+
error: error instanceof Error ? error.message : "An error occurred",
175+
}),
176+
{ status: 500, headers: { "Content-Type": "application/json" } }
177+
);
178+
}
179+
}

0 commit comments

Comments
 (0)