Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 72 additions & 16 deletions apps/web/e2e/agents-lifecycle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ test("creates, previews, edits, and removes bounded Function and anonymous HTTP
await page.getByRole("button", { name: /^Create agent/ }).click();
await page.getByLabel("Name").fill("Tool Agent");
await page.getByLabel("Instructions").fill("Use only the configured tools.");
await page.getByLabel("Harness").selectOption("claude_sdk");
await page.getByLabel("Model").selectOption({ label: "Custom model ID…" });
await page.getByLabel("Custom model ID").fill("fixture/tool-model");

Expand All @@ -366,13 +367,15 @@ test("creates, previews, edits, and removes bounded Function and anonymous HTTP
await expect(previewBody).toContainText('"name": "lookup_customer"');
await expect(previewBody).toContainText('"type": "mcp"');
await expect(previewBody).toContainText('"required": true');
await expect(previewBody).toContainText('"harness": "claude_sdk"');

await page.getByRole("button", { name: "Save Agent definition" }).click();
await expect(page.getByRole("status")).toContainText("Agent definition saved as");
let requests = await fixtureRequests(request);
const creates = requests.filter((entry) => entry.method === "POST" && entry.path === "/v1/agents");
expect(creates).toHaveLength(1);
expect(creates[0]?.body).toEqual({
x_agents_core: { harness: "claude_sdk" },
model: "fixture/tool-model",
name: "Tool Agent",
instructions: "Use only the configured tools.",
Expand Down Expand Up @@ -403,6 +406,7 @@ test("creates, previews, edits, and removes bounded Function and anonymous HTTP
const setup = page.locator(".agent-setup-page");
await expect(setup.getByRole("heading", { name: "Saved definition" })).toBeVisible();
await expect(page.getByRole("dialog")).toHaveCount(0);
await expect(setup.getByLabel("Harness")).toHaveValue("claude_sdk");
const editFunction = setup.locator(".agent-tool-card").filter({ hasText: "Function" }).first();
await editFunction.getByLabel("Name", { exact: true }).fill("lookup_customer_v2");
const editMcp = setup.locator(".agent-tool-card").filter({ hasText: "Anonymous HTTP MCP" }).first();
Expand All @@ -422,7 +426,9 @@ test("creates, previews, edits, and removes bounded Function and anonymous HTTP
defer_loading: false,
},
]);
expect(updates[0]?.body).not.toHaveProperty("x_agents_core");

await setup.getByLabel("Harness").selectOption("codex");
await setup.locator(".agent-tool-card").filter({ hasText: "Function" }).first().getByRole("button", { name: "Remove" }).click();
await setup.getByRole("button", { name: "Save changes" }).click();
await expect(setup.getByRole("status")).toContainText("Agent definition updated");
Expand All @@ -431,6 +437,7 @@ test("creates, previews, edits, and removes bounded Function and anonymous HTTP
updates = requests.filter((entry) => entry.method === "POST" && entry.path.startsWith("/v1/agents/agent_created_"));
expect(updates).toHaveLength(2);
expect(updates[1]?.body?.tools).toEqual([]);
expect(updates[1]?.body?.x_agents_core).toEqual({ harness: "codex" });
});

test("keeps Source Files controls out of the System status page", async ({ page, request }) => {
Expand Down Expand Up @@ -2439,44 +2446,93 @@ test("presents Dashboard page-chain results and System boundaries without extra

await page.getByRole("button", { name: "System", exact: true }).click();
const system = page.locator(".system-page");
await expect(system.getByRole("listitem").filter({ hasText: "Core API" })).toContainText("Available");
await expect(system.getByRole("listitem").filter({ hasText: "Vaults" })).toContainText("Available");
await expect(system.getByRole("listitem").filter({ hasText: "Self-hosted" })).toContainText("Enabled");
await expect(system.getByRole("listitem").filter({ hasText: "Runtime status" })).toContainText("Cannot be pre-checked");
await expect(system.getByRole("listitem")).toHaveCount(4);
await expect(system.getByRole("listitem").filter({ hasText: "Daemon gateway" })).toContainText("Enabled");
await expect(system.getByRole("listitem").filter({ hasText: "Managed sandbox" })).toContainText("Docker");
await expect(system.getByRole("listitem").filter({ hasText: "Endpoint overrides" })).toContainText("Configured");
await expect(system.getByRole("listitem")).toHaveCount(3);
await expect(system).not.toContainText("Configured for this process");
await expect(system).not.toContainText("Managed execution");
await expect(system).not.toContainText("Self-hosted execution");
await expect(system).not.toContainText("Default harness");
await expect(system).toContainText("Agent create and edit forms can select any adapter enabled for this Core process");
await expect(system).not.toContainText("Enabled · default");
await expect(system).toContainText("Operator endpoint override: configured");
await expect(system).toContainText("Compiled into this build, but not enabled when this Core process started");
await expect(system).toContainText("Runtime connection, native binary availability, sandbox health, and model execution belong to the relevant Session or Environment");
await expect(system).not.toContainText("Source Files");
await expect(system).not.toContainText("Public capability surface");
await expect(system).not.toContainText("Cannot be pre-checked");

const beforeSystemRefresh = await fixtureRequests(request);
const systemRefresh = system.getByRole("button", { name: "Refresh System status" });
await systemRefresh.click();
await expect.poll(async () => {
const entries = await fixtureRequests(request);
return [count(entries, "/v1/agents"), count(entries, "/v1/agents/sessions")];
}).toEqual([
count(beforeSystemRefresh, "/v1/agents") + 1,
count(beforeSystemRefresh, "/v1/agents/sessions") + 1,
]);
await expect.poll(async () => count(await fixtureRequests(request), "/v1/agents/core/startup-configuration")).toBe(
count(beforeSystemRefresh, "/v1/agents/core/startup-configuration") + 1,
);
const afterSystemRefresh = await fixtureRequests(request);
expect(count(afterSystemRefresh, "/v1/agents")).toBe(count(beforeSystemRefresh, "/v1/agents") + 1);
expect(count(afterSystemRefresh, "/v1/agents/sessions")).toBe(count(beforeSystemRefresh, "/v1/agents/sessions") + 1);
expect(count(afterSystemRefresh, "/v1/agents")).toBe(count(beforeSystemRefresh, "/v1/agents"));
expect(count(afterSystemRefresh, "/v1/agents/sessions")).toBe(count(beforeSystemRefresh, "/v1/agents/sessions"));
expect(count(afterSystemRefresh, "/v1/vaults")).toBe(count(beforeSystemRefresh, "/v1/vaults"));
expect(count(afterSystemRefresh, "/v1/agents/core/startup-configuration")).toBe(
count(beforeSystemRefresh, "/v1/agents/core/startup-configuration") + 1,
);
for (const path of detailPaths) expect(count(afterSystemRefresh, path)).toBe(count(beforeSystemRefresh, path));
await attachScreenshot(page, testInfo, "desktop-system-contract-boundary");

await page.setViewportSize({ width: 778, height: 844 });
const compactSystemBounds = await system.evaluate((element) => ({
viewportWidth: innerWidth,
documentWidth: document.documentElement.scrollWidth,
bodyWidth: document.body.scrollWidth,
right: element.getBoundingClientRect().right,
sectionInset: element.querySelector(".system-config-section")!.getBoundingClientRect().left - element.getBoundingClientRect().left,
sectionEdges: [...element.querySelectorAll(".system-config-section")].map((section) => ({
left: section.getBoundingClientRect().left - element.getBoundingClientRect().left,
right: element.getBoundingClientRect().right - section.getBoundingClientRect().right,
header: section.querySelector("header")!.getBoundingClientRect().left,
content: section.querySelector(".system-harness-grid")!.getBoundingClientRect().left,
explanation: section.querySelector(".system-config-explanation")?.getBoundingClientRect().left ?? null,
})),
boundaryInset: element.querySelector(".system-boundary-note")!.getBoundingClientRect().left - element.getBoundingClientRect().left,
}));
expect(compactSystemBounds.documentWidth).toBeLessThanOrEqual(compactSystemBounds.viewportWidth);
expect(compactSystemBounds.bodyWidth).toBeLessThanOrEqual(compactSystemBounds.viewportWidth);
expect(compactSystemBounds.right).toBeLessThanOrEqual(compactSystemBounds.viewportWidth);
expect(compactSystemBounds.sectionInset).toBe(24);
expect(compactSystemBounds.boundaryInset).toBe(24);
for (const edge of compactSystemBounds.sectionEdges) {
expect({ left: edge.left, right: edge.right }).toEqual({ left: 24, right: 24 });
expect(edge.header).toBe(edge.content);
if (edge.explanation !== null) expect(edge.explanation).toBe(edge.header);
}

await page.setViewportSize({ width: 390, height: 844 });
const systemBounds = await system.evaluate((element) => {
const rows = [...element.querySelectorAll(".system-summary-cell")].map((row) => row.getBoundingClientRect());
const rows = [...element.querySelectorAll(".system-summary-cell")];
return {
viewportWidth: innerWidth,
documentWidth: document.documentElement.scrollWidth,
rowBounds: rows.map((row) => ({ top: row.top, bottom: row.bottom, height: row.height })),
sectionInset: element.querySelector(".system-config-section")!.getBoundingClientRect().left - element.getBoundingClientRect().left,
sectionRightInset: element.getBoundingClientRect().right - element.querySelector(".system-config-section")!.getBoundingClientRect().right,
boundaryInset: element.querySelector(".system-boundary-note")!.getBoundingClientRect().left - element.getBoundingClientRect().left,
rowBounds: rows.map((row) => ({
top: row.getBoundingClientRect().top,
bottom: row.getBoundingClientRect().bottom,
height: row.getBoundingClientRect().height,
borderBottomWidth: getComputedStyle(row).borderBottomWidth,
})),
};
});
expect(systemBounds.documentWidth).toBeLessThanOrEqual(systemBounds.viewportWidth);
expect(systemBounds.sectionInset).toBe(12);
expect(systemBounds.sectionRightInset).toBe(12);
expect(systemBounds.boundaryInset).toBe(12);
for (let index = 1; index < systemBounds.rowBounds.length; index += 1) {
expect(systemBounds.rowBounds[index]!.top).toBeGreaterThanOrEqual(systemBounds.rowBounds[index - 1]!.bottom);
}
expect(systemBounds.rowBounds.every((row) => row.height >= 36)).toBe(true);
expect(systemBounds.rowBounds.slice(0, -1).every((row) => row.borderBottomWidth !== "0px")).toBe(true);
expect(systemBounds.rowBounds.at(-1)?.borderBottomWidth).toBe("0px");
await attachScreenshot(page, testInfo, "narrow-system-contract-boundary");
});

Expand Down
103 changes: 103 additions & 0 deletions apps/web/e2e/core-connection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ interface ProbeInstrumentationWindow extends Window {
__probeCallCount?: number;
__resolveFirstProbe?: (() => void) | null;
__stalledProbeCallCount?: number;
__holdNextLocalStartup?: boolean;
__oldStartupAbortCount?: number;
__resolveOldStartup?: (() => void) | null;
__resolveNewStartup?: (() => void) | null;
}

async function resetFixture(request: APIRequestContext) {
Expand Down Expand Up @@ -260,6 +264,105 @@ test("switches real connection modes and fences stale probes when the draft chan
await expect(reopened.getByRole("alert")).toHaveCount(0);
});

test("clears startup configuration synchronously and fences a stale read when the Core changes", async ({
page,
request,
}) => {
await page.addInitScript(() => {
const target = window as ProbeInstrumentationWindow;
const originalFetch = window.fetch.bind(window);
const startupResponse = (defaultHarness: "codex" | "claude_sdk", provider: "docker" | "microsandbox") => new Response(JSON.stringify({
object: "agents.core.startup_configuration",
schema_version: 1,
supported: {
harnesses: ["claude_sdk", "codex", "mcode"],
managed_sandbox_providers: ["docker", "microsandbox"],
},
configured: {
default_harness: defaultHarness,
enabled_harnesses: [defaultHarness],
daemon_gateway: true,
self_hosted: true,
managed_sandbox: { enabled: true, provider, maintenance: false },
model_providers: [{ harness: defaultHarness, endpoint_configured: true }],
},
}), { status: 200, headers: { "Content-Type": "application/json" } });

target.__holdNextLocalStartup = false;
target.__oldStartupAbortCount = 0;
target.__resolveOldStartup = null;
target.__resolveNewStartup = null;
window.fetch = (input, init) => {
const value = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
const candidate = new URL(value, window.location.href);
if (!candidate.pathname.endsWith("/v1/agents/core/startup-configuration")) return originalFetch(input, init);
const authorization = new Headers(init?.headers).get("Authorization");
if (target.__holdNextLocalStartup && authorization == null) {
target.__holdNextLocalStartup = false;
init?.signal?.addEventListener("abort", () => {
target.__oldStartupAbortCount = (target.__oldStartupAbortCount ?? 0) + 1;
}, { once: true });
return new Promise<Response>((resolve) => {
target.__resolveOldStartup = () => resolve(startupResponse("codex", "docker"));
});
}
if (authorization === "Bearer replacement-token") {
return new Promise<Response>((resolve) => {
target.__resolveNewStartup = () => resolve(startupResponse("claude_sdk", "microsandbox"));
});
}
return originalFetch(input, init);
};
});

await boot(page, request);
await page.getByRole("button", { name: "System", exact: true }).click();
const system = page.locator(".system-page");
await expect(system.locator(".system-harness-card").filter({ hasText: "Codex" })).toContainText("Enabled");
await page.evaluate(() => {
(window as ProbeInstrumentationWindow).__holdNextLocalStartup = true;
});
await system.getByRole("button", { name: "Refresh System status" }).click();
await expect.poll(() => page.evaluate(() => typeof (window as ProbeInstrumentationWindow).__resolveOldStartup)).toBe("function");

const { dialog } = await openConnection(page);
await dialog.getByRole("radio", { name: /Other compatible Core/ }).click();
await dialog.getByLabel("Compatible Core base URL").fill(`${new URL(page.url()).origin}/v1`);
await dialog.getByLabel("Bearer token").fill("replacement-token");
await dialog.getByRole("button", { name: "Apply connection" }).click();

const daemonGateway = system.getByRole("listitem").filter({ hasText: "Daemon gateway" });
await expect(daemonGateway).toContainText("Checking…");
await expect(system).not.toContainText("Configured for this process");
await expect.poll(() => page.evaluate(() => (window as ProbeInstrumentationWindow).__oldStartupAbortCount ?? 0)).toBe(1);
await expect.poll(() => page.evaluate(() => typeof (window as ProbeInstrumentationWindow).__resolveNewStartup)).toBe("function");
await page.evaluate(() => (window as ProbeInstrumentationWindow).__resolveNewStartup?.());
await expect(system.locator(".system-harness-card").filter({ hasText: "Claude SDK" })).toContainText("Enabled");
await expect(system.getByRole("listitem").filter({ hasText: "Managed sandbox" })).toContainText("Microsandbox");

await page.evaluate(() => (window as ProbeInstrumentationWindow).__resolveOldStartup?.());
await expect(system.locator(".system-harness-card").filter({ hasText: "Claude SDK" })).toContainText("Enabled");
await expect(system).not.toContainText("Docker · Maintenance");
});

for (const status of [404, 405]) {
test(`shows startup configuration as unsupported when an older Core returns ${status}`, async ({ page, request }) => {
await page.route("**/v1/agents/core/startup-configuration", (route) => route.fulfill({
status,
contentType: "application/json",
body: JSON.stringify({ error: { code: "unsupported", message: "Unavailable." } }),
}));
await boot(page, request);
await page.getByRole("button", { name: "System", exact: true }).click();

const system = page.locator(".system-page");
await expect(system.getByRole("listitem").filter({ hasText: "Daemon gateway" })).toContainText("Not exposed");
await expect(system).toContainText("This Core version does not expose the startup configuration extension");
await expect(system).not.toContainText("Configured for this process");
await expect(system).not.toContainText("Checking…");
});
}

test("announces loading, authenticated access, and each safe failure state from one GET", async ({
page,
request,
Expand Down
25 changes: 25 additions & 0 deletions apps/web/e2e/fixture-core.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,30 @@ const server = http.createServer(async (request, response) => {
const body = request.method === "GET" || request.method === "DELETE" ? undefined : await readJson(request);
recordRequest(request, url, body);

if (request.method === "GET" && url.pathname === "/v1/agents/core/startup-configuration") {
if (url.search) return sendError(response, 400, "Fixture startup configuration does not accept query parameters.");
response.setHeader("cache-control", "no-store");
return sendJson(response, {
object: "agents.core.startup_configuration",
schema_version: 1,
supported: {
harnesses: ["claude_sdk", "codex", "mcode"],
managed_sandbox_providers: ["docker", "microsandbox"],
},
configured: {
default_harness: "codex",
enabled_harnesses: ["claude_sdk", "codex"],
daemon_gateway: true,
self_hosted: true,
managed_sandbox: { enabled: true, provider: "docker", maintenance: false },
model_providers: [
{ harness: "claude_sdk", endpoint_configured: false },
{ harness: "codex", endpoint_configured: true },
],
},
});
}

if (url.pathname === "/v1/vaults") {
if (request.method === "GET") return sendJson(response, page(state.vaults));
if (request.method === "POST") {
Expand Down Expand Up @@ -973,6 +997,7 @@ const server = http.createServer(async (request, response) => {
const defaults = savedAgent(`agent_created_${state.sequence}`, body.name ?? null, body.model, baseline + state.sequence);
const created = {
...defaults,
...(body.x_agents_core === undefined ? {} : { x_agents_core: body.x_agents_core }),
instructions: body.instructions ?? null,
metadata: body.metadata ?? {},
multi_agent: body.multi_agent ?? { enabled: false, max_concurrent_subagents: null },
Expand Down
Loading
Loading