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");
    }
  });
});