Files
BrowserSkill/apps/extension/src/tools/window.ts
T
NianJiu 4549ed0892 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.
2026-08-13 17:31:23 +08:00

86 lines
2.6 KiB
TypeScript
Executable File

// Window-tool handlers: `tool.window_resize` resizes the session's
// Agent Window via `chrome.windows.update`.
import type { SessionManager } from "@/session-manager/manager";
import type { RpcError } from "@/transport/types";
import { validateWindowSize } from "./session";
import { isRpcError, lookupSession } from "./shared";
/**
* Mirror of bsk-protocol `WindowResizeParams` /
* `WindowResizeResult` (see crates/bsk-protocol/src/tools/window.rs).
*/
export interface WindowResizeParams {
session_id: string;
width: number;
height: number;
}
export interface WindowResizeResult {
window_id: number;
width: number;
height: number;
}
/**
* Subset of `chrome.windows` we depend on, injectable so unit tests
* can fake the browser without monkey-patching the global `chrome`.
*/
export interface WindowResizeApi {
update(windowId: number, updateInfo: { width: number; height: number }): Promise<unknown>;
}
export const chromeWindowResizeApi: WindowResizeApi = {
async update(windowId, updateInfo) {
return chrome.windows.update(windowId, updateInfo);
},
};
/**
* Handler for `tool.window_resize` (called by the daemon over WS).
*
* Resizes the session's Agent Window to the given outer dimensions in
* CSS pixels. chrome API failures are surfaced as `protocol_error`
* (§4.5 reserves `cdp_failed` for raw CDP errors).
*/
export async function handleWindowResize(
manager: SessionManager,
params: WindowResizeParams,
api: WindowResizeApi = chromeWindowResizeApi,
signal?: AbortSignal,
): Promise<WindowResizeResult | RpcError> {
if (signal?.aborted) return { code: "cancelled", message: "window_resize aborted" };
const ctxOrErr = lookupSession(manager, params, "window_resize");
if (isRpcError(ctxOrErr)) return ctxOrErr;
const ctx = ctxOrErr;
const sizeOrErr = validateWindowSize(params.width, params.height);
if (isRpcError(sizeOrErr)) return sizeOrErr;
if (!sizeOrErr) {
// validateWindowSize only returns undefined when both are absent,
// which is valid for session_start but not for an explicit resize.
return {
code: "invalid_params",
message: "window_resize requires width and height",
};
}
try {
if (signal?.aborted) return { code: "cancelled", message: "window_resize aborted" };
await api.update(ctx.agentWindowId, {
width: sizeOrErr.width,
height: sizeOrErr.height,
});
} catch (err) {
return {
code: "protocol_error",
message: err instanceof Error ? err.message : String(err),
};
}
return {
window_id: ctx.agentWindowId,
width: sizeOrErr.width,
height: sizeOrErr.height,
};
}