Files
diegosouzapw--omniroute/tests/unit/memory-embedding-static-potion.test.ts
2026-07-13 13:39:12 +08:00

171 lines
6.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, beforeEach } from "node:test";
import assert from "node:assert/strict";
import {
tokenizeWordPiece,
meanPool,
_injectModel,
type PotionModel,
} from "../../src/lib/memory/embedding/staticPotion";
import type { EmbeddingError } from "../../src/lib/memory/embedding/types";
import { invalidate as invalidateCache } from "../../src/lib/memory/embedding/cache";
// ---- Mock model setup ----
// Vocab: {"[UNK]":0, "hello":1, "world":2}
// Matrix: 3 rows × 4 dims
// Row 0 ([UNK]): [0.0, 0.0, 0.0, 0.0]
// Row 1 (hello): [1.0, 0.0, 0.0, 0.0]
// Row 2 (world): [0.0, 1.0, 0.0, 0.0]
function makeMockModel(): PotionModel {
const vocab: Record<string, number> = { "[UNK]": 0, "hello": 1, "world": 2 };
const matrix = new Float32Array([
0.0, 0.0, 0.0, 0.0, // row 0 = [UNK]
1.0, 0.0, 0.0, 0.0, // row 1 = hello
0.0, 1.0, 0.0, 0.0, // row 2 = world
]);
return { vocab, matrix, dim: 4, vocabSize: 3, unkIdx: 0 };
}
describe("memory-embedding-static-potion tokenizer", () => {
const mock = makeMockModel();
it("tokenizes known words to their vocab IDs", () => {
const ids = tokenizeWordPiece("hello world", mock.vocab);
assert.deepStrictEqual(ids, [1, 2]);
});
it("unknown words fall back to [UNK] (id=0)", () => {
const ids = tokenizeWordPiece("foo bar", mock.vocab);
assert.deepStrictEqual(ids, [0, 0]);
});
it("mixed known and unknown tokens", () => {
const ids = tokenizeWordPiece("hello foo world", mock.vocab);
assert.deepStrictEqual(ids, [1, 0, 2]);
});
it("empty string returns no tokens", () => {
const ids = tokenizeWordPiece("", mock.vocab);
assert.deepStrictEqual(ids, []);
});
it("case-insensitive tokenization", () => {
// tokenizeWordPiece lowercases input
const ids = tokenizeWordPiece("Hello World", mock.vocab);
assert.deepStrictEqual(ids, [1, 2]);
});
});
describe("memory-embedding-static-potion mean pooling", () => {
const mock = makeMockModel();
it("mean pools hello + world to [0.5, 0.5, 0, 0]", () => {
const ids = [1, 2]; // hello, world
const result = meanPool(ids, mock.matrix, mock.dim, mock.vocabSize, mock.unkIdx);
assert.ok(result instanceof Float32Array);
assert.strictEqual(result.length, 4);
assert.ok(Math.abs(result[0] - 0.5) < 0.001, `dim0 should be 0.5, got ${result[0]}`);
assert.ok(Math.abs(result[1] - 0.5) < 0.001, `dim1 should be 0.5, got ${result[1]}`);
assert.ok(Math.abs(result[2] - 0.0) < 0.001, `dim2 should be 0, got ${result[2]}`);
});
it("pooling [UNK] returns zero vector", () => {
const ids = [0]; // [UNK]
const result = meanPool(ids, mock.matrix, mock.dim, mock.vocabSize, mock.unkIdx);
for (const v of result) {
assert.ok(Math.abs(v) < 0.001, `All dims should be 0, got ${v}`);
}
});
it("empty token list returns zero vector", () => {
const result = meanPool([], mock.matrix, mock.dim, mock.vocabSize, mock.unkIdx);
for (const v of result) {
assert.ok(Math.abs(v) < 0.001, `All dims should be 0, got ${v}`);
}
});
it("out-of-range token ID falls back to unkIdx", () => {
const ids = [999]; // out of range
const result = meanPool(ids, mock.matrix, mock.dim, mock.vocabSize, mock.unkIdx);
// Should use row 0 ([UNK]) = all zeros
for (const v of result) {
assert.ok(Math.abs(v) < 0.001, `All dims should be 0 (unk), got ${v}`);
}
});
});
describe("memory-embedding-static-potion embedStatic with mock", () => {
beforeEach(() => {
invalidateCache();
_injectModel(makeMockModel());
});
it("embedStatic returns EmbeddingResult for 'hello world'", async () => {
const { embedStatic } = await import("../../src/lib/memory/embedding/staticPotion");
const result = await embedStatic("hello world");
assert.ok("vector" in result, "Should return EmbeddingResult");
assert.ok((result as { vector: Float32Array }).vector instanceof Float32Array);
assert.strictEqual((result as { dimensions: number }).dimensions, 4);
assert.strictEqual((result as { source: string }).source, "static");
});
it("embedStatic uses [UNK] for 'foo' (not in mock vocab)", async () => {
const { embedStatic } = await import("../../src/lib/memory/embedding/staticPotion");
const result = await embedStatic("foo");
assert.ok("vector" in result);
const vec = (result as { vector: Float32Array }).vector;
// foo -> [UNK] -> row 0 = [0, 0, 0, 0]
for (const v of vec) {
assert.ok(Math.abs(v) < 0.001, `Should be 0 for UNK, got ${v}`);
}
});
it("model load failure returns EmbeddingError with reason model_load_failed", async () => {
// Plan 21 fix: previously this test was tautological (`assert.ok(true)`).
// Force a real load-failure path: point the cache dir at /dev/null/<subdir>
// so fs.mkdir() fails with ENOTDIR (/dev/null is a file, not a dir).
// embedStatic catches the error and must return EmbeddingError with
// reason="model_load_failed" (staticPotion.ts:225-232).
_injectModel(null);
const prevCacheDir = process.env.MEMORY_STATIC_CACHE_DIR;
process.env.MEMORY_STATIC_CACHE_DIR = `/dev/null/potion-load-fail-${process.pid}-${Date.now()}`;
try {
const { embedStatic } = await import(
"../../src/lib/memory/embedding/staticPotion"
);
const result = await embedStatic("hello world");
assert.ok(
!("vector" in result),
`Expected EmbeddingError but got result with vector: ${JSON.stringify(result)}`
);
const err = result as EmbeddingError;
assert.strictEqual(err.source, "static");
assert.strictEqual(err.reason, "model_load_failed");
assert.ok(
typeof err.message === "string" && err.message.length > 0,
"EmbeddingError.message must be a non-empty sanitized string"
);
} finally {
if (prevCacheDir === undefined) {
delete process.env.MEMORY_STATIC_CACHE_DIR;
} else {
process.env.MEMORY_STATIC_CACHE_DIR = prevCacheDir;
}
_injectModel(makeMockModel()); // restore for other tests
}
});
it("second call reuses singleton model (no re-load)", async () => {
const { embedStatic } = await import("../../src/lib/memory/embedding/staticPotion");
// First call
const r1 = await embedStatic("hello");
// Second call — should reuse singleton
const r2 = await embedStatic("hello");
assert.ok("vector" in r1);
assert.ok("vector" in r2);
// Both succeed with same model
assert.strictEqual((r1 as { source: string }).source, "static");
assert.strictEqual((r2 as { source: string }).source, "static");
});
});