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

> Discover how the Open-Notebook context builder utility constructs token-aware, prioritized context from notebooks and sources for AI model prompt templates. Optimize your LLM prompts today.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-18

---

**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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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

```python
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

```python
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

```python
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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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.