> ## Documentation Index
> Fetch the complete documentation index at: https://trytilde.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# LangChain and LangGraph

> Run a LangChain or LangGraph agent on Tilde with the TypeScript or Python LangChain adapter.

The LangChain adapter runs agents built with LangChain's `createAgent` (`create_agent` in Python), which runs on LangGraph. It is a LangChain middleware. It works with LangChain 1 and LangGraph 1.

<Columns cols={2}>
  <Card title="TypeScript example" icon="github" href="https://github.com/trytilde/tilde/tree/main/sdk/ts/examples/langchain-example-agent">
    A complete LangChain agent in TypeScript.
  </Card>

  <Card title="Python example" icon="github" href="https://github.com/trytilde/tilde/tree/main/sdk/py/examples/example-agent-langchain">
    A complete LangChain agent in Python.
  </Card>
</Columns>

## Install

<CodeGroup>
  ```bash TypeScript theme={"system"}
  npm i @trytilde/sdk @trytilde/sdk-langchain-node langchain @langchain/core @langchain/openai
  ```

  ```bash Python theme={"system"}
  pip install trytilde trytilde-langchain langchain-openai
  ```
</CodeGroup>

## How it works

Add the Tilde middleware to the agent. On each model call, it adds the channel's tools, the agent's Tilde and bundled tools, and skills. It runs Tilde tool calls, and adds new user input to the agent's state.

<CodeGroup>
  ```typescript TypeScript theme={"system"}
  import { inference, type AgentContext } from "@trytilde/sdk";
  import {
    convertToLangChainMessages,
    tildeLangChain,
    tildeMiddleware,
  } from "@trytilde/sdk-langchain-node";
  import { ChatOpenAI } from "@langchain/openai";
  import { createAgent } from "langchain";
  import { bundledTools } from "./bundled-tools.js";

  const { baseURL, apiKey, fetch } = inference("default");

  export const agent = createAgent({
    name: "support-agent",
    model: new ChatOpenAI({
      apiKey,
      configuration: { baseURL, fetch },
      model: "gpt-4o-mini",
    }),
    systemPrompt: "You are a support assistant. Reply with the channel tools.",
    middleware: [tildeMiddleware({ bundled: bundledTools })],
  });

  export async function respond(ctx: AgentContext) {
    const history = await ctx.message.history();
    const messages = await convertToLangChainMessages({
      messages: history.items,
      context: ctx,
    });
    // tildeLangChain(ctx) is required. The middleware refuses to run without it.
    await agent.invoke({ messages }, { ...tildeLangChain(ctx), recursionLimit: 16 });
  }
  ```

  ```python Python theme={"system"}
  import tilde
  from langchain.agents import create_agent
  from langchain_openai import ChatOpenAI
  from tilde_langchain import convert_to_langchain_messages, tilde_middleware

  from bundled_tools import TOOLS

  INFERENCE = tilde.inference("default")

  agent = create_agent(
      ChatOpenAI(
          model="gpt-4o-mini",
          base_url=INFERENCE.base_url,
          api_key=INFERENCE.api_key,
          http_async_client=INFERENCE.async_client(),
          http_client=INFERENCE.client(),
      ),
      system_prompt="You are a support assistant. Reply with the channel tools.",
      middleware=[tilde_middleware(bundled=TOOLS)],
      name="support-agent",
  )

  async def respond(ctx: tilde.AgentContext) -> None:
      history = await ctx.message.history()
      messages = await convert_to_langchain_messages(history.items, context=ctx)
      await agent.ainvoke({"messages": messages}, {"recursion_limit": 16})
  ```
</CodeGroup>

The adapter also works with `createReactAgent` and `bindTools`, through `withTildeTools`.

## Feature compatibility

| Feature | Support | Notes |
| - | - | - |
| Inference gateway | Yes | |
| Framework trace spans | Partial | LangChain emits no OpenTelemetry spans. Tilde records its own spans. |
| Tilde and channel tools | Yes | |
| Bundled tools | Yes | Write LangChain `tool` (TypeScript) or `@tool` (Python) tools. Tools in the graph's `ToolNode` are also registered. |
| Prompt versioning | Yes | Registers `<name>/system_prompt`, `PromptTemplate`, and `ChatPromptTemplate`. Python also versions `@dynamic_prompt`. |
| Native skills | No | Skills arrive as `list_skills` and `read_skill` tools, with a summary in the instructions. |
| New input during a run | Yes | |

## Limitations

* **Python is async only.** Call the agent with `ainvoke` or `astream`.
* **Dynamic prompts in TypeScript.** A `dynamicSystemPromptMiddleware` prompt is not versioned, because its text is hidden in a closure. Discovery warns. Use [`definePrompt`](/docs/prompts/overview#declare-a-prompt) for it.
* **External prompts.** LangSmith Hub prompts and Jinja2 templates are reported as warnings, not versioned.
* **Injected state.** In [search mode](/docs/tools/overview#tool-discovery), a tool that needs LangGraph-injected state, such as `ToolRuntime` or `InjectedState`, runs without that state.
* **Tracing.** LangSmith tracing is separate from Tilde, and sends data to LangSmith.
