How the Open Notebook Context Builder Constructs Prompts for AI Models

The Open Notebook context builder constructs prompts for AI models by aggregating sources, notes, and insights into prioritized, token-aware context items that are deduplicated, truncated to fit within model limits, and formatted into a dictionary ready for prompt template interpolation.

The context builder is the core utility in the lfnovo/open-notebook repository that transforms raw notebook data into LLM-ready prompt content. Located in open_notebook/utils/context_builder.py, this asynchronous pipeline gathers data from multiple domain models, applies intelligent filtering, and ensures the final output respects token budgets before injection into AI prompts.

How the Context Builder Works

The ContextBuilder class follows a modular, asynchronous workflow designed to handle complex data aggregation while maintaining strict token constraints.

Initializing the Builder

When instantiating ContextBuilder(**kwargs), the __init__ method (lines 65‑98) stores all input parameters—including source_id, notebook_id, include_insights, and max_tokens—in self.params. If no ContextConfig is provided, the builder creates a default configuration with predefined priority weights for different content types.

Orchestrating the Build Process

The await builder.build() method (lines 105‑138) serves as the main orchestration entry point. It first clears any previous context items, then sequentially invokes private helper methods to load data for the requested entities based on the initialization parameters.

Adding Source Context

For individual source retrieval, _add_source_context (lines 142‑202) loads the Source record from open_notebook/domain/source.py and fetches either short or long content snippets via source.get_context. When include_insights is enabled, it also retrieves processed insights through source.get_insights. Each retrieved piece is wrapped in a ContextItem object with a priority value derived from self.context_config.priority_weights.

Adding Notebook Context

When processing entire notebooks, _add_notebook_context (lines 210‑250) loads the Notebook record and iterates over its associated sources and notes. This method respects custom configuration maps in ContextConfig that specify whether to include "insights", "full content", or exclude specific items entirely.

Adding Note Context

The _add_note_context method (lines 254‑288) handles individual note IDs by fetching the Note record from open_notebook/domain/note.py, determining the appropriate content length, wrapping it in a ContextItem, and adding it to the builder's internal collection.

Processing Custom Parameters

The _process_custom_params hook (lines 296‑304) allows subclasses to extend the builder's behavior. By default, it only logs any custom_* kwargs passed during initialization, providing a clean extension point for specialized context processing.

Deduplicating and Prioritizing Content

Before finalization, the builder calls remove_duplicates (lines 351‑363) to eliminate any ContextItem instances sharing the same id, ensuring no source or note appears twice in the context. Then prioritize (lines 315‑319) sorts the remaining items by their priority value in descending order (highest first). The default ContextConfig assigns weights of source:100, insight:75, and note:50.

Enforcing Token Limits

If max_tokens is specified, truncate_to_fit (lines 320‑349) walks the sorted item list from the end (lowest priority) and removes items until the total token count—computed via token_count from open_notebook/utils/token_utils.py—falls within the specified limit. This guarantees the final prompt will not exceed the model's context window.

Formatting the Final Response

The _format_response method (lines 367‑416) groups the processed items by type (sources, notes, insights), calculates the total token count, and returns a structured dictionary. This output format allows downstream LangGraph workflows to directly interpolate the content into Jinja2 prompt templates without additional processing.

Using the Context Builder in Practice

The repository provides three convenience functions that wrap the ContextBuilder class for common use cases (lines 421‑495).

Building Context for a Notebook

To construct context for an entire notebook with token ceiling enforcement:

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,
    )
    # Returns: {"sources": [...], "notes": [...], "insights": [...], ...}

    return ctx

Building Context for Individual Sources

For single-source context generation including AI-generated insights:

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

Mixing Sources and Notes

To combine arbitrary sources and notes into a single context:

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

Key Implementation Details

The context builder leverages asynchronous I/O throughout the pipeline, utilizing FastAPI's async stack and the SurrealDB driver to efficiently handle large notebooks. Key architectural components include:

Summary

  • The ContextBuilder class in open_notebook/utils/context_builder.py aggregates data from notebooks, sources, and notes into unified context objects.
  • Content is wrapped in ContextItem instances with configurable priority weights (sources:100, insights:75, notes:50 by default).
  • Deduplication ensures unique content, while token-aware truncation enforces model limits by removing lowest-priority items first.
  • Three convenience functions—build_notebook_context, build_source_context, and build_mixed_context—provide simple async interfaces for common use cases.
  • The final output is a dictionary formatted for direct insertion into Jinja2 prompt templates, used by downstream AI workflows.

Frequently Asked Questions

How does the context builder handle token limits?

The context builder enforces token limits through the truncate_to_fit method, which removes lowest-priority items until the total token count falls within the specified max_tokens parameter. This ensures the final prompt never exceeds the model's context window while preserving the most important content.

Can I customize which content types are included in the context?

Yes, the ContextConfig class allows customization of content inclusion through sources and notes maps that specify whether to include "insights", "full content", or exclude items entirely. You can also override the default priority weights to change how different content types are ranked during truncation.

Is the context builder compatible with async workflows?

Absolutely. The entire ContextBuilder pipeline is implemented asynchronously using async/await patterns, making it compatible with FastAPI endpoints and LangGraph workflows. All database operations through SurrealDB use async drivers to maintain efficiency when processing large notebooks.

What is the difference between build_notebook_context and build_source_context?

build_notebook_context aggregates all sources and notes belonging to a specific notebook ID, while build_source_context focuses on a single source and optionally includes its AI-generated insights. The former is ideal for comprehensive queries across entire notebooks, while the latter is optimized for deep-dives into specific source materials.

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 →