# Architectural Differences Between Chat, Ask, and Transformation LangGraph Workflows in Open Notebook

> Explore architectural differences in Open Notebooks Chat, Ask, and Transformation LangGraph workflows. Understand state management, graph topology, and execution patterns for efficient development.

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

---

**Open Notebook implements three distinct LangGraph workflows—Chat, Ask, and Transformation—that differ fundamentally in state management, graph topology, and execution patterns, with Chat using persistent SQLite checkpointing for conversations, Ask generating dynamic multi-step research graphs, and Transformation executing single-step content rewrites.**

Open Notebook is an open-source knowledge management system that leverages LangGraph to orchestrate LLM interactions through specialized agentic workflows. While all three workflows utilize LangGraph's `StateGraph` abstraction, they diverge significantly in their state shapes, node architectures, and runtime characteristics. Understanding these architectural differences is essential for developers extending the platform or integrating with its API.

## State Management and Graph Topology

The three workflows define distinct state schemas that reflect their specific operational requirements.

**Chat Workflow** uses `ThreadState` (defined in [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py)) to maintain message history, notebook context, and conversation metadata. This state persists across interactions, enabling multi-turn conversations with contextual grounding.

**Ask Workflow** also uses `ThreadState` (defined in [`open_notebook/graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/ask.py)) but extends it with a subsidiary `SubGraphState` for each search operation. The state tracks the original question, a generated search strategy, intermediate answers, and the final synthesized response. This structure supports the workflow's dynamic expansion pattern.

**Transformation Workflow** employs a simpler `TransformationState` (defined in [`open_notebook/graphs/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/transformation.py)) containing only the input text, source reference, transformation definition, and output field. This minimal state reflects the single-step nature of content rewriting operations.

## Node Structure and Execution Flow

Each workflow implements a distinct graph topology optimized for its specific use case.

**Chat** implements a linear pipeline: `START → agent → END`. The single `agent` node calls the LLM with accumulated messages and returns the response. There are no conditional branches or dynamic node creation.

