Files
openworker/surfaces/gui/e2e/compaction.spec.ts
T
Devika Verma 4fa8acffed compaction: Settings overrides + GUI divider (OPE-27 3/4)
Settings -> Models grows a Context compaction card next to Token savings:
the trigger % of the context window (10-95), the absolute token cap
(clamped 10k-2M), and the summarizer-model pin (default: the session's
own model). POST /v1/settings/compaction persists them; engines read the
knobs live per check, so changes apply to running sessions immediately.

The "context compacted" divider rides the existing notice machinery: the
persisted `compacted` notice replays on reload (itemsFromMessages) and
the live COMPACTED event appends the same info notice mid-turn. The
transcript itself stays intact - outbound-only by construction.

Covered by vitest (marker replay), a settings-card e2e (defaults +
clamped POSTs + model pin), and a mid-session divider e2e driven by the
fixtures' scripted `compacted` event.
2026-07-29 16:20:24 +05:30

76 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// OPE-27 — auto-compaction GUI: the Settings card's two overrides + summarizer-model
// pin POST through, and the "context compacted" divider renders inline mid-session
// (driven by the fixtures' scripted `compacted` event) without touching the transcript.
import { expect } from "@playwright/test";
import { test } from "./fixtures";
test("Settings: Context compaction card edits threshold, cap, and summarizer model", async ({
page,
}) => {
await page.goto("/");
await page.getByTestId("account-row").click();
await page.getByRole("button", { name: "Settings", exact: true }).click();
await page.getByRole("button", { name: "Models", exact: true }).click();
const card = page.getByTestId("compaction-card");
await expect(card).toBeVisible();
await expect(card.getByText("Context compaction")).toBeVisible();
// Defaults render when the backend doesn't send the fields (older-backend robustness).
await expect(card.getByTestId("compaction-threshold")).toHaveValue("80");
await expect(card.getByTestId("compaction-cap")).toHaveValue("250000");
await expect(card.getByTestId("compaction-model")).toHaveValue("");
// Threshold edits POST as a fraction, clamped to 1095%.
const [req] = await Promise.all([
page.waitForRequest(
(r) => r.url().endsWith("/v1/settings/compaction") && r.method() === "POST",
),
card.getByTestId("compaction-threshold").fill("70"),
]);
expect(req.postDataJSON()).toEqual({ compaction_threshold_pct: 0.7 });
const [req2] = await Promise.all([
page.waitForRequest(
(r) => r.url().endsWith("/v1/settings/compaction") && r.method() === "POST",
),
card.getByTestId("compaction-cap").fill("100000"),
]);
expect(req2.postDataJSON()).toEqual({ compaction_cap_tokens: 100000 });
// Summarizer pin: the picker offers the session-default plus the configured models.
const [req3] = await Promise.all([
page.waitForRequest(
(r) => r.url().endsWith("/v1/settings/compaction") && r.method() === "POST",
),
card.getByTestId("compaction-model").selectOption("gpt-4o-mini"),
]);
expect(req3.postDataJSON()).toEqual({ compaction_model: "gpt-4o-mini" });
});
test("the compacted divider renders mid-session and the transcript stays intact", async ({
page,
}) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
const box = page.getByPlaceholder(/Ask the coworker/);
// An earlier exchange that must survive the compaction marker (transcript intact).
await box.fill("remember the launch date");
await box.press("Enter");
await expect(page.getByText("Echo: remember the launch date").first()).toBeVisible({
timeout: 10_000,
});
await box.fill("compact the context");
await box.press("Enter");
await expect(
page.getByText("Context compacted — earlier turns were summarized").first(),
).toBeVisible({ timeout: 10_000 });
await expect(
page.getByText("Still on it — continuing where I left off.").first(),
).toBeVisible();
// Outbound-only: everything before the divider is still on screen.
await expect(page.getByText("Echo: remember the launch date").first()).toBeVisible();
});