131 lines
3.9 KiB
TypeScript
131 lines
3.9 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { resolvePolicy } from "./config.ts";
|
|
import { buildContextPacket } from "./packet.ts";
|
|
import { createEmptyLedger, mergeCandidates, type MemoryCandidate } from "./ledger.ts";
|
|
|
|
const baseCandidate: Omit<MemoryCandidate, "kind" | "subject" | "text"> = {
|
|
scope: "session",
|
|
sourceEntryId: "seed",
|
|
sourceType: "user",
|
|
timestamp: 1,
|
|
confidence: 1,
|
|
};
|
|
|
|
function estimateTokens(text: string) {
|
|
return Math.ceil(text.length / 4);
|
|
}
|
|
|
|
function memory(candidate: Pick<MemoryCandidate, "kind" | "subject" | "text"> & Partial<Omit<MemoryCandidate, "kind" | "subject" | "text">>): MemoryCandidate {
|
|
return {
|
|
...baseCandidate,
|
|
...candidate,
|
|
sourceEntryId: candidate.sourceEntryId ?? candidate.subject,
|
|
};
|
|
}
|
|
|
|
function buildPolicy(packetTokenCap: number) {
|
|
return {
|
|
...resolvePolicy({ mode: "balanced", contextWindow: 200_000 }),
|
|
packetTokenCap,
|
|
};
|
|
}
|
|
|
|
test("buildContextPacket keeps top-ranked facts from a section when the cap is tight", () => {
|
|
const expected = [
|
|
"## Active goal",
|
|
"- Keep packets compact.",
|
|
"",
|
|
"## Constraints",
|
|
"- Preserve the highest-priority constraint.",
|
|
"",
|
|
"## Key decisions",
|
|
"- Render selected sections in stable order.",
|
|
].join("\n");
|
|
const policy = buildPolicy(estimateTokens(expected));
|
|
const ledger = mergeCandidates(createEmptyLedger(), [
|
|
memory({ kind: "goal", subject: "goal", text: "Keep packets compact." }),
|
|
memory({ kind: "constraint", subject: "constraint-a", text: "Preserve the highest-priority constraint.", confidence: 1, timestamp: 3 }),
|
|
memory({
|
|
kind: "constraint",
|
|
subject: "constraint-b",
|
|
text: "Avoid dropping every constraint just because one extra bullet is too large for a tight packet cap.",
|
|
confidence: 0.6,
|
|
timestamp: 2,
|
|
}),
|
|
memory({
|
|
kind: "decision",
|
|
subject: "decision-a",
|
|
text: "Render selected sections in stable order.",
|
|
confidence: 0.9,
|
|
timestamp: 4,
|
|
sourceType: "assistant",
|
|
}),
|
|
]);
|
|
|
|
const packet = buildContextPacket(ledger, policy);
|
|
|
|
assert.equal(packet.text, expected);
|
|
assert.equal(packet.estimatedTokens, policy.packetTokenCap);
|
|
});
|
|
|
|
test("buildContextPacket uses cross-kind weights when only one lower-priority section can fit", () => {
|
|
const expected = [
|
|
"## Active goal",
|
|
"- Keep the agent moving.",
|
|
"",
|
|
"## Current task",
|
|
"- Fix packet trimming.",
|
|
].join("\n");
|
|
const policy = buildPolicy(estimateTokens(expected));
|
|
const ledger = mergeCandidates(createEmptyLedger(), [
|
|
memory({ kind: "goal", subject: "goal", text: "Keep the agent moving." }),
|
|
memory({
|
|
kind: "decision",
|
|
subject: "decision-a",
|
|
text: "Keep logs concise.",
|
|
confidence: 1,
|
|
timestamp: 2,
|
|
sourceType: "assistant",
|
|
}),
|
|
memory({
|
|
kind: "activeTask",
|
|
subject: "task-a",
|
|
text: "Fix packet trimming.",
|
|
confidence: 1,
|
|
timestamp: 2,
|
|
sourceType: "assistant",
|
|
}),
|
|
]);
|
|
|
|
const packet = buildContextPacket(ledger, policy);
|
|
|
|
assert.equal(packet.text, expected);
|
|
assert.equal(packet.estimatedTokens, policy.packetTokenCap);
|
|
});
|
|
|
|
test("buildContextPacket keeps a goal ahead of newer low-priority facts at realistic timestamp scales", () => {
|
|
const expected = [
|
|
"## Active goal",
|
|
"- Keep the agent on track.",
|
|
].join("\n");
|
|
const policy = buildPolicy(estimateTokens(expected));
|
|
const ledger = mergeCandidates(createEmptyLedger(), [
|
|
memory({ kind: "goal", subject: "goal", text: "Keep the agent on track.", timestamp: 1_000_000 }),
|
|
memory({
|
|
kind: "relevantFile",
|
|
subject: "runtime-file",
|
|
text: "src/runtime.ts",
|
|
timestamp: 10_000_000,
|
|
confidence: 1,
|
|
sourceType: "assistant",
|
|
scope: "branch",
|
|
}),
|
|
]);
|
|
|
|
const packet = buildContextPacket(ledger, policy);
|
|
|
|
assert.equal(packet.text, expected);
|
|
assert.equal(packet.estimatedTokens, policy.packetTokenCap);
|
|
});
|