---
title: "LangGraph"
icon: 'diagram-project'
description: "Build a stateful conversational AI agent with LangGraph and Honcho"
sidebarTitle: 'LangGraph'
---

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)
uv add honcho-ai langgraph langchain-core openai python-dotenv
```

```bash Python (pip)
pip install honcho-ai langgraph langchain-core openai python-dotenv
```

```bash TypeScript (npm)
npm install @honcho-ai/sdk @langchain/langgraph openai dotenv
```

```bash TypeScript (yarn)
yarn add @honcho-ai/sdk @langchain/langgraph openai dotenv
```

```bash TypeScript (pnpm)
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
OPENAI_API_KEY=your_openai_key
```

<Note>
This tutorial uses the Honcho demo server at 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
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
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
class State(TypedDict):
    user_message: str
    assistant_response: str
    user: Peer
    assistant: Peer
    session: Session
```

```typescript TypeScript
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
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
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
graph = StateGraph(State) \
    .add_node("chatbot", chatbot) \
    .add_edge(START, "chatbot") \
    .add_edge("chatbot", END) \
    .compile()
```

```typescript TypeScript
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
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
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>
