# Les 14 — Agents
## Slide Overzicht (Klas A — 3 uur fysiek, demo-driven)

**Lesvorm:** Tim demonstreert klassikaal. Studenten kijken. Zelf bouwen = huiswerk.
**Demo-app:** Nieuwe research-agent (from scratch, los van Polderfest)
**Vervolg op:** Les 13 — Cursor + Vercel deploy
**Aansluit op:** Les 15 — RAG + Embeddings

---

## Slide 1: Title
### Les 14 — Agents

**Visual:**
- Background: CREAM
- "Les 14" in BLUE
- "Agents" in BLACK
- Subtitle: "Een LLM in een loop met tools — autonoom tot het klaar is"

---

## Slide 2: Terugblik
### Waar staan we?

**Vorige les (Les 12):**
- Tool Calling — AI roept zelf functies aan
- `tool({ description, inputSchema, execute })`
- `stopWhen: stepCountIs(5)` — multi-step
- Polderfest chat met 6 tools (search, stats, schedule, favorites)

**Wat een tool-call bot nog NIET kan:**
- Lange ketens (30+ stappen)
- Eigen plan opstellen + bijstellen
- Tools die andere tools triggeren
- Dynamisch het model wisselen per stap

**Vandaag: agents. Eén stap verder.**

**Visual:** Pijltje van "5-step tool calling" naar "20-50 step agent loop"

---

## Slide 3: Planning
### Vandaag — 180 minuten

| Onderwerp | Duur |
|-----------|------|
| Welkom + Terugblik | 10 min |
| Theorie: wat is een agent? | 30 min |
| **Live Demo 1** — Setup nieuwe research-agent | 25 min |
| **Live Demo 2** — ToolLoopAgent + stopWhen | 25 min |
| **Pauze** | 15 min |
| **Live Demo 3** — prepareStep + dynamic control | 25 min |
| **Live Demo 4** — Planning patterns + done-tool | 20 min |
| Wanneer agent vs tool-call vs workflow? | 10 min |
| Lesopdracht + Huiswerk uitleg | 15 min |
| Vragen + Afsluiting | 5 min |

**Format:** Demo-driven. Code-fragmenten in slides + live in editor.

---

## Slide 4: Wat is een agent?
### LLM + Tools + Loop

**De definitie van Vercel AI SDK:**
> Agents are LLMs that use tools in a loop to accomplish tasks.

**Drie componenten:**

1. **LLM** — beslist wat de volgende actie is
2. **Tools** — uitbreiding (search, read, write, anything)
3. **Loop** — runtime die deze twee orchestreert
   - *Context management:* wat ziet model in elke stap
   - *Stopping condition:* wanneer is de taak klaar

**Het verschil met Les 12:**
- Les 12: tot 5 stappen, korte taken
- Les 14: 20-50+ stappen, langere autonome workflows

**Visual:** Loop-diagram — LLM → kies tool → execute → resultaat → LLM → ... → klaar

---

## Slide 5: De anatomie van de loop
### Wat gebeurt er per stap?

```
┌─────────────────────────────────────┐
│   Loop iteratie (1 step):           │
│                                     │
│   1. Stuur messages naar model      │
│   2. Model genereert response:      │
│      - text? → loop stopt           │
│      - tool-call? → ga door         │
│   3. Voer tool execute() uit        │
│   4. Voeg tool-result toe aan msgs  │
│   5. Check stop-conditie            │
│   6. Volgende iteratie              │
└─────────────────────────────────────┘
```

**De loop stopt wanneer:**
- Model geeft text in plaats van tool-call (natural finish), OF
- `stopWhen`-conditie is voldaan, OF
- Tool zonder execute wordt aangeroepen (done-pattern), OF
- Tool-call needs approval

**Default in v6:** `stepCountIs(20)` — veiligheidsgrens.

---

## Slide 6: ToolLoopAgent
### De nieuwe agent-abstractie in v6

**In plaats van zelf streamText loopen, gebruik je ToolLoopAgent:**

