reduce testing
CI / verify (pull_request) Successful in 8s

This commit is contained in:
2026-10-08 09:34:13 +02:00
parent 6f86d1af28
commit 59da616bc5
13 changed files with 299 additions and 2318 deletions
+77 -93
View File
@@ -91,7 +91,10 @@ async function host() {
callback: (editor: {
add: (definition: { execute: typeof command }) => void;
}) => void,
) => callback({ add: (definition) => (command = definition.execute) }),
) =>
callback({
add: (definition) => (command = definition.execute),
}),
},
session: {
hook: async (name: string, callback: (event: Event) => Promise<void> | void) => {
@@ -106,7 +109,11 @@ async function host() {
: { id: sessionID, agent: "build" },
create: async (input: { parentID: string; model: object }) => {
expect(input.parentID).toBe("ses_root");
expect(input.model).toEqual({ providerID: "acme", id: "cheap", variant: "xhigh" });
expect(input.model).toEqual({
providerID: "acme",
id: "cheap",
variant: "xhigh",
});
return { id: "ses_worker" };
},
generate: async ({ sessionID, prompt }: { sessionID: string; prompt: string }) => {
@@ -116,7 +123,10 @@ async function host() {
agent: "build",
system: [{ type: "text", text: "host system" }],
messages: [
new Entry({ role: "user", content: [{ type: "text", text: prompt }] }),
new Entry({
role: "user",
content: [{ type: "text", text: prompt }],
}),
],
tools: {},
};
@@ -137,7 +147,11 @@ async function host() {
sessionID,
agent: "build",
system: [
{ type: "text", text: "host one", cache: { type: "ephemeral" } },
{
type: "text",
text: "host one",
cache: { type: "ephemeral" },
},
{ type: "text", text: "host two" },
],
messages: messages.map((message) => new Entry(message)),
@@ -187,7 +201,10 @@ test("optchat is off by default, refuses child sessions, and hides its tools whe
test("turns see the view and the new message; compactions retry Too long and build the tree", async () => {
const h = await host();
await h.command()({ sessionID: "ses_root", prompt: { text: "/optchat on" } });
await h.command()({
sessionID: "ses_root",
prompt: { text: "/optchat on" },
});
expect(h.notices.at(-1)).toStartWith("[optchat] on. 0 messages");
const long = "please remember: " + "detail ".repeat(100);
h.replies.push("x".repeat(700), "y".repeat(600), "z".repeat(400));
@@ -204,7 +221,10 @@ test("turns see the view and the new message; compactions retry Too long and bui
expect(first.messages[1]!.content[0]!.text).toBe(long);
// System start and end, and the request's end; no whole view block yet.
expect(hints(first)).toBe(3);
expect(first.messages[1]!.content[0]!.cache).toEqual({ type: "ephemeral", ttlSeconds: 300 });
expect(first.messages[1]!.content[0]!.cache).toEqual({
type: "ephemeral",
ttlSeconds: 300,
});
await settle();
// The compaction ran in the worker with the same system prompt, retried twice, and kept the shortest line.
@@ -226,7 +246,12 @@ test("turns see the view and the new message; compactions retry Too long and bui
role: "assistant",
content: [
{ type: "reasoning", text: "never logged" },
{ type: "tool-call", id: "c1", name: "read", input: { path: "a" } },
{
type: "tool-call",
id: "c1",
name: "read",
input: { path: "a" },
},
],
},
{
@@ -241,8 +266,16 @@ test("turns see the view and the new message; compactions retry Too long and bui
},
],
},
{ id: "m4", role: "assistant", content: [{ type: "text", text: "Read a." }] },
{ id: "m5", role: "user", content: [{ type: "text", text: "and now?" }] },
{
id: "m4",
role: "assistant",
content: [{ type: "text", text: "Read a." }],
},
{
id: "m5",
role: "user",
content: [{ type: "text", text: "and now?" }],
},
]);
// Messages before the new one are summarized before the turn; short ones are their own lines.
expect(second.messages.map((message) => message.role)).toEqual(["user", "user"]);
@@ -330,7 +363,12 @@ test("dropped reasoning parts and tool messages without ids do not re-log or ski
role: "assistant",
content: [
{ type: "reasoning", text: "" },
{ type: "tool-call", id: "c1", name: "read", input: { path: "a" } },
{
type: "tool-call",
id: "c1",
name: "read",
input: { path: "a" },
},
],
},
{
@@ -360,9 +398,17 @@ test("dropped reasoning parts and tool messages without ids do not re-log or ski
content: message.content.filter((part) => part.type !== "reasoning"),
}));
await h.turn("ses_root", [
{ id: "m0", role: "system", content: [{ type: "text", text: "Instructions updated" }] },
{
id: "m0",
role: "system",
content: [{ type: "text", text: "Instructions updated" }],
},
...after,
{ id: "m5", role: "assistant", content: [{ type: "text", text: "ok" }] },
{
id: "m5",
role: "assistant",
content: [{ type: "text", text: "ok" }],
},
{ id: "m6", role: "user", content: [{ type: "text", text: "again" }] },
]);
await settle();
@@ -378,85 +424,23 @@ test("dropped reasoning parts and tool messages without ids do not re-log or ski
]);
});
test("instruction updates before the turn stay after the view", async () => {
// Regression: system-role messages before the turn start were dropped.
const h = await host();
await h.command()({ sessionID: "ses_root", prompt: { text: "on" } });
const event = await h.turn("ses_root", [
{ id: "m1", role: "user", content: [{ type: "text", text: "hi" }] },
{ id: "m2", role: "assistant", content: [{ type: "text", text: "hello" }] },
{ id: "m3", role: "system", content: [{ type: "text", text: "Instructions updated" }] },
{ id: "m4", role: "user", content: [{ type: "text", text: "next" }] },
]);
expect(event.messages.map((message) => message.role)).toEqual(["user", "system", "user"]);
expect(event.messages[1]!.content[0]!.text).toBe("Instructions updated");
if (h.cleanup) await h.cleanup();
test("without compactionModel, optchat registers nothing", async () => {
const options = { compactionModel: "", dataDir: "" };
const registered: string[] = [];
const record = (name: string) => async () => {
registered.push(name);
return { dispose: async () => {} };
};
const context = {
options,
tool: { transform: record("tool") },
command: { transform: record("command") },
session: { hook: record("hook") },
};
// SAFETY: setup must return before touching any host service; a call is recorded and fails the test.
const setup = optchat.setup as (
context: Pick<Plugin.Context, "options">,
) => ReturnType<typeof optchat.setup>;
expect(await setup(context)).toBeUndefined();
expect(registered).toEqual([]);
});
test("checkpoints are not logged, provider-executed calls end a turn, and empty replies stop retries", async () => {
const h = await host();
await h.command()({ sessionID: "ses_root", prompt: { text: "on" } });
h.replies.push("");
const event = await h.turn("ses_root", [
{
id: "m1",
role: "user",
content: [
{ type: "text", text: "<conversation-checkpoint>old</conversation-checkpoint>" },
],
},
{
id: "m2",
role: "assistant",
content: [
{
type: "tool-call",
id: "w1",
name: "web_search",
input: {},
providerExecuted: true,
},
{ type: "text", text: "x".repeat(600) },
],
},
{ id: "m3", role: "user", content: [{ type: "text", text: "next" }] },
]);
// The turn is the new message; the provider-executed call did not keep the old turn open.
expect(event.messages.map((message) => message.content[0]!.text)).toEqual([
"<chat>\n0+1|tool: web_search {}\n1+1|(not summarized yet: zoom it)\n</chat>",
"next",
]);
await settle();
// The empty reply ended its compaction without a "Too long" retry; the failure is retried at
// the next message, as a fresh task.
expect(h.generated.map((request) => request.messages.length)).toEqual([2, 2]);
if (h.cleanup) await h.cleanup();
expect(await logged(h.directory)).toEqual([
"tool: web_search {}",
`agent: ${"x".repeat(600)}`,
"user: next",
]);
});
test.each([{}, { compactionModel: "", dataDir: "" }])(
"without compactionModel (%j), optchat registers nothing",
async (options) => {
const registered: string[] = [];
const record = (name: string) => async () => {
registered.push(name);
return { dispose: async () => {} };
};
const context = {
options,
tool: { transform: record("tool") },
command: { transform: record("command") },
session: { hook: record("hook") },
};
// SAFETY: setup must return before touching any host service; a call is recorded and fails the test.
const setup = optchat.setup as (
context: Pick<Plugin.Context, "options">,
) => ReturnType<typeof optchat.setup>;
expect(await setup(context)).toBeUndefined();
expect(registered).toEqual([]);
},
);