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

# LangGraph

> Build a stateful conversational AI agent with LangGraph and Honcho

Integrate Honcho with LangGraph to build a conversational AI agent that maintains memory across sessions. This guide shows you how to use Honcho's memory layer with LangGraph's orchestration.

<Note>
  The full code is available on [GitHub](https://github.com/plastic-labs/honcho/tree/main/examples/langgraph) with examples in both [Python](https://github.com/plastic-labs/honcho/blob/main/examples/langgraph/python/main.py) and [TypeScript](https://github.com/plastic-labs/honcho/blob/main/examples/langgraph/typescript/main.ts)
</Note>

## What We're Building

We'll create a conversational agent that remembers and reasons over past exchanges with the user. Here's how the pieces fit together:

* **LangGraph** orchestrates the conversation flow
* **Honcho** stores messages and retrieves relevant context
* **Your LLM** generates responses using Honcho's formatted context

The key benefit: You don't manually manage conversation history, token limits, or message formatting. Honcho handles memory so you can focus on your agent's logic.

<Note>
  This tutorial demonstrates a simple linear conversation flow to show
  how Honcho integrates with LangGraph. For production applications,
  you'll likely want to add LangGraph features like conditional routing,
  tool calling, and multi-agent orchestration.
</Note>

## Setup

Install required packages:

<CodeGroup>
  ```bash Python (uv) theme={null}
  uv add honcho-ai langgraph langchain-core openai python-dotenv
  ```

  ```bash Python (pip) theme={null}
  pip install honcho-ai langgraph langchain-core openai python-dotenv
  ```

  ```bash TypeScript (npm) theme={null}
  npm install @honcho-ai/sdk @langchain/langgraph openai dotenv
  ```

  ```bash TypeScript (yarn) theme={null}
  yarn add @honcho-ai/sdk @langchain/langgraph openai dotenv
  ```

  ```bash TypeScript (pnpm) theme={null}
  pnpm add @honcho-ai/sdk @langchain/langgraph openai dotenv
  ```
</CodeGroup>

This tutorial uses OpenAI, but Honcho works with any LLM provider. Create a `.env` file with your API keys:

```bash theme={null}
OPENAI_API_KEY=your_openai_key
```

<Note>
  This tutorial uses the Honcho demo server at [https://demo.honcho.dev](https://demo.honcho.dev) which runs a small instance of Honcho on the latest version. For production, get your Honcho API key at [app.honcho.dev](https://app.honcho.dev). For local development, use `environment="local"`.
</Note>

## Initialize Clients

<CodeGroup>
  ```python Python theme={null}
  import os
  from dotenv import load_dotenv
  from typing_extensions import TypedDict
  from honcho import Honcho, Peer, Session
  from openai import OpenAI
  from langgraph.graph import StateGraph, START, END

  load_dotenv()

  # Initialize Honcho
  honcho = Honcho()

  # Initialize OpenAI
  llm = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
  ```

  ```typescript TypeScript theme={null}
  import * as dotenv from "dotenv";
  import { Honcho, Peer, Session } from "@honcho-ai/sdk";
  import OpenAI from "openai";
  import { Annotation } from "@langchain/langgraph";
  import { StateGraph, START, END } from "@langchain/langgraph";
  import * as readline from "readline/promises";

  dotenv.config();

  // Initialize Honcho
  const honcho = new Honcho({});

  // Initialize OpenAI
  const llm = new OpenAI({
    apiKey: process.env.OPENAI_API_KEY
  });
  ```
</CodeGroup>

## Define LangGraph State

Define your state schema to pass data through the graph. The state stores Honcho objects directly along with the current user message and assistant response.

<Note>
  Before proceeding, it's important to understand Honcho's core concepts (`Peers` and `Sessions`). Review the [Honcho Architecture](/v3/documentation/core-concepts/architecture) to familiarize yourself with these primitives.
</Note>

<CodeGroup>
  ```python Python theme={null}
  class State(TypedDict):
      user_message: str
      assistant_response: str
      user: Peer
      assistant: Peer
      session: Session
  ```

  ```typescript TypeScript theme={null}
  const StateAnnotation = Annotation.Root({
    userMessage: Annotation<string>(),
    assistantResponse: Annotation<string>(),
    user: Annotation<Peer>(),
    assistant: Annotation<Peer>(),
    session: Annotation<Session>(),
  });

  type State = typeof StateAnnotation.State;
  ```
</CodeGroup>

## Build the LangGraph

Define your chatbot logic, using Honcho to retrieve conversation context. This function demonstrates how Honcho can store messages, retrieve context, and generate responses.

<CodeGroup>
  ```python Python theme={null}
  def chatbot(state: State):
      user_message = state["user_message"]

      # Get objects from state
      user = state["user"]
      assistant = state["assistant"]
      session = state["session"]

      # Step 1: Store the user's message in the session
      # This adds it to Honcho's memory for future context retrieval
      session.add_messages([user.message(user_message)])

      # Step 2: Get context in OpenAI format with token limit
      # context() retrieves relevant conversation history
      # tokens=2000 limits the context to 2000 tokens to manage costs and fit within model limits
      # to_openai() converts it to the format expected by OpenAI's API
      messages = session.context(tokens=2000).to_openai(assistant=assistant)

      # Step 3: Generate response using the context
      response = llm.chat.completions.create(
          model="gpt-5.1",
          messages=messages
      )
      assistant_response = response.choices[0].message.content

      # Step 4: Store assistant response in Honcho for future context
      session.add_messages([assistant.message(assistant_response)])

      return {"assistant_response": assistant_response}
  ```

  ```typescript TypeScript theme={null}
  async function chatbot(state: State) {
    const userMessage = state.userMessage;

    // Get objects from state
    const user = state.user;
    const assistant = state.assistant;
    const session = state.session;

    // Step 1: Store the user's message in the session
    // This adds it to Honcho's memory for future context retrieval
    await session.addMessages([user.message(userMessage)]);

    // Step 2: Get context in OpenAI format with token limit
    // context() retrieves relevant conversation history
    // tokens: 2000 limits the context to 2000 tokens to manage costs and fit within model limits
    // toOpenAI() converts it to the format expected by OpenAI's API
    const messages = (await session.context({ tokens: 2000 })).toOpenAI(assistant);

    // Step 3: Generate response using the context
    const response = await llm.chat.completions.create({
      model: "gpt-5.1",
      messages: messages
    });
    const assistantResponse = response.choices[0].message.content!;

    // Step 4: Store assistant response for future context
    await session.addMessages([assistant.message(assistantResponse)]);

    return { assistantResponse: assistantResponse };
  }
  ```
</CodeGroup>

Now let's build the LangGraph:

<CodeGroup>
  ```python Python theme={null}
  graph = StateGraph(State) \
      .add_node("chatbot", chatbot) \
      .add_edge(START, "chatbot") \
      .add_edge("chatbot", END) \
      .compile()
  ```

  ```typescript TypeScript theme={null}
  const graph = new StateGraph(StateAnnotation)
    .addNode("chatbot", chatbot)
    .addEdge(START, "chatbot")
    .addEdge("chatbot", END)
    .compile();
  ```
</CodeGroup>

### Understanding context()

The [`context()`](/v3/documentation/features/get-context) method retrieves comprehensive conversation context and formats it for your LLM. It automatically:

* **Manages conversation history** - Tracks all messages and determines what's relevant
* **Respects token limits** - Stays within context window constraints without manual counting
* **Handles long conversations** - Combines recent detailed messages with summaries of older exchanges
* **Provides `peer` understanding** - Includes representations and `peer` cards when requested

The `SessionContext` object always includes fields for messages, summaries, `peer` representations, and `peer` cards. By default, only `messages` and `summary` are populated. To populate peer-specific context, pass a `peer_target` parameter:

**Using `peer_target` for Context:**

* **Without `peer_perspective`**: Returns Honcho's omniscient view of `peer_target` (all conclusions and context)
* **With `peer_perspective`**: Returns what `peer_perspective` knows about `peer_target` (perspective-based conclusions and context)

That's it. Call `session.context().to_openai(assistant)` and you get properly formatted context tailored for your assistant.

<Tip>
  **Adding System Prompts:** Since `context()` returns conversation messages, you can easily prepend custom system instructions. Just add your system prompt to the beginning of the messages array before sending it to your LLM: `[{"role": "system", "content": "..."}, ...context_messages]`.
</Tip>

<Note>
  For more details on all available parameters, see [`context() documentation`](/v3/documentation/features/get-context)
</Note>

## Chat Loop

Now we'll create the main conversation function. To simplify logic, we initialize Honcho objects once per conversation and pass them through the LangGraph state.

The `run_conversation_turn` function initializes a Honcho `Session` and `Peer` objects, passes them to the LangGraph, and returns the assistant's response. By calling it repeatedly with the same `user_id` and in the same session, the chat builds context over time.

<Note>
  **Production Usage:** Honcho accepts any nanoid-compatible string for `user_id` and `session_id`. You can use IDs directly from your authentication system (Auth0, Firebase, Clerk, etc.) and session management without modification.

  This tutorial uses hardcoded values for simplicity.
</Note>

<CodeGroup>
  ```python Python theme={null}
  def run_conversation_turn(user_id: str, user_input: str, session_id: str | None = None):
      if not session_id:
          session_id = f"session_{user_id}"

      # Initialize Honcho objects
      user = honcho.peer(user_id)
      assistant = honcho.peer("assistant")
      session = honcho.session(session_id)

      result = graph.invoke({
          "user_message": user_input,
          "user": user,
          "assistant": assistant,
          "session": session
      })

      return result["assistant_response"]

  if __name__ == "__main__":
    print("Welcome to the AI Assistant! How can I help you today?")
    user_id = "test-user-123"
    while True:
        user_input = input("You: ")
        if user_input.lower() in ['quit', 'exit']:
            break
        response = run_conversation_turn(user_id, user_input)
        print(f"Assistant: {response}\n")
  ```

  ```typescript TypeScript theme={null}
  async function runConversationTurn(
    userId: string,
    userInput: string,
    sessionId?: string
  ): Promise<string> {
    if (!sessionId) {
      sessionId = `session_${userId}`;
    }

    // Initialize Honcho objects
    const user = await honcho.peer(userId);
    const assistant = await honcho.peer("assistant");
    const session = await honcho.session(sessionId);

    const result = await graph.invoke({
      userMessage: userInput,
      user: user,
      assistant: assistant,
      session: session,
    });

    return result.assistantResponse;
  }

  // Interactive chat loop
  async function main() {
    console.log("Welcome to the AI Assistant! How can I help you today?");
    const userId = "test-user-123";

    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    });

    while (true) {
      const userInput = await rl.question("You: ");
      if (userInput.toLowerCase() === "quit" || userInput.toLowerCase() === "exit") {
        rl.close();
        break;
      }
      const response = await runConversationTurn(userId, userInput);
      console.log(`Assistant: ${response}\n`);
    }
  }

  main();
  ```
</CodeGroup>

## Next Steps

Now that you have a working LangGraph integration with Honcho, you can:

* **Create custom [LangChain tools](https://docs.langchain.com/oss/python/langchain/tools#customize-tool-properties) for your agent** - to fully utilize Honcho's memory & context management features
* **Build a multi-agent LangGraph** where each agent is a Honcho `Peer` with its own memory

## Related Resources

<CardGroup cols={2}>
  <Card title="Get Context" icon="messages" href="/v3/documentation/features/get-context">
    Learn more about retrieving and formatting conversation context
  </Card>

  <Card title="MCP Integration" icon="star-of-life" href="/v3/guides/integrations/mcp">
    Use Honcho in Claude Desktop with MCP
  </Card>
</CardGroup>