```typescript
import { ToolLoopAgent, tool, stepCountIs } from "ai";

const researchAgent = new ToolLoopAgent({
  model: "openai/gpt-4o",
  system: "You are a research assistant...",
  tools: {
    webSearch,
    readPage,
    saveReport,
  },
  stopWhen: stepCountIs(30),
});

const result = await researchAgent.generate({
  prompt: "Onderzoek de impact van AI op de Nederlandse bouwsector",
});

console.log(result.text);   // antwoord
console.log(result.steps);  // alle stappen
```

**Wat krijg je:**
- Minder boilerplate (geen eigen loop schrijven)
- Herbruikbaar (definieer 1x, gebruik overal)
- Built-in loop, context, stopping

**Visual:** Side-by-side: handmatige while-loop vs ToolLoopAgent.

---

## Slide 7: Stop-condities
### Wanneer is een agent klaar?

**Built-in condities:**

| Conditie | Wanneer | Wanneer gebruiken |
|----------|---------|-------------------|
| `stepCountIs(N)` | Na N stappen | Default veiligheid |
| `hasToolCall("done")` | Specifieke tool gebruikt | Done-pattern |
| `isLoopFinished()` | Nooit — model bepaalt | Lange autonomie |

**Combineren met array:**
```typescript
stopWhen: [
  stepCountIs(50),         // max budget
  hasToolCall("submit"),   // OF submit-tool aangeroepen
]
```

**Custom conditie:**
```typescript
const budgetExceeded: StopCondition<typeof tools> = ({ steps }) => {
  const cost = computeCost(steps);
  return cost > 0.50; // stop bij $0.50
};
```

**Visual:** Drie traffic lights — rood (step limit), oranje (tool reached), groen (kostgrens).

---

## Slide 8: prepareStep
### Per stap iets anders doen

**`prepareStep` runt VOOR elke stap. Je kunt aanpassen:**
- Model wisselen (mini → sonnet voor complex)
- Tools beperken (alleen search in fase 1, alleen write in fase 3)
- Messages trimmen (context-budget bewaken)
- `toolChoice` forceren

**Voorbeeld — dynamic model:**
```typescript
new ToolLoopAgent({
  model: "openai/gpt-4o-mini",  // default
  prepareStep: async ({ stepNumber, messages }) => {
    if (stepNumber > 2 && messages.length > 10) {
      return { model: "anthropic/claude-sonnet-4.5" };
    }
    return {}; // niks aanpassen
  },
});
```

**Voorbeeld — fase-gebaseerde tools:**
```typescript
prepareStep: async ({ stepNumber }) => {
  if (stepNumber <= 3) return { activeTools: ["webSearch"] };
  if (stepNumber <= 6) return { activeTools: ["readPage"] };
  return { activeTools: ["saveReport"], toolChoice: "required" };
};
```

---

## Slide 9: Wat we vandaag bouwen
### Research-agent from scratch

**Doel:** Een agent die zelfstandig een onderzoeksvraag beantwoordt door web te zoeken, pagina's te lezen, en een rapport in Supabase op te slaan.

**Stack:**
- Next.js 16 + TypeScript + Tailwind + Shadcn
- AI SDK v6 (ToolLoopAgent)
- Tavily API (web search)
- Supabase (rapport opslag)
- OpenAI gpt-4o / Anthropic Sonnet

**Tools die we bouwen:**

| Tool | Wat | Gebruik in flow |
|------|-----|-----------------|
| `webSearch` | Tavily query → 5 resultaten | Fase 1: oriëntatie |
| `readPage` | URL → fulltext extractie | Fase 2: diepgang |
| `saveReport` | Insert in `research_reports` | Fase 3: opslaan |
| `done` | No-execute, signaal klaar | Eind: stoppen |

**Visual:** Diagram van research-flow: vraag → search → read → save → done.

---

## Slide 10: LIVE DEMO 1 — Setup research-agent
### ~25 min

