Open Notebook LangGraph Workflows: Source Chat vs Ask Explained

Open Notebook implements two distinct LangGraph state-graph workflows—Source Chat for single-source conversation and Ask for multi-step vector search research—each using different state schemas, node architectures, and context-building strategies.

Open Notebook leverages LangGraph to orchestrate complex LLM interactions through specialized workflows defined in open_notebook/graphs/source_chat.py and open_notebook/graphs/ask.py. While both workflows generate AI responses, they serve fundamentally different user intents: conversing with a specific document versus conducting open-ended research across your entire knowledge base.

Core Purpose and Interaction Models

Source Chat: Conversational Source Exploration

The Source Chat workflow enables users to explore a single source—such as a PDF, webpage, or video—through natural conversation. It builds a comprehensive context from the source content and its derived insights, then injects this into a chat prompt to generate responses that reference specific source material. This workflow is optimized for deep dives into individual documents where maintaining the full context of the source is critical.

Ask: Multi-Step Research and Synthesis

The Ask workflow answers open-ended questions by searching across the entire vector store. Rather than focusing on one document, it executes a strategy that may involve multiple vector searches, processes each result set through sub-graphs, and synthesizes findings into a final comprehensive answer. This approach supports complex research queries that require aggregating information from multiple sources.

State Schemas and Graph Architecture

SourceChatState vs ThreadState

Each workflow maintains distinct state definitions reflecting their operational requirements:

SourceChatState (defined in open_notebook/graphs/source_chat.py) tracks:

  • messages: Conversation history
  • source_id: Target document identifier
  • source and insights: The loaded source and its extracted insights
  • context: Generated full-text context (up to 50,000 tokens)
  • model_override: Optional alternative model selection
  • context_indicators: Dictionary tracking which sources and insights were referenced

ThreadState (defined in open_notebook/graphs/ask.py) tracks:

  • question: The original user query
  • strategy: A list of Search objects generated by the LLM
  • answers: Accumulated responses from each search execution
  • final_answer: The synthesized result

Node Structure and Topology

The Source Chat graph compiles to a linear pipeline: START → source_chat_agent → END. The single node source_chat_agent calls call_model_with_source_context to build context and generate a response.

The Ask graph compiles to a three-node structure with conditional branching:

  1. agent: Creates a search strategy via the strategy_model
  2. provide_answer: Executes vector searches and generates intermediate answers (may run multiple times via trigger_queries)
  3. write_final_answer: Synthesizes all sub-answers using the final_answer_model

Context Building and Retrieval Strategies

Full-Text Context Assembly

Source Chat relies on ContextBuilder (from open_notebook/utils/context_builder.py) to pull the source record, associated insights, and metadata. The _format_source_context method formats this into a rich prompt context that can consume up to 50k tokens, providing the LLM with comprehensive source material via the source_chat/system prompt template.

Vector Search Results

Ask bypasses explicit context building in favor of dynamic retrieval. The provide_answer node executes vector_search queries against SurrealDB for each term in the strategy. The raw search results serve as the context, fed directly to the ask/query_process prompt alongside user instructions. This approach prioritizes relevance over completeness.

Model Provisioning and Execution

Synchronous vs Asynchronous Provisioning

Source Chat invokes provision_langchain_model synchronously within a new event loop using run_in_new_loop, because the graph operates in a synchronous context. It supports an optional model_override parameter for flexible model selection.

Ask uses asynchronous provisioning with await provision_langchain_model throughout its async graph. It employs three distinct configurable model IDs: strategy_model for planning, answer_model for processing search results, and final_answer_model for synthesis.

Error Handling Patterns

Both workflows utilize classify_error from open_notebook/utils/error_classifier.py to normalize exceptions into OpenNotebookError subclasses. Source Chat wraps the entire call in a single try/except block, while Ask implements granular error handling within each node (call_model_with_messages, provide_answer, write_final_answer).

Implementation Examples

Invoking Source Chat

from open_notebook.graphs.source_chat import source_chat_graph

state = {
    "messages": [],
    "source_id": "src_12345",
    "model_override": None,
}

result = source_chat_graph.invoke(state)
print(result["messages"][-1].content)

Invoking Ask

from open_notebook.graphs.ask import graph

state = {
    "question": "What are the performance trade-offs of LangGraph?",
}

answer = graph.invoke(state)
print(answer["final_answer"])

Summary

  • Source Chat provides a linear, single-source conversation workflow using SourceChatState and full-text context building via ContextBuilder.
  • Ask implements a multi-step research workflow using ThreadState, conditional branching via trigger_queries, and vector search aggregation.
  • Model provisioning differs significantly: Source Chat uses synchronous calls with optional overrides, while Ask uses async provisioning with role-specific models (strategy, answer, final).
  • Context strategies contrast sharply: Source Chat builds comprehensive source context (up to 50k tokens), while Ask relies on dynamic vector search results.
  • Both workflows share the classify_error utility for consistent error handling but implement it at different granularities.

Frequently Asked Questions

What is the primary difference between Source Chat and Ask workflows?

Source Chat is designed for exploring a single document through conversation, building rich context from that specific source and its insights. Ask is designed for research questions that require searching across multiple sources, implementing a strategy-planning phase and aggregating results from multiple vector searches before synthesizing a final answer.

How does the state management differ between these LangGraph workflows?

Source Chat uses SourceChatState which tracks a specific source_id, conversation messages, and pre-built context strings. Ask uses ThreadState which tracks a question, a generated strategy of search terms, accumulated answers from each search execution, and a final answer string.

Can I use different AI models for different stages of the Ask workflow?

Yes. The Ask workflow in open_notebook/graphs/ask.py supports three distinct model configurations: strategy_model for generating the search plan, answer_model for processing individual search results, and final_answer_model for synthesizing the comprehensive response.

Why does Source Chat use synchronous model provisioning while Ask uses async?

Source Chat runs in a synchronous context and therefore calls provision_langchain_model within a new event loop using run_in_new_loop. The Ask workflow is implemented as an async graph, allowing it to use await provision_langchain_model directly, which is more efficient for I/O-bound operations like multiple parallel vector searches.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →