75601988c2
- Cover, TOC, 5 dividers, 3 recap slides - 5 sections (chains, langgraph, deepagents, openswe, ecosystem) - design-system.js with theme tokens + 9 helper functions - research/: timeline + sources + per-tech notes - final-compile.js + merge.js for rebuild pipeline - output/: langchain-evolution.pptx (2.3 MB) + langchain-evolution.pdf (1.1 MB) + 7 sample previews
1395 lines
46 KiB
JavaScript
1395 lines
46 KiB
JavaScript
/**
|
|
* compile.js -- Section 3: Deep Agents 1.0
|
|
* ----------------------------------------------------------------------------
|
|
* Builds section3.pptx (26 slides, 16:9, dark theme, code-heavy).
|
|
* Audience: engineers. Tutorial-style, no introductory filler.
|
|
*
|
|
* Usage: node compile.js
|
|
* Output: section3.pptx (in this directory)
|
|
*
|
|
* Sources: research/per-tech/deepagents.md (snapshot 2026-06-22).
|
|
* Helpers: ../design-system.js (slideBase, addHeader, addCodeBlock,
|
|
* addCallout, addProsCons, addPageNumber, addSectionDivider,
|
|
* addSourceLine, highlightPython).
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const pptxgen = require('pptxgenjs');
|
|
|
|
// design-system.js may live in <deck>/design-system.js or one level up.
|
|
// Try a few candidates so the script runs from any workdir.
|
|
function loadDesignSystem() {
|
|
const candidates = [
|
|
path.join(__dirname, '..', '..', 'design-system.js'),
|
|
path.join(__dirname, '..', 'design-system.js'),
|
|
path.join(__dirname, 'design-system.js'),
|
|
path.resolve(process.cwd(), 'design-system.js'),
|
|
path.resolve(process.cwd(), '..', 'design-system.js'),
|
|
path.resolve(process.cwd(), '..', '..', 'design-system.js'),
|
|
];
|
|
for (const c of candidates) {
|
|
if (fs.existsSync(c)) {
|
|
return require(c);
|
|
}
|
|
}
|
|
throw new Error('design-system.js not found. Tried:\n ' + candidates.join('\n '));
|
|
}
|
|
|
|
const ds = loadDesignSystem();
|
|
const { theme, helpers, layouts } = ds;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Boot
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const pres = new pptxgen();
|
|
pres.layout = 'LAYOUT_16x9';
|
|
pres.title = 'Deep Agents 1.0 -- harness, todos, virtual FS, subagents';
|
|
pres.author = 'lc-evo-deck';
|
|
pres.subject = 'LangChain Evolution Deck / Section 3';
|
|
|
|
const SECTION_NUM = 3;
|
|
const TOTAL_SLIDES = 26;
|
|
|
|
// Page-number counter (advances as slides are added).
|
|
let pageNum = 0;
|
|
function nextPage() { pageNum += 1; return pageNum; }
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Slide factories
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function contentSlide(opts) {
|
|
const slide = pres.addSlide();
|
|
helpers.slideBase(slide, pres, theme);
|
|
helpers.addHeader(slide, pres, theme, {
|
|
eyebrow: opts.eyebrow || `SECTION 3: DEEP AGENTS`,
|
|
title: opts.title,
|
|
sectionNumber: opts.sectionNumber != null ? opts.sectionNumber : SECTION_NUM,
|
|
});
|
|
helpers.addPageNumber(slide, pres, theme, nextPage());
|
|
if (opts.source) {
|
|
helpers.addSourceLine(slide, pres, theme, { source: opts.source });
|
|
}
|
|
return slide;
|
|
}
|
|
|
|
function dividerSlide(opts) {
|
|
const slide = pres.addSlide();
|
|
helpers.addSectionDivider(slide, pres, theme, {
|
|
number: opts.number,
|
|
eyebrow: opts.eyebrow,
|
|
title: opts.title,
|
|
intro: opts.intro,
|
|
});
|
|
helpers.addPageNumber(slide, pres, theme, nextPage());
|
|
return slide;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Code-block helper (local, normalizes filePath / size)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function codeBlock(slide, opts) {
|
|
helpers.addCodeBlock(slide, pres, theme, {
|
|
x: opts.x, y: opts.y, w: opts.w, h: opts.h,
|
|
code: opts.code,
|
|
language: 'python',
|
|
filePath: opts.filePath,
|
|
startLine: opts.startLine || 1,
|
|
highlightLines: opts.highlightLines,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 1: Section divider / cover
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
dividerSlide({
|
|
number: '03',
|
|
eyebrow: 'SECTION 3',
|
|
title: 'Deep Agents 1.0',
|
|
intro: `Batteries-included agent harness: planning tool, virtual filesystem,
|
|
subagents with isolated context, pluggable backends, HITL middleware.
|
|
Built on LangGraph + LangChain 1.0 middleware. Inspired by Claude Code,
|
|
Deep Research, Manus.`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 2: Problem -- limits of LangGraph
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.1 PROBLEM',
|
|
title: 'LangGraph limits: why a new layer',
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 1.0,
|
|
kind: 'warning',
|
|
title: 'LangGraph is a runtime, not an agent harness.',
|
|
text: `You still have to wire planning, filesystem access, subagent isolation,
|
|
HITL approval, and context offload yourself.`,
|
|
});
|
|
|
|
helpers.addProsCons(slide, pres, theme, {
|
|
x: 0.5, y: 2.65, w: 9.0, h: 2.3,
|
|
pros: [
|
|
'Full control over graph topology, cycles, parallel branches (Send)',
|
|
'Durable execution, checkpointing, interrupt-based HITL are first-class',
|
|
'Stable public API until 2.0 (released 22 Oct 2025)',
|
|
],
|
|
cons: [
|
|
'Boilerplate-heavy: planning tool, fs tools, subagent wiring -- all manual',
|
|
'No built-in context overflow strategy (every tool result floods the main thread)',
|
|
'No opinionated "coding/research" agent defaults -- you re-implement Claude Code patterns',
|
|
],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 3: Solution -- batteries-included harness
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.1 SOLUTION',
|
|
title: 'Deep Agents: opinionated defaults',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/overview',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 1.05,
|
|
kind: 'info',
|
|
title: 'Analogy: Django over raw WSGI',
|
|
text: `Same runtime (LangGraph), but with conventions and pre-built middleware.
|
|
You give up some flexibility in exchange for "everything just works".`,
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: 2.5, w: 5.5, h: 2.4,
|
|
code: [
|
|
`# One import, one call -- you get:`,
|
|
`# - write_todos planning tool`,
|
|
`# - ls / read_file / write_file / edit_file`,
|
|
`# - glob, grep, execute (bash)`,
|
|
`# - task tool for subagents`,
|
|
`# - summarization middleware`,
|
|
``,
|
|
`from deepagents import create_deep_agent`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="openai:gpt-4.1",`,
|
|
` tools=[my_tool],`,
|
|
` system_prompt="...",`,
|
|
`)`,
|
|
].join('\n'),
|
|
filePath: 'examples/hello.py',
|
|
startLine: 1,
|
|
highlightLines: [9, 10, 11, 12, 13, 14],
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 6.3, y: 2.5, w: 3.2, h: 2.4,
|
|
kind: 'success',
|
|
title: 'Stack',
|
|
text: `LangGraph (runtime)
|
|
-> create_agent (LangChain 1.0, thin harness)
|
|
-> create_deep_agent (opinionated harness)
|
|
|
|
Built-in: planning, FS, subagents, HITL, skills.`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 4: Install
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.2 INSTALL',
|
|
title: 'pip install deepagents',
|
|
sectionNumber: 3,
|
|
source: 'pypi.org/project/deepagents/',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 1.1,
|
|
code: [
|
|
`pip install deepagents`,
|
|
`# or, with uv:`,
|
|
`uv add deepagents`,
|
|
`# JS analogue:`,
|
|
`npm install deepagents`,
|
|
].join('\n'),
|
|
filePath: 'setup.sh',
|
|
startLine: 1,
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: 2.7, w: 9.0, h: 1.0,
|
|
kind: 'info',
|
|
title: 'Latest stable (snapshot 2026-06-22)',
|
|
text: `Python: deepagents 0.6.11 (no formal 1.0 yet).
|
|
Repo: github.com/langchain-ai/deepagents (~24.9k stars).
|
|
License: MIT. JS package: deepagents (npm).`,
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: 3.85, w: 9.0, h: 1.05,
|
|
kind: 'warning',
|
|
title: 'Dependencies',
|
|
text: `deepagents pulls in langchain, langgraph, langchain-core.
|
|
API keys via env vars: OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 5: create_deep_agent -- hello world
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.3 HELLO WORLD',
|
|
title: 'create_deep_agent: hello world',
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents README',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 5.6, h: 3.4,
|
|
code: [
|
|
`from deepagents import create_deep_agent`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="openai:gpt-4.1",`,
|
|
` tools=[],`,
|
|
` system_prompt="You are a helpful assistant.",`,
|
|
`)`,
|
|
``,
|
|
`result = agent.invoke({`,
|
|
` "messages": "Write a haiku about Python"`,
|
|
`})`,
|
|
`print(result["messages"][-1].content)`,
|
|
].join('\n'),
|
|
filePath: 'examples/hello.py',
|
|
startLine: 1,
|
|
highlightLines: [3, 4, 5, 6],
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 6.3, y: layouts.CONTENT_TOP, w: 3.2, h: 3.4,
|
|
kind: 'info',
|
|
title: 'What you get for free',
|
|
text: `- write_todos tool
|
|
- ls / read_file / write_file / edit_file
|
|
- glob, grep, execute (bash)
|
|
- task tool for subagents
|
|
- summarization middleware
|
|
- same LangGraph runtime as create_agent`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 6: create_deep_agent -- parameters
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.3 API',
|
|
title: 'create_deep_agent: full API',
|
|
sectionNumber: 3,
|
|
source: 'reference.langchain.com/python/deepagents',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.6,
|
|
code: [
|
|
`from deepagents import create_deep_agent`,
|
|
`from deepagents.backends import FilesystemBackend`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="anthropic:claude-sonnet-4-5",`,
|
|
` tools=[my_tool],`,
|
|
` system_prompt="...",`,
|
|
` subagents=[researcher, writer],`,
|
|
` skills=["./skills/review.md"],`,
|
|
` backend=FilesystemBackend("./ws"),`,
|
|
` middleware=[my_hitl, my_logger],`,
|
|
` checkpointer=InMemorySaver(),`,
|
|
` store=InMemoryStore(),`,
|
|
` interrupt_on={"bash": True},`,
|
|
`)`,
|
|
].join('\n'),
|
|
filePath: 'examples/full_api.py',
|
|
startLine: 1,
|
|
highlightLines: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 7: System prompt & instructions
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.4 INSTRUCTIONS',
|
|
title: 'System prompt: how to talk to a deep agent',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/customization',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.5,
|
|
code: [
|
|
`SYSTEM_PROMPT = """`,
|
|
`You are a senior backend engineer.`,
|
|
``,
|
|
`WORKFLOW:`,
|
|
` 1. Plan with write_todos before non-trivial work.`,
|
|
` 2. Explore the codebase via ls / glob / grep first.`,
|
|
` 3. Use edit_file for surgical changes, write_file for new files.`,
|
|
` 4. Delegate research tasks to the "researcher" subagent.`,
|
|
` 5. Run tests via execute; never claim success without output.`,
|
|
``,
|
|
`CONSTRAINTS:`,
|
|
` - Do not modify files outside ./src.`,
|
|
` - Stop and ask the user if requirements are ambiguous.`,
|
|
`"""`,
|
|
``,
|
|
`agent = create_deep_agent(model=..., system_prompt=SYSTEM_PROMPT)`,
|
|
].join('\n'),
|
|
filePath: 'examples/system_prompt.py',
|
|
startLine: 1,
|
|
highlightLines: [4, 5, 6, 7, 8, 12, 13],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 8: Built-in tools -- overview
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.5 TOOLS OVERVIEW',
|
|
title: 'Built-in fs + planning tools',
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents README',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 0.85,
|
|
kind: 'info',
|
|
title: 'Eight opinionated defaults, all active unless you override.',
|
|
text: `Planning, filesystem, search, shell, and subagent delegation -- one import, zero setup.`,
|
|
});
|
|
|
|
const tools = [
|
|
['write_todos', 'plan / decompose a task into ordered steps'],
|
|
['ls', 'list directory entries in the virtual FS'],
|
|
['read_file', 'read one or many files with line offsets'],
|
|
['write_file', 'create or overwrite a file in the FS'],
|
|
['edit_file', 'surgical string-replace edits (matches all occurrences)'],
|
|
['glob', 'find files by pattern (e.g. **/*.py)'],
|
|
['grep', 'regex search across files with context'],
|
|
['execute', 'run a shell command (sandboxed if a backend enforces it)'],
|
|
['task', 'delegate to a named subagent with isolated context'],
|
|
];
|
|
|
|
const colX = [0.5, 5.05];
|
|
const colW = 4.4;
|
|
for (let i = 0; i < tools.length; i += 1) {
|
|
const col = i % 2;
|
|
const row = Math.floor(i / 2);
|
|
const x = colX[col];
|
|
const y = 2.5 + row * 0.78;
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: x, y: y, w: colW, h: 0.68,
|
|
fill: { color: theme.palette.bg.elevated },
|
|
line: { color: theme.palette.border.subtle, width: 0.75 },
|
|
rectRadius: 0.06,
|
|
});
|
|
slide.addText(tools[i][0], {
|
|
x: x + 0.15, y: y + 0.05, w: 1.3, h: 0.28,
|
|
fontFace: helpers.withFallback(theme.fonts.code),
|
|
fontSize: 13,
|
|
color: theme.palette.accent.tertiary,
|
|
bold: true,
|
|
});
|
|
slide.addText(tools[i][1], {
|
|
x: x + 1.5, y: y + 0.07, w: colW - 1.65, h: 0.55,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 11,
|
|
color: theme.palette.text.secondary,
|
|
valign: 'middle',
|
|
});
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 9: Built-in tools -- write_file + edit_file example
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.5 TOOLS',
|
|
title: 'write_file and edit_file in action',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/overview',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 5.6, h: 3.5,
|
|
code: [
|
|
`# The agent calls these tools by name;`,
|
|
`# you describe the goal in the prompt.`,
|
|
``,
|
|
`PROMPT = """`,
|
|
`1. Write src/hello.py with a greet(name) function.`,
|
|
`2. Use edit_file to add a docstring to greet().`,
|
|
`3. Use write_file to add tests/test_hello.py.`,
|
|
`"""`,
|
|
``,
|
|
`agent = create_deep_agent(model="openai:gpt-4.1")`,
|
|
`agent.invoke({"messages": PROMPT})`,
|
|
].join('\n'),
|
|
filePath: 'examples/fs_tools.py',
|
|
startLine: 1,
|
|
highlightLines: [4, 5, 6, 7],
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 6.3, y: layouts.CONTENT_TOP, w: 3.2, h: 3.5,
|
|
kind: 'success',
|
|
title: 'Context overflow protection',
|
|
text: `Tool outputs larger than a threshold are offloaded to the virtual FS
|
|
and replaced with a path + summary in the message history. The agent
|
|
can re-read specific portions on demand. This is what lets deep agents
|
|
handle large repos without blowing the context window.`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 10: write_todos -- concept
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.6 PLANNING',
|
|
title: 'write_todos: explicit planning inside the graph',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/overview',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 0.95,
|
|
kind: 'info',
|
|
title: 'write_todos is just a tool, like any other.',
|
|
text: `The LLM emits a structured plan, the graph stores it in state["todos"],
|
|
and every subsequent model call sees the current plan in the system message.`,
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: 2.5, w: 9.0, h: 2.4,
|
|
code: [
|
|
`write_todos(`,
|
|
` todos=[`,
|
|
` {"content": "Read repo structure", "status": "in_progress",`,
|
|
` "activeForm": "Reading repo structure"},`,
|
|
` {"content": "Implement greet()", "status": "pending",`,
|
|
` "activeForm": "Implementing greet()"},`,
|
|
` {"content": "Add pytest cases", "status": "pending",`,
|
|
` "activeForm": "Adding pytest cases"},`,
|
|
` ]`,
|
|
`)`,
|
|
`# Status: pending | in_progress | completed`,
|
|
`# activeForm: present-continuous shown in UI`,
|
|
].join('\n'),
|
|
filePath: 'examples/write_todos.py',
|
|
startLine: 1,
|
|
highlightLines: [2, 3, 4, 5, 6, 7, 8, 9],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 11: write_todos -- Plan-Act-Reflect pattern
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.6 PATTERN',
|
|
title: 'Plan, Act, Reflect loop',
|
|
sectionNumber: 3,
|
|
source: 'blog.langchain.com/introducing-deepagents-cli',
|
|
});
|
|
|
|
const boxes = [
|
|
{ x: 0.5, title: '1. PLAN', body: `write_todos:
|
|
- decompose task
|
|
- order steps
|
|
- mark in_progress` },
|
|
{ x: 3.7, title: '2. ACT', body: `execute tool call
|
|
(read_file, edit_file, ...)
|
|
or delegate via task` },
|
|
{ x: 6.9, title: '3. REFLECT', body: `update todo status
|
|
re-plan if blocked
|
|
log progress` },
|
|
];
|
|
const boxY = layouts.CONTENT_TOP;
|
|
const boxH = 2.2;
|
|
const boxW = 2.9;
|
|
for (let i = 0; i < boxes.length; i += 1) {
|
|
const b = boxes[i];
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: b.x, y: boxY, w: boxW, h: boxH,
|
|
fill: { color: theme.palette.bg.elevated },
|
|
line: { color: theme.palette.accent.primary, width: 1.5 },
|
|
rectRadius: 0.1,
|
|
});
|
|
slide.addText(b.title, {
|
|
x: b.x + 0.15, y: boxY + 0.1, w: boxW - 0.3, h: 0.4,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 14,
|
|
color: theme.palette.accent.primary,
|
|
bold: true,
|
|
});
|
|
slide.addText(b.body, {
|
|
x: b.x + 0.15, y: boxY + 0.55, w: boxW - 0.3, h: boxH - 0.7,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 12,
|
|
color: theme.palette.text.secondary,
|
|
valign: 'top',
|
|
});
|
|
if (i < boxes.length - 1) {
|
|
slide.addShape(pres.ShapeType.rightArrow, {
|
|
x: b.x + boxW + 0.02, y: boxY + boxH / 2 - 0.12,
|
|
w: 0.2, h: 0.25,
|
|
fill: { color: theme.palette.accent.secondary },
|
|
line: { type: 'none' },
|
|
});
|
|
}
|
|
}
|
|
|
|
slide.addShape(pres.ShapeType.line, {
|
|
x: 1.95, y: boxY + boxH + 0.25, w: 6.2, h: 0,
|
|
line: { color: theme.palette.border.strong, width: 1.5, endArrowType: 'triangle', beginArrowType: 'none' },
|
|
});
|
|
slide.addText('loop until all todos = completed', {
|
|
x: 2.5, y: boxY + boxH + 0.3, w: 5.0, h: 0.3,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 11,
|
|
color: theme.palette.text.muted,
|
|
italic: true,
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: 4.3, w: 9.0, h: 0.65,
|
|
kind: 'info',
|
|
text: `The graph state carries the plan -- every LLM call sees it in the
|
|
system message, so the agent self-monitors progress across turns.`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 12: Subagents -- concept + task tool
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.7 SUBAGENTS',
|
|
title: 'task tool: delegate, isolate, return',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/overview',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 1.05,
|
|
kind: 'info',
|
|
title: 'Why subagents?',
|
|
text: `Long tool outputs and exploratory searches pollute the main thread.
|
|
A subagent runs in its own scratchpad and returns a compressed summary --
|
|
the parent context stays clean.`,
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: 2.5, w: 9.0, h: 2.4,
|
|
code: [
|
|
`# When the main agent emits a tool call like:`,
|
|
`task(`,
|
|
` subagent_type="researcher",`,
|
|
` description="Find papers on RAG evaluation",`,
|
|
` prompt="Search arXiv for 2025-2026 RAG evaluation surveys. `,
|
|
` Return a 150-word summary with 3 citations.",`,
|
|
`)`,
|
|
``,
|
|
`# Deep Agents spins up a fresh deep agent with the researcher profile,`,
|
|
`# runs it to completion, and returns only the final message.`,
|
|
].join('\n'),
|
|
filePath: 'examples/task_call.py',
|
|
startLine: 1,
|
|
highlightLines: [2, 3, 4, 5, 6],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 13: Subagents -- minimal example
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.7 EXAMPLE',
|
|
title: 'Subagents: minimal example',
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents README',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.5,
|
|
code: [
|
|
`from deepagents import create_deep_agent`,
|
|
``,
|
|
`researcher = {`,
|
|
` "name": "researcher",`,
|
|
` "description": "Does deep web research, returns citations",`,
|
|
` "system_prompt": "You are a research specialist. Always cite sources.",`,
|
|
` "tools": [web_search], # optional, can be []`,
|
|
`}`,
|
|
``,
|
|
`writer = {`,
|
|
` "name": "writer",`,
|
|
` "description": "Polishes prose into a final report",`,
|
|
` "system_prompt": "You are a writing specialist.",`,
|
|
` "tools": [],`,
|
|
`}`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="openai:gpt-4.1",`,
|
|
` tools=[],`,
|
|
` subagents=[researcher, writer],`,
|
|
`)`,
|
|
``,
|
|
`agent.invoke({"messages": "Research quantum computing and write a 200-word summary."})`,
|
|
].join('\n'),
|
|
filePath: 'examples/subagents.py',
|
|
startLine: 1,
|
|
highlightLines: [4, 5, 6, 7, 11, 12, 13, 14, 19, 20, 21, 22],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 14: Subagents -- context isolation diagram
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.7 ISOLATION',
|
|
title: 'Isolated context for subagents',
|
|
sectionNumber: 3,
|
|
source: 'blog.langchain.com/introducing-deepagents-cli',
|
|
});
|
|
|
|
const mainX = 0.5;
|
|
const mainY = layouts.CONTENT_TOP;
|
|
const mainW = 3.0;
|
|
const mainH = 3.5;
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: mainX, y: mainY, w: mainW, h: mainH,
|
|
fill: { color: theme.palette.bg.elevated },
|
|
line: { color: theme.palette.accent.primary, width: 1.5 },
|
|
rectRadius: 0.1,
|
|
});
|
|
slide.addText('MAIN AGENT', {
|
|
x: mainX + 0.15, y: mainY + 0.1, w: mainW - 0.3, h: 0.3,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 11,
|
|
color: theme.palette.accent.primary,
|
|
bold: true,
|
|
charSpacing: 4,
|
|
});
|
|
slide.addText(`context = [
|
|
user task,
|
|
summary from researcher,
|
|
summary from writer
|
|
]`, {
|
|
x: mainX + 0.15, y: mainY + 0.5, w: mainW - 0.3, h: mainH - 0.7,
|
|
fontFace: helpers.withFallback(theme.fonts.code),
|
|
fontSize: 12,
|
|
color: theme.palette.text.primary,
|
|
valign: 'top',
|
|
});
|
|
|
|
slide.addShape(pres.ShapeType.line, {
|
|
x: mainX + mainW, y: mainY + mainH / 2, w: 0.6, h: 0,
|
|
line: { color: theme.palette.accent.secondary, width: 2, endArrowType: 'triangle' },
|
|
});
|
|
slide.addText(`task("researcher")`, {
|
|
x: mainX + mainW + 0.02, y: mainY + mainH / 2 - 0.25, w: 1.4, h: 0.5,
|
|
fontFace: helpers.withFallback(theme.fonts.code),
|
|
fontSize: 11,
|
|
color: theme.palette.accent.secondary,
|
|
bold: true,
|
|
align: 'center',
|
|
});
|
|
|
|
const subX = 4.95;
|
|
const subY1 = layouts.CONTENT_TOP;
|
|
const subW = 4.55;
|
|
const subH = 1.6;
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: subX, y: subY1, w: subW, h: subH,
|
|
fill: { color: theme.palette.bg.code },
|
|
line: { color: theme.palette.border.accent, width: 1.2 },
|
|
rectRadius: 0.08,
|
|
});
|
|
slide.addText('SUBAGENT: researcher', {
|
|
x: subX + 0.15, y: subY1 + 0.08, w: subW - 0.3, h: 0.28,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 11,
|
|
color: theme.palette.accent.tertiary,
|
|
bold: true,
|
|
charSpacing: 2,
|
|
});
|
|
slide.addText(`context = [
|
|
full web_search results,
|
|
all 14 sources,
|
|
notes, drafts, citations
|
|
]
|
|
return: 150-word summary`, {
|
|
x: subX + 0.15, y: subY1 + 0.4, w: subW - 0.3, h: subH - 0.5,
|
|
fontFace: helpers.withFallback(theme.fonts.code),
|
|
fontSize: 11,
|
|
color: theme.palette.text.secondary,
|
|
valign: 'top',
|
|
});
|
|
|
|
const subY2 = subY1 + subH + 0.3;
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: subX, y: subY2, w: subW, h: subH,
|
|
fill: { color: theme.palette.bg.code },
|
|
line: { color: theme.palette.border.accent, width: 1.2 },
|
|
rectRadius: 0.08,
|
|
});
|
|
slide.addText('SUBAGENT: writer', {
|
|
x: subX + 0.15, y: subY2 + 0.08, w: subW - 0.3, h: 0.28,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 11,
|
|
color: theme.palette.accent.tertiary,
|
|
bold: true,
|
|
charSpacing: 2,
|
|
});
|
|
slide.addText(`context = [
|
|
researcher summary,
|
|
original user task
|
|
]
|
|
return: polished 200-word report`, {
|
|
x: subX + 0.15, y: subY2 + 0.4, w: subW - 0.3, h: subH - 0.5,
|
|
fontFace: helpers.withFallback(theme.fonts.code),
|
|
fontSize: 11,
|
|
color: theme.palette.text.secondary,
|
|
valign: 'top',
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 15: Virtual filesystem -- state['files']
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.8 VIRTUAL FS',
|
|
title: `Virtual FS: state files dict`,
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents README',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 1.1,
|
|
kind: 'info',
|
|
title: 'Files live in graph state, not on disk by default.',
|
|
text: `StateBackend keeps everything in state["files"]. Survives across
|
|
turns in the same thread; never touches disk unless you swap backends.`,
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: 2.6, w: 9.0, h: 2.3,
|
|
code: [
|
|
`# Inspect the virtual filesystem after a run:`,
|
|
`result = agent.invoke({"messages": "Summarize repo"})`,
|
|
``,
|
|
`files = result.get("files", {})`,
|
|
`for path, doc in files.items():`,
|
|
` print(f"{path}: {len(doc.get('content', []))} bytes")`,
|
|
``,
|
|
`# /repo/src/main.py: 421 bytes`,
|
|
`# /repo/README.md: 1804 bytes`,
|
|
].join('\n'),
|
|
filePath: 'examples/virtual_fs.py',
|
|
startLine: 1,
|
|
highlightLines: [3, 4, 5, 6],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 16: Middleware -- four hook points
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.9 MIDDLEWARE',
|
|
title: 'Middleware: four hook points',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/langchain/middleware',
|
|
});
|
|
|
|
const midX = 2.4;
|
|
const midY = layouts.CONTENT_TOP + 0.1;
|
|
const midW = 2.4;
|
|
const midH = 1.85;
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: midX, y: midY, w: midW, h: 0.95,
|
|
fill: { color: theme.palette.bg.elevated },
|
|
line: { color: theme.palette.accent.tertiary, width: 1.5 },
|
|
rectRadius: 0.1,
|
|
});
|
|
slide.addText('MODEL\n(LLM call)', {
|
|
x: midX, y: midY + 0.05, w: midW, h: 0.85,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 13,
|
|
color: theme.palette.accent.tertiary,
|
|
bold: true,
|
|
align: 'center',
|
|
valign: 'middle',
|
|
});
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: midX, y: midY + midH, w: midW, h: 0.95,
|
|
fill: { color: theme.palette.bg.elevated },
|
|
line: { color: theme.palette.accent.primary, width: 1.5 },
|
|
rectRadius: 0.1,
|
|
});
|
|
slide.addText('TOOLS\n(execute)', {
|
|
x: midX, y: midY + midH + 0.05, w: midW, h: 0.85,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 13,
|
|
color: theme.palette.accent.primary,
|
|
bold: true,
|
|
align: 'center',
|
|
valign: 'middle',
|
|
});
|
|
|
|
// Connector arrow MODEL -> TOOLS
|
|
slide.addShape(pres.ShapeType.downArrow, {
|
|
x: midX + midW / 2 - 0.15, y: midY + 1.0, w: 0.3, h: 0.8,
|
|
fill: { color: theme.palette.accent.secondary },
|
|
line: { type: 'none' },
|
|
});
|
|
|
|
// Hook labels: 4 small pills around the central column
|
|
const hooks = [
|
|
{ x: 0.6, y: midY + 0.1, label: 'before_model' },
|
|
{ x: 0.6, y: midY + 0.6, label: 'after_model' },
|
|
{ x: midX + midW + 0.3, y: midY + midH + 0.1, label: 'before_tool' },
|
|
{ x: midX + midW + 0.3, y: midY + midH + 0.6, label: 'after_tool' },
|
|
];
|
|
for (const h of hooks) {
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: h.x, y: h.y, w: 1.65, h: 0.4,
|
|
fill: { color: theme.palette.bg.code },
|
|
line: { color: theme.palette.accent.secondary, width: 1.2 },
|
|
rectRadius: 0.06,
|
|
});
|
|
slide.addText(h.label, {
|
|
x: h.x, y: h.y, w: 1.65, h: 0.4,
|
|
fontFace: helpers.withFallback(theme.fonts.code),
|
|
fontSize: 11,
|
|
color: theme.palette.accent.secondary,
|
|
bold: true,
|
|
align: 'center',
|
|
valign: 'middle',
|
|
});
|
|
}
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: 4.4, w: 9.0, h: 0.55,
|
|
kind: 'info',
|
|
text: `Same middleware system as LangChain 1.0 create_agent.
|
|
Mix custom middleware with built-ins: Summarization, HumanInTheLoop, Filesystem, SubAgent.`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 17: Middleware -- example
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.9 MIDDLEWARE',
|
|
title: 'Custom middleware: logging + PII redaction',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/langchain/middleware',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.5,
|
|
code: [
|
|
`from langchain.agents.middleware import AgentMiddleware`,
|
|
`from deepagents import create_deep_agent`,
|
|
``,
|
|
`class LoggerMiddleware(AgentMiddleware):`,
|
|
` def before_model(self, state, runtime):`,
|
|
` print(f"[model] {len(state['messages'])} msgs in")`,
|
|
` return state`,
|
|
``,
|
|
` def after_tool(self, state, runtime, tool_result):`,
|
|
` print(f"[tool] {tool_result.tool_call_id} -> `
|
|
+ `{len(str(tool_result.content))} chars")`,
|
|
` return state`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="openai:gpt-4.1",`,
|
|
` middleware=[LoggerMiddleware(), HumanInTheLoopMiddleware(`,
|
|
` interrupt_on={"execute": True}, # ask before running bash`,
|
|
` )],`,
|
|
`)`,
|
|
].join('\n'),
|
|
filePath: 'examples/middleware.py',
|
|
startLine: 1,
|
|
highlightLines: [5, 6, 7, 8, 9, 10, 16, 17, 18],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 18: Backends -- overview
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.10 BACKENDS',
|
|
title: 'Pluggable backends: 4 flavors',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/backends',
|
|
});
|
|
|
|
const cards = [
|
|
{
|
|
name: 'StateBackend',
|
|
sub: 'default',
|
|
desc: `Everything in graph state["files"]. Zero disk I/O.
|
|
Perfect for short-lived, sandboxed runs.`,
|
|
color: theme.palette.accent.tertiary,
|
|
},
|
|
{
|
|
name: 'FilesystemBackend',
|
|
sub: 'local disk',
|
|
desc: `Real directory on the host. Persists across runs.
|
|
Use when the agent should see/edit your repo directly.`,
|
|
color: theme.palette.accent.primary,
|
|
},
|
|
{
|
|
name: 'StoreBackend',
|
|
sub: 'cross-thread',
|
|
desc: `Lives in a LangGraph Store (Postgres, Redis).
|
|
Shared between threads and across sessions.`,
|
|
color: theme.palette.accent.secondary,
|
|
},
|
|
{
|
|
name: 'CompositeBackend',
|
|
sub: 'route by path',
|
|
desc: `Route reads/writes to different backends depending on path prefix.
|
|
"/workspace" -> Filesystem, "/memory" -> Store.`,
|
|
color: theme.palette.state.success,
|
|
},
|
|
];
|
|
|
|
const cardY = layouts.CONTENT_TOP;
|
|
const cardH = 1.65;
|
|
const cardW = 4.4;
|
|
for (let i = 0; i < cards.length; i += 1) {
|
|
const col = i % 2;
|
|
const row = Math.floor(i / 2);
|
|
const x = 0.5 + col * (cardW + 0.2);
|
|
const y = cardY + row * (cardH + 0.2);
|
|
slide.addShape(pres.ShapeType.roundRect, {
|
|
x: x, y: y, w: cardW, h: cardH,
|
|
fill: { color: theme.palette.bg.elevated },
|
|
line: { color: cards[i].color, width: 1.2 },
|
|
rectRadius: 0.08,
|
|
});
|
|
slide.addText(cards[i].name, {
|
|
x: x + 0.2, y: y + 0.1, w: cardW - 0.4, h: 0.3,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 14,
|
|
color: cards[i].color,
|
|
bold: true,
|
|
});
|
|
slide.addText(cards[i].sub, {
|
|
x: x + 0.2, y: y + 0.4, w: cardW - 0.4, h: 0.25,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 10,
|
|
color: theme.palette.text.muted,
|
|
italic: true,
|
|
});
|
|
slide.addText(cards[i].desc, {
|
|
x: x + 0.2, y: y + 0.65, w: cardW - 0.4, h: cardH - 0.75,
|
|
fontFace: helpers.withFallback(theme.fonts.ui),
|
|
fontSize: 11,
|
|
color: theme.palette.text.secondary,
|
|
valign: 'top',
|
|
});
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 19: Backends -- CompositeBackend example
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.10 COMPOSITE',
|
|
title: 'CompositeBackend: route by path prefix',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/backends',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.5,
|
|
code: [
|
|
`from deepagents import create_deep_agent`,
|
|
`from deepagents.backends import (`,
|
|
` CompositeBackend, FilesystemBackend, StoreBackend`,
|
|
`)`,
|
|
`from langgraph.store.memory import InMemoryStore`,
|
|
``,
|
|
`store = InMemoryStore() # or PostgresStore in prod`,
|
|
``,
|
|
`backend = CompositeBackend(`,
|
|
` default=FilesystemBackend(root_dir="./workspace"),`,
|
|
` routes={`,
|
|
` "/memory/": StoreBackend(store=store, namespace=("agent", "kb")),`,
|
|
` "/scratch/": FilesystemBackend(root_dir="/tmp/scratch"),`,
|
|
` },`,
|
|
`)`,
|
|
``,
|
|
`agent = create_deep_agent(model=..., backend=backend)`,
|
|
`# /workspace/notes.md -> local disk`,
|
|
`# /memory/lessons.md -> Postgres, shared across sessions`,
|
|
`# /scratch/tmp.py -> ephemeral tmpfs`,
|
|
].join('\n'),
|
|
filePath: 'examples/composite_backend.py',
|
|
startLine: 1,
|
|
highlightLines: [12, 13, 14, 15, 20, 21, 22],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 20: Human-in-the-loop
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.11 HITL',
|
|
title: 'interrupt_on: approve tool calls',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/human-in-the-loop',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.4,
|
|
code: [
|
|
`from langchain.agents.middleware import HumanInTheLoopMiddleware`,
|
|
`from deepagents import create_deep_agent`,
|
|
`from langgraph.checkpoint.memory import InMemorySaver`,
|
|
`from langgraph.types import Command`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="openai:gpt-4.1",`,
|
|
` checkpointer=InMemorySaver(),`,
|
|
` middleware=[HumanInTheLoopMiddleware(`,
|
|
` interrupt_on={`,
|
|
` "execute": True, # bash -- always ask`,
|
|
` "write_file": True, # disk writes -- always ask`,
|
|
` "task": False, # subagents -- run unattended`,
|
|
` },`,
|
|
` )],`,
|
|
`)`,
|
|
``,
|
|
`cfg = {"configurable": {"thread_id": "user-42"}}`,
|
|
`try:`,
|
|
` agent.invoke({"messages": "deploy to staging"}, cfg)`,
|
|
`except InterruptedError:`,
|
|
` decision = ask_user("Approve execute()?") # your UI`,
|
|
` agent.invoke(Command(resume=decision), cfg)`,
|
|
].join('\n'),
|
|
filePath: 'examples/hitl.py',
|
|
startLine: 1,
|
|
highlightLines: [9, 10, 11, 12, 13, 14, 24, 25, 26, 27],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 21: Streaming
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.12 STREAMING',
|
|
title: 'stream_mode: tokens, updates, events',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/streaming',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 5.7, h: 3.5,
|
|
code: [
|
|
`cfg = {"configurable": {"thread_id": "user-42"}}`,
|
|
``,
|
|
`# 1. Stream model tokens as they arrive`,
|
|
`for token, meta in agent.stream(`,
|
|
` {"messages": "..."}, cfg,`,
|
|
` stream_mode="messages",`,
|
|
`):`,
|
|
` print(token.content, end="", flush=True)`,
|
|
``,
|
|
`# 2. Stream state updates per node`,
|
|
`for chunk in agent.stream(`,
|
|
` {"messages": "..."}, cfg,`,
|
|
` stream_mode="updates",`,
|
|
`):`,
|
|
` print(chunk) # {"model": {...}, "tools": {...}}`,
|
|
``,
|
|
`# 3. Subagent streams are surfaced as`,
|
|
`# {"subagent": {"name": "researcher", "chunk": ...}}`,
|
|
].join('\n'),
|
|
filePath: 'examples/streaming.py',
|
|
startLine: 1,
|
|
highlightLines: [4, 5, 6, 12, 13, 14],
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 6.4, y: layouts.CONTENT_TOP, w: 3.1, h: 3.5,
|
|
kind: 'info',
|
|
title: 'stream_mode values',
|
|
text: `- "values": full state after each node
|
|
- "updates": delta per node (LangGraph-style)
|
|
- "messages": token-by-token LLM output
|
|
- "events": low-level LangGraph events
|
|
- "custom": writer().emit(...) from inside nodes`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 22: LangSmith integration
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.13 LANGSMITH',
|
|
title: 'Tracing and evaluation: works out of the box',
|
|
sectionNumber: 3,
|
|
source: 'docs.smith.langchain.com',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 0.9,
|
|
kind: 'info',
|
|
title: 'No code changes required.',
|
|
text: `Set LANGSMITH_TRACING=true plus LANGSMITH_API_KEY and LANGSMITH_PROJECT.
|
|
Every deep-agent run is traced as a parent run with subagent runs nested underneath.`,
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: 2.55, w: 9.0, h: 2.3,
|
|
code: [
|
|
`export LANGSMITH_TRACING=true`,
|
|
`export LANGSMITH_API_KEY=lsv2_...`,
|
|
`export LANGSMITH_PROJECT=deepagents-evals`,
|
|
``,
|
|
`python my_deep_agent.py`,
|
|
`# -> all runs visible in smith.langchain.com`,
|
|
`# -> subagent runs nested under the parent`,
|
|
`# -> token usage, latency, tool errors captured`,
|
|
].join('\n'),
|
|
filePath: 'examples/langsmith.sh',
|
|
startLine: 1,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 23: Example -- research agent
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.14 RESEARCH AGENT',
|
|
title: 'Real example: arXiv research agent',
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents examples/',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.5,
|
|
code: [
|
|
`from langchain.tools import tool`,
|
|
`from deepagents import create_deep_agent`,
|
|
``,
|
|
`@tool`,
|
|
`def arxiv_search(query: str, max_results: int = 5) -> str:`,
|
|
` """Search arXiv for papers matching the query."""`,
|
|
` import arxiv`,
|
|
` client = arxiv.Client()`,
|
|
` results = list(client.results(arxiv.Search(query=query, `
|
|
+ `max_results=max_results)))`,
|
|
` return "\\n\\n".join(`,
|
|
` f"{r.title}\\n{r.summary[:300]}..." for r in results`,
|
|
` )`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="openai:gpt-4.1",`,
|
|
` tools=[arxiv_search],`,
|
|
` system_prompt=("You are a research assistant. Always cite paper titles `
|
|
+ `and arXiv IDs."),`,
|
|
` subagents=[{`,
|
|
` "name": "summarizer",`,
|
|
` "description": "Compresses paper abstracts into a paragraph",`,
|
|
` "system_prompt": "You are a precise summarizer.",`,
|
|
` "tools": [],`,
|
|
` }],`,
|
|
`)`,
|
|
].join('\n'),
|
|
filePath: 'examples/research_agent.py',
|
|
startLine: 1,
|
|
highlightLines: [18, 19, 20, 21, 22, 23, 24, 25],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 24: Example -- coding agent
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.14 CODING AGENT',
|
|
title: 'Real example: coding agent, sandboxed',
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents README',
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 3.5,
|
|
code: [
|
|
`from deepagents import create_deep_agent`,
|
|
`from deepagents.backends import SandboxBackend`,
|
|
``,
|
|
`agent = create_deep_agent(`,
|
|
` model="anthropic:claude-sonnet-4-5",`,
|
|
` backend=SandboxBackend(`,
|
|
` provider="daytona", # or modal / runloop`,
|
|
` api_key=os.environ["DAYTONA_API_KEY"],`,
|
|
` image="python:3.12-slim",`,
|
|
` ),`,
|
|
` system_prompt=("You are a coding agent. Always run tests after edits. `
|
|
+ `Stop and ask if requirements are ambiguous."),`,
|
|
`)`,
|
|
``,
|
|
`agent.invoke({"messages": "Add a /healthz endpoint to the FastAPI app, `
|
|
+ `with tests."})`,
|
|
``,
|
|
`# Daytona/Modal/Runloop execute code in an isolated container;`,
|
|
`# the local process never sees a stray rm -rf.`,
|
|
].join('\n'),
|
|
filePath: 'examples/coding_agent.py',
|
|
startLine: 1,
|
|
highlightLines: [4, 5, 6, 7, 8, 9, 10, 11],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 25: What's new in 1.0 + TypeScript
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.15 WHAT IS NEW',
|
|
title: '1.0-rc and the TypeScript port',
|
|
sectionNumber: 3,
|
|
source: 'github.com/langchain-ai/deepagents/releases',
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 4.4, h: 3.5,
|
|
kind: 'info',
|
|
title: 'What is new in 1.0-rc',
|
|
text: `- Full LangChain 1.0 middleware integration
|
|
- Stable Send API for parallel subagents
|
|
- Pluggable backends marked stable
|
|
- Skills: versioning + hot-reload
|
|
- CompositeBackend GA
|
|
- Note: as of snapshot 2026-06-22, latest
|
|
stable is 0.6.11 -- 1.0 ships before EOY 2026`,
|
|
});
|
|
|
|
codeBlock(slide, {
|
|
x: 5.1, y: layouts.CONTENT_TOP, w: 4.4, h: 3.5,
|
|
code: [
|
|
`// TypeScript analogue (deepagentsjs)`,
|
|
`import { createDeepAgent } from "deepagents";`,
|
|
`import { tool, z } from "@langchain/core/tools";`,
|
|
``,
|
|
`const search = tool(`,
|
|
` async ({ q }) => fetch("/api/search?q=" + q).then(r => r.text()),`,
|
|
` { name: "search", schema: z.object({ q: z.string() }) },`,
|
|
`);`,
|
|
``,
|
|
`const agent = await createDeepAgent({`,
|
|
` model: "openai:gpt-4.1",`,
|
|
` tools: [search],`,
|
|
`});`,
|
|
].join('\n'),
|
|
filePath: 'examples/deepagentsjs.ts',
|
|
startLine: 1,
|
|
highlightLines: [10, 11, 12, 13],
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SLIDE 26: Pros/cons + bridge to Open SWE
|
|
// ---------------------------------------------------------------------------
|
|
{
|
|
const slide = contentSlide({
|
|
eyebrow: '3.16 PROS / CONS',
|
|
title: 'When to choose Deep Agents',
|
|
sectionNumber: 3,
|
|
source: 'docs.langchain.com/oss/python/deepagents/overview',
|
|
});
|
|
|
|
helpers.addProsCons(slide, pres, theme, {
|
|
x: 0.5, y: layouts.CONTENT_TOP, w: 9.0, h: 2.5,
|
|
pros: [
|
|
'Batteries included: planning + FS + subagents + HITL + skills in one import',
|
|
'Less boilerplate than raw LangGraph, opinionated defaults that match Claude Code',
|
|
'Pluggable backends (local / Daytona / Modal / Runloop / LangSmith Store)',
|
|
'Skills system: reusable behaviors loaded on-demand',
|
|
'Open source (MIT), traceable through LangSmith out of the box',
|
|
],
|
|
cons: [
|
|
'1.0 not yet shipped (0.6.11 latest on snapshot 2026-06-22) -- breaking changes possible',
|
|
'Opinionated: overriding defaults can be awkward',
|
|
'Sandbox providers require external SaaS accounts',
|
|
'Skills ecosystem is nascent, fewer ready-made skills than for Claude Code',
|
|
'Some middleware + backend combinations are not yet documented',
|
|
],
|
|
});
|
|
|
|
helpers.addCallout(slide, pres, theme, {
|
|
x: 0.5, y: 4.05, w: 9.0, h: 0.9,
|
|
kind: 'info',
|
|
title: 'Bridge to Open SWE',
|
|
text: `Open SWE (next section) is a real coding agent that uses Deep Agents as
|
|
its harness. All the patterns from this section -- write_todos, subagents,
|
|
virtual FS, HITL -- show up unchanged in production at langchain-ai/open-swe.`,
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Save
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const outDir = path.resolve(__dirname);
|
|
const outFile = path.join(outDir, 'section3.pptx');
|
|
pres.writeFile({ fileName: outFile }).then((written) => {
|
|
// eslint-disable-next-line no-console
|
|
console.log('Wrote:', written, '(slides:', pageNum + ')');
|
|
if (pageNum !== TOTAL_SLIDES) {
|
|
// eslint-disable-next-line no-console
|
|
console.warn('WARNING: expected', TOTAL_SLIDES, 'slides, got', pageNum);
|
|
process.exitCode = 1;
|
|
}
|
|
}).catch((err) => {
|
|
// eslint-disable-next-line no-console
|
|
console.error('Failed to write pptx:', err);
|
|
process.exit(1);
|
|
});
|