Skip to content

Commit 2dac250

Browse files
committed
Chapter 3: Add all agents (multi-agent orchestration)
- Add analyst, planner, quiz-master agents - Update route.ts to register all agents - Add placeholder artifact UI components for flashcard and study-plan - Update types with flashcardDelta and studyPlanDelta data types - Update Document.kind to include flashcard and study-plan
1 parent 6b85452 commit 2dac250

File tree

11 files changed

+596
-5
lines changed

11 files changed

+596
-5
lines changed

app/(chat)/api/chat/route.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import {
77
stepCountIs,
88
streamText,
99
} from "ai";
10-
import { createTutorAgent } from "@/lib/ai/agents";
10+
import {
11+
createAnalystAgent,
12+
createPlannerAgent,
13+
createQuizMasterAgent,
14+
createTutorAgent,
15+
} from "@/lib/ai/agents";
1116
import { getWeather } from "@/lib/ai/tools/get-weather";
1217
import { unstable_cache as cache } from "next/cache";
1318
import type { ModelCatalog } from "tokenlens/core";
@@ -182,11 +187,22 @@ export async function POST(request: Request) {
182187
experimental_activeTools:
183188
selectedChatModel === "chat-model-reasoning"
184189
? []
185-
: ["getWeather", "tutor"],
190+
: [
191+
"getWeather",
192+
// Study buddy agents
193+
"tutor",
194+
"quizMaster",
195+
"planner",
196+
"analyst",
197+
],
186198
experimental_transform: smoothStream({ chunking: "word" }),
187199
tools: {
188200
getWeather,
201+
// Study buddy agents
189202
tutor: createTutorAgent({ session, dataStream }),
203+
quizMaster: createQuizMasterAgent({ session, dataStream }),
204+
planner: createPlannerAgent({ session, dataStream }),
205+
analyst: createAnalystAgent({ session, dataStream }),
190206
},
191207
experimental_telemetry: {
192208
isEnabled: isProductionEnvironment,

artifacts/flashcard/client.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use client";
2+
3+
import { Artifact } from "@/components/create-artifact";
4+
5+
// Placeholder flashcard artifact - full implementation coming in Chapter 4
6+
export const flashcardArtifact = new Artifact<"flashcard">({
7+
kind: "flashcard",
8+
description: "Interactive quiz flashcards",
9+
onStreamPart: ({ streamPart, setArtifact }) => {
10+
if (streamPart.type === "data-flashcardDelta") {
11+
setArtifact((draftArtifact) => ({
12+
...draftArtifact,
13+
content: streamPart.data,
14+
isVisible: true,
15+
status: "streaming",
16+
}));
17+
}
18+
},
19+
content: ({ content, status }) => {
20+
if (status === "streaming" || !content) {
21+
return (
22+
<div className="flex h-full flex-col items-center justify-center gap-4 p-8">
23+
<div className="text-muted-foreground">Generating quiz...</div>
24+
<div className="h-2 w-48 animate-pulse rounded bg-muted-foreground/20" />
25+
</div>
26+
);
27+
}
28+
29+
// Parse and display basic quiz data
30+
try {
31+
const data = JSON.parse(content);
32+
return (
33+
<div className="flex h-full flex-col gap-4 overflow-y-auto p-8">
34+
<h2 className="font-bold text-xl">{data.topic}</h2>
35+
<p className="text-muted-foreground">
36+
{data.questions?.length || 0} questions generated
37+
</p>
38+
<div className="rounded-lg border bg-muted/50 p-4">
39+
<p className="text-muted-foreground text-sm">
40+
Full flashcard UI coming in Chapter 4
41+
</p>
42+
</div>
43+
</div>
44+
);
45+
} catch {
46+
return (
47+
<div className="flex h-full items-center justify-center p-8">
48+
<p className="text-muted-foreground">Loading flashcard data...</p>
49+
</div>
50+
);
51+
}
52+
},
53+
actions: [],
54+
toolbar: [],
55+
});

artifacts/study-plan/client.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"use client";
2+
3+
import { Artifact } from "@/components/create-artifact";
4+
5+
// Placeholder study-plan artifact - full implementation coming in Chapter 4
6+
export const studyPlanArtifact = new Artifact<"study-plan">({
7+
kind: "study-plan",
8+
description: "Interactive study plan with progress tracking",
9+
onStreamPart: ({ streamPart, setArtifact }) => {
10+
if (streamPart.type === "data-studyPlanDelta") {
11+
setArtifact((draftArtifact) => ({
12+
...draftArtifact,
13+
content: streamPart.data,
14+
isVisible: true,
15+
status: "streaming",
16+
}));
17+
}
18+
},
19+
content: ({ content, status }) => {
20+
if (status === "streaming" || !content) {
21+
return (
22+
<div className="flex h-full flex-col items-center justify-center gap-4 p-8">
23+
<div className="text-muted-foreground">Creating study plan...</div>
24+
<div className="h-2 w-48 animate-pulse rounded bg-muted-foreground/20" />
25+
</div>
26+
);
27+
}
28+
29+
// Parse and display basic study plan data
30+
try {
31+
const data = JSON.parse(content);
32+
return (
33+
<div className="flex h-full flex-col gap-4 overflow-y-auto p-8">
34+
<h2 className="font-bold text-xl">{data.topic}</h2>
35+
<p className="text-muted-foreground">
36+
{data.duration} - {data.weeks?.length || 0} weeks
37+
</p>
38+
<p className="text-sm">{data.overview}</p>
39+
<div className="rounded-lg border bg-muted/50 p-4">
40+
<p className="text-muted-foreground text-sm">
41+
Full study plan UI coming in Chapter 4
42+
</p>
43+
</div>
44+
</div>
45+
);
46+
} catch {
47+
return (
48+
<div className="flex h-full items-center justify-center p-8">
49+
<p className="text-muted-foreground">Loading study plan data...</p>
50+
</div>
51+
);
52+
}
53+
},
54+
actions: [],
55+
toolbar: [],
56+
});

components/artifact.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
import useSWR, { useSWRConfig } from "swr";
1414
import { useDebounceCallback, useWindowSize } from "usehooks-ts";
1515
import { codeArtifact } from "@/artifacts/code/client";
16+
import { flashcardArtifact } from "@/artifacts/flashcard/client";
1617
import { sheetArtifact } from "@/artifacts/sheet/client";
18+
import { studyPlanArtifact } from "@/artifacts/study-plan/client";
1719
import { textArtifact } from "@/artifacts/text/client";
1820
import { useArtifact } from "@/hooks/use-artifact";
1921
import type { Document, Vote } from "@/lib/db/types";
@@ -32,6 +34,8 @@ export const artifactDefinitions = [
3234
textArtifact,
3335
codeArtifact,
3436
sheetArtifact,
37+
flashcardArtifact,
38+
studyPlanArtifact,
3539
];
3640
export type ArtifactKind = (typeof artifactDefinitions)[number]["kind"];
3741

lib/ai/agents/analyst.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { generateText, tool } from "ai";
2+
import { z } from "zod";
3+
import { myProvider } from "../providers";
4+
import type { AgentResult, CreateAgentProps } from "./types";
5+
6+
const ANALYST_SYSTEM_PROMPT = `You are a document analyst who excels at extracting insights and summarizing content.
7+
8+
Your analysis approach:
9+
- Identify the main themes and key points
10+
- Extract important facts, figures, and arguments
11+
- Note relationships between concepts
12+
- Highlight actionable insights
13+
- Provide clear, structured summaries
14+
15+
For document analysis, provide:
16+
1. Executive summary (2-3 sentences)
17+
2. Key points and main arguments
18+
3. Important details and supporting evidence
19+
4. Connections to broader context
20+
5. Actionable takeaways or study notes
21+
22+
Be thorough but concise. Focus on what would be most valuable for learning and retention.`;
23+
24+
/**
25+
* Analyst Agent - Analyzes documents and extracts key insights
26+
*
27+
* Triggers: "analyze this", "summarize", "key points", "what's important"
28+
* Output: Returns analysis that the orchestrator will present
29+
*/
30+
export const createAnalystAgent = (_props: CreateAgentProps) =>
31+
tool({
32+
description:
33+
"Analyze content, extract key insights, and create summaries. Use when the user wants to understand, summarize, or extract key points from text, documents, or concepts. Triggers: analyze, summarize, key points, main ideas, extract insights, break down.",
34+
inputSchema: z.object({
35+
content: z.string().describe("The text or content to analyze"),
36+
analysisType: z
37+
.enum(["summary", "key-points", "deep-analysis", "study-notes"])
38+
.default("summary")
39+
.describe("Type of analysis to perform"),
40+
focusOn: z
41+
.string()
42+
.optional()
43+
.describe("Specific aspect to focus the analysis on"),
44+
outputLength: z
45+
.enum(["brief", "moderate", "detailed"])
46+
.default("moderate")
47+
.describe("Desired length of the analysis output"),
48+
}),
49+
execute: async ({
50+
content,
51+
analysisType,
52+
focusOn,
53+
outputLength,
54+
}): Promise<AgentResult> => {
55+
const focusContext = focusOn
56+
? `\n\nFocus particularly on: ${focusOn}`
57+
: "";
58+
59+
const lengthGuide = {
60+
brief: "Keep the analysis concise, around 100-200 words.",
61+
moderate: "Provide a balanced analysis, around 300-500 words.",
62+
detailed: "Provide a comprehensive analysis, around 600-800 words.",
63+
};
64+
65+
const analysisGuide = {
66+
summary:
67+
"Create a clear summary highlighting the main message and supporting points.",
68+
"key-points":
69+
"Extract and list the most important points as bullet points with brief explanations.",
70+
"deep-analysis":
71+
"Provide thorough analysis including themes, arguments, evidence, and implications.",
72+
"study-notes":
73+
"Create study-friendly notes with headings, key terms, and memorable takeaways.",
74+
};
75+
76+
const prompt = `Analyze the following content:
77+
78+
---
79+
${content}
80+
---
81+
82+
Analysis type: ${analysisType}
83+
${analysisGuide[analysisType]}
84+
${focusContext}
85+
86+
${lengthGuide[outputLength]}`;
87+
88+
const { text } = await generateText({
89+
model: myProvider.languageModel("chat-model"),
90+
system: ANALYST_SYSTEM_PROMPT,
91+
prompt,
92+
});
93+
94+
return {
95+
agentName: "analyst",
96+
success: true,
97+
summary: text,
98+
data: {
99+
analysisType,
100+
focusOn,
101+
outputLength,
102+
contentLength: content.length,
103+
},
104+
};
105+
},
106+
});

lib/ai/agents/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// Agent type definitions
22

33
// Specialized agents
4+
export { createAnalystAgent } from "./analyst";
5+
export { createPlannerAgent } from "./planner";
6+
export { createQuizMasterAgent } from "./quiz-master";
47
export { createTutorAgent } from "./tutor";
58
export type { AgentContext, AgentResult, CreateAgentProps } from "./types";

0 commit comments

Comments
 (0)