# LangGraph Chat Workflow in Open-Notebook: AI Conversation Architecture

> Explore the LangGraph chat workflow in Open-Notebook. Discover how AI conversations are architected with SQLite checkpoints, an LLM provisioning layer, and response sanitization for efficient and clean user delivery.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: architecture
- Published: 2026-07-02

---

**Open-Notebook implements its AI chat functionality using a LangGraph state graph that persists conversation threads in SQLite checkpoints, processes messages through an Esperanto-based LLM provisioning layer, and sanitizes responses for clean user delivery.**

Open-Notebook leverages LangGraph to manage multi-turn AI conversations through a deterministic state machine. The implementation centers on a lightweight state graph defined in [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py) that orchestrates message flow between users and language models while maintaining conversation context in a SQLite backend.

## ThreadState: The Conversation Blueprint

The chat workflow relies on a strongly-typed state container that defines the structure of every conversation turn.

### Core State Components

The `ThreadState` TypedDict (defined at lines 22-28 in [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py)) encapsulates the minimal data required to maintain conversation continuity:

- **messages**: A list of conversation history objects representing the dialogue between user and AI
- **notebook**: The notebook object providing context and configuration for the conversation
- **context**: Optional additional context that can be injected into specific turns
- **model_override**: A flag allowing runtime switching of the underlying language model

This typed structure ensures that every node in the LangGraph workflow receives predictable input shape, enabling type-safe state transitions throughout the conversation lifecycle.

## The Chat Graph Architecture

Open-Notebook's LangGraph implementation uses a checkpoint-based persistence model that enables resumeable, long-running conversations.

### SQLite Checkpoint Persistence

The workflow stores dialogue state in a SQLite checkpoint, allowing conversations to survive application restarts and enabling features like conversation replay and branching. This persistent layer sits between the graph's execution engine and the LLM invocation nodes, ensuring that `ThreadState` mutations are atomically saved after each model interaction.

### Esperanto Model Provisioning

Rather than directly instantiating LLM clients, the graph delegates model provisioning to an Esperanto-based abstraction layer. This architecture decouples the conversation logic from specific provider implementations (OpenAI, Anthropic, etc.), allowing the `call_model_with_messages` function to request a model instance without managing API keys or endpoint configurations directly.

## Message Processing Pipeline

The core execution logic resides in the `call_model_with_messages` function, which serves as the primary node in the chat graph.

### Building System Prompts with Prompter

Before invoking the LLM, the workflow constructs a system prompt using the `Prompter` class. This component assembles the final payload by combining:

1. Base system instructions defining the AI's role and constraints
2. Notebook-specific context retrieved from the `ThreadState`
3. Optional user-provided context passed through the state dictionary

The `Prompter` handles template rendering and ensures that conversation context fits within the target model's context window.

### Invocation and Response Sanitization

The `call_model_with_messages` function executes a four-step pipeline:

1. **Payload Assembly**: Combines the system prompt with the message history from `ThreadState`
2. **Model Provisioning**: Requests the appropriate LLM client through the Esperanto layer
3. **Generation**: Invokes the model with the assembled messages
4. **Sanitization**: Cleans the raw AI response by stripping HTML-like tags and formatting artifacts before updating the checkpoint

This sanitization step ensures that responses returned to the user interface are clean text without markdown artifacts or XML-style tags that might confuse the frontend renderer.

## Summary

- Open-Notebook uses a **LangGraph state graph** defined in [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py) to manage AI conversations
- **ThreadState** (TypedDict) stores messages, notebook context, and model overrides in a type-safe structure
- Conversations persist via **SQLite checkpoints**, enabling resumeable dialogue threads
- The **Esperanto** abstraction layer handles LLM provisioning, decoupling the graph from specific API providers
- **Response sanitization** removes HTML-like artifacts before final delivery to users

## Frequently Asked Questions

### How does Open-Notebook maintain conversation context across multiple turns?

Open-Notebook maintains context through the `ThreadState` TypedDict, which accumulates message history in the `messages` field. The LangGraph checkpoint mechanism stores this state in SQLite after each turn, allowing the `call_model_with_messages` function to retrieve the full conversation history when processing subsequent user inputs.

### What is the role of the Esperanto layer in the chat workflow?

The Esperanto layer acts as a model provisioning abstraction that sits between the LangGraph workflow and specific LLM providers. When `call_model_with_messages` needs to invoke a model, it requests a client through this layer rather than instantiating API connections directly, enabling support for multiple providers (OpenAI, Anthropic, local models) without modifying the graph logic.

### Can the chat workflow switch models mid-conversation?

Yes. The `ThreadState` includes a `model_override` field that allows the graph to dynamically select different models during execution. When this flag is set, the Esperanto provisioning layer returns the specified model instance instead of the default, enabling use cases like escalating complex queries to more powerful models while keeping simple queries on cost-effective alternatives.

### Where does response sanitization occur in the pipeline?

Response sanitization happens immediately after LLM invocation within the `call_model_with_messages` function. The raw model output is cleaned to remove HTML-like tags and formatting artifacts before being appended to the message history and committed to the SQLite checkpoint, ensuring that downstream UI components receive clean, renderable text.