openclaw / src /agents /tools /computer-tool.schema.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
eb3f11e verified
Raw History Blame Contribute Delete
4.46 kB
import { beforeEach, describe, expect, it } from "vitest";
import {
createComputerTool,
listNodesMock,
loadPairedComputerUseAvailabilityForSurface,
readActionEnum,
resetComputerToolMocks,
v2Descriptor,
} from "./computer-tool.test-helpers.js";
beforeEach(resetComputerToolMocks);
describe("createComputerTool schema", () => {
it("loads paired capabilities only for an exposed ordinary paired surface", async () => {
const sessionTransport = {
resolveNode: async () => ({ nodeId: "session-desktop" }),
invoke: async () => undefined,
};
listNodesMock.mockResolvedValue([]);
await expect(
loadPairedComputerUseAvailabilityForSurface({
computerAllowed: true,
modelHasVision: true,
}),
).resolves.toBeDefined();
expect(listNodesMock).toHaveBeenCalledTimes(1);
for (const params of [
{ computerAllowed: false, modelHasVision: true },
{ computerAllowed: true, modelHasVision: false },
{ computerAllowed: true, modelHasVision: true, embeddedMode: true },
{ computerAllowed: true, modelHasVision: true, computerTransport: sessionTransport },
{ computerAllowed: true, modelHasVision: true, computerTransport: null },
]) {
expect(await loadPairedComputerUseAvailabilityForSurface(params)).toBeUndefined();
}
expect(listNodesMock).toHaveBeenCalledTimes(1);
});
it("keeps an undeclared node on the exact v1 action list", () => {
expect(readActionEnum(createComputerTool())).toEqual([
"screenshot",
"left_click",
"right_click",
"middle_click",
"double_click",
"triple_click",
"mouse_move",
"left_click_drag",
"left_mouse_down",
"left_mouse_up",
"scroll",
"type",
"key",
"hold_key",
"wait",
]);
});
it.each([
["an existing wait", ["screenshot", "wait"]],
["no screenshot", ["list_windows"]],
] as const)("preserves the effective action list with %s", (_name, actions) => {
const tool = createComputerTool({
transport: {
computerUse: v2Descriptor([...actions]),
resolveNode: async () => ({ nodeId: "session-desktop" }),
invoke: async () => undefined,
},
});
expect(readActionEnum(tool)).toEqual(actions);
});
it("keeps override-compatible v1 actions alongside prepared paired v2 actions", () => {
const tool = createComputerTool({
pairedNodeComputerUse: {
actions: ["screenshot", "list_windows"],
guidanceCapabilities: v2Descriptor(["screenshot", "list_windows"]),
},
});
expect(readActionEnum(tool)).toEqual(
expect.arrayContaining(["screenshot", "left_click", "list_windows", "wait"]),
);
expect(readActionEnum(tool)).not.toContain("launch_app");
});
it("keeps model input free of native provider fields", () => {
const schema = JSON.stringify(createComputerTool().parameters);
for (const nativeField of [
"providerTool",
"arguments",
"binaryPath",
"socketPath",
"session",
"driverArgs",
"output_dir",
"destinationRoot",
]) {
expect(schema).not.toContain(`"${nativeField}":`);
}
});
it("does not describe held-key input when the selected session only supports taps", () => {
const tool = createComputerTool({
transport: {
computerUse: v2Descriptor(["screenshot", "key"]),
resolveNode: async () => ({ nodeId: "session-desktop" }),
invoke: async () => undefined,
},
});
expect(JSON.stringify(tool.parameters)).not.toContain("hold_key");
expect(readActionEnum(tool)).toContain("wait");
expect(JSON.stringify(createComputerTool().parameters)).toContain("hold_key");
});
it("publishes Codex-compatible fixed-size coordinate arrays", () => {
const properties = (
createComputerTool().parameters as {
properties?: Record<string, Record<string, unknown>>;
}
).properties;
for (const key of ["coordinate", "startCoordinate"] as const) {
const schema = properties?.[key];
if (!schema) {
throw new Error(`missing ${key} schema`);
}
expect(schema).toMatchObject({
type: "array",
items: { type: "integer", minimum: 0 },
minItems: 2,
maxItems: 2,
});
expect(Array.isArray(schema.items)).toBe(false);
expect(schema).not.toHaveProperty("additionalItems");
}
});
});