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