Hold the late tool settlement search open until the test releases it

This commit is contained in:
Pranit committed 2026-10-22 08:40:45 -04:00
1 parent c21b0e46dd
commit 006164593b
2 files changed
+27 -10

No files matched your search

+17 -1
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const build_options = @import("build_options");
const glob_pattern = @import("../../core/workspace/glob_pattern.zig");
const grep_search = @import("../../core/workspace/grep_search.zig");
const tool_files = @import("../../core/workspace/tool_files.zig");
@@ -165,7 +166,22 @@ pub fn validate(_: tool_dispatch.DispatchContext, _: tool_dispatch.ToolInput) to
/// Searches the resolved root and returns an owned tool result body.
pub fn call(ctx: tool_dispatch.DispatchContext, erased: tool_dispatch.ToolInput) tool_dispatch.DispatchError!tool_dispatch.ToolResult {
return callWithOps(ctx, erased, .{});
const result = try callWithOps(ctx, erased, .{});
holdForTest();
return result;
}
// Only `tests/e2e/tui-interrupt-recovery.test.ts` sets
// `FX_E2E_GREP_RELEASE`: a finished search then waits until the file it
// names exists, so the test can cancel the turn while the tool is still
// running. The libfx artifacts leave it out.
fn holdForTest() void {
if (comptime build_options.libfx) return;
const release_path = io_mod.getenv("FX_E2E_GREP_RELEASE") orelse return;
while (true) : (io_mod.sleep(std.time.ns_per_ms)) {
std.Io.Dir.accessAbsolute(io_mod.getIo(), release_path, .{}) catch continue;
return;
}
}
const StatRootFn = *const fn ([]const u8) anyerror!std.Io.File.Stat;
+10 -9
View File
@@ -853,20 +853,14 @@ while :; do sleep 1; done
const corpus = join(workspace, "corpus");
const stderrPath = join(root, "stderr.log");
const tracePath = join(root, "trace.log");
const releasePath = join(root, "grep-release");
const pattern = "LATE_SUCCESS_NEEDLE";
const callId = "late_success_grep";
mkdirSync(join(home, ".fx"), { recursive: true });
mkdirSync(corpus, { recursive: true });
writeFileSync(join(home, ".fx", "settings.json"), "{}");
// The search must still be running when the second Escape lands, about
// half a second after it starts. Linux searches 30,000 files in about a
// third of a second, so it needs a larger corpus than macOS.
const corpusFiles = process.platform === "darwin" ? 30_000 : 120_000;
for (let index = 0; index < corpusFiles; index += 1) {
writeFileSync(
join(corpus, `candidate-${String(index).padStart(6, "0")}.txt`),
"ordinary corpus text\n",
);
for (let index = 0; index < 3; index += 1) {
writeFileSync(join(corpus, `candidate-${index}.txt`), "ordinary corpus text\n");
}
gateway = startFakeGateway([
@@ -892,6 +886,9 @@ while :; do sleep 1; done
FX_MODEL: FAKE_GATEWAY_MODEL,
FX_TRACE_SCOPES: `${TRACE_SCOPES},tool,ui_activity`,
FX_TRACE_LOG: tracePath,
// The search holds its result until this file exists, so it is
// still running when the turn is cancelled.
FX_E2E_GREP_RELEASE: releasePath,
},
});
await session.waitForComposer(TIMEOUT);
@@ -909,6 +906,10 @@ while :; do sleep 1; done
await session.sendKeys("Escape");
await session.waitForText("What can fx do differently?", TIMEOUT);
expect(Date.now() - cancelStartedAt).toBeLessThan(500);
expect(readTrace(tracePath)).not.toContain(
`event=after_tool_execution call_id=${callId}`,
);
writeFileSync(releasePath, "");
await waitForTrace(tracePath, `event=after_tool_execution`, TIMEOUT);
await waitForTrace(tracePath, "finish processing queued=0", TIMEOUT);