Files
petya 75601988c2 Initial commit: LangChain evolution tutorial deck (132 slides)
- 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
2026-06-22 11:29:03 +03:00

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);
});