Repository navigation
v2.5.0
Added
- Cancellation:
createRagPipelinecreates an AbortController per run
and passes its signal to every component (retriever.retrieve({ signal }),
embedder.embedQuery/embed(text, { signal }),reranker.rerank(q, docs, { signal }),llm.generate(q, docs, { signal })); a newoptions.signal
lets callers cancel. All built-in connectors and rerankers honour it.
AgenticPipelineandIterativeRetrieverpropagate it too. QueryPlanner.plan(query, { llm, signal }): LLM-proposed sub-queries with
strict JSON validation and heuristic fallback (returns a Promise);
AgenticPipelineoptionenableLlmPlanning(defaultfalse).checkNumericConsistency,extractNumbers,detectInjectionand
PRICING_METADATAexports.- Opt-in
detectInjectiononRetrievalGuardto scan retrieved documents for
indirect prompt injection. CostCalculator: pricing provenance (source,asOf,verified), a
pricingoverride, one-time unknown-model warnings
(RAG_UNKNOWN_MODEL_PRICING), longest-match model resolution.EmbeddingRerankercacheSize(LRU of document embeddings) and
concurrencyoptions;MemoryRetrievereviction: 'fifo'option.- Plugin signatures:
computeContentDigest(), a signedcontentDigestthat
binds plugin code, opt-inrequireContentDigestandrequireSignedPlugins,
andregister()'s optional{ content }argument. JWTValidatoroptionssingleUseTokens(defaulttrue) and
maxTrackedJtis(default 100000).AuditLoggerreads its key fromencryptionKeyor
RAG_AUDIT_ENCRYPTION_KEY;requireEncryption: truemakes a missing key an
error..env.examplefordocker compose.npm run test:serialandnpm run format:check.- Working CLI workflow:
rag-pipeline init,ingest <path>,query <question>andrunnow do real work against a persistent local index.
initwrites a pipeline of built-in components (--template local | openai | ollama | anthropic, or interactive prompts in a terminal). FileVectorStore(exported): JSON-file vector index with atomic
writes, embedder/dimension tracking and per-source re-ingestion..ragrc.jsonpipeline resolution: entries{ stage, name, config }
resolve to built-in components, custom plugin modules underplugins, or
plugins registered onpluginRegistry.rag-pipeline serveand a workingDevServer: local HTTP API
(GET /health,POST /query) bound to 127.0.0.1, JSON only, 64 KB body
limit, no CORS.LocalEmbedder.getState()/setState().rag-pipeline hub install <source>installs plugins from a local
directory,.tgz, single.jsfile,npm:<package>or a registry
(sha256-verified). It contains extraction to.rag/plugins, runs a static
security scan (high-risk findings block unless--allow-risky), checks the
stage contract in a separate process, and registers the plugin in
.ragrc.json.PluginHub.installPlugin()uses the same installer.rag-pipeline hub certify submit|check <path>scores a local plugin
from its files (contract, security scan, tests, documentation) against the
BASIC/VERIFIED/ENTERPRISE automated thresholds.rag-pipeline hub listlists plugins registered in the config.rag-pipeline initsetup wizard: chooses the embedder, LLM, retriever and an optional reranker, using only built-ins or custom plugin modules. Connector options are pre-filled with the connector defaults. Each custom plugin is loaded and its stage method checked before it is accepted. The wizard reports which API key environment variables are missing, can run a connection test on request, and previews the JSON before writing.rag-pipeline ai, built on the configured pipeline and index:
ai train embedding [path]refits thelocalTF-IDF embedder and
re-embeds the index;ai benchmarkreports measured p50/p95/mean latency
per stage;ai feedback <question> <docId> --rating up|downstores votes in
.rag/feedback.jsonandai searchapplies them as a capped,
explained score adjustment;ai multimodal process <path>reports type,
characters and chunks for text files (images exit 1: no built-in connector
accepts image input).
Deprecated
- Experimental modules moved to
@devilsdev/rag-pipeline-utils/experimental:
ModelTrainingOrchestrator,FederatedLearningCoordinator,
MultiModalProcessor,AdaptiveRetrievalEngine,SSOManager,
SAMLProvider,OAuth2Provider,ActiveDirectoryProvider,OIDCProvider,
TenantManager,ResourceMonitor,DataGovernanceManager/
DataGovernance,PluginSandboxandPluginCertification. They are
simulated or incomplete (random metrics, SSO that accepts any code outside
production and does not verify SAML or OIDC tokens, random quotas, erasure
that deletes nothing, a non-functional sandbox, fixed certification
scores); see the Experimental docs page. Their main-entry exports still
work but emit a one-timeDeprecationWarning(RAG_DEP_*codes) when
used, are marked@deprecatedin the types, and will be removed from the
main entry in the next major release. The same classes are shared by both
entries, soinstanceofchecks keep working.
Removed
- Unused CLI config templates under
src/cli/templates/(old format,
referenced a schema path that did not exist). - Ten unreachable duplicate modules under
src/ai/and the internal
src/dag/enhanced-dag-engine.js(never reachable from the package entries;
the exported classes are unchanged). - semantic-release configuration and dependencies (releases use
npm publish --provenancefrom the release workflow), duplicate
.eslintrc.jsonand.babelrc, about 50 one-off fix scripts and their
ci:*npm scripts, the trackedjunit.xml, and 14 test suites that never
exercisedsrc/(fake pipelines, mocks, empty timing loops). - CLI placeholders that printed success without doing anything (
ingest,
query,doctor,validate,plugin search|install|publish) and
options that had no effect (--trace,--stats,--parallel,
--streaming,--max-memory,--preview,--validate,--explain,
--abort-timeout,--quiet,config show --format). - The interactive wizard built on hard-coded mock registry data.
- The unregistered
src/cli/commands/ai-ml*command modules: federated
learning, LLM fine-tuning,ai train status|deploy,ai dashboard,
adaptive profiles and multimodalsearch/describe. They called methods
missing from thesrc/aiengines, exited 0 on failure and printed
hard-coded or simulated numbers. Thesrc/ailibrary modules are unchanged. - Unreachable modules that were never exported or registered:
src/dx/
(including a realtime debugger exposing an unauthenticated WebSocket),
src/cli/commands/{dx,docs}.js,src/cli/input-sanitization-middleware.js,
src/cli/plugin-marketplace-commands.js,src/query.js,src/ingest.js,
src/pipeline/pipeline.js,src/core/pipeline-factory.js. The package
exportsmap only exposes.and./cli, so these were never public.
Fixed
evaluateRagDatasetscores the generated answer; it scored the
retrieved documents, so every case failed with zero scores.RetrievalGuardwithenforceACLalso reads a top-levelacl/
requiredRoleon results that havemetadata(it read onlymetadata
then).createRagPipeline: timeouts now cancel work and no stage starts after
an abort (a timeout still resolves{ success: false, error: 'Execution timeout' }; a caller abort resolves'Execution aborted'). Without an llm
it runs retrieval only and returnsanswer: nullinstead of'ok'. Stream
mode withcitationsorevaluateends with one{ token: '', done: true, citations, evaluation }chunk. The artificial 5 ms delay is removed.- Connectors retry only transient failures (network, 408/409/425/429/5xx)
with exponential backoff, jitter andRetry-After; SDK-internal retries are
disabled. API keys are read at construction, and calls without a key fail
fast withMISSING_API_KEY. MemoryRetrieverenforcesmaxDocumentsand rejects mismatched vector
dimensions instead of truncating them.AuditLoggerno longer encrypts with a random per-process key that made
logs unreadable after a restart; legacycreateCipherrecords decrypt on
Node 22+.JWTValidator/jwt-confighonour an explicitclockTolerance/
notBeforeToleranceof 0 (it became 30); the expired-token test is enabled.loadPluginsFromJsonawaits registration and verifies signed manifests
and plugin files before importing them.rag-pipeline init: the connection test aborts its calls after the 15 s
timeout and the CLI exits afterwards.- Benchmarks accept
--iterations=N, no longer abort on the retry
benchmarks' deliberate warm-up failures, and exit when done. - Docs generation no longer hangs: the JSDoc regex backtracked
exponentially on an unterminated/**. - Tests run in parallel again (a suite destroyed the Jest worker's own
stdio streams), no longer rewrite tracked fixtures, and coverage works on
Windows (the test setup no longer patchespath.resolve). - Package import:
require()/importof 2.4.5 failed in every clean
install withCannot find module 'isolated-vm'.isolated-vmis now
loaded only whenPluginSandboxruns and is an optional peer dependency;
pino-prettyis an optional peer as well. Added the missingajv-formats
andmarkeddependencies, pinnedchalkto 4.x (5.x is ESM-only), removed
unuseddotenv. Importing the bundle no longer prints "Missing Contract"
warnings. A tarball smoke test (npm run smoke:pack) now runs in CI and
before publish. createRagPipeline: theembedderresult was computed and discarded,
so vector retrievers never received aqueryVector. Plugins registered on
the exportedpluginRegistryare now resolvable by name, and the timeout
timer is cleared when a run finishes.MemoryRetrieverthrows a clear error when noqueryVectoris given
instead of crashing inside cosine similarity.- README / docs quick start now passes an
embedder; as previously
written it could not retrieve anything fromMemoryRetriever. - Citations with zero retrieved documents no longer fail the run; every
sentence is reported as unsupported. HybridRetrieverpasses the full request (includingqueryVector) to
retrieve(), so vector results are no longer silently dropped, and throws
when every retriever fails.- Guardrails: the retrieval guard (ACL, relevance, freshness) now runs
before generation via the newoptions.filterResultshook; removed
documents are reported by id only; strict-mode blocks no longer return the
raw answer; PII is redacted in citations and evaluation details too. AuditLogger: tenant/user/action filters never matched, so queries and
compliance reports returned every tenant's records. Encryption now uses
createCipherivwith a random IV per field (it threw on Node 22 and reused
the nonce on Node 18/20). The integrity hash now covers action and tenant.InputSanitizer: a regex state bug let command-injection payloads
through after a previously blocked input.LLMRerankersends an actual ranking prompt instead of the raw
question, keeps documents the LLM omits, and honourstopK.- Agentic RAG: with an
embedder, each sub-query and refined query is
embedded on its own instead of reusing the original query vector. - TypeScript: 52 runtime exports (citations, guardrails, hybrid
retrieval, agentic RAG, connectors, rerankers, GraphRAG, ...) had no
declarations. They are now generated from JSDoc at build time into
dist/types/and re-exported fromdist/index.d.ts; the build fails if
any export is undeclared, and the smoke test compiles a TypeScript consumer. doctor/validatereport real findings (unknown components,
missing stages, missing API keys, broken custom plugins) and exit 1 on
errors.doctor --auto-fixno longer lets callers re-enable a shell, no
longer strips Windows path separators, and runs npm on Windows.hub(aliasplugin) commands are registered. There is no default
registry (the old default host does not exist): pass--registry <url>or
setRAG_PLUGIN_REGISTRYfor registry operations.- Hot reload ignore patterns work again (chokidar 4 dropped glob support)
and only JavaScript changes trigger a reload. loadRagConfig()accepts a config file path as well as a directory and no
longer logs to stdout.LocalEmbedderproduced all-zero vectors for corpora of two or fewer
documents (IDF is now smoothed).- Logger: console-style calls such as
logger.error("Failed:", msg)no
longer log the message as one key per character.
Changed
-
Documentation: the README is rewritten with use cases whose code runs
in CI (__tests__/docs/readme-examples.test.jsexecutes every README
example), and.ragrc.json's JSON schema (.ragrc.schema.json, shipped in
the package) now describes thepipeline+pluginsformat the CLI and
loadRagConfig()actually use. -
Metric changes:
- Context recall now measures how much of a reference (ground-truth) answer
the retrieved documents support. Pass it via
PipelineEvaluator.evaluate(result, { referenceAnswer })or
run({ options: { evaluate: true, referenceAnswer } }). Without one,
scores.contextRecallis omitted,details.contextRecallis
{ score: null, skipped: true, reason }, andmetadata.metricsSkipped
lists it. computeGroundednessis a weighted mean over the available components;
without a reference it is(0.4 * faithfulness + 0.3 * contextPrecision) / 0.7.- Claim support checks numbers: a sentence whose numbers (digits, decimals,
percentages, number words) are not in the source scores below 0.4 and is
not grounded. This affects citations, faithfulness, recall,
PostGenerationGuardandSelfCritiqueChecker. "20" equals "twenty".
- Context recall now measures how much of a reference (ground-truth) answer
-
createRagPipelineresults always includeanswerwhen an llm is
configured. -
QueryPlannersplits only at clause or question boundaries, keeps
"salt and pepper"-style phrases intact, and expands comparisons into one
sub-query per entity plus the comparison; results carrysource. -
Prompts: built-in connectors put retrieved context in the user message
as delimited, untrusted reference data, with a system prompt telling the
model to treat it as data. Answers may differ. -
PreRetrievalGuardreturns the query unchanged (no partial deletion) and
reports detections ininjection; strict mode still blocks. Detection
normalises input first. To cut false positives, bare "act as", "jailbreak",
uppercase "DAN", mid-line "system:" and "you are now ready" are no longer
flagged; chat role markers, prompt-exfiltration phrasing and normalisation
bypasses now are. -
CostCalculatorpricesgpt-4o-mini-*andclaude-3-5-sonnet-*
correctly (previously gpt-4 pricing and $0);customPricingentries without
unitdefault to per-1000 tokens. Built-in prices are marked unverified:
theirasOfis when they were added, not when they were checked. -
EmbeddingRerankerlimits concurrency to 4 by default; call
clearCache()after retraining an embedder. -
AuditLoggerwith encryption enabled and no key now disables
encryption with a warning instead of using a throwaway key. -
Plugin trust store is empty by default (the placeholder key is gone).
-
docker composerequiresPOSTGRES_PASSWORD,REDIS_PASSWORDand
GRAFANA_ADMIN_PASSWORD, publishes ports on 127.0.0.1 only, and drops the
debugger port and the Prometheus lifecycle API; the image build fails on
critical runtime vulnerabilities. -
CI: one
ci.ymlworkflow (required checksTest & Lint (18|20|22))
that also enforcesformat:checkand the tarball smoke test, and runs for
pull requests into any branch.npm testruns Jest in parallel. -
DevServernow really listens:start()binds port 3000 by default
(passport: 0for a free port), so existing callers may see
EADDRINUSE. Default host is127.0.0.1(waslocalhost), default
watchPathsis[](was./src/plugins,./src/mocks), and requests
must use a loopbackHostheader while bound to loopback. -
loadRagConfig()error messages now include details
(Config validation failed: ...,Invalid JSON in config file <path>: ...)
and it no longer logs. -
rag-pipeline plugin/hubregistry operations require
--registry <url>orRAG_PLUGIN_REGISTRY.hub certify submittakes a
local plugin path and reports computed scores; it previously issued
certificates from fixed placeholder scores.PluginHub.installPlugin()now
installs into<project>/.rag/pluginsand registers the plugin in the
config (it previously only wrotemetadata.jsontolocalCacheDir), and
getInstalledPlugins()reads the config. -
FileVectorStoreindex files store mostly-zero vectors sparsely and
round values to 7 significant digits (about 10x smaller for thelocal
embedder). -
Grounding scores (citations, faithfulness, context precision/recall,
groundedness,PostGenerationGuard,SelfCritiqueChecker) now measure the
share of a sentence's content words found in a document, optionally
IDF-weighted. They previously used Jaccard similarity against the whole
document, which shrinks with document length: an answer copied verbatim
from a ~70-word chunk scored 0. Scores will be noticeably higher for
grounded answers. -
Default per-sentence similarity threshold raised from 0.3 to 0.5
(CitationTracker.similarityThreshold,PipelineEvaluator.threshold,
faithfulness/recall/hallucination-detectorthreshold). Aggregate
thresholds (groundednessThreshold,approvalThreshold) are unchanged. -
The tokenizer keeps non-ASCII letters (
Políticano longer becomes
poltica) and splits on newlines and hyphens instead of gluing words
together. This also affects BM25, BLEU/ROUGE and the scoring reranker. -
RetrievalGuardwithenforceACLnow fails closed when
context.userPermissionsis missing. -
CitationTracker.track()non-array error message is now
"retrievedDocs must be an array".
Security
- Production dependencies:
npm audit --omit=devreports no high or critical
findings (axios ^1.21.0; overrides for fast-uri, follow-redirects,
form-data, ws and zod). - Experimental SSO: the development bypass that accepted any authorization
code requiresdevBypass: trueand a non-productionNODE_ENVand is
refused in production; OIDC id_tokens are validated (JWKS signature, iss,
aud, exp, nonce); OAuth2/OIDC use PKCE (S256);redirect_uricomes only
from configuration; callbacks must match the stored login request's
provider. - Plugin signatures: Ed25519 verification works (
crypto.verifywith
KeyObjects); a signedcontentDigestbinds plugin code and is always
enforced when present. AuditLoggercompares HMAC signatures in constant time;JWTValidator's
replay store is bounded and expires entries.- Retrieved documents are no longer placed in the LLM system role; prompt
injection detection normalises homoglyphs, leetspeak and zero-width
characters. .secretsis no longer tracked in git (rotate anything it held) and is
excluded from Docker builds.
Known limitations
- Grounding is lexical plus a numeric-consistency check. Not checked:
negation ("not twenty days"), units ("20 hours" vs "20 days"), ordinals, a
lone "one", differently split decimals, and claims that combine facts from
several documents. Document-side matching is lenient ("twenty-five" in a
source also supports "twenty" or "five"). - The
openaiSDK stays on 4.x: newer majors need Node 20+ and will come with
3.0.csv-parsehas one moderate advisory whose fix is a major release. - Experimental SSO cannot refresh OIDC sessions, and
SAMLProviderrefuses
to authenticate. AuditLogger's HMAC signing key is random per process unlesssigningKey
is passed, soverifyIntegrityflags records written before a restart.
Upgrading: see the 2.5.0 release post and Migration guide. Deprecated exports keep working in 2.5 with a one-time warning and are removed from the main entry in 3.0.