Skip to content

Latest commit

Β 

History

History
476 lines (401 loc) Β· 24.1 KB

File metadata and controls

476 lines (401 loc) Β· 24.1 KB

Chapter 5: Complete Architecture Review

In this final chapter, we'll step back and review the complete Study Buddy architecture, understand how all pieces fit together, and explore ideas for extending the system.

Branch: workshop/chapter-05-complete

git checkout workshop/chapter-05-complete

Teaching Notes for Presenters

Workshop Recap: React Parallels

Chapter Key AI SDK Concept React Parallel
0 useChat / streamText useState + useEffect for async data
1 Tools with Zod schemas Custom hooks with typed props
2 Tool-as-agent pattern HOCs that fetch their own data
3 Multi-agent orchestration React Router for user intent
4 Artifacts with persistence Controlled components with form state

Key Takeaways to Emphasize

  1. "The AI SDK is React-friendly by design"

    • Same mental models: hooks, components, state
    • Streaming = Suspense for AI responses
    • Tools/agents = just functions with extra metadata
  2. "Start simple, add complexity as needed"

    • Chapter 0 β†’ 5 is a natural progression
    • Don't start with 10 agents; start with 1
    • Artifacts are optional until you need persistence
  3. "The orchestrator is your routing layer"

    • Good descriptions = good routing
    • Test with edge cases ("What's the weather in a fictional city?")
    • The AI is smarter than you think at understanding intent

Final Demo Suggestions

  • Show a complete flow: learn β†’ quiz β†’ study plan β†’ check progress
  • Demonstrate version history on artifacts
  • Show the database (Mongo Express) to prove persistence

Post-Workshop Resources

Common Post-Workshop Questions

  • "Can I use this with OpenAI/GPT-4?" - Yes! Just change the provider
  • "How do I add authentication?" - It's already built in (NextAuth)
  • "What about rate limiting?" - Already implemented (see lib/ai/entitlements.ts)
  • "How do I deploy this?" - Standard Vercel/Next.js deployment

Learning Objectives

By the end of this chapter, you'll understand:

  • The complete data flow from user input to AI response
  • How orchestration, agents, and artifacts work together
  • Best practices for production deployments
  • Ideas for extending the system

The Complete Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           User Interface                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚                         Chat Panel                                   β”‚β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚β”‚
β”‚  β”‚  β”‚ User: "Quiz me on JavaScript closures"                          β”‚β”‚β”‚
β”‚  β”‚  β”‚                                                                  β”‚β”‚β”‚
β”‚  β”‚  β”‚ AI: I've created a quiz for you! [Artifact opens β†’]             β”‚β”‚β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚                                    β”‚                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚                         Artifact Panel                               β”‚β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚β”‚
β”‚  β”‚  β”‚  Quiz: JavaScript Closures                                      β”‚β”‚β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚β”‚β”‚
β”‚  β”‚  β”‚  β”‚ Q1: What is a closure?                                    β”‚  β”‚β”‚β”‚
β”‚  β”‚  β”‚  β”‚ β—‹ A) A function with access to outer scope                β”‚  β”‚β”‚β”‚
β”‚  β”‚  β”‚  β”‚ β—‹ B) A JavaScript class                                   β”‚  β”‚β”‚β”‚
β”‚  β”‚  β”‚  β”‚ β—‹ C) A loop construct                                     β”‚  β”‚β”‚β”‚
β”‚  β”‚  β”‚  β”‚ β—‹ D) A data type                                          β”‚  β”‚β”‚β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚β”‚β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Flow: Complete Journey

Let's trace a complete request through the system:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 1. USER INPUT                                                            β”‚
β”‚    User types: "Quiz me on JavaScript closures"                          β”‚
β”‚    β†’ useChat hook captures input                                         β”‚
β”‚    β†’ POST request to /api/chat                                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                                      ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 2. API ROUTE                                                             β”‚
β”‚    /app/(chat)/api/chat/route.ts                                         β”‚
β”‚    β†’ Authenticates user (session)                                        β”‚
β”‚    β†’ Creates dataStream for streaming                                    β”‚
β”‚    β†’ Calls streamText with orchestrator model                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                                      ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 3. ORCHESTRATOR (Claude Haiku)                                           β”‚
β”‚    Analyzes user intent                                                  β”‚
β”‚    Reads tool descriptions:                                              β”‚
β”‚    - tutor: "explain", "teach me"                                        β”‚
β”‚    - quizMaster: "quiz me", "test me" ← MATCHES!                         β”‚
β”‚    - planner: "study plan", "roadmap"                                    β”‚
β”‚    β†’ Decides to call quizMaster tool                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                                      ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 4. QUIZ MASTER AGENT                                                     β”‚
β”‚    lib/ai/agents/quiz-master.ts                                          β”‚
β”‚    β†’ Writes artifact metadata to dataStream:                             β”‚
β”‚       data-id: "abc-123"                                                 β”‚
β”‚       data-title: "Quiz: JavaScript Closures"                            β”‚
β”‚       data-kind: "flashcard"                                             β”‚
β”‚       data-clear: null                                                   β”‚
β”‚    β†’ Calls generateObject to create quiz questions                       β”‚
β”‚    β†’ Streams content: data-flashcardDelta: "{...quiz JSON...}"           β”‚
β”‚    β†’ Signals completion: data-finish: null                               β”‚
β”‚    β†’ Saves to database                                                   β”‚
β”‚    β†’ Returns AgentResult                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                                      ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 5. DATA STREAM HANDLER (Client)                                          β”‚
β”‚    components/data-stream-handler.tsx                                    β”‚
β”‚    β†’ Receives streamed data parts                                        β”‚
β”‚    β†’ data-id β†’ Sets artifact ID                                          β”‚
β”‚    β†’ data-kind β†’ Finds flashcardArtifact definition                      β”‚
β”‚    β†’ data-flashcardDelta β†’ Calls onStreamPart handler                    β”‚
β”‚    β†’ Updates useArtifact global state                                    β”‚
β”‚    β†’ data-finish β†’ Sets status to "idle"                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                                      ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 6. ARTIFACT VIEWER                                                       β”‚
β”‚    artifacts/flashcard/client.tsx                                        β”‚
β”‚    β†’ FlashcardViewer component renders                                   β”‚
β”‚    β†’ Parses JSON content                                                 β”‚
β”‚    β†’ Displays interactive quiz UI                                        β”‚
β”‚    β†’ Handles user clicks on answers                                      β”‚
β”‚    β†’ Shows explanations and tracks score                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

File Structure Summary

ai-chatbot/
β”œβ”€β”€ app/
β”‚   └── (chat)/
β”‚       └── api/
β”‚           └── chat/
β”‚               └── route.ts          # Orchestrator + all agents
β”‚
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ ai/
β”‚   β”‚   β”œβ”€β”€ providers.ts              # AI model configuration
β”‚   β”‚   β”œβ”€β”€ prompts.ts                # System prompts
β”‚   β”‚   β”œβ”€β”€ tools/
β”‚   β”‚   β”‚   └── get-weather.ts        # Weather tool
β”‚   β”‚   └── agents/
β”‚   β”‚       β”œβ”€β”€ index.ts              # Barrel export for all agents
β”‚   β”‚       β”œβ”€β”€ types.ts              # Agent type definitions
β”‚   β”‚       β”œβ”€β”€ tutor.ts              # Tutor agent (text response)
β”‚   β”‚       β”œβ”€β”€ quiz-master.ts        # Quiz Master agent (flashcard artifact)
β”‚   β”‚       β”œβ”€β”€ planner.ts            # Planner agent (study-plan artifact)
β”‚   β”‚       └── analyst.ts            # Analyst agent (text response)
β”‚   β”œβ”€β”€ db/
β”‚   β”‚   β”œβ”€β”€ queries.ts                # Database operations
β”‚   β”‚   └── types.ts                  # MongoDB types
β”‚   └── types.ts                      # Custom data stream types
β”‚
β”œβ”€β”€ artifacts/
β”‚   β”œβ”€β”€ flashcard/
β”‚   β”‚   β”œβ”€β”€ server.ts                 # FlashcardData type
β”‚   β”‚   └── client.tsx                # Flashcard artifact + viewer
β”‚   β”œβ”€β”€ study-plan/
β”‚   β”‚   β”œβ”€β”€ server.ts                 # StudyPlanData type
β”‚   β”‚   └── client.tsx                # Study plan artifact + viewer
β”‚   β”œβ”€β”€ text/                         # Built-in text artifact
β”‚   β”œβ”€β”€ code/                         # Built-in code artifact
β”‚   └── sheet/                        # Built-in spreadsheet artifact
β”‚
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ artifact.tsx                  # Artifact panel + registry
β”‚   └── data-stream-handler.tsx       # Processes streaming data
β”‚
└── hooks/
    └── use-artifact.ts               # Global artifact state

