681d7daf65
- Replaced the separate GUI-linked pi_natives.desktop.linux-x64 addon with a pure-Rust X11 backend (x11rb RustConnection capture via RandR/GetImage, XTest input with keysym mapping) compiled into the core addon on every published target; Linux arm64 and musl are now supported and headless hosts load the addon unaffected. - Removed the native-desktop-linux cargo feature, desktop_unsupported.rs, lazy desktop loader, second napi build, desktop packaging/CI steps, GUI build dependencies, and the now-unreferenced vendored libspa crate; reverted setup-system-deps to main. - Preserved the desktop input hardening semantics on the unified backend: XTest layouts reject negative origins and coordinates beyond 0..=32767, batch coordinates stay bound to the frame last returned to JS with intermediate screenshots deferred, coordinate input requires a previously returned frame, and failed chord releases still release every held key. - Enforced a 60s worker-side execute deadline (DESKTOP_DEADLINE_EXCEEDED): no input is emitted after expiry and wait-heavy batches are rejected upfront. - Added int32 fail-closed validation for coordinates, drag points, and scroll deltas at the JS ingress and gateway schema. - Exposed computer to models without native OpenAI computer-use support as a regular function tool with a typed GA action schema across OpenAI, Azure, and Codex Responses providers, including named forced choice. - Added the /computer slash command (on/off/status/toggle) for session-only enablement via runtime tool registration in SessionTools. - Updated docs, changelogs, and contract tests accordingly.
85 lines
3.5 KiB
TypeScript
85 lines
3.5 KiB
TypeScript
import { describe, expect, it, vi } from "bun:test";
|
|
import { executeAcpBuiltinSlashCommand } from "@oh-my-pi/pi-coding-agent/slash-commands/acp-builtins";
|
|
import type { SlashCommandRuntime } from "@oh-my-pi/pi-coding-agent/slash-commands/types";
|
|
|
|
function acpRuntime(options?: { enabled?: boolean; applyResult?: boolean }) {
|
|
const store = { "computer.enabled": options?.enabled ?? false };
|
|
const get = vi.fn((path: string) => store[path as keyof typeof store]);
|
|
const override = vi.fn((path: string, value: boolean) => {
|
|
store[path as keyof typeof store] = value;
|
|
});
|
|
const set = vi.fn();
|
|
const setComputerToolEnabled = vi.fn(async () => options?.applyResult ?? true);
|
|
const output = vi.fn();
|
|
const runtime = {
|
|
session: { settings: { get, override, set }, setComputerToolEnabled },
|
|
output,
|
|
} as unknown as SlashCommandRuntime;
|
|
return { get, override, set, setComputerToolEnabled, output, runtime };
|
|
}
|
|
|
|
describe("/computer slash command", () => {
|
|
it("toggles a disabled session on: slate refresh first, then session-only override", async () => {
|
|
const h = acpRuntime({ enabled: false });
|
|
|
|
const result = await executeAcpBuiltinSlashCommand("/computer", h.runtime);
|
|
|
|
expect(result).toEqual({ consumed: true });
|
|
expect(h.setComputerToolEnabled).toHaveBeenCalledWith(true);
|
|
expect(h.override).toHaveBeenCalledWith("computer.enabled", true);
|
|
expect(h.set).not.toHaveBeenCalled();
|
|
expect(h.output).toHaveBeenCalledWith("Computer use enabled for this session.");
|
|
});
|
|
|
|
it("toggles an enabled session off", async () => {
|
|
const h = acpRuntime({ enabled: true });
|
|
|
|
await executeAcpBuiltinSlashCommand("/computer", h.runtime);
|
|
|
|
expect(h.setComputerToolEnabled).toHaveBeenCalledWith(false);
|
|
expect(h.override).toHaveBeenCalledWith("computer.enabled", false);
|
|
expect(h.output).toHaveBeenCalledWith("Computer use disabled for this session.");
|
|
});
|
|
|
|
it("honors explicit on/off regardless of current state", async () => {
|
|
const on = acpRuntime({ enabled: true });
|
|
await executeAcpBuiltinSlashCommand("/computer on", on.runtime);
|
|
expect(on.setComputerToolEnabled).toHaveBeenCalledWith(true);
|
|
expect(on.override).toHaveBeenCalledWith("computer.enabled", true);
|
|
|
|
const off = acpRuntime({ enabled: false });
|
|
await executeAcpBuiltinSlashCommand("/computer off", off.runtime);
|
|
expect(off.setComputerToolEnabled).toHaveBeenCalledWith(false);
|
|
expect(off.override).toHaveBeenCalledWith("computer.enabled", false);
|
|
});
|
|
|
|
it("reports status without touching the tool slate or settings", async () => {
|
|
const h = acpRuntime({ enabled: true });
|
|
|
|
await executeAcpBuiltinSlashCommand("/computer status", h.runtime);
|
|
|
|
expect(h.setComputerToolEnabled).not.toHaveBeenCalled();
|
|
expect(h.override).not.toHaveBeenCalled();
|
|
expect(h.output).toHaveBeenCalledWith("Computer use is on.");
|
|
});
|
|
|
|
it("leaves the override untouched when the session cannot build the tool", async () => {
|
|
const h = acpRuntime({ enabled: false, applyResult: false });
|
|
|
|
await executeAcpBuiltinSlashCommand("/computer on", h.runtime);
|
|
|
|
expect(h.setComputerToolEnabled).toHaveBeenCalledWith(true);
|
|
expect(h.override).not.toHaveBeenCalled();
|
|
expect(h.output).toHaveBeenCalledWith("Computer use is unavailable in this session.");
|
|
});
|
|
|
|
it("rejects unknown arguments with usage", async () => {
|
|
const h = acpRuntime();
|
|
|
|
await executeAcpBuiltinSlashCommand("/computer bogus", h.runtime);
|
|
|
|
expect(h.setComputerToolEnabled).not.toHaveBeenCalled();
|
|
expect(h.output).toHaveBeenCalledWith("Usage: /computer [on|off|status]");
|
|
});
|
|
});
|