mirror of
https://github.com/SikongJueluo/pi-extensions.git
synced 2026-10-05 20:02:55 +08:00
- move evidence.ts and conversation.ts into evidence/ as bash.ts and conversation.ts - move prompt.ts and model.ts into judge/ - move highrisk.ts and judge.ts into authority/, renaming judge.ts to enforce.ts to avoid clashing with the judge/ directory - move review.ts and audit.ts into telemetry/ - move config.ts and catalog.ts into config/ as judge.ts and catalog.ts - rewrite static and dynamic imports across src, tools, and tests to the new paths - fix the models-catalog.json relative URL broken by the move (caught by fallow unresolved-import) - update the PIEXTENSIO-12 module map in the ADR to the new paths - add editorconfig for 4-space ts indentation
112 lines
4.0 KiB
TypeScript
112 lines
4.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
buildConversationEvidence,
|
|
type ConversationProbe,
|
|
} from "../src/evidence/conversation";
|
|
|
|
function entry(text: string): unknown {
|
|
return {
|
|
type: "message",
|
|
message: { role: "user", content: [{ type: "text", text }] },
|
|
};
|
|
}
|
|
function assistantEntry(text: string): unknown {
|
|
return {
|
|
type: "message",
|
|
message: { role: "assistant", content: [{ type: "text", text }] },
|
|
};
|
|
}
|
|
function compactionEntry(): unknown {
|
|
return { type: "compaction", summary: "derived" };
|
|
}
|
|
|
|
describe("buildConversationEvidence — whitelist", () => {
|
|
it("keeps only user text, excludes assistant and non-message entries", () => {
|
|
const probe: ConversationProbe = {
|
|
getActiveEntries: () => [
|
|
entry("first user"),
|
|
assistantEntry("assistant reasoning"),
|
|
{ type: "label", name: "x" },
|
|
entry("second user"),
|
|
],
|
|
};
|
|
const evidence = buildConversationEvidence(probe);
|
|
expect(evidence.items).toEqual([
|
|
{ position: 1, role: "user", text: "first user" },
|
|
{ position: 2, role: "user", text: "second user" },
|
|
]);
|
|
expect(evidence.hasCompaction).toBe(false);
|
|
expect(evidence.truncated).toBe(false);
|
|
expect(evidence.renderedChars).toBe("first user".length + "second user".length);
|
|
});
|
|
|
|
it("accepts string message content", () => {
|
|
const probe: ConversationProbe = {
|
|
getActiveEntries: () => [
|
|
{
|
|
type: "message",
|
|
message: { role: "user", content: "plain string" },
|
|
},
|
|
],
|
|
};
|
|
expect(buildConversationEvidence(probe).items[0]?.text).toBe("plain string");
|
|
});
|
|
|
|
it("flags compaction presence without leaking summary text", () => {
|
|
const probe: ConversationProbe = {
|
|
getActiveEntries: () => [compactionEntry(), entry("after")],
|
|
};
|
|
const evidence = buildConversationEvidence(probe);
|
|
expect(evidence.hasCompaction).toBe(true);
|
|
expect(evidence.items).toHaveLength(1);
|
|
});
|
|
});
|
|
|
|
describe("buildConversationEvidence — bounds", () => {
|
|
it("keeps at most 16 items, newest window, and marks truncation", () => {
|
|
const entries = Array.from({ length: 20 }, (_, i) => entry(`user-${i}`));
|
|
const evidence = buildConversationEvidence({ getActiveEntries: () => entries });
|
|
expect(evidence.items).toHaveLength(16);
|
|
expect(evidence.truncated).toBe(true);
|
|
expect(evidence.items[0]?.text).toBe("user-4");
|
|
expect(evidence.items[15]?.text).toBe("user-19");
|
|
expect(evidence.items[15]?.position).toBe(16);
|
|
});
|
|
|
|
it("preserves the latest user even when it alone exceeds the char budget", () => {
|
|
const huge = "x".repeat(15_000);
|
|
const evidence = buildConversationEvidence({
|
|
getActiveEntries: () => [entry("small"), entry(huge)],
|
|
});
|
|
expect(evidence.items).toHaveLength(1);
|
|
expect(evidence.items[0]?.text).toBe(huge);
|
|
expect(evidence.truncated).toBe(true);
|
|
});
|
|
|
|
it("drops the oldest head when the character budget is exceeded", () => {
|
|
const evidence = buildConversationEvidence({
|
|
getActiveEntries: () => [
|
|
entry("a".repeat(7_000)),
|
|
entry("b".repeat(7_000)), // both would exceed 12,000
|
|
entry("tail"),
|
|
],
|
|
});
|
|
expect(evidence.items.map((i) => i.text)).toEqual([
|
|
"b".repeat(7_000),
|
|
"tail",
|
|
]);
|
|
expect(evidence.truncated).toBe(true);
|
|
expect(evidence.renderedChars).toBeLessThanOrEqual(12_001);
|
|
});
|
|
|
|
it("returns empty evidence for an empty branch", () => {
|
|
const evidence = buildConversationEvidence({ getActiveEntries: () => [] });
|
|
expect(evidence).toEqual({
|
|
items: [],
|
|
hasCompaction: false,
|
|
truncated: false,
|
|
renderedChars: 0,
|
|
});
|
|
});
|
|
});
|