memos/apps/memos-local-plugin/tests/unit/skill/packager.test.ts

132 lines
3.5 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { buildSkillRow } from "../../../core/skill/packager.js";
import { rootLogger } from "../../../core/logger/index.js";
import type { Embedder } from "../../../core/embedding/types.js";
import type { PolicyRow, SkillRow } from "../../../core/types.js";
import { makeDraft, makeSkillConfig, NOW, vec } from "./_helpers.js";
function mkPolicy(): PolicyRow {
return {
id: "po_pkg" as PolicyRow["id"],
title: "install",
trigger: "pip install errors on alpine",
procedure: "apk add, retry",
verification: "pip install succeeds",
boundary: "alpine",
support: 4,
gain: 0.4,
status: "active",
sourceEpisodeIds: ["ep_1" as PolicyRow["sourceEpisodeIds"][number]],
inducedBy: "l2.l2.induction.v1",
decisionGuidance: { preference: [], antiPattern: [] },
vec: vec([1, 0, 0]),
createdAt: NOW,
updatedAt: NOW,
};
}
function fakeEmbedder(): Embedder {
return {
dimensions: 3,
provider: "openai_compatible",
model: "fake",
async embedOne() {
return vec([0.1, 0.2, 0.3]);
},
async embedMany(inputs) {
return inputs.map(() => vec([0.1, 0.2, 0.3]));
},
stats() {
return {
hits: 0,
misses: 0,
requests: 0,
roundTrips: 0,
failures: 0,
lastOkAt: null,
lastError: null,
};
},
resetCache() {
/* noop */
},
async close() {
/* noop */
},
};
}
const log = rootLogger.child({ channel: "core.skill.packager" });
describe("skill/packager", () => {
it("builds a candidate skill row with embedding + invocation guide", async () => {
const r = await buildSkillRow(
{
draft: makeDraft(),
policy: mkPolicy(),
evidenceEpisodeIds: ["ep_1" as PolicyRow["sourceEpisodeIds"][number]],
},
{ embedder: fakeEmbedder(), log, config: makeSkillConfig({ minSupport: 3 }) },
);
expect(r.freshMint).toBe(true);
expect(r.row.status).toBe("candidate");
expect(r.row.invocationGuide).toContain("Alpine");
expect(r.row.vec).not.toBeNull();
expect(r.row.sourcePolicyIds).toContain("po_pkg");
expect(r.row.eta).toBeGreaterThanOrEqual(makeSkillConfig().minEtaForRetrieval);
});
it("preserves the existing skill id when rebuilding", async () => {
const existing = {
id: "sk_old" as SkillRow["id"],
name: "old",
status: "active",
invocationGuide: "",
procedureJson: null,
eta: 0.8,
support: 3,
gain: 0.3,
trialsAttempted: 5,
trialsPassed: 5,
sourcePolicyIds: ["po_pkg" as PolicyRow["id"]],
sourceWorldModelIds: [],
evidenceAnchors: [],
vec: null,
createdAt: NOW,
updatedAt: NOW,
version: 1,
} as SkillRow;
const r = await buildSkillRow(
{
draft: makeDraft(),
policy: mkPolicy(),
evidenceEpisodeIds: [],
existing,
},
{ embedder: null, log, config: makeSkillConfig() },
);
expect(r.row.id).toBe("sk_old");
expect(r.row.trialsAttempted).toBe(5);
expect(r.freshMint).toBe(false);
});
it("survives embedder failure", async () => {
const bad: Embedder = {
...fakeEmbedder(),
async embedOne() {
throw new Error("embed boom");
},
};
const r = await buildSkillRow(
{
draft: makeDraft(),
policy: mkPolicy(),
evidenceEpisodeIds: [],
},
{ embedder: bad, log, config: makeSkillConfig() },
);
expect(r.row.vec).toBeNull();
});
});