fix: trim custom message exclusion tests

This commit is contained in:
Armin Ronacher
2026-06-14 23:44:15 +02:00
Unverified
parent 290af80186
commit 8c545d2ea1
5 changed files with 31 additions and 321 deletions
@@ -4,7 +4,6 @@ import { getModel } from "@earendil-works/pi-ai";
import { readFileSync } from "fs";
import { join } from "path";
import { beforeEach, describe, expect, it } from "vitest";
import { prepareBranchEntries } from "../src/core/compaction/branch-summarization.ts";
import {
type CompactionSettings,
calculateContextTokens,
@@ -19,7 +18,6 @@ import {
import {
buildSessionContext,
type CompactionEntry,
type CustomMessageEntry,
type ModelChangeEntry,
migrateSessionEntries,
parseSessionEntries,
@@ -94,22 +92,6 @@ function createMessageEntry(message: AgentMessage): SessionMessageEntry {
return entry;
}
function createCustomMessageEntry(content: string, excludeFromContext?: boolean): CustomMessageEntry {
const id = `test-id-${entryCounter++}`;
const entry: CustomMessageEntry = {
type: "custom_message",
id,
parentId: lastId,
timestamp: new Date().toISOString(),
customType: "status",
content,
display: true,
excludeFromContext,
};
lastId = id;
return entry;
}
function createCompactionEntry(summary: string, firstKeptEntryId: string): CompactionEntry {
const id = `test-id-${entryCounter++}`;
const entry: CompactionEntry = {
@@ -413,59 +395,6 @@ describe("buildSessionContext", () => {
});
});
describe("prepareCompaction with custom messages", () => {
it("should ignore excluded custom messages in compaction and branch-summary preparation", () => {
const excludedCustom = createCustomMessageEntry("x".repeat(1000), true);
const user = createMessageEntry(createUserMessage("keep"));
const simplePreparation = prepareCompaction([excludedCustom, user], {
enabled: true,
reserveTokens: 0,
keepRecentTokens: 1,
});
const branchPreparation = prepareBranchEntries([excludedCustom, user], 10);
expect(simplePreparation).toBeDefined();
expect(simplePreparation!.tokensBefore).toBe(1);
expect(simplePreparation!.messagesToSummarize).toEqual([]);
expect(branchPreparation.messages.map((message) => message.role)).toEqual(["user"]);
expect(branchPreparation.totalTokens).toBe(1);
resetEntryCounter();
const splitUser = createMessageEntry(createUserMessage("inspect file"));
const assistantWithToolCall = createMessageEntry({
...createAssistantMessage("calling tool"),
content: [{ type: "toolCall", id: "call-1", name: "read", arguments: { path: "file.ts" } }],
});
const splitExcludedCustom = createCustomMessageEntry("tool is running", true);
const toolResult = createMessageEntry({
role: "toolResult",
toolCallId: "call-1",
toolName: "read",
content: [{ type: "text", text: "x".repeat(1000) }],
isError: false,
timestamp: Date.now(),
});
const assistantFinal = createMessageEntry(createAssistantMessage("done"));
const splitPreparation = prepareCompaction(
[splitUser, assistantWithToolCall, splitExcludedCustom, toolResult, assistantFinal],
{
enabled: true,
reserveTokens: 0,
keepRecentTokens: 1,
},
);
expect(splitPreparation).toBeDefined();
expect(splitPreparation!.isSplitTurn).toBe(true);
expect(splitPreparation!.firstKeptEntryId).toBe(assistantFinal.id);
expect(splitPreparation!.turnPrefixMessages.map((message) => message.role)).toEqual([
"user",
"assistant",
"toolResult",
]);
});
});
describe("prepareCompaction with previous compaction", () => {
it("should preserve kept messages across repeated compactions when they still fit", () => {
const u1 = createMessageEntry(createUserMessage("user msg 1 (summarized by compaction1)"));
@@ -258,108 +258,6 @@ describe("AgentSession queue characterization", () => {
expect(getAssistantTexts(harness)).toEqual(["", "original turn complete", "batched follow-up response"]);
});
it("records excluded custom messages immediately without starting provider turns", async () => {
const idleHarness = await createHarness();
harnesses.push(idleHarness);
let providerCalled = false;
idleHarness.setResponses([
() => {
providerCalled = true;
return fauxAssistantMessage("unexpected");
},
]);
await idleHarness.session.sendCustomMessage(
{ customType: "status", content: "display only", display: true, details: {}, excludeFromContext: true },
{ triggerTurn: true },
);
expect(providerCalled).toBe(false);
expect(idleHarness.session.messages[0]).toMatchObject({
role: "custom",
customType: "status",
excludeFromContext: true,
});
expect(idleHarness.getPendingResponseCount()).toBe(1);
for (const deliverAs of ["steer", "followUp"] as const) {
const waiting = await createWaitingHarness();
const { harness, waitForToolStart, promptPromise, releaseToolExecution } = waiting;
harnesses.push(harness);
let providerCalledForQueuedMessage = false;
harness.setResponses([
fauxAssistantMessage(fauxToolCall("wait", {}), { stopReason: "toolUse" }),
fauxAssistantMessage("done"),
() => {
providerCalledForQueuedMessage = true;
return fauxAssistantMessage("unexpected queued turn");
},
]);
await waitForToolStart;
await harness.session.sendCustomMessage(
{
customType: "status",
content: `${deliverAs} display only`,
display: true,
details: {},
excludeFromContext: true,
},
{ deliverAs },
);
const recordedBeforeRelease = harness.session.messages.some(
(message) => message.role === "custom" && message.customType === "status",
);
releaseToolExecution();
await promptPromise;
expect(recordedBeforeRelease).toBe(true);
expect(
harness.session.messages.filter((message) => message.role === "custom" && message.customType === "status"),
).toHaveLength(1);
expect(providerCalledForQueuedMessage).toBe(false);
expect(harness.getPendingResponseCount()).toBe(1);
}
});
it("persists excluded custom messages from message_end hooks after the triggering message", async () => {
const harness = await createHarness({
extensionFactories: [
(pi) => {
pi.on("message_end", (event) => {
if (event.message.role !== "assistant") return;
pi.sendMessage({
customType: "status",
content: "display only",
display: true,
details: {},
excludeFromContext: true,
});
});
},
],
});
harnesses.push(harness);
harness.setResponses([fauxAssistantMessage("reply")]);
await harness.session.prompt("hello");
const stateOrder = harness.session.messages.map((message) =>
message.role === "custom" ? `custom:${message.customType}` : message.role,
);
const branchOrder = harness.sessionManager.getBranch().map((entry) => {
if (entry.type === "message") {
return entry.message.role;
}
if (entry.type === "custom_message") {
return `custom:${entry.customType}`;
}
return entry.type;
});
expect(stateOrder).toEqual(["user", "assistant", "custom:status"]);
expect(branchOrder).toEqual(["user", "assistant", "custom:status"]);
});
it("queues custom messages with deliverAs steer while streaming", async () => {
const waiting = await createWaitingHarness();
const { harness, waitForToolStart, promptPromise, releaseToolExecution } = waiting;
@@ -72,6 +72,13 @@ describe("AgentSession retry and event characterization", () => {
harness.session.messages.some((message) => message.role === "custom" && message.customType === "status"),
).toBe(true);
expect(harness.session.messages[harness.session.messages.length - 1]?.role).toBe("assistant");
expect(
harness.sessionManager.getBranch().map((entry) => {
if (entry.type === "message") return entry.message.role;
if (entry.type === "custom_message") return `custom:${entry.customType}`;
return entry.type;
}),
).toEqual(["user", "assistant", "custom:status", "assistant"]);
});
it("retries multiple transient failures and succeeds on the final attempt", async () => {