**Ask** implements a sophisticated conditional graph. The flow begins with an `agent` node that generates a JSON-encoded search strategy. Based on this strategy, the graph dynamically creates multiple `provide_answer` nodes (one per search term) that execute vector searches in parallel. Finally, a `write_final_answer` node synthesizes the aggregated results before reaching `END`. The edge definitions in lines 50-53 of [`ask.py`](https://github.com/lfnovo/open-notebook/blob/main/ask.py) handle this conditional routing.

**Transformation** uses the simplest topology: `START → agent → END`. The single `agent` node applies the transformation prompt to the input text and optionally stores the result back to the source via `source.add_insight`.

## Model Provisioning and Async Handling

The workflows differ significantly in how they handle asynchronous execution and model provisioning.

**Chat Workflow** requires special handling because it may be invoked from synchronous FastAPI routes. According to lines 38-73 of [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py), the workflow wraps `provision_langchain_model` inside a synchronous wrapper that spins a new event loop when called from a sync context. This hybrid approach ensures compatibility with the chat endpoint while maintaining async capabilities within the graph.

**Ask Workflow** operates entirely asynchronously. Each node independently provisions its own model instance via `provision_langchain_model` without special loop handling. The strategy generation, vector search execution, and final answer synthesis all run as async operations.

**Transformation Workflow** also runs fully async, with the single node provisioning its model and executing the transformation in one atomic operation.

## Persistence and Checkpointing

Only the Chat workflow implements persistent state management.

**Chat** utilizes LangGraph's `SqliteSaver` (configured in [`open_notebook/config.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/config.py)) to persist conversation state. This enables long-running conversations to resume across requests and provides durability for the chat interface.

**Ask** operates without checkpointing. The entire multi-step research flow executes within a single request/response cycle, and intermediate states exist only in memory during graph execution.

**Transformation** functions as a fire-and-forget operation with no checkpointing, appropriate for one-off content processing tasks.

## Data Access Patterns

Each workflow interacts with the domain model differently based on its informational requirements.

**Chat** may attach a `Notebook` object to the state to enrich context with existing knowledge. This allows the LLM to reference previously curated content during conversations.

**Ask** bypasses the notebook abstraction and calls the vector store directly via `vector_search` (see lines 98-104 of [`ask.py`](https://github.com/lfnovo/open-notebook/blob/main/ask.py)). This direct access enables semantic search across the knowledge base to gather relevant context for the research task.

**Transformation** directly accesses `Source` records and optionally persists insights back to the source using `source.add_insight`, creating a tight integration between the transformation output and the knowledge repository.

## Error Handling Strategy

All three workflows share a common error classification system using `OpenNotebookError` with the `classify_error` helper to convert exceptions into user-friendly messages. However, each implements workflow-specific wrapping:

- **Chat** handles errors at the graph level with conversational context preservation.
- **Ask** re-wraps errors at each sub-node to preserve the specific stage (strategy generation, search, or synthesis) where failures occur.
- **Transformation** additionally catches validation errors on the source object during the persistence phase.

## Practical Implementation Examples

### Chat Workflow

```python
import httpx

payload = {
    "messages": [{"role": "user", "content": "Explain quantum entanglement"}],
    "model_override": "gpt-4o"
}
response = httpx.post("http://localhost:5055/chat", json=payload)
print(response.json()["messages"][-1]["content"])

```

The FastAPI endpoint creates a `ThreadState` and runs the graph defined in [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py), persisting the conversation to SQLite.

### Ask Workflow

```python
import httpx

payload = {"question": "What are the health benefits of a Mediterranean diet?"}
resp = httpx.post("http://localhost:5055/ask", json=payload)
print(resp.json()["final_answer"])

```

The LLM first creates a JSON strategy containing `Search` objects, the system executes vector searches for each term, then the final synthesis node produces the aggregated answer.

### Transformation Workflow

```python
import httpx

payload = {
    "input_text": "The quick brown fox jumps over the lazy dog.",
    "transformation": {
        "title": "Summarize",
        "prompt": "Summarize the following text in one sentence."
    }
}
resp = httpx.post("http://localhost:5055/transform", json=payload)
print(resp.json()["output"])

```

The workflow in [`open_notebook/graphs/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/transformation.py) sends the text together with the custom prompt to the LLM and returns the cleaned output.

## Summary

- **Chat** provides a linear dialog graph with persistent SQLite checkpointing, requiring sync-to-async adapter code for FastAPI compatibility.
- **Ask** implements a dynamic multi-stage research pipeline that generates search strategies, executes parallel vector searches, and synthesizes final answers without persistence.
- **Transformation** offers a single-step content rewrite operation with optional source persistence, using the simplest state management of the three.
- All workflows share common utilities including `provision_langchain_model` and `OpenNotebookError`, but differ in their graph topology, async handling, and checkpointing strategies.

## Frequently Asked Questions

### Which workflow maintains conversation history across sessions?

Only the **Chat workflow** persists state using LangGraph's `SqliteSaver` (as configured in [`open_notebook/config.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/config.py)), enabling long-running conversations to resume across API calls. The Ask and Transformation workflows operate as stateless, single-request operations.

### How does the Ask workflow handle complex multi-part research questions?

The Ask workflow utilizes **dynamic node generation**. After the initial `agent` node generates a JSON search strategy, the graph conditionally creates multiple `provide_answer` nodes (one per search term) based on the strategy content. These nodes execute vector searches in parallel before the final synthesis step, as implemented in lines 50-53 of [`open_notebook/graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/ask.py).

### Why does the Chat workflow require special synchronous handling while Ask does not?

The Chat workflow includes a synchronous wrapper around `provision_langchain_model` (lines 38-73 of [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py)) because it may be invoked from non-async FastAPI routes. This wrapper spins a new event loop when called from synchronous contexts. The Ask workflow assumes fully async execution throughout its pipeline, eliminating the need for this adapter pattern.

### When should I use the Transformation workflow instead of the Chat workflow?

Use the **Transformation workflow** when you need a one-off content rewrite (summarization, extraction, or restructuring) that optionally persists back to a specific source. Use the **Chat workflow** for interactive, multi-turn conversations where maintaining message history and conversational context is essential. Transformation is atomic and fire-and-forget; Chat is conversational and persistent.