How the Open-Notebook Context Builder Utility Constructs Prompts for AI Models

The Open-Notebook context builder utility assembles token-aware, prioritized context from notebooks, sources, and notes into a structured dictionary ready for LLM prompt templates.

The lfnovo/open-notebook repository provides a sophisticated context builder utility that transforms raw notebook data into optimized prompts for large language models. Located in open_notebook/utils/context_builder.py, this async utility aggregates content from multiple sources, enforces token budgets, and delivers a formatted payload that downstream LangGraph workflows can directly interpolate into Jinja2 templates.

Core Architecture of the Context Builder

The ContextBuilder class follows a modular pipeline design that separates data fetching from formatting and optimization.

Initialization and Configuration

When instantiated, ContextBuilder(**kwargs) stores all request parameters—including source_id, notebook_id, include_insights, and max_tokens—in self.params (lines 65-98). If no configuration object is provided, it initializes a default ContextConfig that defines default priority weights (source:100, insight:75, note:50) and content inclusion rules.

The Async Build Pipeline

The await builder.build() method (lines 105-138) orchestrates the entire process asynchronously:

  1. Clears previous context items
  2. Invokes private helper methods to load data for requested entities
  3. Deduplicates, prioritizes, and truncates to fit token limits
  4. Returns a formatted response dictionary

This async design leverages FastAPI’s stack and the SurrealDB driver to handle large notebooks efficiently without blocking the event loop.

How Context Items Are Aggregated

The builder supports three primary data sources, each handled by dedicated private methods that wrap content in uniform ContextItem objects.

Loading Source Context

When a source_id is provided, _add_source_context (lines 142-202) loads the Source record from open_notebook/domain/source.py. It fetches either a short or long content snippet via source.get_context(), and optionally retrieves insights via source.get_insights(). Each piece receives a priority score derived from self.context_config.priority_weights, ensuring high-value content ranks higher during truncation.

Processing Notebook Entities

For notebook_id requests, _add_notebook_context (lines 210-250) loads the Notebook record and iterates over its associated sources and notes. This method respects custom inclusion maps in ContextConfig, allowing granular control over whether to include "insights", "full content", or exclude specific items entirely.

Handling Individual Notes

The _add_note_context method (lines 254-288) processes arbitrary note IDs by fetching records from open_notebook/domain/note.py and applying the same short/long content logic used for sources. This enables mixing notebook-level and note-level context in a single prompt.

Token-Aware Optimization and Prioritization

Before returning data, the builder applies sophisticated filtering to respect model token limits while preserving the most relevant content.

Deduplication and Priority Weighting

The remove_duplicates method (lines 351-363) eliminates any ContextItem sharing the same id, ensuring a source or note appears only once even if referenced multiple times. Subsequently, prioritize (lines 315-319) sorts items by their computed priority score in descending order (highest priority first).

Token Budget Enforcement

If max_tokens is configured, truncate_to_fit (lines 320-349) walks the sorted list from the lowest priority items upward, removing entries until the total count—computed via token_utils.py—falls within budget. This guarantees the final payload never exceeds the target model's context window.

Formatting Output for AI Prompts

The _format_response method (lines 367-416) performs the final transformation:

  • Groups items by type into sources, notes, and insights arrays
  • Calculates total token consumption
  • Returns a dictionary with metadata and content arrays

Downstream components in open_notebook/graphs/search_and_synthesize.py receive this dictionary and insert the arrays directly into prompt templates, eliminating the need for additional trimming logic during prompt generation.

Practical Implementation Examples

Build Context for a Whole Notebook

from open_notebook.utils.context_builder import build_notebook_context

async def get_notebook_prompt(notebook_id: str):
    ctx = await build_notebook_context(
        notebook_id=notebook_id,
        max_tokens=2048,  # keep prompt under model limit

    )
    # ctx contains {"sources": [...], "notes": [...], "insights": [...]}

    return ctx

Build Context for a Single Source

from open_notebook.utils.context_builder import build_source_context

async def source_prompt(source_id: str):
    ctx = await build_source_context(
        source_id=source_id,
        include_insights=True,
        max_tokens=1500,
    )
    return ctx

Mix Arbitrary Sources and Notes

from open_notebook.utils.context_builder import build_mixed_context

async def mixed_prompt(source_ids, note_ids):
    ctx = await build_mixed_context(
        source_ids=source_ids,
        note_ids=note_ids,
        max_tokens=1800,
    )
    return ctx

These convenience helpers (lines 421-495) in open_notebook/utils/context_builder.py provide simplified interfaces for common use cases while maintaining full access to the underlying ContextBuilder configuration options.

Summary

  • The context builder utility in open_notebook/utils/context_builder.py provides an async pipeline for assembling LLM-ready context from notebooks, sources, and notes.
  • Content passes through deduplication, priority sorting, and token-aware truncation to ensure optimal use of model context windows.
  • Default priority weights (source:100, insight:75, note:50) ensure the most relevant information survives budget cuts.
  • The final output is a dictionary formatted for direct interpolation into Jinja2 prompt templates, consumed by LangGraph workflows like search_and_synthesize.py.

Frequently Asked Questions

How does the context builder handle token limits?

The truncate_to_fit method calculates token counts using open_notebook/utils/token_utils.py, then removes lowest-priority items from the end of the sorted list until the total falls within the max_tokens budget specified during initialization.

Can I customize which content types appear in the final prompt?

Yes. The ContextConfig class allows you to specify inclusion maps for sources and notes, choosing between "insights", "full content", or exclusion. You can also override the default priority weights or subclass ContextBuilder to modify _process_custom_params for custom filtering logic.

What is the difference between build_notebook_context and build_mixed_context?

build_notebook_context loads all sources and notes associated with a specific notebook ID, while build_mixed_context accepts arbitrary lists of source IDs and note IDs, allowing you to construct prompts from disparate elements across multiple notebooks.

Is the context builder synchronous or asynchronous?

The entire pipeline is asynchronous. The build() method and all data-fetching helpers use async/await patterns to efficiently query SurrealDB and handle I/O-bound operations without blocking, making it suitable for FastAPI endpoints and concurrent workflow nodes.

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 →