Agent Communication Pattern

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         ORCHESTRATOR                                     β”‚
β”‚                    (Main Claude Model)                                   β”‚
β”‚                                                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚ System Prompt:                                                       β”‚β”‚
β”‚  β”‚ - You have specialized agents available                              β”‚β”‚
β”‚  β”‚ - tutor: for explanations                                            β”‚β”‚
β”‚  β”‚ - quizMaster: for quizzes (creates flashcard artifact)               β”‚β”‚
β”‚  β”‚ - planner: for study plans (creates study-plan artifact)             β”‚β”‚
β”‚  β”‚ - analyst: for summarizing and analyzing content                     β”‚β”‚
β”‚  β”‚ - Match user intent to the right agent                               β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚                                                                          β”‚
β”‚  Available Tools:                                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚   tutor    β”‚ β”‚ quizMaster β”‚ β”‚  planner   β”‚ β”‚  analyst   β”‚ β”‚weather β”‚ β”‚
β”‚  β”‚            β”‚ β”‚            β”‚ β”‚            β”‚ β”‚            β”‚ β”‚        β”‚ β”‚
β”‚  β”‚ generateTextβ”‚ β”‚creates    β”‚ β”‚creates     β”‚ β”‚generateTextβ”‚ β”‚ Simple β”‚ β”‚
β”‚  β”‚ β†’ text     β”‚ β”‚artifact   β”‚ β”‚artifact    β”‚ β”‚β†’ text      β”‚ β”‚  tool  β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Tool-as-Agent Pattern Deep Dive

Why wrap agents as tools?

Aspect Benefit
Routing Orchestrator uses natural language understanding to pick the right agent
Parameters Zod schemas ensure agents receive valid, typed input
Isolation Each agent has its own prompt and model configuration
Composability Agents can be added/removed without changing core logic
Observability Tool calls are logged and traceable

Data Stream Types Reference

// lib/types.ts
export type CustomUIDataTypes = {
  // Artifact content (each kind has its own delta type)
  textDelta: string;
  imageDelta: string;
  codeDelta: string;
  sheetDelta: string;
  flashcardDelta: string;   // Quiz questions JSON
  studyPlanDelta: string;   // Study plan JSON

  // Other data types
  suggestion: Suggestion;    // Document suggestions
  appendMessage: string;     // Append to message

  // Artifact metadata
  id: string;               // Unique document ID
  title: string;            // Display title
  kind: ArtifactKind;       // Artifact type (typed enum)

  // Control signals
  clear: null;              // Clear previous content
  finish: null;             // Signal completion
  error: string;            // Error signaling from agents

  // Analytics
  usage: AppUsage;          // Token usage data (enriched with costs)
};

Production Considerations

1. Error Handling

Always return graceful errors from agents:

execute: async ({ topic }): Promise<AgentResult> => {
  try {
    // Agent logic...
    return { agentName: "tutor", success: true, summary: text };
  } catch (error) {
    console.error(`[Tutor] Error:`, error);
    return {
      agentName: "tutor",
      success: false,
      summary: "I had trouble with that request. Please try again.",
      data: { error: String(error) },
    };
  }
}