**Wat ik laat zien:**
1. `pnpm create next-app research-agent --typescript --tailwind --app`
2. `pnpm add ai @ai-sdk/openai @ai-sdk/anthropic zod @supabase/supabase-js`
3. `.env.local` — TAVILY_API_KEY, OPENAI_API_KEY, SUPABASE_*
4. Supabase schema: `research_reports` (id, query, summary, sources jsonb, created_at)
5. `lib/tools.ts` — eerste tool `webSearch` met Tavily fetch
6. `lib/agent.ts` — `ToolLoopAgent` initialiseren
7. `app/api/research/route.ts` — POST endpoint die agent.generate() doet
8. Eerste test in terminal: `curl /api/research -d '{"query": "..."}'`

**Belangrijk:** Tavily API key is gratis tier (1000 calls/maand). Studenten krijgen instructie om zelf account te maken.

**Visual:** Folder-tree van de research-agent repo.

---

## Slide 11: LIVE DEMO 2 — ToolLoopAgent + stopWhen
### ~25 min

**Wat ik laat zien:**
1. Tweede en derde tool toevoegen: `readPage`, `saveReport`
2. `ToolLoopAgent` configuren met alle drie + `stopWhen: stepCountIs(30)`
3. System prompt schrijven: "plan eerst, search dan, lees relevante pagina's, vat samen, sla op"
4. Test met `"Schrijf een rapport over de Polderfest 2027 lineup"`
5. `result.steps` loggen — zien dat agent 8-15 stappen doet
6. Wisselen naar `isLoopFinished()` — zien dat agent zelf stopt
7. `hasToolCall("saveReport")` toevoegen — stoppen zodra opgeslagen

**Visual:** Console-log met alle stappen (toolName, input, output) — laat zien hoe agent zelf plant.

---

## Slide 12: Pauze
### 15 minuten

---

## Slide 13: LIVE DEMO 3 — prepareStep
### ~25 min

**Wat ik laat zien:**

**Use case 1 — Dynamic model:**
- Default: `gpt-4o-mini` (snel + goedkoop)
- Vanaf stap 5: `claude-sonnet-4.5` (beter reasoning)
- Console-log per stap welk model

**Use case 2 — Fase-gebaseerde tools:**
- Stap 0-3: alleen `webSearch` (oriëntatie)
- Stap 4-7: alleen `readPage` (diepgang)
- Stap 8+: alleen `saveReport` + `done` (afronden)
- Zien: agent kan niet 'cheaten' door te vroeg op te slaan

**Use case 3 — Context-trimming:**
- Na 15 messages: trim oude tool-results
- System prompt + laatste 10 berichten
- Voorkomt token-explosie bij lange agents

**Visual:** Timeline-strip met de drie fasen + model-switch.

---

## Slide 14: LIVE DEMO 4 — Done-tool + custom stop
### ~20 min

**Wat ik laat zien:**

**Pattern 1 — Done-tool (no-execute):**
```typescript
done: tool({
  description: "Signaleer dat onderzoek klaar is.",
  inputSchema: z.object({
    finalReportId: z.number(),
    summary: z.string(),
  }),
  // GEEN execute — stopt de loop
})
```
Met `toolChoice: "required"` forceer je dat agent ALTIJD een tool aanroept — en `done` is hoe-ie stopt.

**Pattern 2 — Custom stop op kosten:**
```typescript
const costLimit: StopCondition<typeof tools> = ({ steps }) => {
  const tokens = steps.reduce((sum, s) =>
    sum + (s.usage?.totalTokens ?? 0), 0);
  return tokens > 50_000;
};
```

**Pattern 3 — Plan-act-reflect loop:**
- Stap 0: agent maakt plan (text)
- Stap 1-N: voert plan uit (tools)
- Eind: agent schrijft reflectie (text)

**Visual:** Plan-Act-Reflect ReAct-diagram.

---

## Slide 15: Wanneer agent vs tool-call vs workflow?
### Niet alles hoeft autonoom

| Scenario | Aanpak |
|----------|--------|
| Vraag → 1 tool → antwoord | Plain tool-call |
| Vraag → 2-5 tools → antwoord | `stopWhen: stepCountIs(5)` (Les 12) |
| Onderzoek → 10-50 tools → rapport | **Agent** (Les 14) |
| Productie pipeline met validatie | **Workflow** (explicit code) |
| Wettelijk: must be reproducible | **Workflow** — geen agent |

