
























@@ -8,11 +8,13 @@
88 * - Auto-capture filtering
99 */
101011+import { Buffer } from "node:buffer";
1112import { describe, test, expect, vi } from "vitest";
1213import memoryPlugin, {
1314detectCategory,
1415formatRelevantMemoriesContext,
1516looksLikePromptInjection,
17+normalizeEmbeddingVector,
1618normalizeRecallQuery,
1719shouldCapture,
1820} from "./index.js";
@@ -57,6 +59,10 @@ function createMockModule(): LanceDbModule {
5759} as unknown as LanceDbModule;
5860}
596162+function invokeEmbeddingCreate(mock: ReturnType<typeof vi.fn>, body: unknown) {
63+return (mock as unknown as (body: unknown) => unknown)(body);
64+}
65+6066function createRuntimeLoader(
6167overrides: {
6268env?: NodeJS.ProcessEnv;
@@ -351,7 +357,9 @@ describe("memory plugin e2e", () => {
351357}));
352358vi.doMock("openai", () => ({
353359default: class MockOpenAI {
354-embeddings = { create: embeddingsCreate };
360+post = vi.fn((_path: string, opts: { body?: unknown }) =>
361+invokeEmbeddingCreate(embeddingsCreate, opts.body),
362+);
355363},
356364}));
357365vi.doMock("./lancedb-runtime.js", () => ({
@@ -417,7 +425,6 @@ describe("memory plugin e2e", () => {
417425expect(embeddingsCreate).toHaveBeenCalledWith({
418426model: "text-embedding-3-small",
419427input: expectedRecallQuery,
420-encoding_format: "float",
421428});
422429expect(expectedRecallQuery).toHaveLength(120);
423430expect(vectorSearch).toHaveBeenCalledWith([0.1, 0.2, 0.3]);
@@ -491,7 +498,9 @@ describe("memory plugin e2e", () => {
491498}));
492499vi.doMock("openai", () => ({
493500default: class MockOpenAI {
494-embeddings = { create: embeddingsCreate };
501+post = vi.fn((_path: string, opts: { body?: unknown }) =>
502+invokeEmbeddingCreate(embeddingsCreate, opts.body),
503+);
495504},
496505}));
497506vi.doMock("./lancedb-runtime.js", () => ({
@@ -568,7 +577,6 @@ describe("memory plugin e2e", () => {
568577expect(embeddingsCreate).toHaveBeenCalledWith({
569578model: "text-embedding-3-small",
570579input: "what editor should i use?",
571-encoding_format: "float",
572580});
573581expect(result).toMatchObject({
574582prependContext: expect.stringContaining("I prefer Helix for editing code."),
@@ -622,7 +630,9 @@ describe("memory plugin e2e", () => {
622630}));
623631vi.doMock("openai", () => ({
624632default: class MockOpenAI {
625-embeddings = { create: embeddingsCreate };
633+post = vi.fn((_path: string, opts: { body?: unknown }) =>
634+invokeEmbeddingCreate(embeddingsCreate, opts.body),
635+);
626636},
627637}));
628638vi.doMock("./lancedb-runtime.js", () => ({
@@ -745,7 +755,9 @@ describe("memory plugin e2e", () => {
745755}));
746756vi.doMock("openai", () => ({
747757default: class MockOpenAI {
748-embeddings = { create: embeddingsCreate };
758+post = vi.fn((_path: string, opts: { body?: unknown }) =>
759+invokeEmbeddingCreate(embeddingsCreate, opts.body),
760+);
749761},
750762}));
751763vi.doMock("./lancedb-runtime.js", () => ({
@@ -844,7 +856,9 @@ describe("memory plugin e2e", () => {
844856}));
845857vi.doMock("openai", () => ({
846858default: class MockOpenAI {
847-embeddings = { create: embeddingsCreate };
859+post = vi.fn((_path: string, opts: { body?: unknown }) =>
860+invokeEmbeddingCreate(embeddingsCreate, opts.body),
861+);
848862},
849863}));
850864vi.doMock("./lancedb-runtime.js", () => ({
@@ -905,7 +919,6 @@ describe("memory plugin e2e", () => {
905919expect(embeddingsCreate).toHaveBeenCalledWith({
906920model: "text-embedding-3-small",
907921input: "I prefer Helix for editing code every day.",
908-encoding_format: "float",
909922});
910923expect(vectorSearch).toHaveBeenCalledTimes(1);
911924expect(add).toHaveBeenCalledTimes(1);
@@ -970,7 +983,9 @@ describe("memory plugin e2e", () => {
970983}));
971984vi.doMock("openai", () => ({
972985default: class MockOpenAI {
973-embeddings = { create: embeddingsCreate };
986+post = vi.fn((_path: string, opts: { body?: unknown }) =>
987+invokeEmbeddingCreate(embeddingsCreate, opts.body),
988+);
974989},
975990}));
976991vi.doMock("./lancedb-runtime.js", () => ({
@@ -1047,7 +1062,6 @@ describe("memory plugin e2e", () => {
10471062expect(embeddingsCreate).toHaveBeenCalledWith({
10481063model: "text-embedding-3-small",
10491064input: "I prefer Helix for editing code every day.",
1050-encoding_format: "float",
10511065});
10521066expect(add).toHaveBeenCalledWith([
10531067expect.objectContaining({
@@ -1106,7 +1120,9 @@ describe("memory plugin e2e", () => {
11061120}));
11071121vi.doMock("openai", () => ({
11081122default: class MockOpenAI {
1109-embeddings = { create: embeddingsCreate };
1123+post = vi.fn((_path: string, opts: { body?: unknown }) =>
1124+invokeEmbeddingCreate(embeddingsCreate, opts.body),
1125+);
11101126},
11111127}));
11121128vi.doMock("./lancedb-runtime.js", () => ({
@@ -1231,7 +1247,9 @@ describe("memory plugin e2e", () => {
12311247}));
12321248vi.doMock("openai", () => ({
12331249default: class MockOpenAI {
1234-embeddings = { create: embeddingsCreate };
1250+post = vi.fn((_path: string, opts: { body?: unknown }) =>
1251+invokeEmbeddingCreate(embeddingsCreate, opts.body),
1252+);
12351253},
12361254}));
12371255vi.doMock("./lancedb-runtime.js", () => ({
@@ -1336,7 +1354,9 @@ describe("memory plugin e2e", () => {
13361354}));
13371355vi.doMock("openai", () => ({
13381356default: class MockOpenAI {
1339-embeddings = { create: embeddingsCreate };
1357+post = vi.fn((_path: string, opts: { body?: unknown }) =>
1358+invokeEmbeddingCreate(embeddingsCreate, opts.body),
1359+);
13401360},
13411361}));
13421362vi.doMock("./lancedb-runtime.js", () => ({
@@ -1425,12 +1445,10 @@ describe("memory plugin e2e", () => {
14251445expect(harness.embeddingsCreate).toHaveBeenNthCalledWith(1, {
14261446model: "text-embedding-3-small",
14271447input: "I prefer Helix for editing code every day.",
1428-encoding_format: "float",
14291448});
14301449expect(harness.embeddingsCreate).toHaveBeenNthCalledWith(2, {
14311450model: "text-embedding-3-small",
14321451input: "I prefer Fish for shell commands every day.",
1433-encoding_format: "float",
14341452});
14351453expect(harness.add).toHaveBeenCalledTimes(2);
14361454} finally {
@@ -1493,7 +1511,6 @@ describe("memory plugin e2e", () => {
14931511expect(harness.embeddingsCreate).toHaveBeenNthCalledWith(3, {
14941512model: "text-embedding-3-small",
14951513input: "I prefer Deno for small scripts every day.",
1496-encoding_format: "float",
14971514});
14981515expect(harness.add).toHaveBeenCalledTimes(3);
14991516} finally {
@@ -1555,7 +1572,9 @@ describe("memory plugin e2e", () => {
15551572}));
15561573vi.doMock("openai", () => ({
15571574default: class MockOpenAI {
1558-embeddings = { create: embeddingsCreate };
1575+post = vi.fn((_path: string, opts: { body?: unknown }) =>
1576+invokeEmbeddingCreate(embeddingsCreate, opts.body),
1577+);
15591578},
15601579}));
15611580vi.doMock("./lancedb-runtime.js", () => ({
@@ -1611,7 +1630,6 @@ describe("memory plugin e2e", () => {
16111630expect(embeddingsCreate).toHaveBeenCalledWith({
16121631model: "text-embedding-3-small",
16131632input: "hello dimensions",
1614-encoding_format: "float",
16151633dimensions: 1024,
16161634});
16171635} finally {
@@ -1651,7 +1669,9 @@ describe("memory plugin e2e", () => {
16511669}));
16521670vi.doMock("openai", () => ({
16531671default: class MockOpenAI {
1654-embeddings = { create: embeddingsCreate };
1672+post = vi.fn((_path: string, opts: { body?: unknown }) =>
1673+invokeEmbeddingCreate(embeddingsCreate, opts.body),
1674+);
16551675},
16561676}));
16571677vi.doMock("./lancedb-runtime.js", () => ({
@@ -1833,6 +1853,31 @@ describe("memory plugin e2e", () => {
18331853expect(normalizeRecallQuery(`look up ${"x".repeat(200)}`, 120)).toHaveLength(120);
18341854});
183518551856+test("normalizeEmbeddingVector accepts float arrays and base64 float32 responses", async () => {
1857+expect(normalizeEmbeddingVector([0.1, 0.2, 0.3])).toEqual([0.1, 0.2, 0.3]);
1858+1859+const bytes = Buffer.alloc(2 * Float32Array.BYTES_PER_ELEMENT);
1860+const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
1861+view.setFloat32(0, 1.25, true);
1862+view.setFloat32(Float32Array.BYTES_PER_ELEMENT, -2.5, true);
1863+1864+const decoded = normalizeEmbeddingVector(bytes.toString("base64"));
1865+expect(decoded[0]).toBeCloseTo(1.25);
1866+expect(decoded[1]).toBeCloseTo(-2.5);
1867+});
1868+1869+test("normalizeEmbeddingVector rejects malformed embedding payloads", async () => {
1870+expect(() => normalizeEmbeddingVector([0.1, Number.NaN])).toThrow(
1871+"Embedding response contains non-numeric values",
1872+);
1873+expect(() => normalizeEmbeddingVector("abc")).toThrow(
1874+"Base64 embedding response has invalid byte length",
1875+);
1876+expect(() => normalizeEmbeddingVector(undefined)).toThrow(
1877+"Embedding response is missing a vector",
1878+);
1879+});
1880+18361881test("formatRelevantMemoriesContext escapes memory text and marks entries as untrusted", async () => {
18371882const context = formatRelevantMemoriesContext([
18381883{
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。