fix(extension): make tool cancellation cooperative (#89)

Tool cancellation is now cooperative end-to-end: the queue stays busy until compensation completes, cancellation is checked cooperatively across the pipeline, the fallback window is compensated too, and cleanup_failed is surfaced explicitly. Includes a gated delayed-compensation E2E test.
This commit is contained in:
NianJiu
2026-08-13 17:31:23 +08:00
committed by GitHub
parent 37fbaacc94
commit 4549ed0892
20 changed files with 904 additions and 214 deletions
+21 -1
View File
@@ -1,5 +1,6 @@
import type { SessionManager } from "@/session-manager/manager";
import { type SessionManager, SessionStartCleanupError } from "@/session-manager/manager";
import type { RpcError } from "@/transport/types";
import { rpcError } from "./errors";
import { clearRecordingForSession } from "./record";
import { isRpcError } from "./shared";
import { returnBorrowedTab, type TabManagementDeps } from "./tabs";
@@ -58,6 +59,10 @@ export interface SessionStartResult {
agent_window_id?: number;
}
export interface SessionStartDeps {
signal?: AbortSignal;
}
export interface SessionStopParams {
session_id: string;
}
@@ -91,6 +96,7 @@ export interface SessionStopDeps {
export async function handleSessionStart(
manager: SessionManager,
params: SessionStartParams,
deps: SessionStartDeps = {},
): Promise<SessionStartResult | RpcError> {
if (!params?.session_id) {
return {
@@ -104,9 +110,23 @@ export async function handleSessionStart(
const ctx = await manager.start(params.session_id, {
size: sizeOrErr,
focused: params.focused,
signal: deps.signal,
});
return { agent_window_id: ctx.agentWindowId };
} catch (err) {
if (err instanceof SessionStartCleanupError) {
return rpcError("protocol_error", "cleanup_failed", err.message, {
resource_type: "agent_window",
resource_id: err.windowId,
});
}
if (
typeof err === "object" &&
err !== null &&
(err as { name?: string }).name === "AbortError"
) {
return { code: "cancelled", message: "session_start aborted" };
}
// chrome.windows.create / SessionManager failures are not CDP
// failures (§4.5 reserves cdp_failed for raw CDP errors). Surface
// them as protocol_error so the CLI maps to the right exit code