From 2ba53f1490e9d288020d4af8fa79f2e1b8a277c6 Mon Sep 17 00:00:00 2001 From: Nick Huang Date: Wed, 5 Nov 2025 23:57:24 -0500 Subject: [PATCH 1/4] Deepagents JS docs --- src/docs.json | 27 +- src/oss/deepagents/backends.mdx | 99 ++++++- src/oss/deepagents/customization.mdx | 72 ++++- src/oss/deepagents/human-in-the-loop.mdx | 175 ++++++++++- src/oss/deepagents/long-term-memory.mdx | 313 +++++++++++--------- src/oss/deepagents/middleware.mdx | 160 +++++++++- src/oss/deepagents/quickstart.mdx | 102 ++++++- src/oss/deepagents/subagents.mdx | 252 +++++++++++++++- src/oss/reference/deepagents-javascript.mdx | 4 + 9 files changed, 1026 insertions(+), 178 deletions(-) create mode 100644 src/oss/reference/deepagents-javascript.mdx diff --git a/src/docs.json b/src/docs.json index 3905df8dd8..f144d555b1 100644 --- a/src/docs.json +++ b/src/docs.json @@ -583,6 +583,30 @@ } ] }, + { + "tab": "Deep Agents", + "pages": [ + "oss/javascript/deepagents/overview", + { + "group": "Get started", + "pages": [ + "oss/javascript/deepagents/quickstart", + "oss/javascript/deepagents/customization" + ] + }, + { + "group": "Core capabilities", + "pages": [ + "oss/javascript/deepagents/harness", + "oss/javascript/deepagents/backends", + "oss/javascript/deepagents/subagents", + "oss/javascript/deepagents/human-in-the-loop", + "oss/javascript/deepagents/long-term-memory", + "oss/javascript/deepagents/middleware" + ] + } + ] + }, { "tab": "Integrations", "pages": [ @@ -709,7 +733,8 @@ "group": "Reference", "pages": [ "oss/javascript/reference/langchain-javascript", - "oss/javascript/reference/langgraph-javascript" + "oss/javascript/reference/langgraph-javascript", + "oss/javascript/reference/deepagents-javascript" ] }, { diff --git a/src/oss/deepagents/backends.mdx b/src/oss/deepagents/backends.mdx index 5001d70970..2dcd90d210 100644 --- a/src/oss/deepagents/backends.mdx +++ b/src/oss/deepagents/backends.mdx @@ -37,6 +37,21 @@ agent = create_deep_agent( ``` ::: +:::js +```typescript +import { createDeepAgent } from "deepagents"; +import { StateBackend } from "deepagents"; + +// By default we provide a StateBackend +const agent = createDeepAgent(); + +// Under the hood, it looks like +const agent2 = createDeepAgent({ + backend: (rt) => new StateBackend(rt), // Note that the tools access State through the runtime.state +}); +``` +::: + **How it works:** - Stores files in LangGraph agent state for the current thread. - Persists across multiple agent turns on the same thread via checkpoints. @@ -47,17 +62,28 @@ agent = create_deep_agent( ### FilesystemBackend (local disk) +:::python ```python from deepagents.backends import FilesystemBackend agent = create_deep_agent( - backend=FilesystemBackend(root_dir="/Users/nh/Desktop/") + backend=FilesystemBackend(root_dir=".", virtual_mode=True) ) ``` +::: + +:::js +```typescript +import { createDeepAgent, FilesystemBackend } from "deepagents"; + +const agent = createDeepAgent({ + backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }), +}); +``` +::: **How it works:** - Reads/writes real files under a configurable `root_dir`. -- Note: `root_dir` must be an absolute path. - You can optionally set `virtual_mode=True` to sandbox and normalize paths under `root_dir`. - Uses secure path resolution, prevents unsafe symlink traversal when possible, can use ripgrep for fast `grep`. @@ -68,13 +94,30 @@ agent = create_deep_agent( ### StoreBackend (LangGraph Store) +:::python ```python +from langgraph.store.memory import InMemoryStore from deepagents.backends import StoreBackend agent = create_deep_agent( - backend=(lambda rt: StoreBackend(rt)) # Note that the tools access Store through the runtime.store + backend=(lambda rt: StoreBackend(rt)), # Note that the tools access Store through the runtime.store + store=InMemoryStore() ) ``` +::: + +:::js +```typescript +import { createDeepAgent, StoreBackend } from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph"; + +const store = new InMemoryStore() +const agent = createDeepAgent({ + backend: (rt) => new StoreBackend(rt), + store +}); +``` +::: **How it works:** - Stores files in a LangGraph `BaseStore` provided by the runtime, enabling cross‑thread durable storage. @@ -89,18 +132,37 @@ agent = create_deep_agent( :::python ```python from deepagents import create_deep_agent -from deepagents.backends import FilesystemBackend -from deepagents.backends.composite import build_composite_state_backend +from deepagents.backends import CompositeBackend, StateBackend, StoreBackend +from langgraph.store.memory import InMemoryStore composite_backend = lambda rt: CompositeBackend( - default=StateBackend(rt) + default=StateBackend(rt), routes={ "/memories/": StoreBackend(rt), - "/docs/": CustomBackend() } ) -agent = create_deep_agent(backend=composite_backend) +agent = create_deep_agent( + backend=composite_backend, + store=InMemoryStore() # Store passed to create_deep_agent, not backend +) +``` +::: + +:::js +```typescript +import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph"; + +const compositeBackend = (rt) => new CompositeBackend( + new StateBackend(rt), + { + "/memories/": new StoreBackend(rt), + } +); + +const store = new InMemoryStore() +const agent = createDeepAgent({ backend: compositeBackend, store }); ``` ::: @@ -129,12 +191,12 @@ Route parts of the namespace to different backends. Commonly used to persist `/m :::python ```python from deepagents import create_deep_agent -from deepagents.backends import FilesystemBackend -from deepagents.backends.composite import build_composite_state_backend +from deepagents.backends import CompositeBackend, StateBackend, FilesystemBackend composite_backend = lambda rt: CompositeBackend( + default=StateBackend(rt), routes={ - "/memories/": FilesystemBackend(root_dir="/deepagents/myagent"), + "/memories/": FilesystemBackend(root_dir="/deepagents/myagent", virtual_mode=True), }, ) @@ -142,6 +204,21 @@ agent = create_deep_agent(backend=composite_backend) ``` ::: +:::js +```typescript +import { createDeepAgent, CompositeBackend, FilesystemBackend, StateBackend } from "deepagents"; + +const compositeBackend = (rt) => new CompositeBackend( + new StateBackend(rt), + { + "/memories/": new FilesystemBackend({ rootDir: "/deepagents/myagent", virtualMode: true }), + }, +); + +const agent = createDeepAgent({ backend: compositeBackend }); +``` +::: + Behavior: - `/workspace/plan.md` → StateBackend (ephemeral) - `/memories/agent.md` → FilesystemBackend under `/deepagents/myagent` diff --git a/src/oss/deepagents/customization.mdx b/src/oss/deepagents/customization.mdx index 92d2542661..6e50bbf008 100644 --- a/src/oss/deepagents/customization.mdx +++ b/src/oss/deepagents/customization.mdx @@ -24,7 +24,25 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +import { ChatAnthropic } from "@langchain/anthropic"; +import { ChatOpenAI } from "@langchain/openai"; +import { createDeepAgent } from "deepagents"; + +// Using Anthropic +const agent = createDeepAgent({ + model: new ChatAnthropic({ + model: "claude-sonnet-4-20250514", + temperature: 0, + }), +}); + +// Using OpenAI +const agent2 = createDeepAgent({ + model: new ChatOpenAI({ + model: "gpt-5", + temperature: 0, + }), +}); ``` ::: @@ -51,7 +69,13 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +import { createDeepAgent } from "deepagents"; + +const researchInstructions = `You are an expert researcher. Your job is to conduct thorough research, and then write a polished report.`; + +const agent = createDeepAgent({ + systemPrompt: researchInstructions, +}); ``` ::: @@ -90,7 +114,49 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +import { tool } from "langchain"; +import { TavilySearch } from "@langchain/tavily"; +import { createDeepAgent } from "deepagents"; +import { z } from "zod"; + +const internetSearch = tool( + async ({ + query, + maxResults = 5, + topic = "general", + includeRawContent = false, + }: { + query: string; + maxResults?: number; + topic?: "general" | "news" | "finance"; + includeRawContent?: boolean; + }) => { + const tavilySearch = new TavilySearch({ + maxResults, + tavilyApiKey: process.env.TAVILY_API_KEY, + includeRawContent, + topic, + }); + return await tavilySearch._call({ query }); + }, + { + name: "internet_search", + description: "Run a web search", + schema: z.object({ + query: z.string().describe("The search query"), + maxResults: z.number().optional().default(5), + topic: z + .enum(["general", "news", "finance"]) + .optional() + .default("general"), + includeRawContent: z.boolean().optional().default(false), + }), + }, +); + +const agent = createDeepAgent({ + tools: [internetSearch], +}); ``` ::: diff --git a/src/oss/deepagents/human-in-the-loop.mdx b/src/oss/deepagents/human-in-the-loop.mdx index 5e96a27ee4..c1b68270f2 100644 --- a/src/oss/deepagents/human-in-the-loop.mdx +++ b/src/oss/deepagents/human-in-the-loop.mdx @@ -52,7 +52,53 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +import { tool } from "langchain"; +import { createDeepAgent } from "deepagents"; +import { MemorySaver } from "@langchain/langgraph"; +import { z } from "zod"; +import { v4 as uuidv4 } from 'uuid'; // install uuid package: npm install uuid + +const deleteFile = tool( + async ({ path }: { path: string }) => { + return `Deleted ${path}`; + }, + { + name: "delete_file", + description: "Delete a file from the filesystem.", + schema: z.object({ + path: z.string(), + }), + }, +); + +const sendEmail = tool( + async ({ to, subject, body }: { to: string; subject: string; body: string }) => { + return `Sent email to ${to}`; + }, + { + name: "send_email", + description: "Send an email.", + schema: z.object({ + to: z.string(), + subject: z.string(), + body: z.string(), + }), + }, +); + +// Checkpointer is REQUIRED for human-in-the-loop +const checkpointer = new MemorySaver(); + +const agent = createDeepAgent({ + model: "claude-sonnet-4-5-20250929", + tools: [deleteFile, sendEmail], + interruptOn: { + delete_file: true, // Default: approve, edit, reject + read_file: false, // No interrupts needed + send_email: { allowedDecisions: ["approve", "reject"] }, // No editing + }, + checkpointer, // Required! +}); ``` ::: @@ -83,7 +129,16 @@ interrupt_on = { :::js ```typescript -// TODO: Add JS implementation +const interruptOn = { + // Sensitive operations: allow all options + delete_file: { allowedDecisions: ["approve", "edit", "reject"] }, + + // Moderate risk: approval or rejection only + write_file: { allowedDecisions: ["approve", "reject"] }, + + // Must approve (no rejection allowed) + critical_operation: { allowedDecisions: ["approve"] }, +}; ``` ::: @@ -139,7 +194,51 @@ print(result["messages"][-1]["content"]) :::js ```typescript -// TODO: Add JS implementation +import { v4 as uuidv4 } from "uuid"; +import { Command } from "@langchain/langgraph"; + +// Create config with thread_id for state persistence +const config = { configurable: { thread_id: uuidv4() } }; + +// Invoke the agent +let result = await agent.invoke({ + messages: [{ role: "user", content: "Delete the file temp.txt" }], +}, config); + +// Check if execution was interrupted +if (result.__interrupt__) { + // Extract interrupt information + const interrupts = result.__interrupt__[0].value; + const actionRequests = interrupts.actionRequests; + const reviewConfigs = interrupts.reviewConfigs; + + // Create a lookup map from tool name to review config + const configMap = Object.fromEntries( + reviewConfigs.map((cfg) => [cfg.actionName, cfg]) + ); + + // Display the pending actions to the user + for (const action of actionRequests) { + const reviewConfig = configMap[action.name]; + console.log(`Tool: ${action.name}`); + console.log(`Arguments: ${JSON.stringify(action.args)}`); + console.log(`Allowed decisions: ${reviewConfig.allowedDecisions}`); + } + + // Get user decisions (one per actionRequest, in order) + const decisions = [ + { type: "approve" } // User approved the deletion + ]; + + // Resume execution with decisions + result = await agent.invoke( + new Command({ resume: { decisions } }), + config // Must use the same config! + ); +} + +// Process final result +console.log(result.messages[result.messages.length - 1].content); ``` ::: @@ -180,7 +279,33 @@ if result.get("__interrupt__"): :::js ```typescript -// TODO: Add JS implementation +const config = { configurable: { thread_id: uuidv4() } }; + +let result = await agent.invoke({ + messages: [{ + role: "user", + content: "Delete temp.txt and send an email to admin@example.com" + }] +}, config); + +if (result.__interrupt__) { + const interrupts = result.__interrupt__[0].value; + const actionRequests = interrupts.actionRequests; + + // Two tools need approval + console.assert(actionRequests.length === 2); + + // Provide decisions in the same order as actionRequests + const decisions = [ + { type: "approve" }, // First tool: delete_file + { type: "reject" } // Second tool: send_email + ]; + + result = await agent.invoke( + new Command({ resume: { decisions } }), + config + ); +} ``` ::: @@ -215,7 +340,27 @@ if result.get("__interrupt__"): :::js ```typescript -// TODO: Add JS implementation +if (result.__interrupt__) { + const interrupts = result.__interrupt__[0].value; + const actionRequest = interrupts.actionRequests[0]; + + // Original args from the agent + console.log(actionRequest.args); // { to: "everyone@company.com", ... } + + // User decides to edit the recipient + const decisions = [{ + type: "edit", + editedAction: { + name: actionRequest.name, // Must include the tool name + args: { to: "team@company.com", subject: "...", body: "..." } + } + }]; + + result = await agent.invoke( + new Command({ resume: { decisions } }), + config + ); +} ``` ::: @@ -249,7 +394,25 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +const agent = createDeepAgent({ + tools: [deleteFile, readFile], + interruptOn: { + delete_file: true, + read_file: false, + }, + subagents: [{ + name: "file-manager", + description: "Manages file operations", + systemPrompt: "You are a file management assistant.", + tools: [deleteFile, readFile], + interruptOn: { + // Override: require approval for reads in this subagent + delete_file: true, + read_file: true, // Different from main agent! + } + }], + checkpointer +}); ``` ::: diff --git a/src/oss/deepagents/long-term-memory.mdx b/src/oss/deepagents/long-term-memory.mdx index 7594eac82a..001f5e12dd 100644 --- a/src/oss/deepagents/long-term-memory.mdx +++ b/src/oss/deepagents/long-term-memory.mdx @@ -3,51 +3,70 @@ title: Long-term memory description: Learn how to extend deep agents with persistent memory across threads --- -Deep agents come with a local filesystem to offload memory. This filesystem is stored in state and is therefore **transient to a single thread**—files are lost when the conversation ends. +Deep agents come with a local filesystem to offload memory. By default, this filesystem is stored in agent state and is **transient to a single thread**—files are lost when the conversation ends. -You can extend deep agents with **long-term memory** by providing a LangGraph `Store` and setting `use_longterm_memory=True`. This enables persistent storage that survives across threads and conversations. +You can extend deep agents with **long-term memory** by using a **CompositeBackend** that routes specific paths to persistent storage. This enables hybrid storage where some files persist across threads while others remain ephemeral. ## Setup +Configure long-term memory by using a `CompositeBackend` that routes the `/memories/` path to a `StoreBackend`: + :::python ```python from deepagents import create_deep_agent +from deepagents.backends import CompositeBackend, StateBackend, StoreBackend from langgraph.store.memory import InMemoryStore -store = InMemoryStore() # Or any other Store object +def make_backend(runtime): + return CompositeBackend( + default=StateBackend(runtime), # Ephemeral storage + routes={ + "/memories/": StoreBackend(runtime) # Persistent storage + } + ) + agent = create_deep_agent( - store=store, - use_longterm_memory=True + store=InMemoryStore(), # Required for StoreBackend + backend=make_backend ) ``` ::: :::js ```typescript -// TODO: Add JS implementation +import { createDeepAgent } from "deepagents"; +import { CompositeBackend, StateBackend, StoreBackend } from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph-checkpoint"; + +const agent = createDeepAgent({ + store: new InMemoryStore(), // Required for StoreBackend + backend: (config) => new CompositeBackend( + new StateBackend(config), // Ephemeral storage + { "/memories/": new StoreBackend(config) } // Persistent storage + ), +}); ``` ::: ## How it works -When long-term memory is enabled, deep agents maintain **two separate filesystems**: +When using `CompositeBackend`, deep agents maintain **two separate filesystems**: ### 1. Short-term (transient) filesystem -- Stored in the agent's state +- Stored in the agent's state (via `StateBackend`) - Persists only within a single thread - Files are lost when the thread ends -- Accessed through standard paths: `/notes.txt` +- Accessed through standard paths: `/notes.txt`, `/workspace/draft.md` ### 2. Long-term (persistent) filesystem -- Stored in a LangGraph Store +- Stored in a LangGraph Store (via `StoreBackend`) - Persists across all threads and conversations -- Files survive indefinitely -- Accessed through the special prefix: `/memories/notes.txt` - -## The /memories/ path convention +- Survives agent restarts +- Accessed through paths prefixed with `/memories/`: `/memories/preferences.txt` -**The key to long-term memory is the `/memories/` path prefix:** +### Path routing +The `CompositeBackend` routes file operations based on path prefixes: - Files with paths starting with `/memories/` are stored in the Store (persistent) - Files without this prefix remain in transient state - All filesystem tools (`ls`, `read_file`, `write_file`, `edit_file`) work with both @@ -68,7 +87,15 @@ agent.invoke({ :::js ```typescript -// TODO: Add JS implementation +// Transient file (lost after thread ends) +await agent.invoke({ + messages: [{ role: "user", content: "Write draft to /draft.txt" }], +}); + +// Persistent file (survives across threads) +await agent.invoke({ + messages: [{ role: "user", content: "Save final report to /memories/report.txt" }], +}); ``` ::: @@ -97,7 +124,20 @@ agent.invoke({ :::js ```typescript -// TODO: Add JS implementation +import { v4 as uuidv4 } from "uuid"; + +// Thread 1: Write to long-term memory +const config1 = { configurable: { thread_id: uuidv4() } }; +await agent.invoke({ + messages: [{ role: "user", content: "Save my preferences to /memories/preferences.txt" }], +}, config1); + +// Thread 2: Read from long-term memory (different conversation!) +const config2 = { configurable: { thread_id: uuidv4() } }; +await agent.invoke({ + messages: [{ role: "user", content: "What are my preferences?" }], +}, config2); +// Agent can read /memories/preferences.txt from the first thread ``` ::: @@ -110,8 +150,11 @@ Store user preferences that persist across sessions: :::python ```python agent = create_deep_agent( - store=store, - use_longterm_memory=True, + store=InMemoryStore(), + backend=lambda rt: CompositeBackend( + default=StateBackend(rt), + routes={"/memories/": StoreBackend(rt)} + ), system_prompt="""When users tell you their preferences, save them to /memories/user_preferences.txt so you remember them in future conversations.""" ) @@ -120,7 +163,14 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +const agent = createDeepAgent({ + store: new InMemoryStore(), + backend: (config) => new CompositeBackend( + new StateBackend(config), + { "/memories/": new StoreBackend(config) } + ), + systemPrompt: `When users tell you their preferences, save them to /memories/user_preferences.txt so you remember them in future conversations.`, +}); ``` ::: @@ -131,8 +181,11 @@ An agent can update its own instructions based on feedback: :::python ```python agent = create_deep_agent( - store=store, - use_longterm_memory=True, + store=InMemoryStore(), + backend=lambda rt: CompositeBackend( + default=StateBackend(rt), + routes={"/memories/": StoreBackend(rt)} + ), system_prompt="""You have a file at /memories/instructions.txt with additional instructions and preferences. @@ -146,7 +199,18 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +const agent = createDeepAgent({ + store: new InMemoryStore(), + backend: (config) => new CompositeBackend( + new StateBackend(config), + { "/memories/": new StoreBackend(config) } + ), + systemPrompt: `You have a file at /memories/instructions.txt with additional instructions and preferences. + + Read this file at the start of conversations to understand user preferences. + + When users provide feedback like "please always do X" or "I prefer Y", update /memories/instructions.txt using the edit_file tool.`, +}); ``` ::: @@ -173,7 +237,16 @@ agent.invoke({ :::js ```typescript -// TODO: Add JS implementation +// Conversation 1: Learn about a project +await agent.invoke({ + messages: [{ role: "user", content: "We're building a web app with React. Save project notes." }], +}); + +// Conversation 2: Use that knowledge +await agent.invoke({ + messages: [{ role: "user", content: "What framework are we using?" }], +}); +// Agent reads /memories/project_notes.txt from previous conversation ``` ::: @@ -184,8 +257,11 @@ Maintain research state across sessions: :::python ```python research_agent = create_deep_agent( - store=store, - use_longterm_memory=True, + store=InMemoryStore(), + backend=lambda rt: CompositeBackend( + default=StateBackend(rt), + routes={"/memories/": StoreBackend(rt)} + ), system_prompt="""You are a research assistant. Save your research progress to /memories/research/: @@ -200,7 +276,21 @@ research_agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +const researchAgent = createDeepAgent({ + store: new InMemoryStore(), + backend: (config) => new CompositeBackend( + new StateBackend(config), + { "/memories/": new StoreBackend(config) } + ), + systemPrompt: `You are a research assistant. + + Save your research progress to /memories/research/: + - /memories/research/sources.txt - List of sources found + - /memories/research/notes.txt - Key findings and notes + - /memories/research/report.md - Final report draft + + This allows research to continue across multiple sessions.`, +}); ``` ::: @@ -217,13 +307,29 @@ Good for testing and development, but data is lost on restart: from langgraph.store.memory import InMemoryStore store = InMemoryStore() -agent = create_deep_agent(store=store, use_longterm_memory=True) +agent = create_deep_agent( + store=store, + backend=lambda rt: CompositeBackend( + default=StateBackend(rt), + routes={"/memories/": StoreBackend(rt)} + ) +) ``` ::: :::js ```typescript -// TODO: Add JS implementation +import { InMemoryStore } from "@langchain/langgraph-checkpoint"; +import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents"; + +const store = new InMemoryStore(); +const agent = createDeepAgent({ + store, + backend: (config) => new CompositeBackend( + new StateBackend(config), + { "/memories/": new StoreBackend(config) } + ), +}); ``` ::: @@ -237,13 +343,31 @@ from langgraph.store.postgres import PostgresStore import os store = PostgresStore(connection_string=os.environ["DATABASE_URL"]) -agent = create_deep_agent(store=store, use_longterm_memory=True) +agent = create_deep_agent( + store=store, + backend=lambda rt: CompositeBackend( + default=StateBackend(rt), + routes={"/memories/": StoreBackend(rt)} + ) +) ``` ::: :::js ```typescript -// TODO: Add JS implementation +import { PostgresStore } from "@langchain/langgraph-checkpoint-postgres"; +import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents"; + +const store = new PostgresStore({ + connectionString: process.env.DATABASE_URL, +}); +const agent = createDeepAgent({ + store, + backend: (config) => new CompositeBackend( + new StateBackend(config), + { "/memories/": new StoreBackend(config) } + ), +}); ``` ::: @@ -251,125 +375,32 @@ agent = create_deep_agent(store=store, use_longterm_memory=True) ### Use descriptive paths -Organize long-term files with clear, hierarchical paths: - -:::python -```python -# ✅ Good: Organized and descriptive -/memories/user_preferences/language.txt -/memories/projects/project_alpha/status.txt -/memories/research/quantum_computing/sources.txt - -# ❌ Bad: Generic and unorganized -/memories/temp.txt -/memories/data.txt -/memories/file1.txt -``` -::: - -### Document what gets persisted - -In system prompts, clarify when to use long-term vs short-term storage: - -:::python -```python -system_prompt="""You have access to two types of storage: - -SHORT-TERM (paths without /memories/): -- Current conversation notes -- Temporary scratch work -- Draft documents - -LONG-TERM (paths starting with /memories/): -- User preferences and settings -- Completed reports and documents -- Knowledge that should persist across conversations -- Project state and progress - -Always use /memories/ for information that should survive beyond this conversation.""" -``` -::: - -### Isolate storage by assistant ID - -For multi-tenant applications, provide an `assistant_id` to isolate storage: +Organize persistent files with clear paths: -:::python -```python -config = { - "configurable": { - "thread_id": "thread-123", - }, - "metadata": { - "assistant_id": "user-456" # Namespace isolation - } -} - -agent.invoke({"messages": [...]}, config=config) ``` -::: - -Each assistant gets its own namespace in the Store, preventing cross-contamination. - -### Use persistent stores in production - -:::python -```python -# ❌ Development only - data lost on restart -store = InMemoryStore() - -# ✅ Production - data persists -from langgraph.store.postgres import PostgresStore -store = PostgresStore(connection_string=os.environ["DATABASE_URL"]) +/memories/user_preferences.txt +/memories/research/topic_a/sources.txt +/memories/research/topic_a/notes.txt +/memories/project/requirements.md ``` -::: - -## Listing files -The `ls` tool shows files from both filesystems: +### Document the memory structure -:::python -```python -agent.invoke({ - "messages": [{"role": "user", "content": "List all files"}] -}) +Tell the agent what's stored where in your system prompt: -# Example output: -# Transient files: -# - /draft.txt -# - /temp_notes.txt -# -# Long-term files: -# - /memories/user_preferences.txt -# - /memories/project_status.txt ``` -::: - -Files from the Store are prefixed with `/memories/` in listings. - -## Limitations - -### Store is required - -You must provide a Store when enabling long-term memory: - -:::python -```python -# ❌ This will error -agent = create_deep_agent(use_longterm_memory=True) # Missing store! - -# ✅ Correct -agent = create_deep_agent( - use_longterm_memory=True, - store=InMemoryStore() -) +Your persistent memory structure: +- /memories/preferences.txt: User preferences and settings +- /memories/context/: Long-term context about the user +- /memories/knowledge/: Facts and information learned over time ``` -::: -### Agents must use correct paths +### Prune old data -The agent must learn to use the `/memories/` prefix for persistence. The system prompt teaches this, but the agent must follow the instructions. +Implement periodic cleanup of outdated persistent files to keep storage manageable. -### No automatic cleanup +### Choose the right storage -Long-term files persist indefinitely. There's no built-in TTL or automatic cleanup. You'll need to implement cleanup strategies if needed. +- **Development**: Use `InMemoryStore` for quick iteration +- **Production**: Use `PostgresStore` or other persistent stores +- **Multi-tenant**: Consider using assistant_id-based namespacing in your store diff --git a/src/oss/deepagents/middleware.mdx b/src/oss/deepagents/middleware.mdx index 253003f86c..c6677e5ded 100644 --- a/src/oss/deepagents/middleware.mdx +++ b/src/oss/deepagents/middleware.mdx @@ -43,7 +43,19 @@ agent = create_agent( :::js ```typescript -// TODO: Add JS implementation +import { createAgent, todoListMiddleware } from "langchain"; + +// todoListMiddleware is included by default in createDeepAgent +// You can customize it if building a custom agent +const agent = createAgent({ + model: "claude-sonnet-4-5-20250929", + middleware: [ + todoListMiddleware({ + // Optional: Custom addition to the system prompt + systemPrompt: "Use the write_todos tool to...", + }), + ], +}); ``` ::: @@ -58,6 +70,7 @@ Context engineering is a main challenge in building effective agents. This is pa - **write_file**: Write a new file to the filesystem - **edit_file**: Edit an existing file in the filesystem +:::python ```python from langchain.agents import create_agent from deepagents.middleware.filesystem import FilesystemMiddleware @@ -68,7 +81,7 @@ agent = create_agent( model="claude-sonnet-4-5-20250929", middleware=[ FilesystemMiddleware( - long_term_memory=False, # Enables access to long-term memory, defaults to False. You must attach a store to use long-term memory. + backend=None, # Optional: custom backend (defaults to StateBackend) system_prompt="Write to the filesystem when...", # Optional custom addition to the system prompt custom_tool_descriptions={ "ls": "Use the ls tool when...", @@ -78,15 +91,40 @@ agent = create_agent( ], ) ``` +::: + +:::js +```typescript +import { createAgent } from "langchain"; +import { createFilesystemMiddleware } from "deepagents"; + +// FilesystemMiddleware is included by default in createDeepAgent +// You can customize it if building a custom agent +const agent = createAgent({ + model: "claude-sonnet-4-5-20250929", + middleware: [ + createFilesystemMiddleware({ + backend: undefined, // Optional: custom backend (defaults to StateBackend) + systemPrompt: "Write to the filesystem when...", // Optional custom system prompt override + customToolDescriptions: { + ls: "Use the ls tool when...", + read_file: "Use the read_file tool to...", + }, // Optional: Custom descriptions for filesystem tools + }), + ], +}); +``` +::: ### Short-term vs. long-term filesystem -By default, these tools write to a local "filesystem" in your graph state. If you provide a `Store` object to your agent runtime, you can also enable saving to long-term memory, which persists **across** different threads of your agent. +By default, these tools write to a local "filesystem" in your graph state. To enable persistent storage across threads, configure a `CompositeBackend` that routes specific paths (like `/memories/`) to a `StoreBackend`. :::python ```python from langchain.agents import create_agent from deepagents.middleware import FilesystemMiddleware +from deepagents.backends import CompositeBackend, StateBackend, StoreBackend from langgraph.store.memory import InMemoryStore store = InMemoryStore() @@ -96,7 +134,10 @@ agent = create_agent( store=store, middleware=[ FilesystemMiddleware( - long_term_memory=True, + backend=lambda rt: CompositeBackend( + default=StateBackend(rt), + routes={"/memories/": StoreBackend(rt)} + ), custom_tool_descriptions={ "ls": "Use the ls tool when...", "read_file": "Use the read_file tool to..." @@ -109,11 +150,34 @@ agent = create_agent( :::js ```typescript -// TODO: Add JS implementation +import { createAgent } from "langchain"; +import { createFilesystemMiddleware } from "deepagents"; +import { CompositeBackend, StateBackend, StoreBackend } from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph-checkpoint"; + +const store = new InMemoryStore(); + +const agent = createAgent({ + model: "claude-sonnet-4-5-20250929", + store, + middleware: [ + createFilesystemMiddleware({ + backend: (config) => new CompositeBackend( + new StateBackend(config), + { "/memories/": new StoreBackend(config) } + ), + systemPrompt: "Write to the filesystem when...", // Optional custom system prompt override + customToolDescriptions: { + ls: "Use the ls tool when...", + read_file: "Use the read_file tool to...", + }, // Optional: Custom descriptions for filesystem tools + }), + ], +}); ``` ::: -If you enable `use_longterm_memory=True` and provide a `Store` in your agent runtime, then any files prefixed with **/memories/** are saved to the long-term memory store. Note that any agents deployed on LangGraph Platform are automatically provided with a long-term memory store. +When you configure a `CompositeBackend` with a `StoreBackend` for `/memories/`, any files prefixed with **/memories/** are saved to persistent storage and survive across different threads. Files without this prefix remain in ephemeral state storage. ## Subagent middleware @@ -121,6 +185,7 @@ Handing off tasks to subagents isolates context, keeping the main (supervisor) a The subagents middleware allows you to supply subagents through a `task` tool. +:::python ```python from langchain_core.tools import tool from langchain.agents import create_agent @@ -144,7 +209,7 @@ agent = create_agent( "description": "This subagent can get weather in cities.", "system_prompt": "Use the get_weather tool to get the weather in a city.", "tools": [get_weather], - "model": "gpt-4.1", + "model": "gpt-4o", "middleware": [], } ], @@ -152,6 +217,49 @@ agent = create_agent( ], ) ``` +::: + +:::js +```typescript +import { tool } from "langchain"; +import { createAgent } from "langchain"; +import { createSubAgentMiddleware } from "deepagents"; +import { z } from "zod"; + +const getWeather = tool( + async ({ city }: { city: string }) => { + return `The weather in ${city} is sunny.`; + }, + { + name: "get_weather", + description: "Get the weather in a city.", + schema: z.object({ + city: z.string(), + }), + }, +); + +const agent = createAgent({ + model: "claude-sonnet-4-5-20250929", + middleware: [ + createSubAgentMiddleware({ + defaultModel: "claude-sonnet-4-5-20250929", + defaultTools: [], + subagents: [ + { + name: "weather", + description: "This subagent can get weather in cities.", + systemPrompt: "Use the get_weather tool to get the weather in a city.", + tools: [getWeather], + model: "gpt-4o", + middleware: [], + }, + ], + }), + ], +}); +``` +::: A subagent is defined with a **name**, **description**, **system prompt**, and **tools**. You can also provide a subagent with a custom **model**, or with additional **middleware**. This can be particularly useful when you want to give the subagent an additional state key to share with the main agent. @@ -194,7 +302,43 @@ agent = create_agent( :::js ```typescript -// TODO: Add JS implementation +import { tool } from "langchain"; +import { createAgent } from "langchain"; +import { createSubAgentMiddleware, type SubAgent } from "deepagents"; +import { z } from "zod"; + +const getWeather = tool( + async ({ city }: { city: string }) => { + return `The weather in ${city} is sunny.`; + }, + { + name: "get_weather", + description: "Get the weather in a city.", + schema: z.object({ + city: z.string(), + }), + }, +); + +const weatherSubagent: SubAgent = { + name: "weather", + description: "This subagent can get weather in cities.", + systemPrompt: "Use the get_weather tool to get the weather in a city.", + tools: [getWeather], + model: "gpt-4o", + middleware: [], +}; + +const agent = createAgent({ + model: "claude-sonnet-4-5-20250929", + middleware: [ + createSubAgentMiddleware({ + defaultModel: "claude-sonnet-4-5-20250929", + defaultTools: [], + subagents: [weatherSubagent], + }), + ], +}); ``` ::: diff --git a/src/oss/deepagents/quickstart.mdx b/src/oss/deepagents/quickstart.mdx index 2a60af41ed..97d51ae980 100644 --- a/src/oss/deepagents/quickstart.mdx +++ b/src/oss/deepagents/quickstart.mdx @@ -11,6 +11,7 @@ Before you begin, make sure you have an API key from a model provider (e.g., Ant ### Step 1: Install dependencies +:::python ```bash pip pip install deepagents tavily-python @@ -24,6 +25,23 @@ Before you begin, make sure you have an API key from a model provider (e.g., Ant poetry add deepagents tavily-python ``` +::: + +:::js + + ```bash npm + npm install deepagents @langchain/tavily + ``` + + ```bash yarn + yarn add deepagents @langchain/tavily + ``` + + ```bash pnpm + pnpm add deepagents @langchain/tavily + ``` + +::: ### Step 2: Set up your API keys @@ -61,12 +79,59 @@ def internet_search( :::js ```typescript -// TODO: Add JS implementation +import { tool } from "langchain"; +import { TavilySearch } from "@langchain/tavily"; +import { z } from "zod"; + +const internetSearch = tool( + async ({ + query, + maxResults = 5, + topic = "general", + includeRawContent = false, + }: { + query: string; + maxResults?: number; + topic?: "general" | "news" | "finance"; + includeRawContent?: boolean; + }) => { + const tavilySearch = new TavilySearch({ + maxResults, + tavilyApiKey: process.env.TAVILY_API_KEY, + includeRawContent, + topic, + }); + return await tavilySearch._call({ query }); + }, + { + name: "internet_search", + description: "Run a web search", + schema: z.object({ + query: z.string().describe("The search query"), + maxResults: z + .number() + .optional() + .default(5) + .describe("Maximum number of results to return"), + topic: z + .enum(["general", "news", "finance"]) + .optional() + .default("general") + .describe("Search topic category"), + includeRawContent: z + .boolean() + .optional() + .default(false) + .describe("Whether to include raw content"), + }), + }, +); ``` ::: ### Step 4: Create a deep agent +:::python ```python # System prompt to steer the agent to be an expert researcher research_instructions = """You are an expert researcher. Your job is to conduct thorough research and then write a polished report. @@ -83,15 +148,50 @@ agent = create_deep_agent( system_prompt=research_instructions ) ``` +::: + +:::js +```typescript +import { createDeepAgent } from "deepagents"; + +// System prompt to steer the agent to be an expert researcher +const researchInstructions = `You are an expert researcher. Your job is to conduct thorough research and then write a polished report. + +You have access to an internet search tool as your primary means of gathering information. + +## \`internet_search\` + +Use this to run an internet search for a given query. You can specify the max number of results to return, the topic, and whether raw content should be included. +`; + +const agent = createDeepAgent({ + tools: [internetSearch], + systemPrompt: researchInstructions, +}); +``` +::: ### Step 5: Run the agent +:::python ```python result = agent.invoke({"messages": [{"role": "user", "content": "What is langgraph?"}]}) # Print the agent's response print(result["messages"][-1].content) ``` +::: + +:::js +```typescript +const result = await agent.invoke({ + messages: [{ role: "user", content: "What is langgraph?" }], +}); + +// Print the agent's response +console.log(result.messages[result.messages.length - 1].content); +``` +::: ## What happened? diff --git a/src/oss/deepagents/subagents.mdx b/src/oss/deepagents/subagents.mdx index e2d1169507..19e0b07480 100644 --- a/src/oss/deepagents/subagents.mdx +++ b/src/oss/deepagents/subagents.mdx @@ -50,6 +50,7 @@ For complex workflows, use a pre-built LangGraph graph: ## Using SubAgent +:::python ```python import os from typing import Literal @@ -86,6 +87,66 @@ agent = create_deep_agent( subagents=subagents ) ``` +::: + +:::js +```typescript +import { tool } from "langchain"; +import { TavilySearch } from "@langchain/tavily"; +import { createDeepAgent } from "deepagents"; +import { ChatAnthropic } from "@langchain/anthropic"; +import { z } from "zod"; + +const internetSearch = tool( + async ({ + query, + maxResults = 5, + topic = "general", + includeRawContent = false, + }: { + query: string; + maxResults?: number; + topic?: "general" | "news" | "finance"; + includeRawContent?: boolean; + }) => { + const tavilySearch = new TavilySearch({ + maxResults, + tavilyApiKey: process.env.TAVILY_API_KEY, + includeRawContent, + topic, + }); + return await tavilySearch._call({ query }); + }, + { + name: "internet_search", + description: "Run a web search", + schema: z.object({ + query: z.string().describe("The search query"), + maxResults: z.number().optional().default(5), + topic: z + .enum(["general", "news", "finance"]) + .optional() + .default("general"), + includeRawContent: z.boolean().optional().default(false), + }), + }, +); + +const researchSubagent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: new ChatAnthropic({model:"claude-sonnet-4-5-20250929"}), // Optional override, defaults to main agent model +}; +const subagents = [researchSubagent]; + +const agent = createDeepAgent({ + model: new ChatAnthropic({model:"claude-sonnet-4-5-20250929"}), + subagents: subagents, +}); +``` +::: ## Using CompiledSubAgent @@ -123,7 +184,31 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +import { createDeepAgent, CompiledSubAgent } from "deepagents"; +import { createAgent } from "langchain"; + +// Create a custom agent graph +const customGraph = createAgent({ + model: yourModel, + tools: specializedTools, + prompt: "You are a specialized agent for data analysis...", +}); + +// Use it as a custom subagent +const customSubagent: CompiledSubAgent = { + name: "data-analyzer", + description: "Specialized agent for complex data analysis tasks", + runnable: customGraph, +}; + +const subagents = [customSubagent]; + +const agent = createDeepAgent({ + model: "claude-sonnet-4-5-20250929", + tools: [internetSearch], + systemPrompt: researchInstructions, + subagents: subagents, +}); ``` ::: @@ -181,7 +266,24 @@ research_subagent = { :::js ```typescript -// TODO: Add JS implementation +const researchSubagent = { + name: "research-agent", + description: "Conducts in-depth research using web search and synthesizes findings", + systemPrompt: `You are a thorough researcher. Your job is to: + + 1. Break down the research question into searchable queries + 2. Use internet_search to find relevant information + 3. Synthesize findings into a comprehensive but concise summary + 4. Cite sources when making claims + + Output format: + - Summary (2-3 paragraphs) + - Key findings (bullet points) + - Sources (with URLs) + + Keep your response under 500 words to maintain clean context.`, + tools: [internetSearch], +}; ``` ::: @@ -207,7 +309,17 @@ email_agent = { :::js ```typescript -// TODO: Add JS implementation +// ✅ Good: Focused tool set +const emailAgent = { + name: "email-sender", + tools: [sendEmail, validateEmail], // Only email-related +}; + +// ❌ Bad: Too many tools +const emailAgentBad = { + name: "email-sender", + tools: [sendEmail, webSearch, databaseQuery, fileUpload], // Unfocused +}; ``` ::: @@ -230,7 +342,7 @@ subagents = [ "description": "Analyzes financial data and market trends", "system_prompt": "You are an expert financial analyst...", "tools": [get_stock_price, analyze_fundamentals], - "model": "openai:gpt-4o", # Better for numerical analysis + "model": "openai:gpt-5", # Better for numerical analysis }, ] ``` @@ -238,7 +350,22 @@ subagents = [ :::js ```typescript -// TODO: Add JS implementation +const subagents = [ + { + name: "contract-reviewer", + description: "Reviews legal documents and contracts", + systemPrompt: "You are an expert legal reviewer...", + tools: [readDocument, analyzeContract], + model: "claude-sonnet-4-5-20250929", // Large context for long documents + }, + { + name: "financial-analyst", + description: "Analyzes financial data and market trends", + systemPrompt: "You are an expert financial analyst...", + tools: [getStockPrice, analyzeFundamentals], + model: "gpt-5", // Better for numerical analysis + }, +]; ``` ::: @@ -266,7 +393,19 @@ data_analyst = { :::js ```typescript -// TODO: Add JS implementation +const dataAnalyst = { + systemPrompt: `Analyze the data and return: + 1. Key insights (3-5 bullet points) + 2. Overall confidence score + 3. Recommended next actions + + Do NOT include: + - Raw data + - Intermediate calculations + - Detailed tool outputs + + Keep response under 300 words.`, +}; ``` ::: @@ -311,7 +450,34 @@ agent = create_deep_agent( :::js ```typescript -// TODO: Add JS implementation +import { createDeepAgent } from "deepagents"; + +const subagents = [ + { + name: "data-collector", + description: "Gathers raw data from various sources", + systemPrompt: "Collect comprehensive data on the topic", + tools: [webSearch, apiCall, databaseQuery], + }, + { + name: "data-analyzer", + description: "Analyzes collected data for insights", + systemPrompt: "Analyze data and extract key insights", + tools: [statisticalAnalysis], + }, + { + name: "report-writer", + description: "Writes polished reports from analysis", + systemPrompt: "Create professional reports from insights", + tools: [formatDocument], + }, +]; + +const agent = createDeepAgent({ + model: "claude-sonnet-4-5-20250929", + systemPrompt: "You coordinate data analysis and reporting. Use subagents for specialized tasks.", + subagents: subagents, +}); ``` ::: @@ -333,6 +499,8 @@ Each subagent works with clean context focused only on its task. **Solutions**: 1. **Make descriptions more specific:** + + :::python ```python # ✅ Good {"name": "research-specialist", "description": "Conducts in-depth research on specific topics using web search. Use when you need detailed information that requires multiple searches."} @@ -340,8 +508,21 @@ Each subagent works with clean context focused only on its task. # ❌ Bad {"name": "helper", "description": "helps with stuff"} ``` + ::: + + :::js + ```typescript + // ✅ Good + { name: "research-specialist", description: "Conducts in-depth research on specific topics using web search. Use when you need detailed information that requires multiple searches." } + + // ❌ Bad + { name: "helper", description: "helps with stuff" } + ``` + ::: 2. **Instruct main agent to delegate:** + + :::python ```python agent = create_deep_agent( system_prompt="""...your instructions... @@ -351,6 +532,19 @@ Each subagent works with clean context focused only on its task. subagents=[...] ) ``` + ::: + + :::js + ```typescript + const agent = createDeepAgent({ + systemPrompt: `...your instructions... + + IMPORTANT: For complex tasks, delegate to your subagents using the task() tool. + This keeps your context clean and improves results.`, + subagents: [...] + }); + ``` + ::: ### Context still getting bloated @@ -359,6 +553,8 @@ Each subagent works with clean context focused only on its task. **Solutions**: 1. **Instruct subagent to return concise results:** + + :::python ```python system_prompt="""... @@ -366,8 +562,21 @@ Each subagent works with clean context focused only on its task. Do NOT include raw data, intermediate search results, or detailed tool outputs. Your response should be under 500 words.""" ``` + ::: + + :::js + ```typescript + systemPrompt: `... + + IMPORTANT: Return only the essential summary. + Do NOT include raw data, intermediate search results, or detailed tool outputs. + Your response should be under 500 words.` + ``` + ::: 2. **Use filesystem for large data:** + + :::python ```python system_prompt="""When you gather large amounts of data: 1. Save raw data to /data/raw_results.txt @@ -376,6 +585,18 @@ Each subagent works with clean context focused only on its task. This keeps context clean.""" ``` + ::: + + :::js + ```typescript + systemPrompt: `When you gather large amounts of data: + 1. Save raw data to /data/raw_results.txt + 2. Process and analyze the data + 3. Return only the analysis summary + + This keeps context clean.` + ``` + ::: ### Wrong subagent being selected @@ -383,6 +604,7 @@ Each subagent works with clean context focused only on its task. **Solution**: Differentiate subagents clearly in descriptions: +:::python ```python subagents = [ { @@ -395,3 +617,19 @@ subagents = [ } ] ``` +::: + +:::js +```typescript +const subagents = [ + { + name: "quick-researcher", + description: "For simple, quick research questions that need 1-2 searches. Use when you need basic facts or definitions.", + }, + { + name: "deep-researcher", + description: "For complex, in-depth research requiring multiple searches, synthesis, and analysis. Use for comprehensive reports.", + } +]; +``` +::: diff --git a/src/oss/reference/deepagents-javascript.mdx b/src/oss/reference/deepagents-javascript.mdx new file mode 100644 index 0000000000..bd59558703 --- /dev/null +++ b/src/oss/reference/deepagents-javascript.mdx @@ -0,0 +1,4 @@ +--- +title: Deep Agents +url: https://reference.langchain.com/javascript/deepagents/ +--- From 300778970486cc12cc18843c381733b8e430bb28 Mon Sep 17 00:00:00 2001 From: nhuang-lc Date: Thu, 6 Nov 2025 06:59:22 -0800 Subject: [PATCH 2/4] Update src/oss/deepagents/middleware.mdx Co-authored-by: Christian Bromann --- src/oss/deepagents/middleware.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/oss/deepagents/middleware.mdx b/src/oss/deepagents/middleware.mdx index c6677e5ded..4aa6112eda 100644 --- a/src/oss/deepagents/middleware.mdx +++ b/src/oss/deepagents/middleware.mdx @@ -151,8 +151,7 @@ agent = create_agent( :::js ```typescript import { createAgent } from "langchain"; -import { createFilesystemMiddleware } from "deepagents"; -import { CompositeBackend, StateBackend, StoreBackend } from "deepagents"; +import { createFilesystemMiddleware, CompositeBackend, StateBackend, StoreBackend } from "deepagents"; import { InMemoryStore } from "@langchain/langgraph-checkpoint"; const store = new InMemoryStore(); From 7b8bfc00bb143dd4c93262caf6b5ff529ab29f5d Mon Sep 17 00:00:00 2001 From: nhuang-lc Date: Thu, 6 Nov 2025 06:59:28 -0800 Subject: [PATCH 3/4] Update src/oss/deepagents/middleware.mdx Co-authored-by: Christian Bromann --- src/oss/deepagents/middleware.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/oss/deepagents/middleware.mdx b/src/oss/deepagents/middleware.mdx index 4aa6112eda..759b35d3cf 100644 --- a/src/oss/deepagents/middleware.mdx +++ b/src/oss/deepagents/middleware.mdx @@ -301,8 +301,7 @@ agent = create_agent( :::js ```typescript -import { tool } from "langchain"; -import { createAgent } from "langchain"; +import { tool, createAgent } from "langchain"; import { createSubAgentMiddleware, type SubAgent } from "deepagents"; import { z } from "zod"; From 5a428b84dcf54003b34a210e24381b974b52fd75 Mon Sep 17 00:00:00 2001 From: nhuang-lc Date: Thu, 6 Nov 2025 06:59:33 -0800 Subject: [PATCH 4/4] Update src/oss/deepagents/backends.mdx Co-authored-by: Christian Bromann --- src/oss/deepagents/backends.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/oss/deepagents/backends.mdx b/src/oss/deepagents/backends.mdx index 2dcd90d210..1d1c2d56bc 100644 --- a/src/oss/deepagents/backends.mdx +++ b/src/oss/deepagents/backends.mdx @@ -39,8 +39,7 @@ agent = create_deep_agent( :::js ```typescript -import { createDeepAgent } from "deepagents"; -import { StateBackend } from "deepagents"; +import { createDeepAgent, StateBackend } from "deepagents"; // By default we provide a StateBackend const agent = createDeepAgent();