@polyweave/sleuth (1.0.6)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/sleuth@1.0.6"@polyweave/sleuth": "1.0.6"About this package
@polyweave/sleuth
SLEUTH retrieval pipeline as a bt-harness tool.
Synopsis
import { createSleuthTool } from '@polyweave/sleuth';
const tool = createSleuthTool({
apiKey: process.env.API_KEY,
model: 'deepseek-v4-flash',
dataset: [
'What is the capital of France?',
{ query: 'Explain quantum computing' }
],
retriever: myRetrieverAdapter,
clueDiscovery: myClueAdapter,
pageScreen: myScreenAdapter,
difficultyAssess: myAssessAdapter,
reasoner: myReasonerAdapter,
topK: 5
});
tool.sink.write({ type: 'TOOL_CALL', content: {} });
tool.source.pipe(createFrameSink((frame) => {
if (frame.type === 'TOOL_RESULT') console.log('Results:', frame.content.results);
if (frame.type === 'ERROR') console.error(frame.content.message);
}));
Install
npm install @polyweave/sleuth
Why
SLEUTH is a 5-stage retrieval pipeline implemented as a bt-harness duplex tool. It processes batches of queries through sequential stages — retrieve, clue discovery, page screening, difficulty assessment, reasoning — each powered by pluggable adapters (duplex or callback). It supports optional feedback-descent answer refinement (LLM-driven iterative improvement), multi-state store integration for structured entity storage, and tick-driven advancement for stepwise execution. Use it for batched research QA, structured retrieval, and agent-driven search over document stores.
API
createSleuthTool(options)
Creates a SLEUTH retrieval pipeline tool.
createSleuthTool(options: object) → { source, sink, _toolName, getResults, close }
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
options.apiKey |
string |
Yes | — | API key for LLM calls |
options.model |
string |
No | 'deepseek-v4-flash' |
Model name used for agent and evaluator |
options.dataset |
string[] | { query, question }[] |
No | [] |
Array of query items; strings are treated as query |
options.retriever |
duplex | callback | No | — | Adapter for candidate page retrieval; receives { query, pages, topK } |
options.clueDiscovery |
duplex | callback | No | — | Adapter for extracting clues from candidate pages; receives { query, page, index } |
options.pageScreen |
duplex | callback | No | — | Adapter for screening/relevance filtering of pages; receives { query, page, index } |
options.difficultyAssess |
duplex | callback | No | — | Adapter for assessing query difficulty and generating reasoning instructions; receives { query, context } |
options.reasoner |
duplex | callback | No | — | Adapter for final reasoning and answer generation; receives { query, context, difficulty, instructions } |
options.topK |
number |
No | 5 |
Number of candidate pages to retrieve per query |
options.state |
multi-state store | object | No | — | Multi-state store for structured entity storage (SleuthCandidate, SleuthEvidence, SleuthAnswer), or { docStore, textStore } for simple document storage |
options.refineAnswer |
object |
No | — | Feedback descent refinement config: { enabled: boolean, iterations: number, patience: number } |
options.createAdapter |
function |
No | — | Custom adapter factory forwarded to the inner bt-harness |
options.adapterConfig |
object |
No | — | Adapter factory configuration forwarded to the inner bt-harness |
options.debug |
boolean |
No | false |
Enable debug output on the inner bt-harness |
Return Value
Returns an object:
| Property | Type | Description |
|---|---|---|
source |
push-stream source | Subscribe with source.pipe(sink); emits TOOL_RESULT, ERROR, DESCRIPTION frames |
sink |
push-stream sink | Accepts TOOL_CALL, TICK, CANCEL, ABORT, DESCRIBE frames |
_toolName |
string |
Always 'sleuth' |
getResults() |
function → array |
Returns accumulated results array (parsed from doc store) |
close() |
function |
Closes the internal document store |
Frame Protocol
Input frames (write to sink)
| Frame Type | Content | Description |
|---|---|---|
TOOL_CALL |
{ dataset } |
Start pipeline execution; dataset overrides options.dataset |
TICK |
— | Advance one step in the current bt-harness (for tick-driven execution) |
CANCEL |
— | Cancel the current harness and the active refine harness |
ABORT |
— | Abort the current harness |
DESCRIBE |
{ streamId } |
Request a description frame |
Output frames (read from source)
| Frame Type | Content | Description |
|---|---|---|
TOOL_RESULT |
{ results, itemCount, itemsProcessed, failed } |
Pipeline completed; results is an array of { answer, result } per item |
ERROR |
{ message } |
Pipeline error or harness validation failure |
DESCRIPTION |
{ name, description, capabilities, schema } |
Response to DESCRIBE |
Internal Tools (available to agents during pipeline execution)
| Tool Name | Args | Description |
|---|---|---|
sleuth_read |
{ sectionId } |
Read any document section from the internal doc store |
sleuth_retrieve |
{ query, pages } |
Retrieve candidate pages using the retriever adapter |
sleuth_clue |
{ query, page, index } |
Extract clues from a candidate page using the clueDiscovery adapter |
sleuth_screen |
{ query, page, index } |
Screen a page for relevance using the pageScreen adapter |
sleuth_assess |
{ query } |
Assess difficulty using the difficultyAssess adapter |
sleuth_reason |
{ query, answer } |
Reason and produce an answer; pass answer to store directly without invoking reasoner |
sleuth_search |
{ query, limit } |
Full-text search across indexed documents (only available when textStore is configured) |
sleuth_query |
{ query | dsl } or query DSL |
Structured query against multi-state store (only available with state multi-state store) |
sleuth_multi_search |
{ query, limit } |
Unified multi-store search (only available with state multi-state store) |
Error Conditions
TOOL_CALLwhile already running: emitsERRORframe withmessage: 'Already running'- Invalid harness (parse failure, missing tools): emits
ERRORframe with harness error messages - Adapter callback error: returns
{ error }in tool result with the error message string reasonernot provided duringsleuth_reason: returns{ error: 'No reasoner provided' }- Multi-state store not configured during
sleuth_query: returns{ results: [], note: 'Multi-state store not configured...' } - Multi-state store not configured during
sleuth_multi_search: returns{ results: [], note: '...' } - Refinement harness invalid: silently falls back to base answer
Pipeline Stages (5-stage sequential BT)
The behavior tree spec defines sequential execution:
- retrieve — Read current item, call
sleuth_retrieve(query) - clue_discovery — For each candidate, call
sleuth_clue - page_screen — Screen each page via
sleuth_screen(label), retain pages markedRorCR - difficulty_assess — Assess difficulty, generate instructions via
sleuth_assess - reason — Produce final answer via
sleuth_reason(answer), increment@itemIndex
The pipeline processes all items sequentially. When @itemIndex reaches itemCount, the harness sets @complete = true and emits TOOL_RESULT.
Feedback Descent Refinement
When options.refineAnswer.enabled is true, after the reasoner produces a base answer, a nested bt-harness runs an iterative refinement loop:
- propose — agent reads best answer + evidence, generates improved candidate
- evaluate — evaluator compares candidate vs best against evidence, sets
@preferred - promote_best — if preferred, the candidate becomes the new best
- increment_stagnant — if not preferred, increment stagnation counter
The loop stops when @iteration >= iterations or @stagnant >= patience. The best answer is returned.
Tests
npm test
Covers: tool creation with all adapter combinations, 5-stage pipeline execution, candidate retrieval and evidence collection, page screening with label filtering, difficulty assessment, reasoning with and without answer refinement, multi-state entity storage and querying, tick-driven advancement, CANCEL/ABORT handling.
Requirements
- Node.js 22+
- ESM only
Dependencies: @polyweave/core, @polyweave/bt-harness, @polyweave/state, @polyweave/tools, @polyweave/loop-utils
Dependencies
Dependencies
| ID | Version |
|---|---|
| @polyweave/bt-harness | * |
| @polyweave/core | * |
| @polyweave/loop-utils | * |
Development Dependencies
| ID | Version |
|---|---|
| @rigor/core | * |