@polyweave/raptor (1.0.6)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/raptor@1.0.6"@polyweave/raptor": "1.0.6"About this package
@polyweave/raptor
RAPTOR (Recursive Abstractive Processing for Tree-Organized Retrieval) hierarchy indexing and retrieval on Polyweave state stores.
Published as @polyweave/raptor.
Synopsis
import {
createRaptor,
createRaptorRetriever,
createSummaryRefinerBt
} from '@polyweave/raptor';
var raptor = createRaptor({
textStore: myTextStore,
treeStore: myTreeStore,
multiState: myMultiState,
summarizer: myLlmAdapter,
embedder: myEmbedder
});
var docs = [
{ id: '1', text: 'Machine learning is a subset of artificial intelligence...' },
{ id: '2', text: 'Deep learning uses neural networks with multiple layers...' }
];
raptor.ingestDocument({ docId: 'doc-1', text: docs.map(function(d) { return d.text; }).join('\n\n'), leaves: docs }, function(err, result) {
if (err) throw err;
var results = raptor.search('neural network architecture', { limit: 5, kind: 'summary' });
console.log(results);
});
Install
npm install @polyweave/raptor
Why
LLM-based retrieval fails at scale when contexts exceed the model's context window. RAPTOR solves this by recursively clustering document chunks and generating hierarchical summaries — building a tree where leaf nodes hold original chunks and internal nodes hold LLM-generated summaries of their children. Retrieval traverses the tree from coarse (root summaries) to fine (leaves), enabling relevance search across arbitrarily large document collections without expanding the context window. Combined with Polyweave's state stores (document, text, tree, graph) and uncertainty tracking (HHEM-based hallucination scoring, citation verification), raptor provides a complete hierarchical indexing pipeline with built-in quality gates.
API
createRaptor(options)
Creates a RAPTOR hierarchical document indexer.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options.textStore |
object |
Yes | — | Text store implementing index(id, text, opts), indexWithEmbedding(id, text, opts), get(id), and getState(). Throws at construction if textStore.index is not a function. |
options.treeStore |
object |
No | null |
Tree store duplex for hierarchy persistence. Receives TREE_UPSERT frames on sink.write. |
options.graphStore |
object |
No | null |
Graph store duplex for fact relationships. Receives FACT_INSERT frames on sink.write. |
options.multiState |
object |
No | null |
Multi-state search provider. Required for search() — throws at call time if multiState.search is not a function. |
options.embedder |
function |
No | null |
Callback-style embedder: (text, function(err, embedding)). Used for cosine similarity clustering and embedding-based uncertainty scoring. |
options.summarizer |
function |
No | truncation |
Summarizer: (group, context, function(err, summaryText)). Default truncates children text to maxSummaryLength chars. For meaningful hierarchies, provide an LLM adapter. |
options.branchFactor |
number |
No | 4 |
Max children per summary node. Lower = deeper trees, more summarization. Clamped to minimum 2. |
options.treeId |
string |
No | 'raptor' |
Namespace for tree structure in treeStore. |
options.maxSummaryLength |
number |
No | 320 |
Max summary character length for the default (truncation) summarizer. Clamped to minimum 32. |
options.uncertainty |
object |
No | {...} |
Uncertainty configuration sub-object. |
options.uncertainty.enabled |
boolean |
No | true |
Enable hallucination scoring via HHEM segmented decision. |
options.uncertainty.summarySimilarityMode |
string |
No | embedding (if embedder present) or lexical |
How to score summary-vs-children similarity. 'embedding' uses cosine similarity; 'lexical' uses text overlap. |
options.uncertainty.summaryThreshold |
number |
No | 0.08 |
HHEM decision threshold for hallucination flagging. |
options.uncertainty.qaThreshold |
number |
No | 0.4 |
HHEM decision threshold for QA report hallucination detection. |
options.uncertainty.summaryPenalty |
number |
No | 0.5 |
Penalty applied to hallucinated segments in scoring. |
options.uncertainty.citationMinJaccard |
number |
No | 0.35 |
Minimum Jaccard similarity for citation validity. |
options.summaryRefinement |
object |
No | {...} |
Iterative summary refinement configuration. |
options.summaryRefinement.enabled |
boolean |
No | false |
Enable bt-harness-based iterative summary refinement. |
options.summaryRefinement.hardGateEnabled |
boolean |
No | false |
Reject summaries below confidence threshold instead of accepting the best available. |
options.summaryRefinement.failClosed |
boolean |
No | false |
When true and hardGateEnabled, call done with an Error if no candidate passes the gate. |
options.summaryRefinement.iterations |
number |
No | 3 |
Max refinement iterations. Clamped to minimum 1. |
options.summaryRefinement.patience |
number |
No | 2 |
Stagnation tolerance before stopping. Clamped to minimum 1. |
options.summaryRefinement.minImprovement |
number |
No | 0.02 |
Minimum score improvement to consider a revision better. Clamped to minimum 0. |
options.summaryRefinement.targetConfidence |
number |
No | 0.7 |
Confidence threshold for hardGateEnabled. |
options.summaryRefinement.maxRejectedRetries |
number |
No | 4 |
Extra iterations when hard gate rejects candidates. Clamped to minimum 0. |
options.summaryRefinement.basePrompt |
string |
No | 'Summarize faithfully. Include only information present in the source children. Avoid boilerplate and keep it concise.' |
Base summarization prompt. |
options.summaryRefinement.promptMutator |
function |
No | null |
Custom prompt mutation: (bestPrompt, history, context, bestScore) → new prompt. When absent, cycles through 3 built-in mutations. |
Returns: { ingestDocument, search, stores, getArtifactUncertainty }
| Method | Signature | Description |
|---|---|---|
ingestDocument(payload, done) |
(object, function) → calls done(err, result) |
Splits a document into leaves (paragraphs or explicit payload.leaves), indexes leaves, builds hierarchical summaries level by level, indexes QA reports if provided. Callback receives { documentId, rootId, leafCount, summaryCount, qaReportCount, leaves, summaries, qaReports, uncertainty }. |
search(query, options) |
`(string | object, object)→Array` |
stores |
{ textStore, treeStore, graphStore, multiState } |
Reference to the stores passed at construction. |
getArtifactUncertainty(docId) |
(string) → `object |
null` |
createRaptorRetriever(options)
Creates a RAPTOR tree retriever as a callback-style function.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options.raptor |
object |
Yes | — | RAPTOR instance from createRaptor. Must have search() and optionally stores.textStore, getArtifactUncertainty(). Throws at construction if raptor.search is not a function. |
options.textStore |
object |
No | raptor.stores.textStore |
Text store for resolving docId to text content. |
options.defaultLimit |
number |
No | 6 |
Default number of results when payload does not specify topK. |
Returns: function(payload, done) — a retriever callback.
Payload fields (can also be a plain string query):
| Field | Type | Default | Description |
|---|---|---|---|
payload.query or payload.question |
string |
— | Search query. If payload is a string, it is used as the query. |
payload.topK |
number |
options.defaultLimit |
Number of results to return. |
payload.documentId |
string |
— | Filter to a specific document. |
payload.kind |
string |
— | Filter to a specific artifact kind ('leaf', 'summary', 'qa_report'). |
payload.kinds |
string[] |
— | Filter to multiple kinds (OR filter). |
payload.level |
number |
— | Filter to a specific tree level. |
payload.filters |
object |
— | Additional attribute filters. |
payload.candidateStores |
string[] |
— | Candidate store IDs. |
payload.candidateLimit |
number |
— | Candidate count limit. |
payload.planner |
string |
— | Query planner mode. |
payload.queryMode |
string |
— | Query mode override. |
payload.jag |
boolean |
true |
Enable JAG (Join-Aware-Gather) optimization. |
The done callback receives (err, pages) where each page is { docId, score, text, attributes, uncertainty }.
createSummaryRefinerBt(opts)
Creates a behavior tree harness for iteratively refining summaries through propose-evaluate-promote cycles.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
opts.summarizer |
function |
No | — | (children, context, function(err, summaryText)) — the summarizer function. |
opts.children |
array |
No | [] |
Source artifacts being summarized. |
opts.context |
object |
No | {} |
Context passed through to the summarizer. |
opts.basePrompt |
string |
No | 'Summarize the children faithfully and concisely.' |
Initial summarization prompt. |
opts.iterations |
number |
No | 3 |
Max propose-evaluate cycles. |
opts.patience |
number |
No | 2 |
Stagnation tolerance (unchanged best score). |
opts.minImprovement |
number |
No | 0.02 |
Minimum score improvement threshold. |
opts.scorer |
function |
No | () => 1 |
(summaryText, children) → number (0–1). |
opts.gateFn |
function |
No | () => true |
(candidate) → boolean for hard gating. |
opts.computeUncertainty |
function |
No | null |
(summaryText, children) → uncertainty metrics with { confidence, hallucinationScore, hallucinated }. |
opts.promptMutator |
function |
No | null |
(bestPrompt, history, context) → string. When absent, cycles through 3 built-in mutations. |
Returns: { run, close }
| Method | Signature | Description |
|---|---|---|
run(done) |
(function) → calls done(err, { text, revisionAttempts, failed }) |
Starts the BT refinement loop. Calls back with the best summary found. |
close() |
() |
Closes the internal document store. |
splitParagraphs(text)
Splits text on blank line boundaries (\n\s*\n) into an array of trimmed, non-empty strings. Returns [] for non-string input.
chunk(items, size)
Splits an array into sub-arrays of size elements (minimum 2). Returns [] for non-array or empty input.
combineFilters(a, b)
Combines two filter objects with AND semantics. Returns null if both are falsy. Returns the non-null filter if one is null.
buildKindFilter(kinds)
Builds an attribute filter for artifact kinds. Returns a single { source: 'attr', key: 'raptorKind', eq: kind } filter for one kind, or an OR filter for multiple kinds. Returns null for empty/non-array input.
clamp01(value)
Clamps a numeric value to [0, 1]. Returns null for non-finite input.
Error Conditions
| Function | Condition | Error |
|---|---|---|
createRaptor() |
textStore.index is not a function |
throw new Error('RAPTOR requires textStore with index().') |
raptor.search() |
multiState is falsy or multiState.search is not a function |
throw new Error('RAPTOR search requires multiState.search().') |
createRaptorRetriever() |
options.raptor is falsy or raptor.search is not a function |
throw new Error('RAPTOR retriever requires raptor.search().') |
createRaptorRetriever() return |
raptor.search() throws during retrieval |
Error passed to done(err) callback |
createSummaryRefinerBt.run() |
BT harness spec is invalid (harness.valid === false) |
done(new Error('Invalid summary refiner: ' + errors)) |
createSummaryRefinerBt.run() |
hardGateEnabled && failClosed, summarizer returns error or empty result |
done(new Error('RAPTOR summary refinement failed: ' + err.message)) |
createSummaryRefinerBt.run() |
hardGateEnabled && failClosed, no candidate text |
done(new Error('RAPTOR summary hard gate failed with no valid candidate')) |
ingestDocument() |
Leaf indexing error | callback(err, ...) with propagated error |
ingestDocument() |
Summary build error | callback(err, ...) with propagated error |
ingestDocument() |
QA report indexing error | callback(err, ...) with propagated error |
Tests
npm test
Runs node --test test/rigor.test.js test/behavioral/raptor.behavioral.test.js test/e2e/raptor.e2e.test.js test/e2e/raptor.openai.e2e.test.js. Covers: RAPTOR index creation, document ingestion and tree building, multi-level retrieval via search(), summary generation and refinement via BT harness, similarity scoring (lexical, embedding, HHEM), chunk clustering, uncertainty scoring, property-based tests, end-to-end integration with OpenAI summarizer.
Requirements
Node.js 22 or later. ESM only.
Peer dependencies: @polyweave/state, @polyweave/state-search.
Dependencies: @polyweave/core, @polyweave/bt-harness, @polyweave/openai, @polyweave/self-improving, @polyweave/tools, @polyweave/uncertainty.
Caveats
- The default summarizer is a simple truncation — for meaningful hierarchical summaries, provide a real LLM summarizer adapter.
- Tree depth grows logarithmically with document count (base
branchFactor). Very large document sets with a low branch factor may produce deep trees with increased retrieval latency. search()requiresmultiStatewith a workingsearch()method. Without it, the indexer can build trees but cannot retrieve.ingestDocumentcallback receives non-nullerronly on indexing failures — summary errors in the default (non-hard-gate) mode are silently handled by producing empty summaries.- HHEM-based similarity and uncertainty scoring uses
@polyweave/uncertaintyinternally. - Embedding-based clustering requires an embedder adapter; without one, lexical (text-overlap) similarity is used.
See Also
Dependencies
Dependencies
| ID | Version |
|---|---|
| @polyweave/bt-harness | * |
| @polyweave/core | * |
| @polyweave/openai | * |
| @polyweave/self-improving | * |
| @polyweave/tools | * |
| @polyweave/uncertainty | * |
Development Dependencies
| ID | Version |
|---|---|
| @rigor/core | * |
Peer Dependencies
| ID | Version |
|---|---|
| @polyweave/state | * |
| @polyweave/state-search | * |