Skip to content

Commit b2c869b

Browse files
authored
Merge 4682290 into d4a01e4
2 parents d4a01e4 + 4682290 commit b2c869b

2 files changed

Lines changed: 33 additions & 4 deletions

File tree

packages/memory-host-sdk/src/host/embeddings.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ function createDeferred<T>() {
3636
return { promise, resolve, reject };
3737
}
3838

39-
function mockLocalEmbeddingRuntime(vector = new Float32Array([2.35, 3.45, 0.63, 4.3])) {
39+
function mockLocalEmbeddingRuntime(
40+
vector: ArrayLike<number> = new Float32Array([2.35, 3.45, 0.63, 4.3]),
41+
) {
4042
const disposeContext = vi.fn();
4143
const disposeModel = vi.fn();
4244
const disposeLlama = vi.fn();
@@ -111,6 +113,26 @@ describe("local embedding provider", () => {
111113
await expect(provider.embedBatch(["test document"])).resolves.toEqual([[0.6, 0.8]]);
112114
});
113115

116+
it("does not read local embedding coordinates past outputDimensionality", async () => {
117+
mockLocalEmbeddingRuntime({
118+
length: 3,
119+
0: 3,
120+
1: 4,
121+
get 2(): number {
122+
throw new Error("tail coordinate should not be read");
123+
},
124+
});
125+
const provider = await createLocalEmbeddingProviderInProcess({
126+
config: {} as never,
127+
provider: "local",
128+
model: "",
129+
fallback: "none",
130+
outputDimensionality: 2,
131+
});
132+
133+
await expect(provider.embedQuery("test query")).resolves.toEqual([0.6, 0.8]);
134+
});
135+
114136
it("passes default contextSize (4096) to createEmbeddingContext when not configured", async () => {
115137
const runtime = mockLocalEmbeddingRuntime();
116138

packages/memory-host-sdk/src/host/embeddings.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ export type LocalEmbeddingProviderRuntimeOptions = {
3131
nodeLlamaCppImportUrl?: string;
3232
};
3333

34+
function copyEmbeddingVector(vector: ArrayLike<number>, maxLength?: number): number[] {
35+
const length = Math.min(maxLength ?? vector.length, vector.length);
36+
const values: number[] = [];
37+
for (let index = 0; index < length; index += 1) {
38+
values.push(vector[index]);
39+
}
40+
return values;
41+
}
42+
3443
async function disposeResources(
3544
resources: Array<DisposableResource | null | undefined>,
3645
): Promise<void> {
@@ -144,9 +153,7 @@ export async function createLocalEmbeddingProviderInProcess(
144153
const outputDimensionality =
145154
typeof options.outputDimensionality === "number" ? options.outputDimensionality : undefined;
146155
const normalize = (vector: ArrayLike<number>): number[] =>
147-
sanitizeAndNormalizeEmbedding(
148-
outputDimensionality ? Array.from(vector).slice(0, outputDimensionality) : Array.from(vector),
149-
);
156+
sanitizeAndNormalizeEmbedding(copyEmbeddingVector(vector, outputDimensionality));
150157

151158
return {
152159
id: "local",

0 commit comments

Comments
 (0)