fix(rag): stop chunker extras from overwriting format and sourceType
PR Checklist
- The commit message follows our guidelines (conventional commits)
- Related issue(s) linked — none filed; found while reading
buildMetadata - Tests for the changes have been added
- Changesets have been added
What is the current behavior?
buildMetadata() sets format and sourceType from its own params (lines 20–23) and then does
Object.assign(meta, params.extra ?? {});
so anything in extra silently overwrites those two identifiers. That contradicts the contract stated a few lines above (base: ... core fields are not overridden by baseMetadata and the comment on baseMetadata).
It bites every chunker that delegates to an inner chunker and forwards the child chunk's metadata through extra, because the child metadata already carries its own format/sourceType:
html-chunker.ts:98(extra: chunk.metadatafromRecursiveChunker)neural-chunker.ts:71andneural-chunker.ts:96slumber-chunker.ts:75table-chunker.ts:66andtable-chunker.ts:109
Observed locally on main (72a46c76):
HTML: [{"id":"html-0","format":"text","sourceType":"sentence"},
{"id":"html-1","format":"text","sourceType":"sentence-token"},
{"id":"html-2","format":"text","sourceType":"sentence-token"}]
TABLE: 17 chunks, every one "format":"text" / "sourceType":"token"
So HtmlChunker — which declares format: "html", sourceType: "html" — reports "text" for all of its chunks, and TableChunker never reports "table" for prose it splits below the token limit. Consumers that filter or boost on metadata.format/metadata.sourceType get the delegate's answer, not the outer chunker's.
json-chunker.ts:89 already papers over this locally with const { sourceType: _ignored, ...chunkExtra } = ..., which is a good indication the precedence problem is real — it just gets fixed one chunker at a time instead of at the source.
What is the new behavior?
extra can still contribute any field it likes, but it can no longer overwrite the format / sourceType declared by the chunker that called buildMetadata:
Object.assign(meta, params.extra ?? {}, { format: params.format, sourceType: params.sourceType });
With this in place the per-chunker destructuring in json-chunker.ts becomes redundant (as would the proposed per-file fix in #1463). I deliberately left json-chunker.ts untouched so this PR stays scoped to the shared helper and does not overlap that PR's files.
Tests
Added packages/rag/src/__tests__/metadata.spec.ts covering the helper directly plus two delegating chunkers.
BEFORE (metadata.ts at main, new spec added)
× buildMetadata > keeps chunker-specific extras without overriding the core identifiers 14ms
× delegating chunkers > HtmlChunker reports html even though it delegates to the recursive chunker 14ms
× delegating chunkers > TableChunker reports table for prose split below the token limit 5ms
Test Files 1 failed | 18 passed (19)
Tests 3 failed | 44 passed (47)
AFTER (with this fix)
Test Files 19 passed (19)
Tests 47 passed (47)
Baseline before adding the new spec was Test Files 18 passed (18) / Tests 43 passed (43) — none of the existing specs asserted metadata.format, which is why this stayed unnoticed.
Notes for reviewers
packages/ragis not in thetest-packagesmatrix ofpull-request.yml, so the rag specs never execute in CI. Worth considering separately from this PR.- Repro/verification ran on Node v24.21.0 with
vitest 3.2.4+js-tiktoken 1.0.21(the only runtime dependency of@voltagent/rag), viavitest run src/__tests__insidepackages/rag. - AI assistance: this change was prepared with an AI coding assistant (Claude via Qoder). I reviewed every line of the diff and the test output above myself; the root cause and the call-site list were confirmed by reading the source, not generated.
fixes (issue): N/A — no issue filed for this yet.
Summary by cubic
Fixes buildMetadata so the caller-declared format and sourceType can no longer be overwritten by the extra metadata that delegating chunkers forward from their inner chunkers.
HtmlChunkerandTableChunkerwere reporting the inner chunker's identifiers (e.g."text"instead of"html"), breaking consumers that filter or boost on those fields.- Adds tests for
buildMetadataand the affected delegating chunkers, with the TableChunker spec now assertingsourceTypeper prose and table chunk group; the per-chunker workaround injson-chunker.tsis redundant but left untouched to avoid overlapping another PR.
Summary by CodeRabbit
- Bug Fixes
- Chunk metadata now consistently reports the format and source type of the chunker that produced it, even when additional metadata contains conflicting values.
- HTML and table chunking results preserve their own identifiers, while retaining other supplied metadata, including extra fields that do not conflict with those identifiers.