Skip to content

ancs21/vectorless-js

Repository files navigation

vectorless-js

Retrieval without embeddings. Instead of chunking a document and searching for text that looks similar, this builds a table of contents, hands it to an LLM, and lets the model pick which section to read, the way a person uses an index.

It runs wherever JS does: the browser through WASM, plus Bun, Node, and Cloudflare Workers. It is a JavaScript port of PageIndex, verified byte-for-byte against its Python tree builder.

Docs: vectorless.js.org

bun add vectorless-js
bun add @llamaindex/liteparse-wasm   # optional, only if you feed it PDFs

Use it

import { buildIndexAuto, ask, complete, type LLMConfig } from "vectorless-js";

const llm: LLMConfig = {
  baseURL: process.env.OPENAI_BASE_URL!,   // https://api.openai.com/v1
  apiKey: process.env.OPENAI_API_KEY,
  model: process.env.OPENAI_MODEL,         // defaults to gpt-4o
};

const doc = await buildIndexAuto(markdown, "lease.pdf", (p) => complete(p, llm));
const { answer, citations } = await ask(doc, "What is the notice period?", llm);

The config mirrors the OpenAI client, so the standard environment variables drop straight in, and anything speaking OpenAI chat completions works. Pass a bare URL instead of a config when you point at a proxy that holds the key.

The PDF reader is a separate import. Keeping it out of the main entry point means readers who feed it Markdown skip the WASM download entirely:

import { initParser, pdfToMarkdown } from "vectorless-js/parse";

await initParser(wasmBytesOrUrl);   // you supply the wasm; the library never guesses
const markdown = await pdfToMarkdown(bytes);

How it works

PDF
 |   liteparse, compiled to WASM. Runs on your machine.
 v
markdown
 |   buildIndex: headings become nodes.
 v   Deterministic, no LLM, free.
tree
 |   The only smart part. The model reads the table of
 v   contents and fetches the one section it picks.
answer + citations

buildIndex turns Markdown headings into a tree without calling an LLM or touching the network, so it costs nothing and gives you the same tree every run. The agent then navigates that tree through three tools that execute locally: get_document, get_document_structure, and get_page_content.

Running the tools locally is what keeps the document at home. On a 28-page filing the model sees about 1.6 KB of section titles and line numbers, picks one, and pulls only those lines. The other 60-odd KB stays where it is, because nothing asked for it. In a browser that extends to the file itself, which you never upload; the only thing crossing the network is text the model chose to read.

Some documents come out flat, and buildIndexAuto repairs them. A PDF that gives every heading the same rank has correct titles and no nesting, so an LLM assigns the depths and nothing but the headings leaves the machine. A contract with no headings at all has nothing to nest, so an LLM infers the outline from the text. Both feed the same deterministic builder.

Beyond one document, ask also takes a corpus keyed by doc id, and routeDocuments reads per-document descriptions to decide which are worth opening. That routing reads descriptions rather than vectors, same as the rest.

Known limits

OCR is off, so born-digital PDFs read fine and scanned pages come back empty. Wiring a JS OCR engine through pdfToMarkdown's config is the fix.

A document with no headings at all goes through reconstructTree, which sends the whole thing to the model. That is fine for a contract and a problem for a large filing: 448 KB of text is a prompt around 133k tokens, which will not fit a 128k context window. Documents that do have headings avoid this, however uniform those headings are, because buildIndexAuto sends only the headings. Check isFlatTree before reaching for reconstruction on a large heading-less document.

The tree holds the document text, so memory tracks document size. A 53 KB contract becomes a 59 KB tree.

Develop

bun install
bun test            # deterministic tree and tool logic
bun run typecheck
bun run build:lib   # library → dist-lib/
bun run dev         # demo app on :5173
bun run docs:dev    # docs site

License

MIT. This is a port of PageIndex by Vectify AI, also MIT. Both notices are in LICENSE.

About

Vectorless, reasoning-based RAG (PageIndex) in JavaScript. Runs in the browser via WASM and anywhere JS runs.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors