Build your own RAG pipeline
Fixed-size chunking·3 min

The chunk record

0 / 1

Every chunk you emit is a record: {id, paragraphId, text, startTok, endTok}. The id is ${paragraphId}::${startTok}-${endTok}. The offsets are token offsets into the paragraph's token array, half-open [startTok, endTok) — so boundaries grade integer-exactly no matter how you slice the string.

src/chunk.ts
export interface Chunk {
  id: string;          // `${paragraphId}::${startTok}-${endTok}`
  paragraphId: string;
  text: string;        // = detokenize(tokens.slice(startTok, endTok))
  startTok: number;    // inclusive
  endTok: number;      // exclusive
}
Token offsets, not character offsets

This is grade-critical. tokenize(text) gives the token array; detokenize(tokens) joins tokens with single spaces. Your chunk's text must equal detokenize(tokens.slice(startTok, endTok)) exactly — so build text from the offsets, don't substring the raw string.