Files
wehub-resource-sync 979fb22d7c
CI / test (20, macos-latest) (push) Waiting to run
CI / test (20, ubuntu-latest) (push) Waiting to run
CI / test (22, macos-latest) (push) Waiting to run
CI / test (22, ubuntu-latest) (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:01:18 +08:00

208 lines
6.0 KiB
TypeScript

import { describe, it, expect, beforeEach, vi } from "vitest";
vi.mock("../src/logger.js", () => ({
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
}));
import { registerVerifyFunction } from "../src/functions/verify.js";
import type { Memory, CompressedObservation, Session } from "../src/types.js";
import { mockKV, mockSdk } from "./helpers/mocks.js";
describe("Verify Function", () => {
let sdk: ReturnType<typeof mockSdk>;
let kv: ReturnType<typeof mockKV>;
beforeEach(() => {
sdk = mockSdk();
kv = mockKV();
vi.clearAllMocks();
registerVerifyFunction(sdk as never, kv as never);
});
it("returns error when id is missing", async () => {
const result = (await sdk.trigger("mem::verify", {})) as {
success: boolean;
error: string;
};
expect(result.success).toBe(false);
expect(result.error).toBe("id is required");
});
it("returns not found for unknown id", async () => {
const result = (await sdk.trigger("mem::verify", {
id: "unknown_123",
})) as { success: boolean; error: string };
expect(result.success).toBe(false);
expect(result.error).toBe("not found");
});
it("verifies a memory with citation chain", async () => {
const session: Session = {
id: "ses_1",
project: "/test/project",
cwd: "/test",
startedAt: "2026-03-01T00:00:00Z",
status: "completed",
observationCount: 2,
};
await kv.set("mem:sessions", "ses_1", session);
const obs: CompressedObservation = {
id: "obs_1",
sessionId: "ses_1",
timestamp: "2026-03-01T00:01:00Z",
type: "decision",
title: "Chose React over Vue",
facts: ["React chosen for ecosystem"],
narrative: "Team decided on React",
concepts: ["react", "frontend"],
files: ["src/App.tsx"],
importance: 8,
confidence: 0.85,
};
await kv.set("mem:obs:ses_1", "obs_1", obs);
const memory: Memory = {
id: "mem_1",
createdAt: "2026-03-01T00:02:00Z",
updatedAt: "2026-03-01T00:02:00Z",
type: "architecture",
title: "Using React for frontend",
content: "The team uses React for the frontend framework",
concepts: ["react", "frontend"],
files: ["src/App.tsx"],
sessionIds: ["ses_1"],
strength: 8,
version: 1,
isLatest: true,
sourceObservationIds: ["obs_1"],
};
await kv.set("mem:memories", "mem_1", memory);
const result = (await sdk.trigger("mem::verify", { id: "mem_1" })) as {
success: boolean;
type: string;
citations: Array<{
observationId: string;
confidence: number;
sessionProject: string;
}>;
citationCount: number;
};
expect(result.success).toBe(true);
expect(result.type).toBe("memory");
expect(result.citationCount).toBe(1);
expect(result.citations[0].observationId).toBe("obs_1");
expect(result.citations[0].confidence).toBe(0.85);
expect(result.citations[0].sessionProject).toBe("/test/project");
});
it("verifies a memory with no source observations", async () => {
const memory: Memory = {
id: "mem_2",
createdAt: "2026-03-01T00:00:00Z",
updatedAt: "2026-03-01T00:00:00Z",
type: "fact",
title: "API uses REST",
content: "The API follows REST conventions",
concepts: ["api", "rest"],
files: [],
sessionIds: [],
strength: 5,
version: 1,
isLatest: true,
};
await kv.set("mem:memories", "mem_2", memory);
const result = (await sdk.trigger("mem::verify", { id: "mem_2" })) as {
success: boolean;
type: string;
citationCount: number;
citations: unknown[];
};
expect(result.success).toBe(true);
expect(result.type).toBe("memory");
expect(result.citationCount).toBe(0);
expect(result.citations).toEqual([]);
});
it("verifies an observation directly", async () => {
const session: Session = {
id: "ses_2",
project: "/my/project",
cwd: "/my",
startedAt: "2026-03-01T00:00:00Z",
status: "active",
observationCount: 1,
};
await kv.set("mem:sessions", "ses_2", session);
const obs: CompressedObservation = {
id: "obs_direct",
sessionId: "ses_2",
timestamp: "2026-03-01T00:01:00Z",
type: "file_write",
title: "Created index.ts",
facts: ["Created file"],
narrative: "Agent created the index file",
concepts: ["typescript"],
files: ["index.ts"],
importance: 6,
confidence: 0.72,
};
await kv.set("mem:obs:ses_2", "obs_direct", obs);
const result = (await sdk.trigger("mem::verify", {
id: "obs_direct",
})) as {
success: boolean;
type: string;
observation: { id: string; confidence: number };
session: { project: string };
};
expect(result.success).toBe(true);
expect(result.type).toBe("observation");
expect(result.observation.id).toBe("obs_direct");
expect(result.observation.confidence).toBe(0.72);
expect(result.session.project).toBe("/my/project");
});
it("returns memory info with supersede chain", async () => {
const memory: Memory = {
id: "mem_v2",
createdAt: "2026-03-02T00:00:00Z",
updatedAt: "2026-03-02T00:00:00Z",
type: "pattern",
title: "Updated pattern",
content: "Updated pattern content",
concepts: ["testing"],
files: [],
sessionIds: [],
strength: 9,
version: 2,
parentId: "mem_v1",
supersedes: ["mem_v1"],
isLatest: true,
};
await kv.set("mem:memories", "mem_v2", memory);
const result = (await sdk.trigger("mem::verify", { id: "mem_v2" })) as {
success: boolean;
memory: {
id: string;
version: number;
parentId: string;
supersedes: string[];
};
};
expect(result.success).toBe(true);
expect(result.memory.version).toBe(2);
expect(result.memory.parentId).toBe("mem_v1");
expect(result.memory.supersedes).toEqual(["mem_v1"]);
});
});