2. Rate Limiting

The app already includes rate limiting:

// lib/ai/entitlements.ts
- Guest users: 20 messages/day
- Regular users: 100 messages/day

3. Cost Management

Each agent call uses tokens. Consider:

  • Using smaller models for simple agents
  • Caching common responses
  • Monitoring usage with the built-in TokenLens integration

4. Database Indexes

Ensure proper indexes for document queries:

// Important indexes for document retrieval
db.documents.createIndex({ id: 1, createdAt: -1 })
db.documents.createIndex({ userId: 1, createdAt: -1 })

Ideas for Extension

1. Add a Code Reviewer Agent

export const createCodeReviewerAgent = ({ session, dataStream }: CreateAgentProps) =>
  tool({
    description: "Review code for best practices, bugs, and improvements.",
    inputSchema: z.object({
      code: z.string().describe("The code to review"),
      language: z.string().describe("Programming language of the code"),
      focusAreas: z
        .array(z.string())
        .optional()
        .describe("Specific areas to focus on (security, performance, etc.)"),
    }),
    execute: async ({ code, language, focusAreas }): Promise<AgentResult> => {
      // Generate code review with generateText...
      return {
        agentName: "code-reviewer",
        success: true,
        summary: reviewText,
        data: { language, focusAreas },
      };
    },
  });

2. Add a Research Agent

An agent that can search the web and summarize findings:

export const createResearcherAgent = ({ session, dataStream }: CreateAgentProps) =>
  tool({
    description: "Research a topic and provide summarized findings.",
    inputSchema: z.object({
      query: z.string().describe("The topic or question to research"),
      depth: z
        .enum(["quick", "thorough"])
        .default("quick")
        .describe("How deep to research"),
    }),
    execute: async ({ query, depth }): Promise<AgentResult> => {
      // Fetch from APIs, summarize with generateText...
      return {
        agentName: "researcher",
        success: true,
        summary: researchFindings,
        data: { query, depth },
      };
    },
  });

3. Add Memory/Context

Store and retrieve conversation context:

// Track what topics the user has learned
const userProgress = await getUserProgress(session.user.id);

// Pass to agents for personalized responses
execute: async ({ topic }) => {
  const previousTopics = userProgress.completedTopics;
  // Adjust explanation based on what they already know
}

4. Add Agent-to-Agent Communication

Let agents call each other:

// After explaining a topic, tutor suggests a quiz
return {
  agentName: "tutor",
  success: true,
  summary: explanation,
  suggestNext: {
    agent: "quizMaster",
    params: { topic }
  }
};

5. Add Progress Tracking Artifact

Create an artifact that shows learning progress:

// artifacts/progress/client.tsx
export const progressArtifact = new Artifact<"progress", ProgressMetadata>({
  kind: "progress",
  description: "Track learning progress across topics.",
  content: ({ content }) => <ProgressDashboard data={content} />,
});

Workshop Recap

Chapter What You Learned
0 Basic chat architecture, streaming, AI SDK fundamentals
1 Tools, Zod schemas, weather example, tool rendering
2 Tool-as-agent pattern, tutor agent, generateText
3 Multi-agent orchestration, quiz master, planner, generateObject
4 Custom artifacts, data streaming, interactive viewers
5 Complete architecture, production considerations, extensions

Key Takeaways

  1. Orchestration is Key: The main model decides which agent to use based on intent
  2. Agents are Tools: The tool-as-agent pattern provides structure and type safety
  3. Artifacts are Powerful: Interactive documents enhance the chat experience
  4. Streaming is Essential: Real-time updates create a responsive feel
  5. Structure Enables Scale: Clean separation makes adding new agents easy

Resources

What's Next?

You now have a fully functional Study Buddy with:

  • A tutor that explains concepts
  • A quiz master that tests knowledge
  • A planner that creates study schedules
  • Interactive artifacts for quizzes and study plans

Take this foundation and make it your own! Add new agents, create custom artifacts, and build the learning assistant of your dreams.

Happy coding!