**Wanneer GEEN agent gebruiken:**
- Deterministisch nodig (audit, finance, juridisch)
- Voorspelbare kosten
- Latency-sensitive (< 1s antwoord)

**Wanneer WEL agent:**
- Open-ended taken (research, planning, debugging)
- Tot stand komen via meerdere stappen
- Cost en latency mag wat hoger

**Quote uit AI SDK docs:** *"Agents are flexible and powerful, but non-deterministic. When you need reliable, repeatable outcomes, use workflow patterns."*

---

## Slide 16: Lesopdracht + Huiswerk
### Bouw je eigen agent

**Lesopdracht (in-class, 30 min):**
- Setup research-agent in eigen repo
- Tavily account aanmaken + key in .env
- Agent draaien met `stepCountIs(10)` en eerste eigen query stellen
- Logs bekijken: hoeveel stappen, welke tools

**Huiswerk (voor Les 14):**
- 4e tool toevoegen — `listReports` om opgeslagen rapporten op te halen
- `prepareStep` toevoegen — minimaal 1 use case (model OF tools OF context)
- Custom `StopCondition` schrijven (kosten OF specifieke conditie)
- `AGENT.md` schrijven: tool-lijst + stop-strategie + 1 voorbeeld-run met logs

**Bonus:**
- UI met live-step-rendering (elke stap als card)
- Sub-agent: 2e agent die per pagina samenvat, hoofdagent gebruikt sub-agent als tool

---

## Slide 17: Volgende les + Afsluiting
### Vragen?

**Vandaag gezien:**
- Agent = LLM + tools + loop
- `ToolLoopAgent` met `stopWhen` en `prepareStep`
- 4 stop-condities: stepCountIs, hasToolCall, isLoopFinished, custom
- prepareStep voor dynamic model / tools / context
- Done-tool pattern voor forced tool calling
- Wanneer wel/niet een agent

**Volgende les (Les 15): RAG + Embeddings**
- Semantic search op grote datasets
- pgvector in Supabase
- Embedding models — wat zijn vectors
- RAG-pipeline: chunk → embed → retrieve → generate
- Combo: RAG-tool in een agent — best of both worlds

**Daarna in deze leerlijn:**
- Les 14-16: Testing + Deployment + Performance
- Les 17-18: Eindopdracht-werkdagen + Pitch

**Vragen? Feedback?**

---

## Slide Summary

| # | Title | Type |
|---|-------|------|
| 1 | Title | Opening |
| 2 | Terugblik | Recap |
| 3 | Planning | 180-min |
| 4 | Wat is een agent | Theorie |
| 5 | Anatomie van de loop | Theorie |
| 6 | ToolLoopAgent | Theorie |
| 7 | Stop-condities | Theorie |
| 8 | prepareStep | Theorie |
| 9 | Wat we vandaag bouwen | Intro demo |
| 10 | **LIVE DEMO 1** — Setup | Demo |
| 11 | **LIVE DEMO 2** — stopWhen | Demo |
| 12 | Pauze | Break |
| 13 | **LIVE DEMO 3** — prepareStep | Demo |
| 14 | **LIVE DEMO 4** — done + custom stop | Demo |
| 15 | Wanneer wel/niet | Reflectie |
| 16 | Lesopdracht + Huiswerk | Praktijk |
| 17 | Afsluiting + Les 14 preview | Closing |

---

## Bronnen

- AI SDK Agents — Overview: https://ai-sdk.dev/docs/agents/overview
- AI SDK Agents — Loop Control: https://ai-sdk.dev/docs/agents/loop-control
- AI SDK Agents — Building Agents: https://ai-sdk.dev/docs/agents/building-agents
- AI SDK Agents — Workflows: https://ai-sdk.dev/docs/agents/workflows
- Tavily API: https://tavily.com/
- Anthropic — Building effective agents: https://www.anthropic.com/research/building-effective-agents
