NodeTool ships a lightweight ingestion pipeline for semantic search and retrieval-augmented generation (RAG) tasks. The indexing logic is split across @nodetool-ai/vectorstore (store, chunking, and embedding) and @nodetool-ai/websocket (the upload route).
Overview
- Collection metadata (
CollectionResponsein@nodetool-ai/protocolpackages/protocol/src/api-types.ts) carries the collection’s name, document count, free-form metadata, andworkflow_name— the resolved name of the workflow id stored undermetadata.workflow, shown in listings. - Vector store – the default backend is SQLite-vec (
@nodetool-ai/vectorstorepackages/vectorstore/src/sqlite-vec-store.ts). Embeddings flow through theVectorProviderabstraction — see Vector Storage for swapping backends (Supabase/pgvector, or the Pinecone stub). - Indexing route –
handleCollectionRequest()(@nodetool-ai/websocketpackages/websocket/src/collection-api.ts) handles the multipart upload and performs the ingestion itself. It is the one collection endpoint that stayed on REST; every other CRUD and query endpoint moved to the tRPCcollectionsrouter.
Default Flow
handleCollectionRequest()matchesPOST /api/collections/:name/index, resolves the collection throughgetDefaultVectorProvider().getCollection(), and checks ownership withcanAccessCollection()— someone else’s collection answers404, not403, so the endpoint cannot be used to probe for names.- The request must be
multipart/form-datawith afilefield. Otherwise the route answers400, and405for a method other thanPOST. A file abovegetMaxUploadBytes()(NODETOOL_MAX_UPLOAD_BYTES, 1 GiB by default) answers413. The file is read as UTF-8 text, split withsplitDocument()from@nodetool-ai/vectorstore(2000 characters per chunk, 1000 overlap), and upserted into the collection as<file name>#<n>chunks carryingsourceandstart_indexmetadata. An empty or whitespace-only file produces zero chunks. The route reads text only, so it does not extract text from PDF, DOCX, or other binary formats. It also passes no embedding function when it opens the collection, so it stores chunk text without calling the collection’s embedding model. To embed during ingestion, use thevector.Index*nodes below. - The route returns
{ path, chunks, error }. ACollectionNotFoundErrorbecomes404; any other provider error is logged and returned as a generic500, because provider errors carry SQL text, file paths, and upstream URLs.
Indexing from a workflow
Index nodes write to a collection and query nodes read from it. Each takes a collection input (see the vector.Collection node, which gets or creates a collection by name and embedding model).
| Node | Purpose |
|---|---|
vector.IndexString |
Index a string under a document id. |
vector.IndexTextChunk |
Index a single text chunk. |
vector.IndexAggregatedText |
Index several text chunks at once with aggregated embeddings from Ollama. |
vector.IndexImage |
Index a list of image assets or files. |
vector.IndexEmbedding |
Index a single precomputed embedding vector, with optional metadata. |
vector.QueryText, vector.QueryImage |
Similarity search by text or image. |
vector.HybridSearch |
Fuses a semantic ranking with a keyword-filtered one by reciprocal rank fusion. |
vector.Count, vector.GetDocuments, vector.Peek |
Inspect a collection. |
vector.RemoveOverlap |
Removes overlapping words between consecutive strings in a list. |
Definitions are in packages/core-nodes/src/nodes/vector.ts. To index a PDF, extract its text first with a node such as lib.pdf.ExtractText.
Configuring the vector store
The default backend is local SQLite-vec. Switch backends with NODETOOL_VECTOR_PROVIDER.
| Variable | Description | Default |
|---|---|---|
NODETOOL_VECTOR_PROVIDER |
sqlite-vec, pinecone, or supabase |
sqlite-vec |
VECTORSTORE_DB_PATH |
Local SQLite-vec database file | vectorstore.db in the NodeTool data dir ($XDG_DATA_HOME/nodetool, falling back to ~/.local/share/nodetool) |
PINECONE_API_KEY |
Required to select pinecone, which is a stub that fails on use |
— |
SUPABASE_URL and SUPABASE_KEY (or SUPABASE_SERVICE_ROLE_KEY) |
Required when provider is supabase. Install the SQL migration once. |
— |
See Vector Storage for backend-specific setup.
CLI & API Integration
POST /api/collections/:name/index(see@nodetool-ai/websocketpackages/websocket/src/collection-api.ts) triggers ingestion via HTTP (multipart/form-data file upload).- The MCP server (
@nodetool-ai/websocketpackages/websocket/src/mcp-server.ts) exposes the CodeAct action toolexecute_codeplusview_imageand the direct set. An IDE plug-in reads collections from inside an action —nodetool.collections.list()andnodetool.collections.query(). It does not index assets. - A deployed server exposes no separate admin ingestion endpoints. The
/admin/*surface@nodetool-ai/deploy’s client used to carry was ported from the retired Python server and never mounted; usePOST /api/collections/:name/indexagainst the deployment instead.
Troubleshooting
- Supabase errors – verify
SUPABASE_URL, the key, and thatpackages/vectorstore/sql/supabase-migration.sqlran on the project. Fall back to local SQLite-vec by settingNODETOOL_VECTOR_PROVIDER=sqlite-vec. - Pinecone errors – the provider is not implemented. Use
sqlite-vecorsupabase. - Large files – ensure
VECTORSTORE_DB_PATHhas disk headroom, or move to a remote backend.
Related Documentation
- Providers – selecting embedding models for ingestion nodes.
- Workflow API – details on
RunJobRequest. - Storage Guide – configuring persistent storage for uploaded documents.