From ca4ed8df63b8b4e6f83f9187edd39dfef25927de Mon Sep 17 00:00:00 2001 From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com> Date: Fri, 15 May 2026 11:03:51 +0200 Subject: [PATCH] make existing snippets testable (#4010) --- .github/workflows/test-code-samples.yml | 1 + pyproject.toml | 1 + .../customization-backend-composite.ts | 23 + .../customization-backend-filesystem.ts | 13 + .../customization-backend-local-shell.ts | 14 + .../deepagents/customization-backend-state.ts | 15 + .../deepagents/customization-backend-store.ts | 18 + .../deepagents/customization-backends.py | 88 ++++ .../deepagents/customization-hitl-basic.py | 45 ++ .../deepagents/customization-hitl-basic.ts | 74 ++++ .../customization-skills-usage-filesystem.ts | 33 ++ .../customization-skills-usage-state.ts | 56 +++ .../customization-skills-usage-store.ts | 52 +++ .../deepagents/customization-skills-usage.py | 117 ++++++ .../customization-subagent-basic.py | 46 ++ .../customization-subagent-basic.ts} | 13 +- .../deepagents/skills/langgraph-docs/SKILL.md | 28 ++ src/code-samples/package-lock.json | 35 ++ src/code-samples/package.json | 1 + src/oss/deepagents/backends.mdx | 26 +- src/oss/deepagents/customization.mdx | 34 +- src/oss/deepagents/human-in-the-loop.mdx | 4 +- src/oss/deepagents/subagents.mdx | 4 +- src/snippets/backend-composite-js.mdx | 15 - src/snippets/backend-store-js.mdx | 16 - .../code-samples/backend-composite-js.mdx | 18 + .../backend-composite-py.mdx | 4 +- .../backend-context-hub-py.mdx | 3 +- .../backend-filesystem-js.mdx | 3 +- .../backend-filesystem-py.mdx | 3 +- .../backend-local-shell-js.mdx | 7 +- .../backend-local-shell-py.mdx | 3 +- .../{ => code-samples}/backend-state-js.mdx | 2 +- .../{ => code-samples}/backend-state-py.mdx | 9 +- .../code-samples/backend-store-js.mdx | 13 + .../{ => code-samples}/backend-store-py.mdx | 9 +- .../hitl-basic-config-js.mdx | 34 +- .../hitl-basic-config-py.mdx | 20 +- .../skills-usage-filesystem-js.mdx | 27 ++ .../skills-usage-filesystem-py.mdx | 29 ++ .../code-samples/skills-usage-state-js.mdx | 43 ++ .../code-samples/skills-usage-state-py.mdx | 260 ++++++++++++ .../code-samples/skills-usage-store-js.mdx | 46 ++ .../code-samples/skills-usage-store-py.mdx | 34 ++ .../code-samples/subagent-basic-js.mdx | 393 ++++++++++++++++++ .../{ => code-samples}/subagent-basic-py.mdx | 10 +- src/snippets/skills-usage-tabs-js.mdx | 165 +------- src/snippets/skills-usage-tabs-py.mdx | 125 +----- uv.lock | 6 + 49 files changed, 1654 insertions(+), 384 deletions(-) create mode 100644 src/code-samples/deepagents/customization-backend-composite.ts create mode 100644 src/code-samples/deepagents/customization-backend-filesystem.ts create mode 100644 src/code-samples/deepagents/customization-backend-local-shell.ts create mode 100644 src/code-samples/deepagents/customization-backend-state.ts create mode 100644 src/code-samples/deepagents/customization-backend-store.ts create mode 100644 src/code-samples/deepagents/customization-backends.py create mode 100644 src/code-samples/deepagents/customization-hitl-basic.py create mode 100644 src/code-samples/deepagents/customization-hitl-basic.ts create mode 100644 src/code-samples/deepagents/customization-skills-usage-filesystem.ts create mode 100644 src/code-samples/deepagents/customization-skills-usage-state.ts create mode 100644 src/code-samples/deepagents/customization-skills-usage-store.ts create mode 100644 src/code-samples/deepagents/customization-skills-usage.py create mode 100644 src/code-samples/deepagents/customization-subagent-basic.py rename src/{snippets/subagent-basic-js.mdx => code-samples/deepagents/customization-subagent-basic.ts} (82%) create mode 100644 src/code-samples/deepagents/skills/langgraph-docs/SKILL.md delete mode 100644 src/snippets/backend-composite-js.mdx delete mode 100644 src/snippets/backend-store-js.mdx create mode 100644 src/snippets/code-samples/backend-composite-js.mdx rename src/snippets/{ => code-samples}/backend-composite-py.mdx (81%) rename src/snippets/{ => code-samples}/backend-context-hub-py.mdx (62%) rename src/snippets/{ => code-samples}/backend-filesystem-js.mdx (76%) rename src/snippets/{ => code-samples}/backend-filesystem-py.mdx (57%) rename src/snippets/{ => code-samples}/backend-local-shell-js.mdx (57%) rename src/snippets/{ => code-samples}/backend-local-shell-py.mdx (51%) rename src/snippets/{ => code-samples}/backend-state-js.mdx (94%) rename src/snippets/{ => code-samples}/backend-state-py.mdx (72%) create mode 100644 src/snippets/code-samples/backend-store-js.mdx rename src/snippets/{ => code-samples}/backend-store-py.mdx (52%) rename src/snippets/{ => code-samples}/hitl-basic-config-js.mdx (63%) rename src/snippets/{ => code-samples}/hitl-basic-config-py.mdx (56%) create mode 100644 src/snippets/code-samples/skills-usage-filesystem-js.mdx create mode 100644 src/snippets/code-samples/skills-usage-filesystem-py.mdx create mode 100644 src/snippets/code-samples/skills-usage-state-js.mdx create mode 100644 src/snippets/code-samples/skills-usage-state-py.mdx create mode 100644 src/snippets/code-samples/skills-usage-store-js.mdx create mode 100644 src/snippets/code-samples/skills-usage-store-py.mdx create mode 100644 src/snippets/code-samples/subagent-basic-js.mdx rename src/snippets/{ => code-samples}/subagent-basic-py.mdx (91%) diff --git a/.github/workflows/test-code-samples.yml b/.github/workflows/test-code-samples.yml index 943efb164..b395ed4a0 100644 --- a/.github/workflows/test-code-samples.yml +++ b/.github/workflows/test-code-samples.yml @@ -117,6 +117,7 @@ jobs: env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} POSTGRES_URI: postgresql://postgres:postgres@127.0.0.1:5432/postgres?sslmode=disable TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }} GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} diff --git a/pyproject.toml b/pyproject.toml index 593e65b15..3b5291a3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ dependencies = [ "langchain-google-genai>=2.0.0", "langchain-daytona>=0.0.5", "daytona>=0.100.0", + "langchain-quickjs>=0.1.2", ] diff --git a/src/code-samples/deepagents/customization-backend-composite.ts b/src/code-samples/deepagents/customization-backend-composite.ts new file mode 100644 index 000000000..5da4a2ba7 --- /dev/null +++ b/src/code-samples/deepagents/customization-backend-composite.ts @@ -0,0 +1,23 @@ +// :snippet-start: backend-composite-js +import { + createDeepAgent, + CompositeBackend, + StateBackend, + StoreBackend, +} from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph"; + +const store = new InMemoryStore(); +// KEEP MODEL +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + backend: new CompositeBackend(new StateBackend(), { + "/memories/": new StoreBackend(), + }), + store, +}); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-backend-filesystem.ts b/src/code-samples/deepagents/customization-backend-filesystem.ts new file mode 100644 index 000000000..87a472a16 --- /dev/null +++ b/src/code-samples/deepagents/customization-backend-filesystem.ts @@ -0,0 +1,13 @@ +// :snippet-start: backend-filesystem-js +import { createDeepAgent, FilesystemBackend } from "deepagents"; + +// KEEP MODEL +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }), +}); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-backend-local-shell.ts b/src/code-samples/deepagents/customization-backend-local-shell.ts new file mode 100644 index 000000000..9862b4236 --- /dev/null +++ b/src/code-samples/deepagents/customization-backend-local-shell.ts @@ -0,0 +1,14 @@ +// :snippet-start: backend-local-shell-js +import { createDeepAgent, LocalShellBackend } from "deepagents"; + +const backend = new LocalShellBackend({ workingDirectory: "." }); +// KEEP MODEL +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + backend, +}); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-backend-state.ts b/src/code-samples/deepagents/customization-backend-state.ts new file mode 100644 index 000000000..4755c034f --- /dev/null +++ b/src/code-samples/deepagents/customization-backend-state.ts @@ -0,0 +1,15 @@ +// :snippet-start: backend-state-js +import { createDeepAgent, StateBackend } from "deepagents"; + +// By default we provide a StateBackend +const agent = createDeepAgent(); + +// Under the hood, it looks like +const agent2 = createDeepAgent({ + backend: new StateBackend(), +}); +// :snippet-end: + +// :remove-start: +if (!agent || !agent2) throw new Error("agents not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-backend-store.ts b/src/code-samples/deepagents/customization-backend-store.ts new file mode 100644 index 000000000..b4cb6476c --- /dev/null +++ b/src/code-samples/deepagents/customization-backend-store.ts @@ -0,0 +1,18 @@ +// :snippet-start: backend-store-js +import { createDeepAgent, StoreBackend } from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph"; + +const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment +// KEEP MODEL +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + backend: new StoreBackend({ + namespace: (ctx) => [ctx.runtime.context.userId], + }), + store, +}); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-backends.py b/src/code-samples/deepagents/customization-backends.py new file mode 100644 index 000000000..78570ff6b --- /dev/null +++ b/src/code-samples/deepagents/customization-backends.py @@ -0,0 +1,88 @@ +"""Customization: virtual filesystem backend examples.""" + +# :snippet-start: backend-state-py +from deepagents import create_deep_agent +from deepagents.backends import StateBackend + +# By default we provide a StateBackend +# KEEP MODEL +agent = create_deep_agent(model="google_genai:gemini-3.1-pro-preview") + +# Under the hood, it looks like +# KEEP MODEL +agent2 = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=StateBackend(), +) +# :snippet-end: + +# :snippet-start: backend-filesystem-py +from deepagents import create_deep_agent +from deepagents.backends import FilesystemBackend + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=FilesystemBackend(root_dir=".", virtual_mode=True), +) +# :snippet-end: + +# :snippet-start: backend-local-shell-py +from deepagents import create_deep_agent +from deepagents.backends import LocalShellBackend + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=LocalShellBackend(root_dir=".", virtual_mode=True, env={"PATH": "/usr/bin:/bin"}), +) +# :snippet-end: + +# :snippet-start: backend-store-py +from deepagents import create_deep_agent +from deepagents.backends import StoreBackend +from langgraph.store.memory import InMemoryStore + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=StoreBackend( + namespace=lambda ctx: (ctx.runtime.context.user_id,), + ), + store=InMemoryStore(), # Good for local dev; omit for LangSmith Deployment +) +# :snippet-end: + +# :snippet-start: backend-context-hub-py +from deepagents import create_deep_agent +from deepagents.backends import ContextHubBackend + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=ContextHubBackend("my-agent"), +) +# :snippet-end: + +# :snippet-start: backend-composite-py +from deepagents import create_deep_agent +from deepagents.backends import CompositeBackend, StateBackend, StoreBackend +from langgraph.store.memory import InMemoryStore + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=CompositeBackend( + default=StateBackend(), + routes={ + "/memories/": StoreBackend(), + }, + ), + store=InMemoryStore(), # Store passed to create_deep_agent, not backend +) +# :snippet-end: + +# :remove-start: +assert agent is not None +assert agent2 is not None +# :remove-end: diff --git a/src/code-samples/deepagents/customization-hitl-basic.py b/src/code-samples/deepagents/customization-hitl-basic.py new file mode 100644 index 000000000..6545a6c54 --- /dev/null +++ b/src/code-samples/deepagents/customization-hitl-basic.py @@ -0,0 +1,45 @@ +"""Customization: human-in-the-loop interrupt_on example.""" + +# :snippet-start: hitl-basic-config-py +from langchain.tools import tool +from deepagents import create_deep_agent +from langgraph.checkpoint.memory import MemorySaver + + +@tool +def remove_file(path: str) -> str: + """Delete a file from the filesystem.""" + return f"Deleted {path}" + + +@tool +def fetch_file(path: str) -> str: + """Read a file from the filesystem.""" + return f"Contents of {path}" + + +@tool +def notify_email(to: str, subject: str, body: str) -> str: + """Send an email.""" + return f"Sent email to {to}" + + +# Checkpointer is REQUIRED for human-in-the-loop +checkpointer = MemorySaver() + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + tools=[remove_file, fetch_file, notify_email], + interrupt_on={ + "remove_file": True, # Default: approve, edit, reject, respond + "fetch_file": False, # No interrupts needed + "notify_email": {"allowed_decisions": ["approve", "reject"]}, # No editing + }, + checkpointer=checkpointer, # Required! +) +# :snippet-end: + +# :remove-start: +assert agent is not None +# :remove-end: diff --git a/src/code-samples/deepagents/customization-hitl-basic.ts b/src/code-samples/deepagents/customization-hitl-basic.ts new file mode 100644 index 000000000..cacf9ca87 --- /dev/null +++ b/src/code-samples/deepagents/customization-hitl-basic.ts @@ -0,0 +1,74 @@ +// :snippet-start: hitl-basic-config-js +import { tool } from "langchain"; +import { createDeepAgent } from "deepagents"; +import { MemorySaver } from "@langchain/langgraph"; +import { z } from "zod"; + +const removeFile = tool( + async ({ path }: { path: string }) => { + return `Deleted ${path}`; + }, + { + name: "remove_file", + description: "Delete a file from the filesystem.", + schema: z.object({ + path: z.string(), + }), + }, +); + +const fetchFile = tool( + async ({ path }: { path: string }) => { + return `Contents of ${path}`; + }, + { + name: "fetch_file", + description: "Read a file from the filesystem.", + schema: z.object({ + path: z.string(), + }), + }, +); + +const notifyEmail = tool( + async ({ + to, + subject, + body, + }: { + to: string; + subject: string; + body: string; + }) => { + return `Sent email to ${to}`; + }, + { + name: "notify_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(); + +// KEEP MODEL +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + tools: [removeFile, fetchFile, notifyEmail], + interruptOn: { + remove_file: true, // Default: approve, edit, reject, respond + fetch_file: false, // No interrupts needed + notify_email: { allowedDecisions: ["approve", "reject"] }, // No editing + }, + checkpointer, // Required! +}); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-skills-usage-filesystem.ts b/src/code-samples/deepagents/customization-skills-usage-filesystem.ts new file mode 100644 index 000000000..2cc01dceb --- /dev/null +++ b/src/code-samples/deepagents/customization-skills-usage-filesystem.ts @@ -0,0 +1,33 @@ +// :snippet-start: skills-usage-filesystem-js +import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; +import { createDeepAgent, FilesystemBackend } from "deepagents"; +import { MemorySaver } from "@langchain/langgraph"; + +const checkpointer = new MemorySaver(); +const backend = new FilesystemBackend({ rootDir: process.cwd() }); + +// KEEP MODEL +const agent = await createDeepAgent({ + model: "google-genai:gemini-3.1-pro-preview", + backend, + skills: ["./examples/skills/"], + interruptOn: { + read_file: true, + write_file: true, + delete_file: true, + }, + checkpointer, // Required! + middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], +}); + +const config = { configurable: { thread_id: `thread-${Date.now()}` } }; +const result = await agent.invoke( + { messages: [{ role: "user", content: "what is langraph?" }] }, + config, +); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +if (!result) throw new Error("result empty"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-skills-usage-state.ts b/src/code-samples/deepagents/customization-skills-usage-state.ts new file mode 100644 index 000000000..d09c6496d --- /dev/null +++ b/src/code-samples/deepagents/customization-skills-usage-state.ts @@ -0,0 +1,56 @@ +import { readFile } from "node:fs/promises"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +// :snippet-start: skills-usage-state-js +import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; +import { createDeepAgent, StateBackend, type FileData } from "deepagents"; +import { MemorySaver } from "@langchain/langgraph"; + +const checkpointer = new MemorySaver(); +const backend = new StateBackend(); + +// :remove-start: +const __dirname = dirname(fileURLToPath(import.meta.url)); +// :remove-end: +function createFileData(content: string): FileData { + const now = new Date().toISOString(); + return { + content: content.split("\n"), + created_at: now, + modified_at: now, + }; +} + +const skillsFiles: Record = {}; +const skillUrl = + "https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md"; +const response = await fetch(skillUrl); +const skillContent = await response.text(); + +skillsFiles["/skills/langgraph-docs/SKILL.md"] = createFileData(skillContent); + +// KEEP MODEL +const agent = await createDeepAgent({ + model: "google-genai:gemini-3.1-pro-preview", + backend, + checkpointer, // Required ! + // IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root. + skills: ["/skills/"], + middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], +}); + +const config = { configurable: { thread_id: `thread-${Date.now()}` } }; +const result = await agent.invoke( + { + messages: [{ role: "user", content: "what is langraph?" }], + files: skillsFiles, + }, + config, +); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +if (!result) throw new Error("result not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-skills-usage-store.ts b/src/code-samples/deepagents/customization-skills-usage-store.ts new file mode 100644 index 000000000..409980ac0 --- /dev/null +++ b/src/code-samples/deepagents/customization-skills-usage-store.ts @@ -0,0 +1,52 @@ +// :snippet-start: skills-usage-store-js +import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; +import { createDeepAgent, StoreBackend, type FileData } from "deepagents"; +import { InMemoryStore, MemorySaver } from "@langchain/langgraph"; + +const checkpointer = new MemorySaver(); +const store = new InMemoryStore(); +const backend = new StoreBackend(); + +function createFileData(content: string): FileData { + const now = new Date().toISOString(); + return { + content: content.split("\n"), + created_at: now, + modified_at: now, + }; +} + +const skillUrl = + "https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md"; + +const response = await fetch(skillUrl); +const skillContent = await response.text(); +const fileData = createFileData(skillContent); + +await store.put(["filesystem"], "/skills/langgraph-docs/SKILL.md", fileData); + +// KEEP MODEL +const agent = await createDeepAgent({ + model: "google-genai:gemini-3.1-pro-preview", + backend, + store, + checkpointer, + // IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root. + skills: ["/skills/"], + middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], +}); + +const config = { + recursionLimit: 50, + configurable: { thread_id: `thread-${Date.now()}` }, +}; +const result = await agent.invoke( + { messages: [{ role: "user", content: "what is langraph?" }] }, + config, +); +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +if (!result) throw new Error("result empty"); +// :remove-end: diff --git a/src/code-samples/deepagents/customization-skills-usage.py b/src/code-samples/deepagents/customization-skills-usage.py new file mode 100644 index 000000000..21d442eda --- /dev/null +++ b/src/code-samples/deepagents/customization-skills-usage.py @@ -0,0 +1,117 @@ +"""Customization: wiring skills with different backends.""" + +# :snippet-start: skills-usage-state-py +from urllib.request import urlopen +from deepagents import create_deep_agent +from deepagents.backends import StateBackend +from deepagents.backends.utils import create_file_data +from langchain_quickjs import CodeInterpreterMiddleware +from langgraph.checkpoint.memory import MemorySaver + +checkpointer = MemorySaver() +backend = StateBackend() + +skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" +with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + +skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), +} + +agent = create_deep_agent( + model="anthropic:claude-sonnet-4-6", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills +) + +result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, +) +# :snippet-end: +assert result is not None + +# :snippet-start: skills-usage-store-py +from urllib.request import urlopen +from deepagents import create_deep_agent +from deepagents.backends import StoreBackend +from deepagents.backends.utils import create_file_data +from langchain_quickjs import CodeInterpreterMiddleware +from langgraph.store.memory import InMemoryStore + +store = InMemoryStore() +backend = StoreBackend() + +skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" +with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + +store.put( + namespace=("filesystem",), + key="/skills/langgraph-docs/SKILL.md", + value=create_file_data(skill_content), +) + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=backend, + store=store, + skills=["/skills/"], + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], +) + +result = agent.invoke( + {"messages": [{"role": "user", "content": "What is langgraph?"}]}, + config={"configurable": {"thread_id": "12345"}}, +) +# :snippet-end: + +from pathlib import Path +# :snippet-start: skills-usage-filesystem-py +from deepagents import create_deep_agent +from deepagents.backends.filesystem import FilesystemBackend +from langchain_quickjs import CodeInterpreterMiddleware +from langgraph.checkpoint.memory import MemorySaver + +# Checkpointer is REQUIRED for human-in-the-loop +checkpointer = MemorySaver() +root_dir = "/Users/user/{project}" +backend = FilesystemBackend(root_dir=root_dir) +# :remove-start: +# Test harness: make test-code-samples runs from the repo root. +example_dir = (Path.cwd() / "src/code-samples/deepagents").resolve() +root_dir = str(example_dir) +backend = FilesystemBackend(root_dir=root_dir, virtual_mode=True) +# :remove-end: + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=backend, + skills=[str(Path(root_dir) / "skills")], + interrupt_on={ + "write_file": True, + "read_file": False, + "edit_file": True, + }, + checkpointer=checkpointer, # Required! + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills +) + +result = agent.invoke( + {"messages": [{"role": "user", "content": "What is langgraph?"}]}, + config={"configurable": {"thread_id": "12345"}}, +) +# :snippet-end: + +# :remove-start: +assert agent is not None +# :remove-end: diff --git a/src/code-samples/deepagents/customization-subagent-basic.py b/src/code-samples/deepagents/customization-subagent-basic.py new file mode 100644 index 000000000..a7e3d971f --- /dev/null +++ b/src/code-samples/deepagents/customization-subagent-basic.py @@ -0,0 +1,46 @@ +"""Customization: subagent configuration example.""" + +# :snippet-start: subagent-basic-py +import os +from typing import Literal + +from deepagents import create_deep_agent +from tavily import TavilyClient + +tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"]) + + +def internet_search( + query: str, + max_results: int = 5, + topic: Literal["general", "news", "finance"] = "general", + include_raw_content: bool = False, +): + """Run a web search""" + return tavily_client.search( + query, + max_results=max_results, + include_raw_content=include_raw_content, + topic=topic, + ) + + +research_subagent = { + "name": "research-agent", + "description": "Used to research more in depth questions", + "system_prompt": "You are a great researcher", + "tools": [internet_search], + "model": "openai:gpt-5.4", # Optional override, defaults to main agent model +} +subagents = [research_subagent] + +# KEEP MODEL +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + subagents=subagents, +) +# :snippet-end: + +# :remove-start: +assert agent is not None +# :remove-end: diff --git a/src/snippets/subagent-basic-js.mdx b/src/code-samples/deepagents/customization-subagent-basic.ts similarity index 82% rename from src/snippets/subagent-basic-js.mdx rename to src/code-samples/deepagents/customization-subagent-basic.ts index 58dd805e2..a91914815 100644 --- a/src/snippets/subagent-basic-js.mdx +++ b/src/code-samples/deepagents/customization-subagent-basic.ts @@ -1,4 +1,4 @@ -```typescript +// :snippet-start: subagent-basic-js import { tool } from "langchain"; import { TavilySearch } from "@langchain/tavily"; import { createDeepAgent, type SubAgent } from "deepagents"; @@ -44,12 +44,17 @@ const researchSubagent: SubAgent = { description: "Used to research more in depth questions", systemPrompt: "You are a great researcher", tools: [internetSearch], - model: "openai:gpt-5.4", // Optional override, defaults to main agent model + model: "openai:gpt-5.4", // Optional override, defaults to main agent model }; const subagents = [researchSubagent]; +// KEEP MODEL const agent = createDeepAgent({ - model: "claude-sonnet-4-6", + model: "google_genai:gemini-3.1-pro-preview", subagents, }); -``` +// :snippet-end: + +// :remove-start: +if (!agent) throw new Error("agent not created"); +// :remove-end: diff --git a/src/code-samples/deepagents/skills/langgraph-docs/SKILL.md b/src/code-samples/deepagents/skills/langgraph-docs/SKILL.md new file mode 100644 index 000000000..bb2126237 --- /dev/null +++ b/src/code-samples/deepagents/skills/langgraph-docs/SKILL.md @@ -0,0 +1,28 @@ +--- +name: langgraph-docs +description: Fetches and references LangGraph Python documentation to build stateful agents, create multi-agent workflows, and implement human-in-the-loop patterns. Use when the user asks about LangGraph, graph agents, state machines, agent orchestration, LangGraph API, or needs LangGraph implementation guidance. +--- + +# langgraph-docs + +## Workflow + +### 1. Fetch the Documentation Index + +Use `fetch_url` to read: https://docs.langchain.com/llms.txt + +This returns a structured list of all available documentation with descriptions. + +### 2. Select Relevant Documentation + +Identify 2-4 most relevant URLs from the index. Prioritize: +- **Implementation questions** — specific how-to guides +- **Conceptual questions** — core concept pages +- **End-to-end examples** — tutorials +- **API details** — reference docs + +### 3. Fetch and Apply + +Use `fetch_url` on the selected URLs, then complete the user's request using the documentation content. + +If `fetch_url` fails or returns empty content, retry once. If it fails again, inform the user and suggest checking https://langchain-ai.github.io/langgraph/ directly. diff --git a/src/code-samples/package-lock.json b/src/code-samples/package-lock.json index 8027ebda8..29b5c5ce8 100644 --- a/src/code-samples/package-lock.json +++ b/src/code-samples/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@langchain/anthropic": "^1.3.22", "@langchain/daytona": "^0.2.0", + "@langchain/google-genai": "^2.1.30", "@langchain/langgraph-checkpoint-postgres": "^1.0.1", "@langchain/openai": "^1.2.12", "@langchain/quickjs": "^0.4.0", @@ -268,6 +269,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1032.0.tgz", "integrity": "sha512-A1wjVhV3IgsZ5td2l4AWgK03EjZ+ldwbiorxuO1hPf7RHJtSdr6oq/gKzyUwP7Tm7ma/M2xS/tplg5C8XB8RWg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", @@ -1440,6 +1442,15 @@ "node": ">=18" } }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@grpc/grpc-js": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", @@ -1583,6 +1594,7 @@ "resolved": "https://registry.npmjs.org/@langchain/core/-/core-1.1.46.tgz", "integrity": "sha512-i8rDC83BpItxChCw4Lf+6tAr+k+OUcbirc5ZkrhI9ywYWmvxegUljLGOGYvtJNTbEAIFkhYIODPE5QRqyjF6sA==", "license": "MIT", + "peer": true, "dependencies": { "@cfworker/json-schema": "^4.0.2", "@standard-schema/spec": "^1.1.0", @@ -1608,6 +1620,21 @@ "deepagents": ">=1.6.0" } }, + "node_modules/@langchain/google-genai": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-2.1.30.tgz", + "integrity": "sha512-0wKgy1NvV89fw5MwYiOOhh18SnUEH20z6MZrPV6Tj2hMAA3jAHVSLlIcCQ2mDRJo2r1aHLV8MDXhzkvD1tEHoQ==", + "license": "MIT", + "dependencies": { + "@google/generative-ai": "^0.24.0" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@langchain/core": "^1.1.43" + } + }, "node_modules/@langchain/langgraph": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-1.3.0.tgz", @@ -1639,6 +1666,7 @@ "resolved": "https://registry.npmjs.org/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-1.0.2.tgz", "integrity": "sha512-F4E5Tr0nt8FGghgdscJtHw+ABzChOHeI80R7Y1pjIHdiJom6c2ieo76vL+FWiny80JmoGqhrVAEIWrw0cXKPxg==", "license": "MIT", + "peer": true, "dependencies": { "uuid": "^10.0.0" }, @@ -1869,6 +1897,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -3372,6 +3401,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3587,6 +3617,7 @@ "resolved": "https://registry.npmjs.org/deepagents/-/deepagents-1.10.2.tgz", "integrity": "sha512-Ptp+t/FgIvMhDbVK0ml3IHcNx3gog3Cbqx+s88H4Hz8ieHG7svuR+/4Mawc/g14FY7mCls7Y8gCcrGb0i3Mi4w==", "license": "MIT", + "peer": true, "dependencies": { "@langchain/core": "^1.1.44", "@langchain/langgraph": "^1.3.0", @@ -4235,6 +4266,7 @@ "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.6.3.tgz", "integrity": "sha512-pXrQ4/4myQvjFFOAUmt5pWRrLEZR20gzIJD7MNdUH+5/S5nLI4ZRBo/SYKC6coaYj9pYTfQdBIzcs+3kfJ5uDA==", "license": "MIT", + "peer": true, "dependencies": { "p-queue": "6.6.2" }, @@ -4501,6 +4533,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.12.0", "pg-pool": "^3.13.0", @@ -4968,6 +5001,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -5187,6 +5221,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/code-samples/package.json b/src/code-samples/package.json index 2e021379b..d8b35f2a8 100644 --- a/src/code-samples/package.json +++ b/src/code-samples/package.json @@ -12,6 +12,7 @@ "dependencies": { "@langchain/anthropic": "^1.3.22", "@langchain/daytona": "^0.2.0", + "@langchain/google-genai": "^2.1.30", "@langchain/langgraph-checkpoint-postgres": "^1.0.1", "@langchain/openai": "^1.2.12", "@langchain/quickjs": "^0.4.0", diff --git a/src/oss/deepagents/backends.mdx b/src/oss/deepagents/backends.mdx index 9d51c3b63..3d7f7a347 100644 --- a/src/oss/deepagents/backends.mdx +++ b/src/oss/deepagents/backends.mdx @@ -3,17 +3,17 @@ title: Backends description: Choose and configure filesystem backends for Deep Agents. You can specify routes to different backends, implement virtual filesystems, and enforce policies. --- -import BackendStatePy from '/snippets/backend-state-py.mdx'; -import BackendStateJs from '/snippets/backend-state-js.mdx'; -import BackendFilesystemPy from '/snippets/backend-filesystem-py.mdx'; -import BackendFilesystemJs from '/snippets/backend-filesystem-js.mdx'; -import BackendLocalShellPy from '/snippets/backend-local-shell-py.mdx'; -import BackendLocalShellJs from '/snippets/backend-local-shell-js.mdx'; -import BackendStorePy from '/snippets/backend-store-py.mdx'; -import BackendStoreJs from '/snippets/backend-store-js.mdx'; -import BackendContextHubPy from '/snippets/backend-context-hub-py.mdx'; -import BackendCompositePy from '/snippets/backend-composite-py.mdx'; -import BackendCompositeJs from '/snippets/backend-composite-js.mdx'; +import BackendStatePy from '/snippets/code-samples/backend-state-py.mdx'; +import BackendStateJs from '/snippets/code-samples/backend-state-js.mdx'; +import BackendFilesystemPy from '/snippets/code-samples/backend-filesystem-py.mdx'; +import BackendFilesystemJs from '/snippets/code-samples/backend-filesystem-js.mdx'; +import BackendLocalShellPy from '/snippets/code-samples/backend-local-shell-py.mdx'; +import BackendLocalShellJs from '/snippets/code-samples/backend-local-shell-js.mdx'; +import BackendStorePy from '/snippets/code-samples/backend-store-py.mdx'; +import BackendStoreJs from '/snippets/code-samples/backend-store-js.mdx'; +import BackendContextHubPy from '/snippets/code-samples/backend-context-hub-py.mdx'; +import BackendCompositePy from '/snippets/code-samples/backend-composite-py.mdx'; +import BackendCompositeJs from '/snippets/code-samples/backend-composite-js.mdx'; Deep Agents expose a filesystem surface to the agent via tools like `ls`, `read_file`, `write_file`, `edit_file`, `glob`, and `grep`. These tools operate through a pluggable backend. The `read_file` tool natively supports image files (`.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`) across all backends, returning them as multimodal content blocks. @@ -218,6 +218,10 @@ Use with extreme caution and only in appropriate environments. ::: + + When deploying to [LangSmith Deployment](/langsmith/deployment), omit the `store` parameter. The platform automatically provisions a store for your agent. + + The `namespace` parameter controls data isolation. For multi-user deployments, always set a [namespace factory](/oss/deepagents/backends#namespace-factories) to isolate data per user or tenant. diff --git a/src/oss/deepagents/customization.mdx b/src/oss/deepagents/customization.mdx index 5796a95e8..57ef6f7c0 100644 --- a/src/oss/deepagents/customization.mdx +++ b/src/oss/deepagents/customization.mdx @@ -6,23 +6,23 @@ description: Learn how to customize Deep Agents with system prompts, tools, suba import ChatModelTabsDaPy from '/snippets/chat-model-tabs-da.mdx'; import ChatModelTabsDaJs from '/snippets/chat-model-tabs-da-js.mdx'; -import HitlBasicConfigPy from '/snippets/hitl-basic-config-py.mdx'; -import HitlBasicConfigJs from '/snippets/hitl-basic-config-js.mdx'; +import HitlBasicConfigPy from '/snippets/code-samples/hitl-basic-config-py.mdx'; +import HitlBasicConfigJs from '/snippets/code-samples/hitl-basic-config-js.mdx'; import SkillsUsageTabsPy from '/snippets/skills-usage-tabs-py.mdx'; import SkillsUsageTabsJs from '/snippets/skills-usage-tabs-js.mdx'; -import BackendStatePy from '/snippets/backend-state-py.mdx'; -import BackendStateJs from '/snippets/backend-state-js.mdx'; -import BackendFilesystemPy from '/snippets/backend-filesystem-py.mdx'; -import BackendFilesystemJs from '/snippets/backend-filesystem-js.mdx'; -import BackendLocalShellPy from '/snippets/backend-local-shell-py.mdx'; -import BackendLocalShellJs from '/snippets/backend-local-shell-js.mdx'; -import BackendStorePy from '/snippets/backend-store-py.mdx'; -import BackendStoreJs from '/snippets/backend-store-js.mdx'; -import BackendContextHubPy from '/snippets/backend-context-hub-py.mdx'; -import BackendCompositePy from '/snippets/backend-composite-py.mdx'; -import BackendCompositeJs from '/snippets/backend-composite-js.mdx'; -import SubagentBasicPy from '/snippets/subagent-basic-py.mdx'; -import SubagentBasicJs from '/snippets/subagent-basic-js.mdx'; +import BackendStatePy from '/snippets/code-samples/backend-state-py.mdx'; +import BackendStateJs from '/snippets/code-samples/backend-state-js.mdx'; +import BackendFilesystemPy from '/snippets/code-samples/backend-filesystem-py.mdx'; +import BackendFilesystemJs from '/snippets/code-samples/backend-filesystem-js.mdx'; +import BackendLocalShellPy from '/snippets/code-samples/backend-local-shell-py.mdx'; +import BackendLocalShellJs from '/snippets/code-samples/backend-local-shell-js.mdx'; +import BackendStorePy from '/snippets/code-samples/backend-store-py.mdx'; +import BackendStoreJs from '/snippets/code-samples/backend-store-js.mdx'; +import BackendContextHubPy from '/snippets/code-samples/backend-context-hub-py.mdx'; +import BackendCompositePy from '/snippets/code-samples/backend-composite-py.mdx'; +import BackendCompositeJs from '/snippets/code-samples/backend-composite-js.mdx'; +import SubagentBasicPy from '/snippets/code-samples/subagent-basic-py.mdx'; +import SubagentBasicJs from '/snippets/code-samples/subagent-basic-js.mdx'; import SandboxBasicPy from '/snippets/deepagents-sandbox-basic-py.mdx'; import SandboxBasicJs from '/snippets/deepagents-sandbox-basic-js.mdx'; import CreateDeepAgentConfigOptionsPy from '/snippets/create-deep-agent-config-options-py.mdx'; @@ -406,6 +406,10 @@ If you are using [skills](#skills) or [memory](#memory), you must add the expect ::: + + When deploying to [LangSmith Deployment](/langsmith/deployment), omit the `store` parameter. The platform automatically provisions a store for your agent. + + The `namespace` parameter controls data isolation. For multi-user deployments, always set a [namespace factory](/oss/deepagents/backends#namespace-factories) to isolate data per user or tenant. diff --git a/src/oss/deepagents/human-in-the-loop.mdx b/src/oss/deepagents/human-in-the-loop.mdx index 02828b44a..ed9089ef3 100644 --- a/src/oss/deepagents/human-in-the-loop.mdx +++ b/src/oss/deepagents/human-in-the-loop.mdx @@ -3,8 +3,8 @@ title: Human-in-the-loop description: Learn how to configure human approval for sensitive tool operations --- -import HitlBasicConfigPy from '/snippets/hitl-basic-config-py.mdx'; -import HitlBasicConfigJs from '/snippets/hitl-basic-config-js.mdx'; +import HitlBasicConfigPy from '/snippets/code-samples/hitl-basic-config-py.mdx'; +import HitlBasicConfigJs from '/snippets/code-samples/hitl-basic-config-js.mdx'; Some tool operations may be sensitive and require human approval before execution. Deep Agents support human-in-the-loop workflows through LangGraph's interrupt capabilities. You can configure which tools require approval using the `interrupt_on` parameter. diff --git a/src/oss/deepagents/subagents.mdx b/src/oss/deepagents/subagents.mdx index 9511aa1c1..13147b88d 100644 --- a/src/oss/deepagents/subagents.mdx +++ b/src/oss/deepagents/subagents.mdx @@ -3,8 +3,8 @@ title: Subagents description: Learn how to use subagents to delegate work and keep context clean --- -import SubagentBasicPy from '/snippets/subagent-basic-py.mdx'; -import SubagentBasicJs from '/snippets/subagent-basic-js.mdx'; +import SubagentBasicPy from '/snippets/code-samples/subagent-basic-py.mdx'; +import SubagentBasicJs from '/snippets/code-samples/subagent-basic-js.mdx'; A deep agent can create subagents to delegate work. You can specify custom subagents in the `subagents` parameter. Subagents are useful for [context quarantine](https://www.dbreunig.com/2025/06/26/how-to-fix-your-context.html#context-quarantine) (keeping the main agent's context clean) and for providing specialized instructions. diff --git a/src/snippets/backend-composite-js.mdx b/src/snippets/backend-composite-js.mdx deleted file mode 100644 index 69a97d4c4..000000000 --- a/src/snippets/backend-composite-js.mdx +++ /dev/null @@ -1,15 +0,0 @@ -```typescript -import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents"; -import { InMemoryStore } from "@langchain/langgraph"; - -const store = new InMemoryStore(); -const agent = createDeepAgent({ - backend: new CompositeBackend( - new StateBackend(), - { - "/memories/": new StoreBackend(), - } - ), - store, -}); -``` diff --git a/src/snippets/backend-store-js.mdx b/src/snippets/backend-store-js.mdx deleted file mode 100644 index 5ba1544de..000000000 --- a/src/snippets/backend-store-js.mdx +++ /dev/null @@ -1,16 +0,0 @@ -```typescript -import { createDeepAgent, StoreBackend } from "deepagents"; -import { InMemoryStore } from "@langchain/langgraph"; - -const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment -const agent = createDeepAgent({ - backend: new StoreBackend({ - namespace: (ctx) => [ctx.runtime.context.userId], - }), - store -}); -``` - - - When deploying to [LangSmith Deployment](/langsmith/deployment), omit the `store` parameter. The platform automatically provisions a store for your agent. - diff --git a/src/snippets/code-samples/backend-composite-js.mdx b/src/snippets/code-samples/backend-composite-js.mdx new file mode 100644 index 000000000..2881d8943 --- /dev/null +++ b/src/snippets/code-samples/backend-composite-js.mdx @@ -0,0 +1,18 @@ +```ts +import { + createDeepAgent, + CompositeBackend, + StateBackend, + StoreBackend, +} from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph"; + +const store = new InMemoryStore(); +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + backend: new CompositeBackend(new StateBackend(), { + "/memories/": new StoreBackend(), + }), + store, +}); +``` diff --git a/src/snippets/backend-composite-py.mdx b/src/snippets/code-samples/backend-composite-py.mdx similarity index 81% rename from src/snippets/backend-composite-py.mdx rename to src/snippets/code-samples/backend-composite-py.mdx index 3f5a89d13..37bd670eb 100644 --- a/src/snippets/backend-composite-py.mdx +++ b/src/snippets/code-samples/backend-composite-py.mdx @@ -9,8 +9,8 @@ agent = create_deep_agent( default=StateBackend(), routes={ "/memories/": StoreBackend(), - } + }, ), - store=InMemoryStore() # Store passed to create_deep_agent, not backend + store=InMemoryStore(), # Store passed to create_deep_agent, not backend ) ``` diff --git a/src/snippets/backend-context-hub-py.mdx b/src/snippets/code-samples/backend-context-hub-py.mdx similarity index 62% rename from src/snippets/backend-context-hub-py.mdx rename to src/snippets/code-samples/backend-context-hub-py.mdx index 8293cb054..0196f9ef0 100644 --- a/src/snippets/backend-context-hub-py.mdx +++ b/src/snippets/code-samples/backend-context-hub-py.mdx @@ -1,8 +1,9 @@ ```python +from deepagents import create_deep_agent from deepagents.backends import ContextHubBackend agent = create_deep_agent( model="google_genai:gemini-3.1-pro-preview", - backend=ContextHubBackend("my-agent") + backend=ContextHubBackend("my-agent"), ) ``` diff --git a/src/snippets/backend-filesystem-js.mdx b/src/snippets/code-samples/backend-filesystem-js.mdx similarity index 76% rename from src/snippets/backend-filesystem-js.mdx rename to src/snippets/code-samples/backend-filesystem-js.mdx index 5171a769a..6c30a334b 100644 --- a/src/snippets/backend-filesystem-js.mdx +++ b/src/snippets/code-samples/backend-filesystem-js.mdx @@ -1,7 +1,8 @@ -```typescript +```ts import { createDeepAgent, FilesystemBackend } from "deepagents"; const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }), }); ``` diff --git a/src/snippets/backend-filesystem-py.mdx b/src/snippets/code-samples/backend-filesystem-py.mdx similarity index 57% rename from src/snippets/backend-filesystem-py.mdx rename to src/snippets/code-samples/backend-filesystem-py.mdx index 91a62ceea..172f6f700 100644 --- a/src/snippets/backend-filesystem-py.mdx +++ b/src/snippets/code-samples/backend-filesystem-py.mdx @@ -1,8 +1,9 @@ ```python +from deepagents import create_deep_agent from deepagents.backends import FilesystemBackend agent = create_deep_agent( model="google_genai:gemini-3.1-pro-preview", - backend=FilesystemBackend(root_dir=".", virtual_mode=True) + backend=FilesystemBackend(root_dir=".", virtual_mode=True), ) ``` diff --git a/src/snippets/backend-local-shell-js.mdx b/src/snippets/code-samples/backend-local-shell-js.mdx similarity index 57% rename from src/snippets/backend-local-shell-js.mdx rename to src/snippets/code-samples/backend-local-shell-js.mdx index 7e5b7382d..8992fe6e5 100644 --- a/src/snippets/backend-local-shell-js.mdx +++ b/src/snippets/code-samples/backend-local-shell-js.mdx @@ -1,6 +1,9 @@ -```typescript +```ts import { createDeepAgent, LocalShellBackend } from "deepagents"; const backend = new LocalShellBackend({ workingDirectory: "." }); -const agent = createDeepAgent({ backend }); +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + backend, +}); ``` diff --git a/src/snippets/backend-local-shell-py.mdx b/src/snippets/code-samples/backend-local-shell-py.mdx similarity index 51% rename from src/snippets/backend-local-shell-py.mdx rename to src/snippets/code-samples/backend-local-shell-py.mdx index 53ab22264..1f9986985 100644 --- a/src/snippets/backend-local-shell-py.mdx +++ b/src/snippets/code-samples/backend-local-shell-py.mdx @@ -1,8 +1,9 @@ ```python +from deepagents import create_deep_agent from deepagents.backends import LocalShellBackend agent = create_deep_agent( model="google_genai:gemini-3.1-pro-preview", - backend=LocalShellBackend(root_dir=".", env={"PATH": "/usr/bin:/bin"}) + backend=LocalShellBackend(root_dir=".", virtual_mode=True, env={"PATH": "/usr/bin:/bin"}), ) ``` diff --git a/src/snippets/backend-state-js.mdx b/src/snippets/code-samples/backend-state-js.mdx similarity index 94% rename from src/snippets/backend-state-js.mdx rename to src/snippets/code-samples/backend-state-js.mdx index 3fc6c476f..8519229c8 100644 --- a/src/snippets/backend-state-js.mdx +++ b/src/snippets/code-samples/backend-state-js.mdx @@ -1,4 +1,4 @@ -```typescript +```ts import { createDeepAgent, StateBackend } from "deepagents"; // By default we provide a StateBackend diff --git a/src/snippets/backend-state-py.mdx b/src/snippets/code-samples/backend-state-py.mdx similarity index 72% rename from src/snippets/backend-state-py.mdx rename to src/snippets/code-samples/backend-state-py.mdx index ca4bd7830..6c4a2bfea 100644 --- a/src/snippets/backend-state-py.mdx +++ b/src/snippets/code-samples/backend-state-py.mdx @@ -1,12 +1,13 @@ ```python +from deepagents import create_deep_agent +from deepagents.backends import StateBackend + # By default we provide a StateBackend agent = create_deep_agent(model="google_genai:gemini-3.1-pro-preview") # Under the hood, it looks like -from deepagents.backends import StateBackend - -agent = create_deep_agent( +agent2 = create_deep_agent( model="google_genai:gemini-3.1-pro-preview", - backend=StateBackend() + backend=StateBackend(), ) ``` diff --git a/src/snippets/code-samples/backend-store-js.mdx b/src/snippets/code-samples/backend-store-js.mdx new file mode 100644 index 000000000..5a3d162d1 --- /dev/null +++ b/src/snippets/code-samples/backend-store-js.mdx @@ -0,0 +1,13 @@ +```ts +import { createDeepAgent, StoreBackend } from "deepagents"; +import { InMemoryStore } from "@langchain/langgraph"; + +const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment +const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + backend: new StoreBackend({ + namespace: (ctx) => [ctx.runtime.context.userId], + }), + store, +}); +``` diff --git a/src/snippets/backend-store-py.mdx b/src/snippets/code-samples/backend-store-py.mdx similarity index 52% rename from src/snippets/backend-store-py.mdx rename to src/snippets/code-samples/backend-store-py.mdx index a1b76b94a..b0246bf6d 100644 --- a/src/snippets/backend-store-py.mdx +++ b/src/snippets/code-samples/backend-store-py.mdx @@ -1,16 +1,13 @@ ```python -from langgraph.store.memory import InMemoryStore +from deepagents import create_deep_agent from deepagents.backends import StoreBackend +from langgraph.store.memory import InMemoryStore agent = create_deep_agent( model="google_genai:gemini-3.1-pro-preview", backend=StoreBackend( namespace=lambda ctx: (ctx.runtime.context.user_id,), ), - store=InMemoryStore() # Good for local dev; omit for LangSmith Deployment + store=InMemoryStore(), # Good for local dev; omit for LangSmith Deployment ) ``` - - - When deploying to [LangSmith Deployment](/langsmith/deployment), omit the `store` parameter. The platform automatically provisions a store for your agent. - diff --git a/src/snippets/hitl-basic-config-js.mdx b/src/snippets/code-samples/hitl-basic-config-js.mdx similarity index 63% rename from src/snippets/hitl-basic-config-js.mdx rename to src/snippets/code-samples/hitl-basic-config-js.mdx index e7bf7fdde..b0313f52c 100644 --- a/src/snippets/hitl-basic-config-js.mdx +++ b/src/snippets/code-samples/hitl-basic-config-js.mdx @@ -1,15 +1,15 @@ -```typescript +```ts import { tool } from "langchain"; import { createDeepAgent } from "deepagents"; import { MemorySaver } from "@langchain/langgraph"; import { z } from "zod"; -const deleteFile = tool( +const removeFile = tool( async ({ path }: { path: string }) => { return `Deleted ${path}`; }, { - name: "delete_file", + name: "remove_file", description: "Delete a file from the filesystem.", schema: z.object({ path: z.string(), @@ -17,12 +17,12 @@ const deleteFile = tool( }, ); -const readFile = tool( +const fetchFile = tool( async ({ path }: { path: string }) => { return `Contents of ${path}`; }, { - name: "read_file", + name: "fetch_file", description: "Read a file from the filesystem.", schema: z.object({ path: z.string(), @@ -30,12 +30,20 @@ const readFile = tool( }, ); -const sendEmail = tool( - async ({ to, subject, body }: { to: string; subject: string; body: string }) => { +const notifyEmail = tool( + async ({ + to, + subject, + body, + }: { + to: string; + subject: string; + body: string; + }) => { return `Sent email to ${to}`; }, { - name: "send_email", + name: "notify_email", description: "Send an email.", schema: z.object({ to: z.string(), @@ -50,12 +58,12 @@ const checkpointer = new MemorySaver(); const agent = createDeepAgent({ model: "google_genai:gemini-3.1-pro-preview", - tools: [deleteFile, readFile, sendEmail], + tools: [removeFile, fetchFile, notifyEmail], interruptOn: { - delete_file: true, // Default: approve, edit, reject, respond - read_file: false, // No interrupts needed - send_email: { allowedDecisions: ["approve", "reject"] }, // No editing + remove_file: true, // Default: approve, edit, reject, respond + fetch_file: false, // No interrupts needed + notify_email: { allowedDecisions: ["approve", "reject"] }, // No editing }, - checkpointer, // Required! + checkpointer, // Required! }); ``` diff --git a/src/snippets/hitl-basic-config-py.mdx b/src/snippets/code-samples/hitl-basic-config-py.mdx similarity index 56% rename from src/snippets/hitl-basic-config-py.mdx rename to src/snippets/code-samples/hitl-basic-config-py.mdx index e98a08741..81d7b6f6a 100644 --- a/src/snippets/hitl-basic-config-py.mdx +++ b/src/snippets/code-samples/hitl-basic-config-py.mdx @@ -3,32 +3,36 @@ from langchain.tools import tool from deepagents import create_deep_agent from langgraph.checkpoint.memory import MemorySaver + @tool -def delete_file(path: str) -> str: +def remove_file(path: str) -> str: """Delete a file from the filesystem.""" return f"Deleted {path}" + @tool -def read_file(path: str) -> str: +def fetch_file(path: str) -> str: """Read a file from the filesystem.""" return f"Contents of {path}" + @tool -def send_email(to: str, subject: str, body: str) -> str: +def notify_email(to: str, subject: str, body: str) -> str: """Send an email.""" return f"Sent email to {to}" + # Checkpointer is REQUIRED for human-in-the-loop checkpointer = MemorySaver() agent = create_deep_agent( model="google_genai:gemini-3.1-pro-preview", - tools=[delete_file, read_file, send_email], + tools=[remove_file, fetch_file, notify_email], interrupt_on={ - "delete_file": True, # Default: approve, edit, reject, respond - "read_file": False, # No interrupts needed - "send_email": {"allowed_decisions": ["approve", "reject"]}, # No editing + "remove_file": True, # Default: approve, edit, reject, respond + "fetch_file": False, # No interrupts needed + "notify_email": {"allowed_decisions": ["approve", "reject"]}, # No editing }, - checkpointer=checkpointer # Required! + checkpointer=checkpointer, # Required! ) ``` diff --git a/src/snippets/code-samples/skills-usage-filesystem-js.mdx b/src/snippets/code-samples/skills-usage-filesystem-js.mdx new file mode 100644 index 000000000..b169306da --- /dev/null +++ b/src/snippets/code-samples/skills-usage-filesystem-js.mdx @@ -0,0 +1,27 @@ +```ts +import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; +import { createDeepAgent, FilesystemBackend } from "deepagents"; +import { MemorySaver } from "@langchain/langgraph"; + +const checkpointer = new MemorySaver(); +const backend = new FilesystemBackend({ rootDir: process.cwd() }); + +const agent = await createDeepAgent({ + model: "google-genai:gemini-3.1-pro-preview", + backend, + skills: ["./examples/skills/"], + interruptOn: { + read_file: true, + write_file: true, + delete_file: true, + }, + checkpointer, // Required! + middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], +}); + +const config = { configurable: { thread_id: `thread-${Date.now()}` } }; +const result = await agent.invoke( + { messages: [{ role: "user", content: "what is langraph?" }] }, + config, +); +``` diff --git a/src/snippets/code-samples/skills-usage-filesystem-py.mdx b/src/snippets/code-samples/skills-usage-filesystem-py.mdx new file mode 100644 index 000000000..d0b1ce42f --- /dev/null +++ b/src/snippets/code-samples/skills-usage-filesystem-py.mdx @@ -0,0 +1,29 @@ +```python +from deepagents import create_deep_agent +from deepagents.backends.filesystem import FilesystemBackend +from langchain_quickjs import CodeInterpreterMiddleware +from langgraph.checkpoint.memory import MemorySaver + +# Checkpointer is REQUIRED for human-in-the-loop +checkpointer = MemorySaver() +root_dir = "/Users/user/{project}" +backend = FilesystemBackend(root_dir=root_dir) + +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=backend, + skills=[str(Path(root_dir) / "skills")], + interrupt_on={ + "write_file": True, + "read_file": False, + "edit_file": True, + }, + checkpointer=checkpointer, # Required! + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills +) + +result = agent.invoke( + {"messages": [{"role": "user", "content": "What is langgraph?"}]}, + config={"configurable": {"thread_id": "12345"}}, +) +``` diff --git a/src/snippets/code-samples/skills-usage-state-js.mdx b/src/snippets/code-samples/skills-usage-state-js.mdx new file mode 100644 index 000000000..23d89370a --- /dev/null +++ b/src/snippets/code-samples/skills-usage-state-js.mdx @@ -0,0 +1,43 @@ +```ts +import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; +import { createDeepAgent, StateBackend, type FileData } from "deepagents"; +import { MemorySaver } from "@langchain/langgraph"; + +const checkpointer = new MemorySaver(); +const backend = new StateBackend(); + +function createFileData(content: string): FileData { + const now = new Date().toISOString(); + return { + content: content.split("\n"), + created_at: now, + modified_at: now, + }; +} + +const skillsFiles: Record = {}; +const skillUrl = + "https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md"; +const response = await fetch(skillUrl); +const skillContent = await response.text(); + +skillsFiles["/skills/langgraph-docs/SKILL.md"] = createFileData(skillContent); + +const agent = await createDeepAgent({ + model: "google-genai:gemini-3.1-pro-preview", + backend, + checkpointer, // Required ! + // IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root. + skills: ["/skills/"], + middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], +}); + +const config = { configurable: { thread_id: `thread-${Date.now()}` } }; +const result = await agent.invoke( + { + messages: [{ role: "user", content: "what is langraph?" }], + files: skillsFiles, + }, + config, +); +``` diff --git a/src/snippets/code-samples/skills-usage-state-py.mdx b/src/snippets/code-samples/skills-usage-state-py.mdx new file mode 100644 index 000000000..48abec28b --- /dev/null +++ b/src/snippets/code-samples/skills-usage-state-py.mdx @@ -0,0 +1,260 @@ + + ```python Google + from urllib.request import urlopen + from deepagents import create_deep_agent + from deepagents.backends import StateBackend + from deepagents.backends.utils import create_file_data + from langchain_quickjs import CodeInterpreterMiddleware + from langgraph.checkpoint.memory import MemorySaver + + checkpointer = MemorySaver() + backend = StateBackend() + + skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" + with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + + skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), + } + + agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills + ) + + result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, + ) + ``` + + ```python OpenAI + from urllib.request import urlopen + from deepagents import create_deep_agent + from deepagents.backends import StateBackend + from deepagents.backends.utils import create_file_data + from langchain_quickjs import CodeInterpreterMiddleware + from langgraph.checkpoint.memory import MemorySaver + + checkpointer = MemorySaver() + backend = StateBackend() + + skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" + with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + + skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), + } + + agent = create_deep_agent( + model="openai:gpt-5.4", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills + ) + + result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, + ) + ``` + + ```python Anthropic + from urllib.request import urlopen + from deepagents import create_deep_agent + from deepagents.backends import StateBackend + from deepagents.backends.utils import create_file_data + from langchain_quickjs import CodeInterpreterMiddleware + from langgraph.checkpoint.memory import MemorySaver + + checkpointer = MemorySaver() + backend = StateBackend() + + skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" + with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + + skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), + } + + agent = create_deep_agent( + model="anthropic:claude-sonnet-4-6", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills + ) + + result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, + ) + ``` + + ```python OpenRouter + from urllib.request import urlopen + from deepagents import create_deep_agent + from deepagents.backends import StateBackend + from deepagents.backends.utils import create_file_data + from langchain_quickjs import CodeInterpreterMiddleware + from langgraph.checkpoint.memory import MemorySaver + + checkpointer = MemorySaver() + backend = StateBackend() + + skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" + with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + + skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), + } + + agent = create_deep_agent( + model="openrouter:anthropic/claude-sonnet-4-6", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills + ) + + result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, + ) + ``` + + ```python Fireworks + from urllib.request import urlopen + from deepagents import create_deep_agent + from deepagents.backends import StateBackend + from deepagents.backends.utils import create_file_data + from langchain_quickjs import CodeInterpreterMiddleware + from langgraph.checkpoint.memory import MemorySaver + + checkpointer = MemorySaver() + backend = StateBackend() + + skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" + with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + + skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), + } + + agent = create_deep_agent( + model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills + ) + + result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, + ) + ``` + + ```python Baseten + from urllib.request import urlopen + from deepagents import create_deep_agent + from deepagents.backends import StateBackend + from deepagents.backends.utils import create_file_data + from langchain_quickjs import CodeInterpreterMiddleware + from langgraph.checkpoint.memory import MemorySaver + + checkpointer = MemorySaver() + backend = StateBackend() + + skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" + with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + + skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), + } + + agent = create_deep_agent( + model="baseten:zai-org/GLM-5", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills + ) + + result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, + ) + ``` + + ```python Ollama + from urllib.request import urlopen + from deepagents import create_deep_agent + from deepagents.backends import StateBackend + from deepagents.backends.utils import create_file_data + from langchain_quickjs import CodeInterpreterMiddleware + from langgraph.checkpoint.memory import MemorySaver + + checkpointer = MemorySaver() + backend = StateBackend() + + skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" + with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + + skills_files = { + "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content), + } + + agent = create_deep_agent( + model="ollama:devstral-2", + backend=backend, + skills=["/skills/"], + checkpointer=checkpointer, + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills + ) + + result = agent.invoke( + { + "messages": [{"role": "user", "content": "What is langgraph?"}], + # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). + "files": skills_files, + }, + config={"configurable": {"thread_id": "12345"}}, + ) + ``` + diff --git a/src/snippets/code-samples/skills-usage-store-js.mdx b/src/snippets/code-samples/skills-usage-store-js.mdx new file mode 100644 index 000000000..5b2099174 --- /dev/null +++ b/src/snippets/code-samples/skills-usage-store-js.mdx @@ -0,0 +1,46 @@ +```ts +import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; +import { createDeepAgent, StoreBackend, type FileData } from "deepagents"; +import { InMemoryStore, MemorySaver } from "@langchain/langgraph"; + +const checkpointer = new MemorySaver(); +const store = new InMemoryStore(); +const backend = new StoreBackend(); + +function createFileData(content: string): FileData { + const now = new Date().toISOString(); + return { + content: content.split("\n"), + created_at: now, + modified_at: now, + }; +} + +const skillUrl = + "https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md"; + +const response = await fetch(skillUrl); +const skillContent = await response.text(); +const fileData = createFileData(skillContent); + +await store.put(["filesystem"], "/skills/langgraph-docs/SKILL.md", fileData); + +const agent = await createDeepAgent({ + model: "google-genai:gemini-3.1-pro-preview", + backend, + store, + checkpointer, + // IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root. + skills: ["/skills/"], + middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], +}); + +const config = { + recursionLimit: 50, + configurable: { thread_id: `thread-${Date.now()}` }, +}; +const result = await agent.invoke( + { messages: [{ role: "user", content: "what is langraph?" }] }, + config, +); +``` diff --git a/src/snippets/code-samples/skills-usage-store-py.mdx b/src/snippets/code-samples/skills-usage-store-py.mdx new file mode 100644 index 000000000..f3f717b2d --- /dev/null +++ b/src/snippets/code-samples/skills-usage-store-py.mdx @@ -0,0 +1,34 @@ +```python +from urllib.request import urlopen +from deepagents import create_deep_agent +from deepagents.backends import StoreBackend +from deepagents.backends.utils import create_file_data +from langchain_quickjs import CodeInterpreterMiddleware +from langgraph.store.memory import InMemoryStore + +store = InMemoryStore() +backend = StoreBackend() + +skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" +with urlopen(skill_url) as response: + skill_content = response.read().decode('utf-8') + +store.put( + namespace=("filesystem",), + key="/skills/langgraph-docs/SKILL.md", + value=create_file_data(skill_content), +) + +agent = create_deep_agent( + model="google_genai:gemini-3.1-pro-preview", + backend=backend, + store=store, + skills=["/skills/"], + middleware=[CodeInterpreterMiddleware(skills_backend=backend)], +) + +result = agent.invoke( + {"messages": [{"role": "user", "content": "What is langgraph?"}]}, + config={"configurable": {"thread_id": "12345"}}, +) +``` diff --git a/src/snippets/code-samples/subagent-basic-js.mdx b/src/snippets/code-samples/subagent-basic-js.mdx new file mode 100644 index 000000000..5779343cb --- /dev/null +++ b/src/snippets/code-samples/subagent-basic-js.mdx @@ -0,0 +1,393 @@ + + ```ts Google + import { tool } from "langchain"; + import { TavilySearch } from "@langchain/tavily"; + import { createDeepAgent, type SubAgent } 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 researchSubagent: SubAgent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: "google-genai:gemini-3.1-pro-preview", // Optional override, defaults to main agent model + }; + const subagents = [researchSubagent]; + + const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + subagents, + }); + ``` + + ```ts OpenAI + import { tool } from "langchain"; + import { TavilySearch } from "@langchain/tavily"; + import { createDeepAgent, type SubAgent } 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 researchSubagent: SubAgent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: "openai:gpt-5.4", // Optional override, defaults to main agent model + }; + const subagents = [researchSubagent]; + + const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + subagents, + }); + ``` + + ```ts Anthropic + import { tool } from "langchain"; + import { TavilySearch } from "@langchain/tavily"; + import { createDeepAgent, type SubAgent } 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 researchSubagent: SubAgent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: "anthropic:claude-sonnet-4-6", // Optional override, defaults to main agent model + }; + const subagents = [researchSubagent]; + + const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + subagents, + }); + ``` + + ```ts OpenRouter + import { tool } from "langchain"; + import { TavilySearch } from "@langchain/tavily"; + import { createDeepAgent, type SubAgent } 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 researchSubagent: SubAgent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: "openrouter:anthropic/claude-sonnet-4-6", // Optional override, defaults to main agent model + }; + const subagents = [researchSubagent]; + + const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + subagents, + }); + ``` + + ```ts Fireworks + import { tool } from "langchain"; + import { TavilySearch } from "@langchain/tavily"; + import { createDeepAgent, type SubAgent } 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 researchSubagent: SubAgent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: "fireworks:accounts/fireworks/models/qwen3p5-397b-a17b", // Optional override, defaults to main agent model + }; + const subagents = [researchSubagent]; + + const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + subagents, + }); + ``` + + ```ts Baseten + import { tool } from "langchain"; + import { TavilySearch } from "@langchain/tavily"; + import { createDeepAgent, type SubAgent } 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 researchSubagent: SubAgent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: "baseten:zai-org/GLM-5", // Optional override, defaults to main agent model + }; + const subagents = [researchSubagent]; + + const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + subagents, + }); + ``` + + ```ts Ollama + import { tool } from "langchain"; + import { TavilySearch } from "@langchain/tavily"; + import { createDeepAgent, type SubAgent } 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 researchSubagent: SubAgent = { + name: "research-agent", + description: "Used to research more in depth questions", + systemPrompt: "You are a great researcher", + tools: [internetSearch], + model: "ollama:devstral-2", // Optional override, defaults to main agent model + }; + const subagents = [researchSubagent]; + + const agent = createDeepAgent({ + model: "google_genai:gemini-3.1-pro-preview", + subagents, + }); + ``` + diff --git a/src/snippets/subagent-basic-py.mdx b/src/snippets/code-samples/subagent-basic-py.mdx similarity index 91% rename from src/snippets/subagent-basic-py.mdx rename to src/snippets/code-samples/subagent-basic-py.mdx index ed4948ece..2f8f6b2d6 100644 --- a/src/snippets/subagent-basic-py.mdx +++ b/src/snippets/code-samples/subagent-basic-py.mdx @@ -1,11 +1,13 @@ ```python import os from typing import Literal -from tavily import TavilyClient + from deepagents import create_deep_agent +from tavily import TavilyClient tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"]) + def internet_search( query: str, max_results: int = 5, @@ -20,6 +22,7 @@ def internet_search( topic=topic, ) + research_subagent = { "name": "research-agent", "description": "Used to research more in depth questions", @@ -29,8 +32,9 @@ research_subagent = { } subagents = [research_subagent] + agent = create_deep_agent( - model="claude-sonnet-4-6", - subagents=subagents + model="google_genai:gemini-3.1-pro-preview", + subagents=subagents, ) ``` diff --git a/src/snippets/skills-usage-tabs-js.mdx b/src/snippets/skills-usage-tabs-js.mdx index ec1fba0be..850a16ed6 100644 --- a/src/snippets/skills-usage-tabs-js.mdx +++ b/src/snippets/skills-usage-tabs-js.mdx @@ -1,166 +1,15 @@ +import SkillsUsageStateJs from '/snippets/code-samples/skills-usage-state-js.mdx'; +import SkillsUsageStoreJs from '/snippets/code-samples/skills-usage-store-js.mdx'; +import SkillsUsageFilesystemJs from '/snippets/code-samples/skills-usage-filesystem-js.mdx'; + - -```typescript -import { createDeepAgent, StateBackend, type FileData } from "deepagents"; -import { MemorySaver } from "@langchain/langgraph"; -import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; - -const checkpointer = new MemorySaver(); -const backend = new StateBackend(); - -function createFileData(content: string): FileData { - const now = new Date().toISOString(); - return { - content: content.split("\n"), - created_at: now, - modified_at: now, - }; -} - -const skillsFiles: Record = {}; - -const skillUrl = - "https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md"; -const response = await fetch(skillUrl); -const skillContent = await response.text(); - -skillsFiles["/skills/langgraph-docs/SKILL.md"] = createFileData(skillContent); - -const agent = await createDeepAgent({ - model: "openai:gpt-5.4", - backend, - checkpointer, - // IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root. - skills: ["/skills/"], - middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], -}); - -const config = { - configurable: { - thread_id: `thread-${Date.now()}`, - }, -}; - -const result = await agent.invoke( - { - messages: [ - { - role: "user", - content: "what is langraph? Use the langgraph-docs skill if available.", - }, - ], - files: skillsFiles, - }, - config, -); -``` - + - -```typescript -import { createDeepAgent, StoreBackend, type FileData } from "deepagents"; -import { - InMemoryStore, - MemorySaver, -} from "@langchain/langgraph"; -import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; - -const checkpointer = new MemorySaver(); -const store = new InMemoryStore(); -const backend = new StoreBackend(); - -function createFileData(content: string): FileData { - const now = new Date().toISOString(); - return { - content: content.split("\n"), - created_at: now, - modified_at: now, - }; -} - -const skillUrl = - "https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md"; - -const response = await fetch(skillUrl); -const skillContent = await response.text(); -const fileData = createFileData(skillContent); - -await store.put(["filesystem"], "/skills/langgraph-docs/SKILL.md", fileData); - -const agent = await createDeepAgent({ - model: "openai:gpt-5.4", - backend, - store: store, - checkpointer, - // IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root. - skills: ["/skills/"], - middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], -}); - -const config = { - recursionLimit: 50, - configurable: { - thread_id: `thread-${Date.now()}`, - }, -}; - -const result = await agent.invoke( - { - messages: [ - { - role: "user", - content: "what is langraph? Use the langgraph-docs skill if available.", - }, - ], - }, - config, -); -``` - + - -```typescript -import { createDeepAgent, FilesystemBackend } from "deepagents"; -import { MemorySaver } from "@langchain/langgraph"; -import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; - -const checkpointer = new MemorySaver(); -const backend = new FilesystemBackend({ rootDir: process.cwd() }); - -const agent = await createDeepAgent({ - model: "openai:gpt-5.4", - backend, - skills: ["./examples/skills/"], - interruptOn: { - read_file: true, - write_file: true, - delete_file: true, - }, - checkpointer, // Required! - middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], -}); - -const config = { - configurable: { - thread_id: `thread-${Date.now()}`, - }, -}; - -const result = await agent.invoke( - { - messages: [ - { - role: "user", - content: "what is langraph? Use the langgraph-docs skill if available.", - }, - ], - }, - config, -); -``` - + diff --git a/src/snippets/skills-usage-tabs-py.mdx b/src/snippets/skills-usage-tabs-py.mdx index 53363bae1..68f46e4c7 100644 --- a/src/snippets/skills-usage-tabs-py.mdx +++ b/src/snippets/skills-usage-tabs-py.mdx @@ -1,126 +1,15 @@ +import SkillsUsageStatePy from '/snippets/code-samples/skills-usage-state-py.mdx'; +import SkillsUsageStorePy from '/snippets/code-samples/skills-usage-store-py.mdx'; +import SkillsUsageFilesystemPy from '/snippets/code-samples/skills-usage-filesystem-py.mdx'; + - ```python - from urllib.request import urlopen - from deepagents import create_deep_agent - from deepagents.backends.utils import create_file_data - from langgraph.checkpoint.memory import MemorySaver - from deepagents.backends import StateBackend - from langchain_quickjs import CodeInterpreterMiddleware - - checkpointer = MemorySaver() - backend = StateBackend() - - skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" - with urlopen(skill_url) as response: - skill_content = response.read().decode('utf-8') - - skills_files = { - "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content) - } - - agent = create_deep_agent( - model="google_genai:gemini-3.1-pro-preview", - backend=backend, - skills=["/skills/"], - checkpointer=checkpointer, - middleware=[CodeInterpreterMiddleware(skills_backend=backend)] # for interpreter skills - ) - - result = agent.invoke( - { - "messages": [ - { - "role": "user", - "content": "What is langgraph?", - } - ], - # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/"). - "files": skills_files - }, - config={"configurable": {"thread_id": "12345"}}, - ) - ``` + - ```python - from urllib.request import urlopen - from deepagents import create_deep_agent - from deepagents.backends import StoreBackend - from deepagents.backends.utils import create_file_data - from langgraph.store.memory import InMemoryStore - from langchain_quickjs import CodeInterpreterMiddleware - - - store = InMemoryStore() - backend = StoreBackend() - - skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md" - with urlopen(skill_url) as response: - skill_content = response.read().decode('utf-8') - - store.put( - namespace=("filesystem",), - key="/skills/langgraph-docs/SKILL.md", - value=create_file_data(skill_content) - ) - - agent = create_deep_agent( - model="google_genai:gemini-3.1-pro-preview", - backend=backend, - store=store, - skills=["/skills/"], - middleware=[CodeInterpreterMiddleware(skills_backend=backend)] # for interpreter skills - ) - - result = agent.invoke( - { - "messages": [ - { - "role": "user", - "content": "What is langgraph?", - } - ] - }, - config={"configurable": {"thread_id": "12345"}}, - ) - ``` + - ```python - from deepagents import create_deep_agent - from langgraph.checkpoint.memory import MemorySaver - from deepagents.backends.filesystem import FilesystemBackend - from langchain_quickjs import CodeInterpreterMiddleware - - # Checkpointer is REQUIRED for human-in-the-loop - checkpointer = MemorySaver() - backend = FilesystemBackend(root_dir="/Users/user/{project}") - - agent = create_deep_agent( - model="google_genai:gemini-3.1-pro-preview", - backend=, - skills=["/Users/user/{project}/skills/"], - interrupt_on={ - "write_file": True, # Default: approve, edit, reject - "read_file": False, # No interrupts needed - "edit_file": True # Default: approve, edit, reject - }, - checkpointer=checkpointer, # Required! - middleware=[CodeInterpreterMiddleware(skills_backend=backend)] # for interpreter skills - ) - - result = agent.invoke( - { - "messages": [ - { - "role": "user", - "content": "What is langgraph?", - } - ] - }, - config={"configurable": {"thread_id": "12345"}}, - ) - ``` + diff --git a/uv.lock b/uv.lock index dffb466c1..158fbceca 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,10 @@ version = 1 revision = 3 requires-python = ">=3.13.0, <4.0.0" +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version < '3.14'", +] [manifest] overrides = [{ name = "pytest-codspeed", specifier = ">=3.1.0,<4.0.0" }] @@ -589,6 +593,7 @@ dependencies = [ { name = "langchain-daytona" }, { name = "langchain-google-genai" }, { name = "langchain-openai" }, + { name = "langchain-quickjs" }, { name = "langgraph-checkpoint-postgres" }, { name = "markdownify" }, { name = "nbconvert" }, @@ -625,6 +630,7 @@ requires-dist = [ { name = "langchain-daytona", specifier = ">=0.0.5" }, { name = "langchain-google-genai", specifier = ">=2.0.0" }, { name = "langchain-openai", specifier = ">=1.1.14" }, + { name = "langchain-quickjs", specifier = ">=0.1.2" }, { name = "langgraph-checkpoint-postgres" }, { name = "markdownify", specifier = ">=0.13.0" }, { name = "nbconvert", specifier = ">=7.17.1" },