- [Overview](#overview)
Table of Contents
Overview
The LoreBook class stores weighted key-value context pairs compatible with NovelAI’s Lorebook system. It provides intelligent context injection based on text matching, weights, and dependency relationships.
@Serializable
data class LoreBook(@Transient val cinit: Boolean = false)
Public Properties
Core Properties
key
var key: String = ""
The lorebook key used for text matching. When this substring is found in scanned text, the associated value is considered for context injection based on token budget and weight priority.
value
var value: String = ""
Context content associated with the key. Can contain any information desired for the LLM - typically events, locations, NPCs, or world-building concepts that provide relevant background context.
weight
var weight: Int = 0
Priority weight for context selection. Higher weights receive priority over lower weights when token budget is limited. Used by context selection algorithms to determine inclusion order.
Relationship Properties
linkedKeys
var linkedKeys: MutableList<String> = mutableListOf()
Additional lorebook keys automatically activated when this entry is selected. When this lorebook is included in context, linked keys are also attempted for inclusion, creating cascading context activation.
aliasKeys
var aliasKeys: MutableList<String> = mutableListOf()
Alternative key strings that trigger this lorebook entry. Any text matching these aliases counts as a hit for the main key, enabling flexible matching patterns and synonyms.
requiredKeys
var requiredKeys: MutableList<String> = mutableListOf()
Dependency keys that must ALL be present in input text for this entry to be eligible for activation. Empty list means no dependencies (always eligible). Enables conditional context activation based on multiple triggers.
Public Functions
Content Management
combineValue(other: LoreBook)
Merges content from another LoreBook into this one.
Behavior:
- Value merging: Appends other’s value to this value with space separator
- Required keys merging: Adds other’s required keys to this entry, avoiding duplicates
- Other properties: Unchanged (key, weight, linkedKeys, aliasKeys remain as-is)
Useful for consolidating related lorebook entries or accumulating context from multiple sources.
Utilities
toMap(): Map<String, LoreBook>
Converts this LoreBook to a single-entry map.
Behavior: Returns Map<String, LoreBook> with this lorebook’s key as the map key and this object as the value. Convenient for integration with ContextWindow’s loreBookKeys map structure.
Scan Surface
The “scan surface” is the text that the lorebook matcher runs against when deciding which entries to inject. The default is the user prompt only — that contract is preserved for any caller that has not opted in.
Default Scan Surface
By default, the lorebook matcher scans only the user prompt (content.text). Neither ContextWindow.contextElements nor ContextWindow.converseHistory are included in the scan. This is the historical behavior and remains the default so existing pipelines keep their selection results.
If your lorebook keys are designed to fire on the user’s most recent message alone, leave the scan surface alone. If your lorebook keys reference concepts that live in earlier context (recent turns of conversation, system-injected context elements, prior assistant replies), the default surface can miss them.
Expanding the Scan Surface
To opt in to a larger scan surface, call buildLorebookScanText(userPrompt, useEntireContext) on the ContextWindow you are about to run selection against. The helper is the canonical way to build the scan text for any of the five lorebook selection/truncation call sites in Pipe.kt.
fun ContextWindow.buildLorebookScanText(
userPrompt: String,
useEntireContext: Boolean
): String
Parameters:
userPrompt: The user prompt text the caller is about to feed to selection.useEntireContext: Whentrue, expand the scan surface to the entire window. Whenfalse, the helper returnsuserPromptunchanged.
Returns: The text to feed into selectLoreBookContext / selectAndTruncateContext.
Behavior Contract
- When
useEntireContextisfalse: returnsuserPromptverbatim, regardless of whatcontextElementsandconverseHistorycontain. This is the default and preserves the historical “scan only the user prompt” contract. - When
useEntireContextistrue: returns the user prompt concatenated withcontextElements(newline-separated) andconverseHistory.history[*].content.text(newline-separated). Empty sources are skipped — there is no trailing newline if either side is empty.
The concatenation order is: userPrompt, then contextElements (if non-empty), then converseHistory.history[*].content.text (if non-empty). Each component is joined with '\n'. The user prompt is always present and always first.
Example
import com.TTT.Context.ContextWindow
import com.TTT.Context.ConverseHistory
import com.TTT.Context.ConverseRole
import com.TTT.Pipe.MultimodalContent
import com.TTT.Context.buildLorebookScanText
val contextWindow = ContextWindow()
contextWindow.contextElements.add(
"Lyra first visited the Silverbrook archives on the eve of the autumn equinox."
)
contextWindow.converseHistory.add(
ConverseRole.user,
MultimodalContent("Tell me about the last time you were in Silverbrook.")
)
contextWindow.converseHistory.add(
ConverseRole.agent,
MultimodalContent("I remember the archives well — the dust on the southern stacks was almost gold in the lamplight.")
)
val userPrompt = "What did Lyra find in the restricted wing?"
val scanText = contextWindow.buildLorebookScanText(userPrompt, true)
// scanText:
// "What did Lyra find in the restricted wing?
// Lyra first visited the Silverbrook archives on the eve of the autumn equinox.
// Tell me about the last time you were in Silverbrook.
// I remember the archives well — the dust on the southern stacks was almost gold in the lamplight."
// With useEntireContext = false, the same call returns userPrompt unchanged:
// "What did Lyra find in the restricted wing?"
Enabling on a Pipe
The Pipe-level DSL flag is what flips useEntireContext to true for every selection/truncation call site in the pipe’s execution path:
val pipe = BedrockPipe()
.setModel("anthropic.claude-3-sonnet-20240229-v1:0")
.useEntireContextForLoreSelection()
See Pipe: useEntireContextForLoreSelection() for the full Pipe-side contract.
MiniBank Per-Page Behavior
In multi-page contexts (MiniBank), each page’s matcher uses the shared user prompt plus that page’s own contextElements and converseHistory — not the main window’s. The per-page isolation is preserved even when useEntireContext = true. The helper is called per page against each page’s ContextWindow, so each page’s lorebook selection sees a scan surface scoped to its own context.
Usage Patterns
Basic Lorebook Entry
val character = LoreBook().apply {
key = "Alice"
value = "Alice is a skilled mage who specializes in fire magic. She has red hair and wears blue robes."
weight = 10
}
Entry with Aliases
val location = LoreBook().apply {
key = "Silverbrook"
value = "A peaceful village nestled in the mountains, known for its crystal-clear streams."
weight = 5
aliasKeys.addAll(listOf("Silver Brook", "the village", "mountain village"))
}
Entry with Dependencies
val event = LoreBook().apply {
key = "dragon attack"
value = "The ancient red dragon Pyraxis attacked the village last winter, destroying the eastern district."
weight = 15
requiredKeys.addAll(listOf("Pyraxis", "village"))
linkedKeys.add("Pyraxis")
}
Entry with Linked Context
val character = LoreBook().apply {
key = "King Marcus"
value = "The wise ruler of the northern kingdom, known for his just laws."
weight = 12
linkedKeys.addAll(listOf("northern kingdom", "royal court"))
aliasKeys.addAll(listOf("the king", "His Majesty", "Marcus"))
}
Combining Entries
val baseEntry = LoreBook().apply {
key = "magic system"
value = "Magic requires focus and energy."
weight = 8
}
val additionalInfo = LoreBook().apply {
value = "Advanced mages can cast without verbal components."
requiredKeys.add("advanced magic")
}
baseEntry.combineValue(additionalInfo)
// Result: "Magic requires focus and energy. Advanced mages can cast without verbal components."
Integration with ContextWindow
LoreBook entries are typically managed through ContextWindow:
val contextWindow = ContextWindow()
// Add entry directly
contextWindow.addLoreBookEntry(
key = "important location",
value = "The Tower of Wisdom stands at the city center.",
weight = 10,
aliasKeys = listOf("tower", "wisdom tower"),
linkedKeys = listOf("city center"),
requiredKeys = listOf("city")
)
// Add using LoreBook object
val entry = LoreBook().apply {
key = "character"
value = "A mysterious figure in dark robes."
weight = 7
}
contextWindow.addLoreBookEntryWithObject(entry)
Next Steps
- Debug Package API - Continue into tracing and monitoring helpers.