agentfootprint 8.9.0 → 8.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -0
- package/CLAUDE.md +4 -0
- package/bin/agentfootprint-index.mjs +192 -0
- package/dist/doors/rag.js +66 -0
- package/dist/doors/rag.js.map +1 -0
- package/dist/esm/doors/rag.d.ts +49 -0
- package/dist/esm/doors/rag.js +50 -0
- package/dist/esm/doors/rag.js.map +1 -0
- package/dist/esm/rag/hash.d.ts +2 -0
- package/dist/esm/rag/hash.js +22 -0
- package/dist/esm/rag/hash.js.map +1 -0
- package/dist/esm/rag/index.d.ts +17 -0
- package/dist/esm/rag/index.js +17 -0
- package/dist/esm/rag/index.js.map +1 -0
- package/dist/esm/rag/indexCorpus.d.ts +102 -0
- package/dist/esm/rag/indexCorpus.js +339 -0
- package/dist/esm/rag/indexCorpus.js.map +1 -0
- package/dist/esm/rag/indexFolder.d.ts +40 -0
- package/dist/esm/rag/indexFolder.js +42 -0
- package/dist/esm/rag/indexFolder.js.map +1 -0
- package/dist/esm/rag/loadDocuments.d.ts +34 -0
- package/dist/esm/rag/loadDocuments.js +160 -0
- package/dist/esm/rag/loadDocuments.js.map +1 -0
- package/dist/esm/rag/loaders/html.d.ts +42 -0
- package/dist/esm/rag/loaders/html.js +48 -0
- package/dist/esm/rag/loaders/html.js.map +1 -0
- package/dist/esm/rag/loaders/index.d.ts +30 -0
- package/dist/esm/rag/loaders/index.js +24 -0
- package/dist/esm/rag/loaders/index.js.map +1 -0
- package/dist/esm/rag/loaders/markdown.d.ts +27 -0
- package/dist/esm/rag/loaders/markdown.js +12 -0
- package/dist/esm/rag/loaders/markdown.js.map +1 -0
- package/dist/esm/rag/loaders/mock.d.ts +28 -0
- package/dist/esm/rag/loaders/mock.js +14 -0
- package/dist/esm/rag/loaders/mock.js.map +1 -0
- package/dist/esm/rag/loaders/pdf.d.ts +39 -0
- package/dist/esm/rag/loaders/pdf.js +90 -0
- package/dist/esm/rag/loaders/pdf.js.map +1 -0
- package/dist/esm/rag/loaders/text.d.ts +23 -0
- package/dist/esm/rag/loaders/text.js +21 -0
- package/dist/esm/rag/loaders/text.js.map +1 -0
- package/dist/esm/rag/splitDocuments.d.ts +21 -0
- package/dist/esm/rag/splitDocuments.js +65 -0
- package/dist/esm/rag/splitDocuments.js.map +1 -0
- package/dist/esm/rag/splitters/byHeading.d.ts +36 -0
- package/dist/esm/rag/splitters/byHeading.js +66 -0
- package/dist/esm/rag/splitters/byHeading.js.map +1 -0
- package/dist/esm/rag/splitters/byParagraph.d.ts +24 -0
- package/dist/esm/rag/splitters/byParagraph.js +16 -0
- package/dist/esm/rag/splitters/byParagraph.js.map +1 -0
- package/dist/esm/rag/splitters/constants.d.ts +19 -0
- package/dist/esm/rag/splitters/constants.js +20 -0
- package/dist/esm/rag/splitters/constants.js.map +1 -0
- package/dist/esm/rag/splitters/fixedWithOverlap.d.ts +31 -0
- package/dist/esm/rag/splitters/fixedWithOverlap.js +34 -0
- package/dist/esm/rag/splitters/fixedWithOverlap.js.map +1 -0
- package/dist/esm/rag/splitters/index.d.ts +50 -0
- package/dist/esm/rag/splitters/index.js +51 -0
- package/dist/esm/rag/splitters/index.js.map +1 -0
- package/dist/esm/rag/splitters/shared.d.ts +87 -0
- package/dist/esm/rag/splitters/shared.js +188 -0
- package/dist/esm/rag/splitters/shared.js.map +1 -0
- package/dist/esm/rag/splitters/wholeDocument.d.ts +16 -0
- package/dist/esm/rag/splitters/wholeDocument.js +10 -0
- package/dist/esm/rag/splitters/wholeDocument.js.map +1 -0
- package/dist/esm/rag/types.d.ts +200 -0
- package/dist/esm/rag/types.js +20 -0
- package/dist/esm/rag/types.js.map +1 -0
- package/dist/rag/hash.js +26 -0
- package/dist/rag/hash.js.map +1 -0
- package/dist/rag/index.js +40 -0
- package/dist/rag/index.js.map +1 -0
- package/dist/rag/indexCorpus.js +344 -0
- package/dist/rag/indexCorpus.js.map +1 -0
- package/dist/rag/indexFolder.js +46 -0
- package/dist/rag/indexFolder.js.map +1 -0
- package/dist/rag/loadDocuments.js +164 -0
- package/dist/rag/loadDocuments.js.map +1 -0
- package/dist/rag/loaders/html.js +53 -0
- package/dist/rag/loaders/html.js.map +1 -0
- package/dist/rag/loaders/index.js +33 -0
- package/dist/rag/loaders/index.js.map +1 -0
- package/dist/rag/loaders/markdown.js +16 -0
- package/dist/rag/loaders/markdown.js.map +1 -0
- package/dist/rag/loaders/mock.js +18 -0
- package/dist/rag/loaders/mock.js.map +1 -0
- package/dist/rag/loaders/pdf.js +118 -0
- package/dist/rag/loaders/pdf.js.map +1 -0
- package/dist/rag/loaders/text.js +26 -0
- package/dist/rag/loaders/text.js.map +1 -0
- package/dist/rag/splitDocuments.js +69 -0
- package/dist/rag/splitDocuments.js.map +1 -0
- package/dist/rag/splitters/byHeading.js +70 -0
- package/dist/rag/splitters/byHeading.js.map +1 -0
- package/dist/rag/splitters/byParagraph.js +20 -0
- package/dist/rag/splitters/byParagraph.js.map +1 -0
- package/dist/rag/splitters/constants.js +23 -0
- package/dist/rag/splitters/constants.js.map +1 -0
- package/dist/rag/splitters/fixedWithOverlap.js +38 -0
- package/dist/rag/splitters/fixedWithOverlap.js.map +1 -0
- package/dist/rag/splitters/index.js +60 -0
- package/dist/rag/splitters/index.js.map +1 -0
- package/dist/rag/splitters/shared.js +199 -0
- package/dist/rag/splitters/shared.js.map +1 -0
- package/dist/rag/splitters/wholeDocument.js +14 -0
- package/dist/rag/splitters/wholeDocument.js.map +1 -0
- package/dist/rag/types.js +21 -0
- package/dist/rag/types.js.map +1 -0
- package/dist/types/doors/rag.d.ts +50 -0
- package/dist/types/doors/rag.d.ts.map +1 -0
- package/dist/types/rag/hash.d.ts +3 -0
- package/dist/types/rag/hash.d.ts.map +1 -0
- package/dist/types/rag/index.d.ts +18 -0
- package/dist/types/rag/index.d.ts.map +1 -0
- package/dist/types/rag/indexCorpus.d.ts +103 -0
- package/dist/types/rag/indexCorpus.d.ts.map +1 -0
- package/dist/types/rag/indexFolder.d.ts +41 -0
- package/dist/types/rag/indexFolder.d.ts.map +1 -0
- package/dist/types/rag/loadDocuments.d.ts +35 -0
- package/dist/types/rag/loadDocuments.d.ts.map +1 -0
- package/dist/types/rag/loaders/html.d.ts +43 -0
- package/dist/types/rag/loaders/html.d.ts.map +1 -0
- package/dist/types/rag/loaders/index.d.ts +31 -0
- package/dist/types/rag/loaders/index.d.ts.map +1 -0
- package/dist/types/rag/loaders/markdown.d.ts +28 -0
- package/dist/types/rag/loaders/markdown.d.ts.map +1 -0
- package/dist/types/rag/loaders/mock.d.ts +29 -0
- package/dist/types/rag/loaders/mock.d.ts.map +1 -0
- package/dist/types/rag/loaders/pdf.d.ts +40 -0
- package/dist/types/rag/loaders/pdf.d.ts.map +1 -0
- package/dist/types/rag/loaders/text.d.ts +24 -0
- package/dist/types/rag/loaders/text.d.ts.map +1 -0
- package/dist/types/rag/splitDocuments.d.ts +22 -0
- package/dist/types/rag/splitDocuments.d.ts.map +1 -0
- package/dist/types/rag/splitters/byHeading.d.ts +37 -0
- package/dist/types/rag/splitters/byHeading.d.ts.map +1 -0
- package/dist/types/rag/splitters/byParagraph.d.ts +25 -0
- package/dist/types/rag/splitters/byParagraph.d.ts.map +1 -0
- package/dist/types/rag/splitters/constants.d.ts +20 -0
- package/dist/types/rag/splitters/constants.d.ts.map +1 -0
- package/dist/types/rag/splitters/fixedWithOverlap.d.ts +32 -0
- package/dist/types/rag/splitters/fixedWithOverlap.d.ts.map +1 -0
- package/dist/types/rag/splitters/index.d.ts +51 -0
- package/dist/types/rag/splitters/index.d.ts.map +1 -0
- package/dist/types/rag/splitters/shared.d.ts +88 -0
- package/dist/types/rag/splitters/shared.d.ts.map +1 -0
- package/dist/types/rag/splitters/wholeDocument.d.ts +17 -0
- package/dist/types/rag/splitters/wholeDocument.d.ts.map +1 -0
- package/dist/types/rag/types.d.ts +201 -0
- package/dist/types/rag/types.d.ts.map +1 -0
- package/package.json +23 -4
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* byParagraph — cut on blank lines, pack up to `maxChars`.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: Strategy (one of `Splitter`).
|
|
5
|
+
* Role: rag/ layer. The right default for prose that carries no headings.
|
|
6
|
+
* Emits: N/A.
|
|
7
|
+
*
|
|
8
|
+
* A blank line is the weakest structural signal a document reliably has, and
|
|
9
|
+
* unlike a character count it at least falls where the author paused. Adjacent
|
|
10
|
+
* paragraphs are packed together until the next one would exceed `maxChars`,
|
|
11
|
+
* so a document of short paragraphs yields whole chunks rather than one chunk
|
|
12
|
+
* per line.
|
|
13
|
+
*
|
|
14
|
+
* A single paragraph longer than `maxChars` is hard-cut — see the note in
|
|
15
|
+
* `shared.ts` on why packing and cutting are separate decisions.
|
|
16
|
+
*/
|
|
17
|
+
import type { Splitter } from '../types.js';
|
|
18
|
+
export interface ByParagraphOptions {
|
|
19
|
+
/** Target chunk size in characters. Default 1000 — see the family docstring. */
|
|
20
|
+
readonly maxChars?: number;
|
|
21
|
+
/** Backward overlap between adjacent chunks. Default 150. */
|
|
22
|
+
readonly overlapChars?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function byParagraph(options?: ByParagraphOptions): Splitter;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DEFAULT_MAX_CHARS, DEFAULT_OVERLAP_CHARS } from './constants.js';
|
|
2
|
+
import { applyOverlap, foldRunts, hardCut, packSpans, paragraphSpans, toPieces } from './shared.js';
|
|
3
|
+
export function byParagraph(options = {}) {
|
|
4
|
+
const maxChars = options.maxChars ?? DEFAULT_MAX_CHARS;
|
|
5
|
+
const overlapChars = options.overlapChars ?? DEFAULT_OVERLAP_CHARS;
|
|
6
|
+
return {
|
|
7
|
+
name: 'byParagraph',
|
|
8
|
+
split(doc) {
|
|
9
|
+
const paragraphs = paragraphSpans(doc.text);
|
|
10
|
+
const packed = packSpans(paragraphs, maxChars);
|
|
11
|
+
const cut = packed.flatMap((span) => span.end - span.start > maxChars ? hardCut(span, maxChars, overlapChars) : [span]);
|
|
12
|
+
return toPieces(doc, applyOverlap(foldRunts(cut), overlapChars));
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=byParagraph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byParagraph.js","sourceRoot":"","sources":["../../../../src/rag/splitters/byParagraph.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AASpG,MAAM,UAAU,WAAW,CAAC,UAA8B,EAAE;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC;IAEnE,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,KAAK,CAAC,GAAmB;YACvB,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAClF,CAAC;YACF,OAAO,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two numbers every splitter defaults to, in one place so they cannot
|
|
3
|
+
* drift apart between strategies.
|
|
4
|
+
*
|
|
5
|
+
* See `splitters/index.ts` for the measurement they come from: `localEmbedder`
|
|
6
|
+
* truncates at 512 wordpiece tokens (~1,800–2,000 characters), silently, and
|
|
7
|
+
* 1,000 characters is ~250 tokens — comfortably inside it.
|
|
8
|
+
*/
|
|
9
|
+
/** Target chunk size in characters. ~250 wordpiece tokens of English. */
|
|
10
|
+
export declare const DEFAULT_MAX_CHARS = 1000;
|
|
11
|
+
/** Overlap between adjacent chunks, so a boundary-spanning sentence is whole somewhere. */
|
|
12
|
+
export declare const DEFAULT_OVERLAP_CHARS = 150;
|
|
13
|
+
/**
|
|
14
|
+
* Below this, a trailing fragment is folded back into the previous chunk
|
|
15
|
+
* rather than shipped on its own. A 12-character chunk consisting of one
|
|
16
|
+
* heading and no body embeds to noise and takes a top-K slot from a real
|
|
17
|
+
* passage.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MIN_CHUNK_CHARS = 50;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two numbers every splitter defaults to, in one place so they cannot
|
|
3
|
+
* drift apart between strategies.
|
|
4
|
+
*
|
|
5
|
+
* See `splitters/index.ts` for the measurement they come from: `localEmbedder`
|
|
6
|
+
* truncates at 512 wordpiece tokens (~1,800–2,000 characters), silently, and
|
|
7
|
+
* 1,000 characters is ~250 tokens — comfortably inside it.
|
|
8
|
+
*/
|
|
9
|
+
/** Target chunk size in characters. ~250 wordpiece tokens of English. */
|
|
10
|
+
export const DEFAULT_MAX_CHARS = 1000;
|
|
11
|
+
/** Overlap between adjacent chunks, so a boundary-spanning sentence is whole somewhere. */
|
|
12
|
+
export const DEFAULT_OVERLAP_CHARS = 150;
|
|
13
|
+
/**
|
|
14
|
+
* Below this, a trailing fragment is folded back into the previous chunk
|
|
15
|
+
* rather than shipped on its own. A 12-character chunk consisting of one
|
|
16
|
+
* heading and no body embeds to noise and takes a top-K slot from a real
|
|
17
|
+
* passage.
|
|
18
|
+
*/
|
|
19
|
+
export const MIN_CHUNK_CHARS = 50;
|
|
20
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/rag/splitters/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,yEAAyE;AACzE,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAEtC,2FAA2F;AAC3F,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fixedWithOverlap — cut every `chars` characters, overlapping by `overlapChars`.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: Strategy (one of `Splitter`).
|
|
5
|
+
* Role: rag/ layer. The fallback for text with no structure to read:
|
|
6
|
+
* transcripts, OCR output, scraped bodies with the markup gone.
|
|
7
|
+
* Emits: N/A.
|
|
8
|
+
*
|
|
9
|
+
* It is the least informed strategy and it is honest about that: it cuts where
|
|
10
|
+
* the counter says, which will sometimes be mid-sentence. The overlap is what
|
|
11
|
+
* makes that survivable — a sentence broken at a boundary is whole in the next
|
|
12
|
+
* chunk. Prefer `byHeading` or `byParagraph` whenever the document gives you
|
|
13
|
+
* anything to work with.
|
|
14
|
+
*
|
|
15
|
+
* Cuts are nudged to the nearest word boundary within a small window, so the
|
|
16
|
+
* common case does not split a word in half. The offsets move with the nudge;
|
|
17
|
+
* they always index the source.
|
|
18
|
+
*/
|
|
19
|
+
import type { Splitter } from '../types.js';
|
|
20
|
+
export interface FixedWithOverlapOptions {
|
|
21
|
+
/** Characters per chunk. Default 1000. */
|
|
22
|
+
readonly chars?: number;
|
|
23
|
+
/** Backward overlap. Default 150. */
|
|
24
|
+
readonly overlapChars?: number;
|
|
25
|
+
/**
|
|
26
|
+
* How far to look for a word boundary before accepting a mid-word cut.
|
|
27
|
+
* Default 40 characters. Set 0 to cut exactly on the count.
|
|
28
|
+
*/
|
|
29
|
+
readonly wordWindow?: number;
|
|
30
|
+
}
|
|
31
|
+
export declare function fixedWithOverlap(options?: FixedWithOverlapOptions): Splitter;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { DEFAULT_MAX_CHARS, DEFAULT_OVERLAP_CHARS } from './constants.js';
|
|
2
|
+
import { applyOverlap, foldRunts, toPieces } from './shared.js';
|
|
3
|
+
export function fixedWithOverlap(options = {}) {
|
|
4
|
+
const chars = options.chars ?? DEFAULT_MAX_CHARS;
|
|
5
|
+
const overlapChars = options.overlapChars ?? DEFAULT_OVERLAP_CHARS;
|
|
6
|
+
const wordWindow = options.wordWindow ?? 40;
|
|
7
|
+
return {
|
|
8
|
+
name: 'fixedWithOverlap',
|
|
9
|
+
split(doc) {
|
|
10
|
+
const text = doc.text;
|
|
11
|
+
const spans = [];
|
|
12
|
+
let start = 0;
|
|
13
|
+
while (start < text.length) {
|
|
14
|
+
let end = Math.min(text.length, start + chars);
|
|
15
|
+
// Nudge back to whitespace, but never past the window and never so far
|
|
16
|
+
// that the chunk collapses.
|
|
17
|
+
if (end < text.length && wordWindow > 0) {
|
|
18
|
+
const floor = Math.max(start + 1, end - wordWindow);
|
|
19
|
+
let candidate = end;
|
|
20
|
+
while (candidate > floor && !/\s/.test(text[candidate] ?? ''))
|
|
21
|
+
candidate -= 1;
|
|
22
|
+
if (candidate > floor)
|
|
23
|
+
end = candidate;
|
|
24
|
+
}
|
|
25
|
+
spans.push({ start, end });
|
|
26
|
+
if (end >= text.length)
|
|
27
|
+
break;
|
|
28
|
+
start = end;
|
|
29
|
+
}
|
|
30
|
+
return toPieces(doc, applyOverlap(foldRunts(spans), overlapChars));
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=fixedWithOverlap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixedWithOverlap.js","sourceRoot":"","sources":["../../../../src/rag/splitters/fixedWithOverlap.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAc3E,MAAM,UAAU,gBAAgB,CAAC,UAAmC,EAAE;IACpE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,iBAAiB,CAAC;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC;IACnE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAE5C,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,KAAK,CAAC,GAAmB;YACvB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;YACtB,MAAM,KAAK,GAAW,EAAE,CAAC;YACzB,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,OAAO,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC3B,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;gBAC/C,uEAAuE;gBACvE,4BAA4B;gBAC5B,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;oBACxC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,GAAG,UAAU,CAAC,CAAC;oBACpD,IAAI,SAAS,GAAG,GAAG,CAAC;oBACpB,OAAO,SAAS,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;wBAAE,SAAS,IAAI,CAAC,CAAC;oBAC9E,IAAI,SAAS,GAAG,KAAK;wBAAE,GAAG,GAAG,SAAS,CAAC;gBACzC,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC3B,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM;oBAAE,MAAM;gBAC9B,KAAK,GAAG,GAAG,CAAC;YACd,CAAC;YACD,OAAO,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;QACrE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rag/splitters — where a document gets cut, and why there.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: Strategy family (factory functions), the same shape as the window
|
|
5
|
+
* and retrieval families. Not a `{ kind }` union: a splitter you write
|
|
6
|
+
* yourself is the same shape as these, unused ones stay out of a
|
|
7
|
+
* bundle, and adding one needs no switch edited anywhere.
|
|
8
|
+
* Role: rag/ layer.
|
|
9
|
+
* Emits: N/A.
|
|
10
|
+
*
|
|
11
|
+
* ── The defaults, and the measurement behind them ───────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* `maxChars: 1000`, `overlapChars: 150`. Those numbers are chosen by
|
|
14
|
+
* CONSTRAINT, not by fashion, and the constraint is measurable:
|
|
15
|
+
*
|
|
16
|
+
* **`localEmbedder`'s default model silently truncates at 512 wordpiece
|
|
17
|
+
* tokens.** Measured directly — embed a long text, embed the same text with an
|
|
18
|
+
* unrelated tail appended, and compare. At 508 base tokens the tail still
|
|
19
|
+
* moves the vector (cosine 0.9965). At 596 it does not (cosine 0.999999): the
|
|
20
|
+
* tail was discarded and nothing said so. 512 wordpiece tokens is roughly
|
|
21
|
+
* 1,800–2,000 characters of English.
|
|
22
|
+
*
|
|
23
|
+
* A chunk of 1,000 characters is about 250 tokens. That sits comfortably
|
|
24
|
+
* inside that cliff, inside the 256-token length the sentence-transformer
|
|
25
|
+
* family was actually trained at, and trivially inside `openaiEmbedder`'s
|
|
26
|
+
* 8,191. Raise it and you approach a limit whose failure mode is silence —
|
|
27
|
+
* half your chunk embedded, full score reported.
|
|
28
|
+
*
|
|
29
|
+
* The 150-character overlap (15%) exists so a sentence spanning a boundary is
|
|
30
|
+
* whole in one of the two neighbours. It is the smallest overlap that reliably
|
|
31
|
+
* does that for English prose; there is nothing deeper claimed for it.
|
|
32
|
+
*
|
|
33
|
+
* ── Which one to use ────────────────────────────────────────────────────────
|
|
34
|
+
*
|
|
35
|
+
* | splitter | cuts on | use when |
|
|
36
|
+
* |---|---|---|
|
|
37
|
+
* | `byHeading()` | Markdown `#` lines | the document declares its own sections — **not a heuristic** |
|
|
38
|
+
* | `byParagraph()` | blank lines | prose with no headings |
|
|
39
|
+
* | `fixedWithOverlap()` | character count | text with no structure at all (transcripts, OCR) |
|
|
40
|
+
* | `wholeDocument()` | nothing | short documents that are already one idea |
|
|
41
|
+
*
|
|
42
|
+
* `byHeading` is the only one that is not guessing. The author already marked
|
|
43
|
+
* where the sections are; the others are inferring boundaries from typography.
|
|
44
|
+
* That is why it is the default for Markdown.
|
|
45
|
+
*/
|
|
46
|
+
export { byParagraph, type ByParagraphOptions } from './byParagraph.js';
|
|
47
|
+
export { byHeading, type ByHeadingOptions } from './byHeading.js';
|
|
48
|
+
export { fixedWithOverlap, type FixedWithOverlapOptions } from './fixedWithOverlap.js';
|
|
49
|
+
export { wholeDocument } from './wholeDocument.js';
|
|
50
|
+
export { DEFAULT_MAX_CHARS, DEFAULT_OVERLAP_CHARS } from './constants.js';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rag/splitters — where a document gets cut, and why there.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: Strategy family (factory functions), the same shape as the window
|
|
5
|
+
* and retrieval families. Not a `{ kind }` union: a splitter you write
|
|
6
|
+
* yourself is the same shape as these, unused ones stay out of a
|
|
7
|
+
* bundle, and adding one needs no switch edited anywhere.
|
|
8
|
+
* Role: rag/ layer.
|
|
9
|
+
* Emits: N/A.
|
|
10
|
+
*
|
|
11
|
+
* ── The defaults, and the measurement behind them ───────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* `maxChars: 1000`, `overlapChars: 150`. Those numbers are chosen by
|
|
14
|
+
* CONSTRAINT, not by fashion, and the constraint is measurable:
|
|
15
|
+
*
|
|
16
|
+
* **`localEmbedder`'s default model silently truncates at 512 wordpiece
|
|
17
|
+
* tokens.** Measured directly — embed a long text, embed the same text with an
|
|
18
|
+
* unrelated tail appended, and compare. At 508 base tokens the tail still
|
|
19
|
+
* moves the vector (cosine 0.9965). At 596 it does not (cosine 0.999999): the
|
|
20
|
+
* tail was discarded and nothing said so. 512 wordpiece tokens is roughly
|
|
21
|
+
* 1,800–2,000 characters of English.
|
|
22
|
+
*
|
|
23
|
+
* A chunk of 1,000 characters is about 250 tokens. That sits comfortably
|
|
24
|
+
* inside that cliff, inside the 256-token length the sentence-transformer
|
|
25
|
+
* family was actually trained at, and trivially inside `openaiEmbedder`'s
|
|
26
|
+
* 8,191. Raise it and you approach a limit whose failure mode is silence —
|
|
27
|
+
* half your chunk embedded, full score reported.
|
|
28
|
+
*
|
|
29
|
+
* The 150-character overlap (15%) exists so a sentence spanning a boundary is
|
|
30
|
+
* whole in one of the two neighbours. It is the smallest overlap that reliably
|
|
31
|
+
* does that for English prose; there is nothing deeper claimed for it.
|
|
32
|
+
*
|
|
33
|
+
* ── Which one to use ────────────────────────────────────────────────────────
|
|
34
|
+
*
|
|
35
|
+
* | splitter | cuts on | use when |
|
|
36
|
+
* |---|---|---|
|
|
37
|
+
* | `byHeading()` | Markdown `#` lines | the document declares its own sections — **not a heuristic** |
|
|
38
|
+
* | `byParagraph()` | blank lines | prose with no headings |
|
|
39
|
+
* | `fixedWithOverlap()` | character count | text with no structure at all (transcripts, OCR) |
|
|
40
|
+
* | `wholeDocument()` | nothing | short documents that are already one idea |
|
|
41
|
+
*
|
|
42
|
+
* `byHeading` is the only one that is not guessing. The author already marked
|
|
43
|
+
* where the sections are; the others are inferring boundaries from typography.
|
|
44
|
+
* That is why it is the default for Markdown.
|
|
45
|
+
*/
|
|
46
|
+
export { byParagraph } from './byParagraph.js';
|
|
47
|
+
export { byHeading } from './byHeading.js';
|
|
48
|
+
export { fixedWithOverlap } from './fixedWithOverlap.js';
|
|
49
|
+
export { wholeDocument } from './wholeDocument.js';
|
|
50
|
+
export { DEFAULT_MAX_CHARS, DEFAULT_OVERLAP_CHARS } from './constants.js';
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/rag/splitters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EAAE,WAAW,EAA2B,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAyB,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAgC,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared machinery for the splitter family.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: internal helpers, not exported from the door.
|
|
5
|
+
* Role: rag/ layer. The offset arithmetic lives here ONCE, because it is the
|
|
6
|
+
* part every splitter must get exactly right and the part that is
|
|
7
|
+
* easy to get subtly wrong per-strategy.
|
|
8
|
+
* Emits: N/A.
|
|
9
|
+
*
|
|
10
|
+
* **The invariant, stated once:** for every piece produced,
|
|
11
|
+
* `doc.text.slice(charStart, charEnd) === piece.text`. Every helper here
|
|
12
|
+
* derives its text BY SLICING rather than by concatenating what it read, which
|
|
13
|
+
* is what makes the invariant true by construction rather than by care.
|
|
14
|
+
*/
|
|
15
|
+
import type { LoadedDocument, SplitPiece } from '../types.js';
|
|
16
|
+
/** A half-open span of the source text. */
|
|
17
|
+
export interface Span {
|
|
18
|
+
readonly start: number;
|
|
19
|
+
readonly end: number;
|
|
20
|
+
readonly heading?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Where this span's OWN content begins, before overlap was prepended.
|
|
23
|
+
*
|
|
24
|
+
* Overlap deliberately reaches backward into the previous chunk, which means
|
|
25
|
+
* `start` can sit on the previous PAGE. Attributing the chunk to that page
|
|
26
|
+
* would cite a page whose text is only the borrowed run-up — so page lookup
|
|
27
|
+
* uses this instead, and it is set only when the two differ.
|
|
28
|
+
*/
|
|
29
|
+
readonly contentStart?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Which page an offset falls on, 1-based, or `undefined` when the document is
|
|
33
|
+
* not paginated.
|
|
34
|
+
*
|
|
35
|
+
* Pages were joined with `'\n\n'` by the loader, so the boundaries are
|
|
36
|
+
* reconstructible exactly. A chunk that straddles a page break is attributed
|
|
37
|
+
* to the page it STARTS on — one number, the one you would turn to first.
|
|
38
|
+
*/
|
|
39
|
+
export declare function pageLocator(doc: LoadedDocument): (offset: number) => number | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Trim a span inward past leading/trailing whitespace, keeping the offsets
|
|
42
|
+
* honest.
|
|
43
|
+
*
|
|
44
|
+
* The naive version — `slice().trim()` — produces text that no longer matches
|
|
45
|
+
* its own offsets. This moves the offsets instead, so the invariant holds.
|
|
46
|
+
* Returns `undefined` when the span is entirely whitespace.
|
|
47
|
+
*/
|
|
48
|
+
export declare function trimSpan(text: string, span: Span): Span | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Pack consecutive units (paragraphs, lines) into spans of at most `maxChars`,
|
|
51
|
+
* then apply `overlapChars` of backward overlap.
|
|
52
|
+
*
|
|
53
|
+
* Units are never split by this function — a single unit longer than `maxChars`
|
|
54
|
+
* becomes its own oversized span, and the caller decides whether to hard-cut
|
|
55
|
+
* it. That separation matters: a 4,000-character paragraph is a real thing in
|
|
56
|
+
* real documents, and silently slicing it mid-word is a different decision from
|
|
57
|
+
* packing.
|
|
58
|
+
*/
|
|
59
|
+
export declare function packSpans(units: readonly Span[], maxChars: number): Span[];
|
|
60
|
+
/**
|
|
61
|
+
* Extend each span backward by `overlapChars`, without crossing the previous
|
|
62
|
+
* span's start.
|
|
63
|
+
*
|
|
64
|
+
* Backward rather than forward so a chunk always ENDS on the boundary its
|
|
65
|
+
* strategy chose — a heading section that ends mid-sentence because of overlap
|
|
66
|
+
* would be a section that lies about where it ends.
|
|
67
|
+
*/
|
|
68
|
+
export declare function applyOverlap(spans: readonly Span[], overlapChars: number): Span[];
|
|
69
|
+
/**
|
|
70
|
+
* Fold a too-small span back into its predecessor.
|
|
71
|
+
*
|
|
72
|
+
* A fragment of a few characters — a stray heading, a signature line — embeds
|
|
73
|
+
* to noise and then competes for a top-K slot with real passages.
|
|
74
|
+
*
|
|
75
|
+
* **It never folds across a heading boundary.** A merged chunk carries the
|
|
76
|
+
* FIRST span's heading, so folding a short section into the one before it
|
|
77
|
+
* would produce a chunk labelled `heading="Alpha"` whose text is Beta's — a
|
|
78
|
+
* citation that names the wrong section, which is worse than a small chunk.
|
|
79
|
+
* Two spans merge only when they are already the same section.
|
|
80
|
+
*/
|
|
81
|
+
export declare function foldRunts(spans: readonly Span[], minChars?: number): Span[];
|
|
82
|
+
/** Turn spans into pieces, slicing the text so the invariant holds by construction. */
|
|
83
|
+
export declare function toPieces(doc: LoadedDocument, spans: readonly Span[]): SplitPiece[];
|
|
84
|
+
/** Hard-cut a span that no packing could fit, at `maxChars` with overlap. */
|
|
85
|
+
export declare function hardCut(span: Span, maxChars: number, overlapChars: number): Span[];
|
|
86
|
+
/** Split into paragraph spans on blank lines, keeping offsets. */
|
|
87
|
+
export declare function paragraphSpans(text: string): Span[];
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { MIN_CHUNK_CHARS } from './constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* Which page an offset falls on, 1-based, or `undefined` when the document is
|
|
4
|
+
* not paginated.
|
|
5
|
+
*
|
|
6
|
+
* Pages were joined with `'\n\n'` by the loader, so the boundaries are
|
|
7
|
+
* reconstructible exactly. A chunk that straddles a page break is attributed
|
|
8
|
+
* to the page it STARTS on — one number, the one you would turn to first.
|
|
9
|
+
*/
|
|
10
|
+
export function pageLocator(doc) {
|
|
11
|
+
const pages = doc.pages;
|
|
12
|
+
if (!pages || pages.length === 0)
|
|
13
|
+
return () => undefined;
|
|
14
|
+
const bounds = [];
|
|
15
|
+
let cursor = 0;
|
|
16
|
+
for (const page of pages) {
|
|
17
|
+
bounds.push(cursor);
|
|
18
|
+
cursor += page.length + 2; // the '\n\n' the loader joined with
|
|
19
|
+
}
|
|
20
|
+
return (offset) => {
|
|
21
|
+
let page = 1;
|
|
22
|
+
for (let i = 0; i < bounds.length; i++) {
|
|
23
|
+
if (offset >= (bounds[i] ?? 0))
|
|
24
|
+
page = i + 1;
|
|
25
|
+
else
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
return page;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Trim a span inward past leading/trailing whitespace, keeping the offsets
|
|
33
|
+
* honest.
|
|
34
|
+
*
|
|
35
|
+
* The naive version — `slice().trim()` — produces text that no longer matches
|
|
36
|
+
* its own offsets. This moves the offsets instead, so the invariant holds.
|
|
37
|
+
* Returns `undefined` when the span is entirely whitespace.
|
|
38
|
+
*/
|
|
39
|
+
export function trimSpan(text, span) {
|
|
40
|
+
let start = span.start;
|
|
41
|
+
let end = span.end;
|
|
42
|
+
while (start < end && /\s/.test(text[start] ?? ''))
|
|
43
|
+
start += 1;
|
|
44
|
+
while (end > start && /\s/.test(text[end - 1] ?? ''))
|
|
45
|
+
end -= 1;
|
|
46
|
+
if (start >= end)
|
|
47
|
+
return undefined;
|
|
48
|
+
return {
|
|
49
|
+
start,
|
|
50
|
+
end,
|
|
51
|
+
...(span.heading !== undefined && { heading: span.heading }),
|
|
52
|
+
...(span.contentStart !== undefined && { contentStart: span.contentStart }),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Pack consecutive units (paragraphs, lines) into spans of at most `maxChars`,
|
|
57
|
+
* then apply `overlapChars` of backward overlap.
|
|
58
|
+
*
|
|
59
|
+
* Units are never split by this function — a single unit longer than `maxChars`
|
|
60
|
+
* becomes its own oversized span, and the caller decides whether to hard-cut
|
|
61
|
+
* it. That separation matters: a 4,000-character paragraph is a real thing in
|
|
62
|
+
* real documents, and silently slicing it mid-word is a different decision from
|
|
63
|
+
* packing.
|
|
64
|
+
*/
|
|
65
|
+
export function packSpans(units, maxChars) {
|
|
66
|
+
const out = [];
|
|
67
|
+
let current;
|
|
68
|
+
for (const unit of units) {
|
|
69
|
+
if (current === undefined) {
|
|
70
|
+
current = unit;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// Same heading, and the merged span still fits.
|
|
74
|
+
const fits = unit.end - current.start <= maxChars;
|
|
75
|
+
const sameSection = current.heading === unit.heading;
|
|
76
|
+
if (fits && sameSection) {
|
|
77
|
+
current = {
|
|
78
|
+
start: current.start,
|
|
79
|
+
end: unit.end,
|
|
80
|
+
...(current.heading !== undefined && { heading: current.heading }),
|
|
81
|
+
};
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
out.push(current);
|
|
85
|
+
current = unit;
|
|
86
|
+
}
|
|
87
|
+
if (current !== undefined)
|
|
88
|
+
out.push(current);
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Extend each span backward by `overlapChars`, without crossing the previous
|
|
93
|
+
* span's start.
|
|
94
|
+
*
|
|
95
|
+
* Backward rather than forward so a chunk always ENDS on the boundary its
|
|
96
|
+
* strategy chose — a heading section that ends mid-sentence because of overlap
|
|
97
|
+
* would be a section that lies about where it ends.
|
|
98
|
+
*/
|
|
99
|
+
export function applyOverlap(spans, overlapChars) {
|
|
100
|
+
if (overlapChars <= 0)
|
|
101
|
+
return [...spans];
|
|
102
|
+
return spans.map((span, i) => {
|
|
103
|
+
if (i === 0)
|
|
104
|
+
return span;
|
|
105
|
+
const floor = spans[i - 1]?.start ?? 0;
|
|
106
|
+
const start = Math.max(floor, span.start - overlapChars);
|
|
107
|
+
// Remember where the chunk's own content starts, so the page it is
|
|
108
|
+
// attributed to is the page it is ABOUT, not the page its run-up borrowed
|
|
109
|
+
// from.
|
|
110
|
+
return start === span.start ? span : { ...span, start, contentStart: span.start };
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Fold a too-small span back into its predecessor.
|
|
115
|
+
*
|
|
116
|
+
* A fragment of a few characters — a stray heading, a signature line — embeds
|
|
117
|
+
* to noise and then competes for a top-K slot with real passages.
|
|
118
|
+
*
|
|
119
|
+
* **It never folds across a heading boundary.** A merged chunk carries the
|
|
120
|
+
* FIRST span's heading, so folding a short section into the one before it
|
|
121
|
+
* would produce a chunk labelled `heading="Alpha"` whose text is Beta's — a
|
|
122
|
+
* citation that names the wrong section, which is worse than a small chunk.
|
|
123
|
+
* Two spans merge only when they are already the same section.
|
|
124
|
+
*/
|
|
125
|
+
export function foldRunts(spans, minChars = MIN_CHUNK_CHARS) {
|
|
126
|
+
const out = [];
|
|
127
|
+
for (const span of spans) {
|
|
128
|
+
const previous = out[out.length - 1];
|
|
129
|
+
const sameSection = previous !== undefined && previous.heading === span.heading;
|
|
130
|
+
if (previous !== undefined && sameSection && span.end - span.start < minChars) {
|
|
131
|
+
out[out.length - 1] = {
|
|
132
|
+
start: previous.start,
|
|
133
|
+
end: span.end,
|
|
134
|
+
...(previous.heading !== undefined && { heading: previous.heading }),
|
|
135
|
+
};
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
out.push(span);
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
/** Turn spans into pieces, slicing the text so the invariant holds by construction. */
|
|
143
|
+
export function toPieces(doc, spans) {
|
|
144
|
+
const pageAt = pageLocator(doc);
|
|
145
|
+
const pieces = [];
|
|
146
|
+
for (const span of spans) {
|
|
147
|
+
const trimmed = trimSpan(doc.text, span);
|
|
148
|
+
if (trimmed === undefined)
|
|
149
|
+
continue;
|
|
150
|
+
// See `Span.contentStart`: the page is the one this chunk is about.
|
|
151
|
+
const page = pageAt(span.contentStart ?? trimmed.start);
|
|
152
|
+
pieces.push({
|
|
153
|
+
// Sliced, never concatenated. This is the invariant.
|
|
154
|
+
text: doc.text.slice(trimmed.start, trimmed.end),
|
|
155
|
+
charStart: trimmed.start,
|
|
156
|
+
charEnd: trimmed.end,
|
|
157
|
+
...(trimmed.heading !== undefined && { heading: trimmed.heading }),
|
|
158
|
+
...(page !== undefined && { page }),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return pieces;
|
|
162
|
+
}
|
|
163
|
+
/** Hard-cut a span that no packing could fit, at `maxChars` with overlap. */
|
|
164
|
+
export function hardCut(span, maxChars, overlapChars) {
|
|
165
|
+
const out = [];
|
|
166
|
+
const stride = Math.max(1, maxChars - overlapChars);
|
|
167
|
+
for (let start = span.start; start < span.end; start += stride) {
|
|
168
|
+
const end = Math.min(span.end, start + maxChars);
|
|
169
|
+
out.push({ start, end, ...(span.heading !== undefined && { heading: span.heading }) });
|
|
170
|
+
if (end >= span.end)
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
/** Split into paragraph spans on blank lines, keeping offsets. */
|
|
176
|
+
export function paragraphSpans(text) {
|
|
177
|
+
const spans = [];
|
|
178
|
+
const separator = /\n[ \t]*\n/g;
|
|
179
|
+
let cursor = 0;
|
|
180
|
+
let match;
|
|
181
|
+
while ((match = separator.exec(text)) !== null) {
|
|
182
|
+
spans.push({ start: cursor, end: match.index });
|
|
183
|
+
cursor = match.index + match[0].length;
|
|
184
|
+
}
|
|
185
|
+
spans.push({ start: cursor, end: text.length });
|
|
186
|
+
return spans.filter((s) => s.end > s.start);
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../src/rag/splitters/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wholeDocument — one chunk per document, no cutting at all.
|
|
3
|
+
*
|
|
4
|
+
* Pattern: Strategy (one of `Splitter`).
|
|
5
|
+
* Role: rag/ layer. For corpora whose documents are already one idea each —
|
|
6
|
+
* FAQ entries, product records, support macros, changelog entries.
|
|
7
|
+
* Emits: N/A.
|
|
8
|
+
*
|
|
9
|
+
* The honest caveat: an embedder truncates, so a document past the model's
|
|
10
|
+
* input ceiling is embedded from its opening only, and the rest is invisible
|
|
11
|
+
* to retrieval while still being injected if it is retrieved. `indexCorpus`
|
|
12
|
+
* records exactly that as `truncated[]` rather than letting it pass — but the
|
|
13
|
+
* fix is a real splitter, not a bigger number.
|
|
14
|
+
*/
|
|
15
|
+
import type { Splitter } from '../types.js';
|
|
16
|
+
export declare function wholeDocument(): Splitter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wholeDocument.js","sourceRoot":"","sources":["../../../../src/rag/splitters/wholeDocument.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,KAAK,CAAC,GAAmB;YACvB,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC"}
|