File size: 4,458 Bytes
eb3f11e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | 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");
}
});
});
|