The embedding vector
# grade this stage (from your course directory)
npx theinference test --stage embed-vector --watchLet's pin down the embedder itself. This step grades the exact 256-dim vector your embedText produces for a fixed text — a numeric adapter, compared with allclose. Get this right and every retrieval downstream lines up.
export const DIM = 256;
// fnv1a(s) is provided. embedText:
// s = " " + text.toLowerCase().replace(/\s+/g," ").trim() + " "
// for each 3-char window gram of s:
// h = fnv1a(gram); bucket = h % DIM; sign = (h & 0x100) ? -1 : 1
// v[bucket] += sign
// L2-normalize v (divide by sqrt(sum of squares); return as-is if norm is 0)
What to build
Implement embedText (via runEmbed)
Implement embedText in src/embed.ts following the pinned algorithm, then wire it into the runEmbed adapter. The adapter receives a text and returns the 256-dim number[].
import { embedText } from "../src/embed.ts";
export function runEmbed(text: string): number[] {
return embedText(text);
}
adapter mode. The harness calls runEmbed on a fixed text and compares your number[] to the reference with allclose (atol 1e-5) and a shape check ([256]).
Two easy mistakes: forgetting to pad the text with a leading/trailing space (short texts then produce no 3-grams), and using the wrong sign bit (h & 0x100). Both shift the vector and fail the allclose. Match the pinned algorithm exactly.