## 1. Project Overview & Quickstart (langchain-ai/langgraphjs) ## File: docs/docs/agents/agents.md # LangGraph quickstart This guide shows you how to set up and use LangGraph's **prebuilt**, **reusable** components, which are designed to help you construct agentic systems quickly and reliably. ## Prerequisites Before you start this tutorial, ensure you have the following: - An [Anthropic](https://console.anthropic.com/settings/keys) API key ## 1. Install dependencies If you haven't already, install LangGraph and LangChain: ``` npm install langchain @langchain/langgraph @langchain/anthropic ``` ## 2. Create an agent Use [`createReactAgent`](/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html) to instantiate an agent: ```ts import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { initChatModel } from "langchain/chat_models/universal"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; const getWeather = tool( // (1)! async (input: { city: string }) => { return `It's always sunny in ${input.city}!`; }, { name: "getWeather", schema: z.object({ city: z.string().describe("The city to get the weather for"), }), } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); // (2)! const agent = createReactAgent({ llm, tools: [getWeather], // (3)! prompt: "You are a helpful assistant", // (4)! }); // Run the agent await agent.invoke({ messages: [{ role: "user", content: "what is the weather in sf" }], }); ``` 1. Define a tool for the agent to use. For more advanced tool usage and customization, check the [tools](./tools.md) page. 2. Provide a language model for the agent to use. To learn more about configuring language models for the agents, check the [models](./models.md) page. 3. Provide a list of tools for the model to use. 4. Provide a system prompt (instructions) to the language model used by the agent. ## 3. Configure an LLM Use [`initChatModel`](https://api.js.langchain.com/functions/langchain.chat_models_universal.initChatModel.html) to configure an LLM with specific parameters, such as temperature: ```ts import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { initChatModel } from "langchain/chat_models/universal"; // highlight-next-line const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest", { // highlight-next-line temperature: 0, }); const agent = createReactAgent({ // highlight-next-line llm, tools: [getWeather], }); ``` See the [models](./models.md) page for more information on how to configure LLMs. ## 4. Add a custom prompt Prompts instruct the LLM how to behave. They can be: - **Static**: A string is interpreted as a **system message** - **Dynamic**: a list of messages generated at **runtime** based on input or configuration === "Static prompt" Define a fixed prompt string or list of messages. ```ts import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { initChatModel } from "langchain/chat_models/universal"; const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getWeather], // A static prompt that never changes // highlight-next-line prompt: "Never answer questions about the weather.", }); await agent.invoke({ messages: "what is the weather in sf", }); ``` === "Dynamic prompt" Define a function that returns a message list based on the agent's state and configuration: ```ts import { BaseMessageLike } from "@langchain/core/messages"; import { RunnableConfig } from "@langchain/core/runnables"; import { initChatModel } from "langchain/chat_models/universal"; import { MessagesAnnotation } from "@langchain/langgraph"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; const prompt = ( state: typeof MessagesAnnotation.State, config: RunnableConfig ): BaseMessageLike[] => { // (1)! const userName = config.configurable?.userName; const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`; return [{ role: "system", content: systemMsg }, ...state.messages]; }; const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getWeather], // highlight-next-line prompt, }); await agent.invoke( { messages: [{ role: "user", content: "what is the weather in sf" }] }, // highlight-next-line { configurable: { userName: "John Smith" } } ); ``` 1. Dynamic prompts allow including non-message [context](./context.md) when constructing an input to the LLM, such as: - Information passed at runtime, like a `userId` or API credentials (using `config`). - Internal agent state updated during a multi-step reasoning process (using `state`). Dynamic prompts can be defined as functions that take `state` and `config` and return a list of messages to send to the LLM. For more information, see [Context](./context.md). ## 5. Add memory To allow multi-turn conversations with an agent, you need to enable [persistence](../concepts/persistence.md) by providing a `checkpointer` when creating an agent. At runtime you need to provide a config containing `thread_id` β€” a unique identifier for the conversation (session): ```ts import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { MemorySaver } from "@langchain/langgraph-checkpoint"; import { initChatModel } from "langchain/chat_models/universal"; // highlight-next-line const checkpointer = new MemorySaver(); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getWeather], // highlight-next-line checkpointer, // (1)! }); // Run the agent // highlight-next-line const config = { configurable: { thread_id: "1" } }; const sfResponse = await agent.invoke( { messages: [{ role: "user", content: "what is the weather in sf" }] }, config // (2)! ); const nyResponse = await agent.invoke( { messages: [{ role: "user", content: "what about new york?" }] }, config ); ``` 1. `checkpointer` allows the agent to store its state at every step in the tool calling loop. This enables [short-term memory](./memory.md#short-term-memory) and [human-in-the-loop](./human-in-the-loop.md) capabilities. 2. Pass configuration with `thread_id` to be able to resume the same conversation on future agent invocations. When you enable the checkpointer, it stores agent state at every step in the provided checkpointer database (or in memory, if using `InMemorySaver`). Note that in the above example, when the agent is invoked the second time with the same `thread_id`, the original message history from the first conversation is automatically included, together with the new user input. For more information, see [Memory](./memory.md). ## 6. Configure structured output To produce structured responses conforming to a schema, use the `responseFormat` parameter. The schema can be defined with a `zod` schema. The result will be accessible via the `structuredResponse` field. ```ts import { z } from "zod"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { initChatModel } from "langchain/chat_models/universal"; const WeatherResponse = z.object({ conditions: z.string(), }); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getWeather], // highlight-next-line responseFormat: WeatherResponse, // (1)! }); const response = await agent.invoke({ messages: [{ role: "user", content: "what is the weather in sf" }], }); // highlight-next-line response.structuredResponse; ``` 1. When `responseFormat` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response. To provide a system prompt to this LLM, use an object `{ prompt, schema }`, e.g., `responseFormat: { prompt, schema: WeatherResponse }`. !!! Note "LLM post-processing" Structured output requires an additional call to the LLM to format the response according to the schema. ## Next steps - [Deploy your agent locally](../tutorials/langgraph-platform/local-server.md) - [Learn more about prebuilt agents](../agents/overview.md) - [LangGraph Platform quickstart](../cloud/quick_start.md) --- ## File: docs/docs/agents/context.md # Context Agents often require more than a list of messages to function effectively. They need **context**. Context includes *any* data outside the message list that can shape agent behavior or tool execution. This can be: - Information passed at runtime, like a `user_id` or API credentials. - Internal state updated during a multi-step reasoning process. - Persistent memory or facts from previous interactions. LangGraph provides **three** primary ways to supply context: | Type | Description | Mutable? | Lifetime | |------------------------------------------------------------------------------|-----------------------------------------------|----------|-------------------------| | [**Config**](#config-static-context) | data passed at the start of a run | ❌ | per run | | [**State**](#state-mutable-context) | dynamic data that can change during execution | βœ… | per run or conversation | | [**Long-term Memory (Store)**](#long-term-memory-cross-conversation-context) | data that can be shared between conversations | βœ… | across conversations | You can use context to: - Adjust the system prompt the model sees - Feed tools with necessary inputs - Track facts during an ongoing conversation ## Providing Runtime Context Use this when you need to inject data into an agent at runtime. ### Config (static context) Config is for immutable data like user metadata or API keys. Use when you have values that don't change mid-run. Specify configuration using a key called **"configurable"** which is reserved for this purpose: ```ts await agent.invoke( { messages: "hi!" }, // highlight-next-line { configurable: { userId: "user_123" } } ) ``` ### State (mutable context) State acts as short-term memory during a run. It holds dynamic data that can evolve during execution, such as values derived from tools or LLM outputs. ```ts const CustomState = Annotation.Root({ ...MessagesAnnotation.spec, userName: Annotation, }); const agent = createReactAgent({ // Other agent parameters... // highlight-next-line stateSchema: CustomState, }) await agent.invoke( // highlight-next-line { messages: "hi!", userName: "Jane" } ) ``` !!! tip "Turning on memory" Please see the [memory guide](./memory.md) for more details on how to enable memory. This is a powerful feature that allows you to persist the agent's state across multiple invocations. Otherwise, the state is scoped only to a single agent run. ### Long-Term Memory (cross-conversation context) For context that spans *across* conversations or sessions, LangGraph allows access to **long-term memory** via a `store`. This can be used to read or update persistent facts (e.g., user profiles, preferences, prior interactions). For more, see the [Memory guide](./memory.md). ## Customizing Prompts with Context Prompts define how the agent behaves. To incorporate runtime context, you can dynamically generate prompts based on the agent's state or config. Common use cases: - Personalization - Role or goal customization - Conditional behavior (e.g., user is admin) === "Using config" ```ts import { BaseMessageLike } from "@langchain/core/messages"; import { RunnableConfig } from "@langchain/core/runnables"; import { initChatModel } from "langchain/chat_models/universal"; import { MessagesAnnotation } from "@langchain/langgraph"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; const prompt = ( state: typeof MessagesAnnotation.State, // highlight-next-line config: RunnableConfig ): BaseMessageLike[] => { // highlight-next-line const userName = config.configurable?.userName; const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`; return [{ role: "system", content: systemMsg }, ...state.messages]; }; const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getWeather], // highlight-next-line prompt }); await agent.invoke( { messages: "hi!" }, // highlight-next-line { configurable: { userName: "John Smith" } } ); ``` === "Using state" ```ts import { BaseMessageLike } from "@langchain/core/messages"; import { RunnableConfig } from "@langchain/core/runnables"; import { initChatModel } from "langchain/chat_models/universal"; import { Annotation, MessagesAnnotation } from "@langchain/langgraph"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; const CustomState = Annotation.Root({ ...MessagesAnnotation.spec, // highlight-next-line userName: Annotation, }); const prompt = ( // highlight-next-line state: typeof CustomState.State, ): BaseMessageLike[] => { // highlight-next-line const userName = state.userName; const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`; return [{ role: "system", content: systemMsg }, ...state.messages]; }; const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getWeather], // highlight-next-line prompt, // highlight-next-line stateSchema: CustomState, }); await agent.invoke( // highlight-next-line { messages: "hi!", userName: "John Smith" }, ); ``` ## Tools Tools can access context through: * Use `RunnableConfig` for config access * Use `runtime.state` (the second argument, typed as `ToolRuntime`) for agent state !!! tip "Browser / web environments" When a tool runs inside a `ToolNode` (including in `createReactAgent`), the `ToolNode` forwards its input (the current graph state) to the tool via `runtime.state`. This works in every runtime, including web browsers. An older alternative, `getCurrentTaskInput()`, relies on [`AsyncLocalStorage`](https://nodejs.org/api/async_hooks.html), which is available in Node.js, Deno, and Cloudflare Workers, but **not** in web browsers. Prefer `runtime.state` for portability. === "Using config" ```ts import { RunnableConfig } from "@langchain/core/runnables"; import { initChatModel } from "langchain/chat_models/universal"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; const getUserInfo = tool( async (input: Record, config: RunnableConfig) => { // highlight-next-line const userId = config.configurable?.userId; return userId === "user_123" ? "User is John Smith" : "Unknown user"; }, { name: "get_user_info", schema: z.object({}), } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getUserInfo], }); await agent.invoke( { messages: "look up user information" }, // highlight-next-line { configurable: { userId: "user_123" } } ); ``` === "Using state" ```ts import { initChatModel } from "langchain/chat_models/universal"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { Annotation, MessagesAnnotation } from "@langchain/langgraph"; import { tool, type ToolRuntime } from "@langchain/core/tools"; import { z } from "zod"; const CustomState = Annotation.Root({ ...MessagesAnnotation.spec, // highlight-next-line userId: Annotation(), }); const getUserInfo = tool( async ( input: Record, // highlight-next-line runtime: ToolRuntime, ) => { // Read the graph state directly from the second argument. // This works in web browsers too (no AsyncLocalStorage required). // highlight-next-line const userId = runtime.state.userId; return userId === "user_123" ? "User is John Smith" : "Unknown user"; }, { name: "get_user_info", schema: z.object({}) } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getUserInfo], // highlight-next-line stateSchema: CustomState, }); await agent.invoke( // highlight-next-line { messages: "look up user information", userId: "user_123" } ); ``` ## Update context from tools Tools can modify the agent's state during execution. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts. ```ts import { Annotation, MessagesAnnotation, LangGraphRunnableConfig, Command } from "@langchain/langgraph"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; import { ToolMessage } from "@langchain/core/messages"; import { initChatModel } from "langchain/chat_models/universal"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; const CustomState = Annotation.Root({ ...MessagesAnnotation.spec, // highlight-next-line userName: Annotation(), // Will be updated by the tool }); const getUserInfo = tool( async ( _input: Record, config: LangGraphRunnableConfig ): Promise => { const userId = config.configurable?.userId; if (!userId) { throw new Error("Please provide a user id in config.configurable"); } const toolCallId = config.toolCall?.id; const name = userId === "user_123" ? "John Smith" : "Unknown user"; // Return command to update state return new Command({ update: { // highlight-next-line userName: name, // Update the message history // highlight-next-line messages: [ new ToolMessage({ content: "Successfully looked up user information", tool_call_id: toolCallId, }), ], }, }); }, { name: "get_user_info", schema: z.object({}), } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getUserInfo], // highlight-next-line stateSchema: CustomState, }); await agent.invoke( { messages: "look up user information" }, // highlight-next-line { configurable: { userId: "user_123" } } ); ``` For more details, see [how to update state from tools](../how-tos/update-state-from-tools.ipynb). --- ## File: docs/docs/agents/deployment.md # Deployment To deploy your LangGraph agent, create and configure a LangGraph app. This setup supports both local development and production deployments. Features: * πŸ–₯️ Local server for development * 🧩 Studio Web UI for visual debugging * ☁️ Cloud and πŸ”§ self-hosted deployment options * πŸ“Š LangSmith integration for tracing and observability !!! info "Requirements" - βœ… You **must** have a [LangSmith account](https://www.langchain.com/langsmith). You can sign up for **free** and get started with the free tier. ## Create a LangGraph app ```bash npm install create-langgraph create-langgraph path/to/your/app ``` Follow the prompts and select `New LangGraph Project`. This will create an empty LangGraph project. You can modify it by replacing the code in `src/agent/graph.ts` with your agent code. For example: ```ts import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { initChatModel } from "langchain/chat_models/universal"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; const getWeather = tool( async (input: { city: string }) => { return `It's always sunny in ${input.city}!`; }, { name: "getWeather", schema: z.object({ city: z.string().describe("The city to get the weather for"), }), } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); // make sure to export the graph that will be used in the LangGraph API server // highlight-next-line export const graph = createReactAgent({ llm, tools: [getWeather], prompt: "You are a helpful assistant" }) ``` ### Install dependencies In the root of your new LangGraph app, install the dependencies: ```shell yarn # install these to use initChatModel with Anthropic yarn add langchain yarn add @langchain/anthropic ``` ### Create an `.env` file You will find a `.env.example` in the root of your new LangGraph app. Create a `.env` file in the root of your new LangGraph app and copy the contents of the `.env.example` file into it, filling in the necessary API keys: ```bash LANGSMITH_API_KEY=lsv2... ANTHROPIC_API_KEY=sk- ``` ## Launch LangGraph server locally ```shell npx @langchain/langgraph-cli dev ``` This will start up the LangGraph API server locally. If this runs successfully, you should see something like: > Welcome to LangGraph.js! > > - πŸš€ API: http://localhost:2024 > > - 🎨 Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 ## LangGraph Studio Web UI LangGraph Studio Web is a specialized UI that you can connect to LangGraph API server to enable visualization, interaction, and debugging of your application locally. Test your graph in the LangGraph Studio Web UI by visiting the URL provided in the output of the `npx @langchain/langgraph-cli dev` command. > - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 ## Deployment Once your LangGraph app is running locally, you can deploy it using LangSmith Deployment or self-hosted options. Refer to the [deployment options guide](https://langchain-ai.github.io/langgraph/tutorials/deployment/) for detailed instructions on all supported deployment models. --- ## File: docs/docs/agents/evals.md # Evals To evaluate your agent's performance you can use `LangSmith` [evaluations](https://docs.smith.langchain.com/evaluation). You would need to first define an evaluator function to judge the results from an agent, such as final outputs or trajectory. Depending on your evaluation technique, this may or may not involve a reference output: ```ts const evaluator = async (params: { inputs: Record; outputs: Record; referenceOutputs?: Record; }) => { // compare agent outputs against reference outputs const outputMessages = params.outputs.messages; const referenceMessages = params.referenceOutputs.messages; const score = compareMessages(outputMessages, referenceMessages); return { key: "evaluator_score", score: score }; }; ``` To get started, you can use prebuilt evaluators from `AgentEvals` package: ```bash npm install agentevals @langchain/core ``` ## Create evaluator A common way to evaluate agent performance is by comparing its trajectory (the order in which it calls its tools) against a reference trajectory: ```ts // highlight-next-line import { createTrajectoryMatchEvaluator } from "agentevals"; const outputs = [ { role: "assistant", tool_calls: [ { function: { name: "get_weather", arguments: JSON.stringify({ city: "san francisco" }), }, }, { function: { name: "get_directions", arguments: JSON.stringify({ destination: "presidio" }), }, }, ], }, ]; const referenceOutputs = [ { role: "assistant", tool_calls: [ { function: { name: "get_weather", arguments: JSON.stringify({ city: "san francisco" }), }, }, ], }, ]; // Create the evaluator const evaluator = createTrajectoryMatchEvaluator({ // highlight-next-line trajectoryMatchMode: "superset", // (1)! }) // Run the evaluator const result = await evaluator({ outputs, referenceOutputs, }); ``` 1. Specify how the trajectories will be compared. `superset` will accept output trajectory as valid if it's a superset of the reference one. Other options include: [strict](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#strict-match), [unordered](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#unordered-match) and [subset](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#subset-and-superset-match) As a next step, learn more about how to [customize trajectory match evaluator](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#agent-trajectory-match). ### LLM-as-a-judge You can use LLM-as-a-judge evaluator that uses an LLM to compare the trajectory against the reference outputs and output a score: ```ts import { // highlight-next-line createTrajectoryLLMAsJudge, TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE } from "agentevals"; const evaluator = createTrajectoryLLMAsJudge({ prompt: TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE, model: "openai:o3-mini", }); ``` ## Run evaluator To run an evaluator, you will first need to create a [LangSmith dataset](https://docs.smith.langchain.com/evaluation/concepts#datasets). To use the prebuilt AgentEvals evaluators, you will need a dataset with the following schema: - **input**: `{ messages: [...] }` input messages to call the agent with. - **output**: `{ messages": [...] }` expected message history in the agent output. For trajectory evaluation, you can choose to keep only assistant messages. ```ts import { evaluate } from "langsmith/evaluation"; import { createTrajectoryMatchEvaluator } from "agentevals"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; const agent = createReactAgent({ ... }) const evaluator = createTrajectoryMatchEvaluator({ ... }) await evaluate( async (inputs) => await agent.invoke(inputs), { // replace with your dataset name data: "", evaluators: [evaluator], } ); ``` --- ## File: docs/docs/agents/human-in-the-loop.md # Human-in-the-loop To review, edit and approve tool calls in an agent you can use LangGraph's built-in [human-in-the-loop](../concepts/human_in_the_loop.md) features, specifically the [`interrupt()`](/langgraphjs/reference/functions/langgraph.interrupt-1.html) primitive. LangGraph allows you to pause execution **indefinitely** β€” for minutes, hours, or even daysβ€”until human input is received. This is possible because the agent state is **checkpointed into a database**, which allows the system to persist execution context and later resume the workflow, continuing from where it left off. For a deeper dive into the **human-in-the-loop** concept, see the [concept guide](../concepts/human_in_the_loop.md).
{: style="max-height:400px"}
A human can review and edit the output from the agent before proceeding. This is particularly critical in applications where the tool calls requested may be sensitive or require human oversight.
## Review tool calls To add a human approval step to a tool: 1. Use `interrupt()` in the tool to pause execution. 2. Resume with a `Command({ resume: ... })` to continue based on human input. ```ts import { MemorySaver } from "@langchain/langgraph-checkpoint"; import { interrupt } from "@langchain/langgraph"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { initChatModel } from "langchain/chat_models/universal"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; // An example of a sensitive tool that requires human review / approval const bookHotel = tool( async (input: { hotelName: string; }) => { let hotelName = input.hotelName; // highlight-next-line const response = interrupt( // (1)! `Trying to call \`book_hotel\` with args {'hotel_name': ${hotelName}}. ` + `Please approve or suggest edits.` ) if (response.type === "accept") { // proceed to execute the tool logic } else if (response.type === "edit") { hotelName = response.args["hotel_name"] } else { throw new Error(`Unknown response type: ${response.type}`) } return `Successfully booked a stay at ${hotelName}.`; }, { name: "bookHotel", schema: z.object({ hotelName: z.string().describe("Hotel to book"), }), } ); // highlight-next-line const checkpointer = new MemorySaver(); // (2)! const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [bookHotel], // highlight-next-line checkpointer // (3)! }); ``` 1. The [`interrupt` function](/langgraphjs/reference/functions/langgraph.interrupt-1.html) pauses the agent graph at a specific node. In this case, we call `interrupt()` at the beginning of the tool function, which pauses the graph at the node that executes the tool. The information inside `interrupt()` (e.g., tool calls) can be presented to a human, and the graph can be resumed with the user input (tool call approval, edit or feedback). 2. The `InMemorySaver` is used to store the agent state at every step in the tool calling loop. This enables [short-term memory](./memory.md#short-term-memory) and [human-in-the-loop](./human-in-the-loop.md) capabilities. In this example, we use `InMemorySaver` to store the agent state in memory. In a production application, the agent state will be stored in a database. 3. Initialize the agent with the `checkpointer`. Run the agent with the `stream()` method, passing the `config` object to specify the thread ID. This allows the agent to resume the same conversation on future invocations. ```ts const config = { configurable: { // highlight-next-line "thread_id": "1" } } for await (const chunk of await agent.stream( { messages: "book a stay at McKittrick hotel" }, // highlight-next-line config )) { console.log(chunk); console.log("\n"); }; ``` > You should see that the agent runs until it reaches the `interrupt()` call, at which point it pauses and waits for human input. Resume the agent with a `Command({ resume: ... })` to continue based on human input. ```ts import { Command } from "@langchain/langgraph"; for await (const chunk of await agent.stream( new Command({ resume: { type: "accept" } }), // (1)! // new Command({ resume: { type: "edit", args: { "hotel_name": "McKittrick Hotel" } } }), // highlight-next-line config )) { console.log(chunk); console.log("\n"); }; ``` 1. The [`interrupt` function](/langgraphjs/reference/functions/langgraph.interrupt-1.html) is used in conjunction with the [`Command`](/langgraphjs/reference/classes/langgraph.Command.html) object to resume the graph with a value provided by the human. ## Additional resources * [Human-in-the-loop in LangGraph](../concepts/human_in_the_loop.md) --- ## File: docs/docs/agents/mcp.md # MCP Integration [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol that standardizes how applications provide tools and context to language models. LangGraph agents can use tools defined on MCP servers through the `@langchain/mcp-adapters` library. Install the `@langchain/mcp-adapters` library to use MCP tools in LangGraph: ```bash npm install @langchain/mcp-adapters ``` ## Use MCP tools The `@langchain/mcp-adapters` package enables agents to use tools defined across one or more MCP servers. ```ts // highlight-next-line import { MultiServerMCPClient } from "@langchain/mcp-adapters"; import { initChatModel } from "langchain/chat_models/universal"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; // highlight-next-line const client = new MultiServerMCPClient({ mcpServers: { "math": { command: "python", // Replace with absolute path to your math_server.py file args: ["/path/to/math_server.py"], transport: "stdio", }, "weather": { // Ensure your start your weather server on port 8000 url: "http://localhost:8000/sse", transport: "sse", } } }) const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, // highlight-next-line tools: await client.getTools() }); const mathResponse = await agent.invoke( { messages: [ { role: "user", content: "what's (3 + 5) x 12?" } ] } ); const weatherResponse = await agent.invoke( { messages: [ { role: "user", content: "what is the weather in nyc?" } ] } ); await client.close(); ``` ## Custom MCP servers To create your own MCP servers, you can use the `mcp` library in Python (or `@modelcontextprotocol/sdk` in TypeScript). These libraries provide a simple way to define tools and run them as servers. Install the MCP library: ```bash pip install mcp ``` Use the following reference implementations to test your agent with MCP tool servers. ```python title="Example Math Server (stdio transport)" from mcp.server.fastmcp import FastMCP mcp = FastMCP("Math") @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" return a + b @mcp.tool() def multiply(a: int, b: int) -> int: """Multiply two numbers""" return a * b if __name__ == "__main__": mcp.run(transport="stdio") ``` ```python title="Example Weather Server (SSE transport)" from mcp.server.fastmcp import FastMCP mcp = FastMCP("Weather") @mcp.tool() async def get_weather(location: str) -> str: """Get weather for location.""" return "It's always sunny in New York" if __name__ == "__main__": mcp.run(transport="sse") ``` ## Additional resources - [MCP documentation](https://modelcontextprotocol.io/introduction) - [MCP Transport documentation](https://modelcontextprotocol.io/docs/concepts/transports) --- ## File: docs/docs/agents/memory.md # Memory LangGraph supports two types of memory essential for building conversational agents: - **[Short-term memory](#short-term-memory)**: Tracks the ongoing conversation by maintaining message history within a session. - **[Long-term memory](#long-term-memory)**: Stores user-specific or application-level data across sessions. This guide demonstrates how to use both memory types with agents in LangGraph. For a deeper understanding of memory concepts, refer to the [LangGraph memory documentation](../concepts/memory.md).
{: style="max-height:400px"}
Both **short-term** and **long-term** memory require persistent storage to maintain continuity across LLM interactions. In production environments, this data is typically stored in a database.
!!! note "Terminology" In LangGraph: - *Short-term memory* is also referred to as **thread-level memory**. - *Long-term memory* is also called **cross-thread memory**. A [thread](../concepts/persistence.md#threads) represents a sequence of related runs grouped by the same `thread_id`. ## Short-term memory Short-term memory enables agents to track multi-turn conversations. To use it, you must: 1. Provide a `checkpointer` when creating the agent. The `checkpointer` enables [persistence](../concepts/persistence.md) of the agent's state. 2. Supply a `thread_id` in the config when running the agent. The `thread_id` is a unique identifier for the conversation session. ```ts // highlight-next-line import { MemorySaver } from "@langchain/langgraph-checkpoint"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { initChatModel } from "langchain/chat_models/universal"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; // highlight-next-line const checkpointer = new MemorySaver(); // (1)! const getWeather = tool( async (input: { city: string }) => { return `It's always sunny in ${input.city}!`; }, { name: "getWeather", schema: z.object({ city: z.string().describe("The city to get the weather for"), }), } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getWeather], // highlight-next-line checkpointer // (2)! }); // Run the agent // highlight-next-line const config = { configurable: { thread_id: "1" } }; // (3)! const sfResponse = await agent.invoke( { messages: [ { role: "user", content: "what is the weather in sf" } ] }, config // (4)! ); const nyResponse = await agent.invoke( { messages: [ { role: "user", content: "what about new york?" } ] }, config ); ``` 1. The `MemorySaver` is a checkpointer that stores the agent's state in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [checkpointer documentation](https://langchain-ai.github.io/langgraphjs/reference/index.html) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready checkpointer for you. 2. The `checkpointer` is passed to the agent. This enables the agent to persist its state across invocations. Please note that 3. A unique `thread_id` is provided in the config. This ID is used to identify the conversation session. The value is controlled by the user and can be any string. 4. The agent will continue the conversation using the same `thread_id`. This will allow the agent to infer that the user is asking specifically about the **weather** in New York. When the agent is invoked the second time with the same `thread_id`, the original message history from the first conversation is automatically included, allowing the agent to infer that the user is asking specifically about the **weather** in New York. !!! Note "LangGraph Platform providers a production-ready checkpointer" If you're using [LangGraph Platform](./deployment.md), during deployment your checkpointer will be automatically configured to use a production-ready database. ## Long-term memory Use long-term memory to store user-specific or application-specific data across conversations. This is useful for applications like chatbots, where you want to remember user preferences or other information. To use long-term memory, you need to: 1. [Configure a store](../how-tos/cross-thread-persistence.ipynb) to persist data across invocations. 2. Use the `config.store` to access the store from within tools or prompts. ### Reading ```ts title="A tool the agent can use to look up user information" import { initChatModel } from "langchain/chat_models/universal"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; // highlight-next-line import { InMemoryStore } from "@langchain/langgraph-checkpoint"; // highlight-next-line import { getStore } from "@langchain/langgraph"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; const store = new InMemoryStore(); // (1)! await store.put( // (2)! ["users"], // (3)! "user_123", // (4)! { name: "John Smith", language: "English", } // (5)! ); // Look up user info tool const getUserInfo = tool( async (input: Record, config: LangGraphRunnableConfig): Promise => { // Same as that provided to `createReactAgent` const store = config.store; // (6)! if (!store) { throw new Error("store is required when compiling the graph"); } const userId = config.configurable?.userId; if (!userId) { throw new Error("userId is required in the config"); } const userInfo = await store.get(["users"], userId); // (7)! return userInfo ? JSON.stringify(userInfo.value) : "Unknown user"; }, { name: "get_user_info", schema: z.object({}), } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [getUserInfo], store, // (8)! }); // Run the agent const response = await agent.invoke( { messages: [ { role: "user", content: "look up user information" } ] }, { configurable: { userId: "user_123" } } ); ``` 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [documentation](https://langchain-ai.github.io/langgraphjs/reference/index.html) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you. 2. For this example, we write some sample data to the store using the `put` method. Please see the [BaseStore.put](https://langchain-ai.github.io/langgraphjs/reference/classes/checkpoint.BaseStore.html#put) API reference for more details. 3. The first argument is the namespace. This is used to group related data together. In this case, we are using the `users` namespace to group user data. 4. A key within the namespace. This example uses a user ID for the key. 5. The data that we want to store for the given user. 6. You can access the store via `config.store` from anywhere in your nodes, tools and prompts. It contains the store that was passed to the agent when it was created. 7. The `get` method is used to retrieve data from the store. The first argument is the namespace, and the second argument is the key. This will return a `StoreValue` object, which contains the value and metadata about the value. 8. The `store` is passed to the agent. This enables the agent to access the store when running tools. ### Writing ```ts title="Example of a tool that updates user information" import { initChatModel } from "langchain/chat_models/universal"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { InMemoryStore } from "@langchain/langgraph-checkpoint"; import { getStore } from "@langchain/langgraph"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; const store = new InMemoryStore(); // (1)! interface UserInfo { // (2)! name: string; } // Save user info tool const saveUserInfo = tool( // (3)! async (input: UserInfo, config: LangGraphRunnableConfig): Promise => { // Same as that provided to `createReactAgent` // highlight-next-line const store = config.store; // (4)! if (!store) { throw new Error("store is required when compiling the graph"); } const userId = config.configurable?.userId; if (!userId) { throw new Error("userId is required in the config"); } await store.put(["users"], userId, input); // (5)! return "Successfully saved user info."; }, { name: "save_user_info", schema: z.object({ name: z.string(), }), } ); const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); const agent = createReactAgent({ llm, tools: [saveUserInfo], // highlight-next-line store, }); // Run the agent await agent.invoke( { messages: [ { role: "user", content: "My name is John Smith" } ] }, { configurable: { userId: "user_123" } } // (6)! ); // You can access the store directly to get the value const userInfo = await store.get(["users"], "user_123") userInfo.value ``` 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [store documentation](../reference/stores.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you. 2. The `UserInfo` class is an interface that defines the structure of the user information. We will specify the same schema below using a zod object, so that the LLM formats the response according to the schema. 3. The `saveUserInfo` is a tool that allows an agent to update user information. This could be useful for a chat application where the user wants to update their profile information. 4. You can access the store via `config.store` from anywhere in your nodes, tools and prompts. It contains the store that was passed to the agent when it was created. 5. The `put` method is used to store data in the store. The first argument is the namespace, and the second argument is the key. This will store the user information in the store. 6. The `userId` is passed in the config. This is used to identify the user whose information is being updated. ## Additional resources * [Memory in LangGraph](../concepts/memory.md) --- ## File: docs/docs/agents/models.md # Models This page describes how to configure the chat model used by an agent. ## Tool calling support To enable tool-calling agents, the underlying LLM must support [tool calling](https://js.langchain.com/docs/concepts/tool_calling/). Compatible models can be found in the [LangChain integrations directory](https://js.langchain.com/docs/integrations/chat/). ## Using `initChatModel` The [`initChatModel`](https://js.langchain.com/docs/how_to/chat_models_universal_init/) utility simplifies model initialization with configurable parameters: ```ts import { initChatModel } from "langchain/chat_models/universal"; const llm = await initChatModel( "anthropic:claude-3-7-sonnet-latest", { temperature: 0, maxTokens: 2048 } ); ``` Refer to the [API reference](https://api.js.langchain.com/functions/langchain.chat_models_universal.initChatModel.html) for advanced options. ## Using provider-specific LLMs If a model provider is not available via `initChatModel`, you can instantiate the provider's model class directly. The model must implement the [`BaseChatModel`](https://api.js.langchain.com/classes/_langchain_core.language_models_chat_models.BaseChatModel.html) interface and support tool calling: ```ts import { ChatAnthropic } from "@langchain/anthropic"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; // highlight-next-line const llm = new ChatAnthropic({ modelName: "claude-3-7-sonnet-latest", temperature: 0, maxTokens: 2048 }); const agent = createReactAgent({ // highlight-next-line llm, // other parameters }); ``` !!! note "Illustrative example" The example above uses `ChatAnthropic`, which is already supported by `initChatModel`. This pattern is shown to illustrate how to manually instantiate a model not available through `initChatModel`. ## Additional resources - [Model integration directory](https://js.langchain.com/docs/integrations/chat/) - [Universal initialization with `initChatModel`](https://js.langchain.com/docs/how_to/chat_models_universal_init/) --- ## File: docs/docs/agents/multi-agent.md # Multi-agent A single agent might struggle if it needs to specialize in multiple domains or manage many tools. To tackle this, you can break your agent into smaller, independent agents and composing them into a [multi-agent system](../concepts/multi_agent.md). In multi-agent systems, agents need to communicate between each other. They do so via [handoffs](#handoffs) β€” a primitive that describes which agent to hand control to and the payload to send to that agent. Two of the most popular multi-agent architectures are: - [supervisor](#supervisor) β€” individual agents are coordinated by a central supervisor agent. The supervisor controls all communication flow and task delegation, making decisions about which agent to invoke based on the current context and task requirements. - [swarm](#swarm) β€” agents dynamically hand off control to one another based on their specializations. The system remembers which agent was last active, ensuring that on subsequent interactions, the conversation resumes with that agent. ## Supervisor Use [`langgraph-supervisor`](https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-supervisor) library to create a supervisor multi-agent system: ```bash npm install @langchain/langgraph-supervisor ``` ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ## Swarm Use [`langgraph-swarm`](https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-swarm) library to create a swarm multi-agent system: ```bash npm install @langchain/langgraph-swarm ``` ```ts import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { ChatAnthropic } from "@langchain/anthropic"; // highlight-next-line import { createSwarm, createHandoffTool } from "@langchain/langgraph-swarm"; const transferToHotelAssistant = createHandoffTool({ agentName: "hotel_assistant", }); const transferToFlightAssistant = createHandoffTool({ agentName: "flight_assistant", }); const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-latest" }); const flightAssistant = createReactAgent({ llm, tools: [bookFlight, transferToHotelAssistant], prompt: "You are a flight booking assistant", name: "flight_assistant", }); const hotelAssistant = createReactAgent({ llm, tools: [bookHotel, transferToFlightAssistant], prompt: "You are a hotel booking assistant", name: "hotel_assistant", }); // highlight-next-line const swarm = createSwarm({ agents: [flightAssistant, hotelAssistant], defaultActiveAgent: "flight_assistant", }).compile(); const stream = await swarm.stream({ messages: [{ role: "user", content: "first book a flight from BOS to JFK and then book a stay at McKittrick Hotel" }] }); for await (const chunk of stream) { console.log(chunk); console.log("\n"); } ``` ## Handoffs A common pattern in multi-agent interactions is **handoffs**, where one agent *hands off* control to another. Handoffs allow you to specify: - **destination**: target agent to navigate to - **payload**: information to pass to that agent This is used both by `langgraph-supervisor` (supervisor hands off to individual agents) and `langgraph-swarm` (an individual agent can hand off to other agents). To implement handoffs with `createReactAgent`, you need to: 1. Create a special tool that can transfer control to a different agent ```ts const transferToBob = tool( async (_) => { return new Command({ // name of the agent (node) to go to // highlight-next-line goto: "bob", // data to send to the agent // highlight-next-line update: { messages: ... }, // indicate to LangGraph that we need to navigate to // agent node in a parent graph // highlight-next-line graph: Command.PARENT, }); }, { name: ..., schema: ..., } ); ``` 1. Create individual agents that have access to handoff tools: ```ts const flightAssistant = createReactAgent( ..., tools: [bookFlight, transferToHotelAssistant] ) const hotelAssistant = createReactAgent( ..., tools=[bookHotel, transferToFlightAssistant] ) ``` 1. Define a parent graph that contains individual agents as nodes: ```ts import { StateGraph, MessagesAnnotation } from "@langchain/langgraph"; const multiAgentGraph = new StateGraph(MessagesAnnotation) .addNode("flight_assistant", flightAssistant) .addNode("hotel_assistant", hotelAssistant) ... ``` Putting this together, here is how you can implement a simple multi-agent system with two agents β€” a flight booking assistant and a hotel booking assistant: ``` /* Detailed source-code truncated for AI context efficiency. */ ``` 1. Access agent's state 2. The `Command` primitive allows specifying a state update and a node transition as a single operation, making it useful for implementing handoffs. 3. Name of the agent or node to hand off to. 4. Take the agent's messages and **add** them to the parent's **state** as part of the handoff. The next agent will see the parent state. 5. Indicate to LangGraph that we need to navigate to agent node in a **parent** multi-agent graph. !!! Note This handoff implementation assumes that: - each agent receives overall message history (across all agents) in the multi-agent system as its input - each agent outputs its internal messages history to the overall message history of the multi-agent system Check out LangGraph [supervisor](https://github.com/langchain-ai/langgraph-supervisor-py#customizing-handoff-tools) and [swarm](https://github.com/langchain-ai/langgraph-swarm-py#customizing-handoff-tools) documentation to learn how to customize handoffs. ## 2. Official Technical Reference & Guides (langchain-ai/docs) # LangChain Docs 🦜 **Welcome!** This repository contains the documentation build pipeline for LangChain projects. * 🏠 [`docs.langchain.com`](https://docs.langchain.com) is our docs home, centralizing LangChain, LangGraph, LangSmith, and LangChain Labs (Deep Agents, Open SWE, Open Agent Platform). This site is hosted on [Mintlify](https://mintlify.com). * πŸ› οΈ [`reference.langchain.com`](https://reference.langchain.com/python/) hosts generated API reference for LangChain, LangGraph, LangSmith, and integration packages. That site is **not** built from this repository (no reference build scripts or output live here). * [`Python reference`](https://reference.langchain.com/python/) * [`JavaScript/TypeScript reference`](https://reference.langchain.com/javascript/) * πŸ’¬ [`chat.langchain.com`](https://chat.langchain.com) is an AI-powered assistant that can answer questions about LangChain documentation. --- **Table of contents:** - [LangChain Docs](#langchain-docs) - [Contribute](#contribute) - [Reference](#reference) - [Repository structure](#repository-structure) - [`docs.langchain.com`](#docslangchaincom) - [`reference.langchain.com`](#referencelangchaincom) - [File formats](#file-formats) - [Available commands](#available-commands) - [Linting](#linting) - [Codespell](#codespell) - [Troubleshooting](#troubleshooting) - [`docs dev` not working / running](#docs-dev-not-working--running) - [Mintlify `.venv` parsing error](#mintlify-venv-parsing-error) - [Warning: page doesn't exist](#warning-page-doesnt-exist) - [General Mintlify errors](#general-mintlify-errors) --- ## Contribute To run a local preview of the documentation: ```bash git clone https://github.com/langchain-ai/docs.git ``` ```bash cd docs ``` ```bash make install ``` ```bash make dev ``` For more information on how to contribute to LangChain documentation, follow the steps outlined in the [contributing guide](https://docs.langchain.com/oss/python/contributing/overview). The contributing guide also explains our documentation types and their writing and quality standards. For detailed information about setting up your development environment and contributing to documentation, see the [documentation contributing guide](https://docs.langchain.com/oss/python/contributing/documentation). To report issues with **reference.langchain.com** (missing pages, broken links, or generated API content), [open a reference documentation issue](https://github.com/langchain-ai/docs/issues/new?template=04-reference-docs.yml) on this repo so maintainers can route it. ## Reference ### Repository structure ```text # --- docs.langchain.com ---------------------------------------------- build/ # Built docs (DO NOT EDIT) packages.yml # Package metadata (indexes, tables, downloads; not the API reference build) pipeline/ # Build pipeline source code scripts/ # Helper scripts src/ # Source documentation files (< EDIT CONTENT HERE) langsmith/ # LangSmith docs oss/ # LangChain, LangGraph, Deep Agents, and integrations docs docs.json # Mintlify site configuration and navigation tests/ # Test files for the pipeline Makefile # Build targets pyproject.toml # Dependencies ``` #### `docs.langchain.com` The Mintlify docs pipeline is structured with `.mdx` source files in `/src` and build artifacts in `/build`. Mintlify deploys from the `/build` folder, which is generated by preprocessing logic. > [!IMPORTANT] > Never edit `/build` directly. The `/src/docs.json` file is used to configure the Mintlify site navigation and settings. Refer to the [Mintlify documentation](https://www.mintlify.com/docs/organize/navigation) for detailed syntax and component usage. Documentation changes follow a PR workflow where all tests must pass before merging. See the [contributing guidelines](https://docs.langchain.com/oss/python/contributing/documentation) for more details. #### `reference.langchain.com` API reference is generated and deployed outside this repo. Browse [Python](https://reference.langchain.com/python/) and [JavaScript/TypeScript](https://reference.langchain.com/javascript/) reference there. If something is wrong with that site, use the [reference docs issue template](https://github.com/langchain-ai/docs/issues/new?template=04-reference-docs.yml). ### File formats * **Markdown files** (`.md`, `.mdx`) - Standard documentation content * **Snippets** (`src/snippets/`) - Reusable MDX content that can be imported into multiple pages. **Important:** Snippets undergo special link preprocessing. When writing links in snippets, be careful about path segments. * **Jupyter notebooks** (`.ipynb`) - Converted to markdown during build, though **these are not recommended for new content!** Your PR will likely be rejected if you attempt to add a Jupyter notebook unless asked to by a maintainer. * **Assets** - Images and other files are copied to the build directory ### Available commands **Make commands:** * `make dev` - Start development mode with file watching and live rebuild * `make build` - Build documentation to `./build` directory * `make broken-links` - Check for broken links in documentation * `make broken-links-with-anchors` - Check for broken links + check links with anchors * `make install` - Install all dependencies * `make clean` - Remove build artifacts * `make test` - Run the test suite * `make lint` - Check code style and formatting * `make format` - Auto-format code * `make lint_md` - Lint markdown files * `make lint_md_fix` - Lint and fix markdown files * `make help` - Show all available commands **`docs` CLI tool:** The `docs` command (installed as `uv run docs`) provides additional functionality: * **`docs migrate `** - Convert MkDocs markdown/notebook files to Mintlify format * `--dry-run` - Preview changes without writing files * `--output ` - Specify output location (default: in-place) * Supports `.md`, `.markdown`, `.ipynb` files * **`docs migrate-docusaurus `** - Convert Docusaurus markdown/notebook files to Mintlify format * `--dry-run` - Preview changes without writing files * `--output ` - Specify output location (default: in-place) * Supports `.md`, `.markdown`, `.mdx`, `.ipynb` files * Converts Docusaurus-specific syntax (admonitions, tabs, imports, etc.) * **`docs mv `** - Move files and update cross-references * `--dry-run` - Preview changes without moving files These can be used directly using the `Makefile` or via the `docs` CLI tool: * **`docs dev`** - Start development mode with file watching and hot reload * Automatically rebuilds changed files from `src/` to `build/` * Launches Mintlify dev server at * Provides automatic browser refresh when files change * `--skip-build` - Skip initial build and use existing build directory * **`docs build`** - Build documentation files * `--watch` - Watch for file changes after building ## Linting After running `make install`, you can use `make lint_prose` to ensure your writing meets our style guide rules. ### Codespell `make lint` runs `uv run codespell src` to check source documentation for common spelling errors. Codespell is configured in `pyproject.toml` under `[tool.codespell]`: * Add custom accepted words to `src/.codespellignore`. This file is referenced by `ignore-words = "src/.codespellignore"`. * Exclude generated files, vendor content, or other paths that should not be spell checked by adding glob patterns to the `skip` setting. * Keep skip patterns scoped. Prefer adding accepted words to `src/.codespellignore` when the word is valid documentation content, and use `skip` when the file or directory should not be checked at all. You can also follow these steps to enable `vale` with VS Code or Cursor: 1. Install the [Vale extension](https://marketplace.visualstudio.com/items?itemName=chrischinchilla.vale-vscode) (Vale by Chris Chinchilla) 2. Install Vale CLI: `brew install vale` (macOS) or see [Vale installation](https://vale.sh/docs/vale-cli/installation/) for other platforms 3. Navigate to the Vale extension settings: - Set `Vale CLI: Config` to the absolute path to `.vale.ini` (in the root of this repo) - Set `Vale CLI: Min Alert Level` to `suggestion` (many rules are coded as suggestions) If you cannot use the VS Code UI to configure Vale, add these settings to your `settings.json`: ```json "vale.valeCLI.config": "/path/to/docs/.vale.ini", "vale.valeCLI.minAlertLevel": "suggestion" ``` **Note:** The extension requires Vale on your `PATH`. If annotations don't appear (e.g., when Cursor is launched from the Dock), launch Cursor from a terminal so it inherits your PATH, or ensure Homebrew is in your shell profile. ## Troubleshooting ### General Mintlify errors In some cases, we use new features that are only available in the latest Mintlify CLI. If you encounter errors, ensure you have the latest version installed: ```bash mint update # or npm install mint ``` ### `docs dev` not working / running Re-do the [steps to set up your dev environment](https://docs.langchain.com/oss/python/contributing/documentation#set-up-local-environment), ensuring you have activated the virtual environment and installed all dependencies. > [!IMPORTANT] > Most of the time, `mint update` solves any `docs dev` / `make dev` issues! ### Mintlify `.venv` parsing error **Problem**: Running `mint broken-links` or other Mintlify commands from the project root causes parsing errors like: ```txt Unable to parse .venv/lib/python3.13/site-packages/soupsieve-2.7.dist-info/licenses/LICENSE.md - 3:48: Unexpected character '@' (U+0040) in name ``` **Root Cause**: Mintlify tries to parse all files in the directory, including Python virtual environment files that contain invalid MDX syntax. **Solutions** (in order of preference): 1. **Use the safe Make commands** (recommended): ```bash make broken-links-with-anchors # Builds docs first, then checks internal links ``` 2. **Run Mintlify commands from the build directory**: ```bash cd build # Change to build directory where final docs are mint broken-links # Now safe to run ``` **Why this works**: The solution ensures Mintlify commands run from the `build/` directory where the final documentation is generated, which is the correct place to check for broken links. This avoids scanning the Python virtual environment in the project root. **Prevention**: Always use the provided Make commands instead of running raw `mint` commands from the project root. ### Warning: page doesn't exist If adding a new group, ensure the root `index.mdx` is included in the `pages` array like: ```json { "group": "New group", "pages": ["new-group/index", "new-group/other-page"] } ``` If the trailing `/index` (no extension included) is omitted, the Mintlify parser will raise a warning even though the site will still build.