mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
7189333ac4
## Summary Adds tool-owned, human-readable interaction messages for every tool definition. Each tool defines its own started, completed, and failed wording (as implemented in https://github.com/software-mansion/argent/pull/367. Messages can use validated parameters, successful results, and safe failure codes. They are to avoid sensitive input such as typed text, cookie values, JavaScript expressions, and URL credentials. Bridges the gap between current Argent <img width="954" height="493" alt="Screenshot%202026-07-28%20at%2015 48 37" src="https://github.com/user-attachments/assets/2c689a93-8ba8-4208-b35e-66eb53c96671" /> and current agent-device <img width="1188" height="476" alt="Zrzut ekranu 2026-07-28 o 20 14 42" src="https://github.com/user-attachments/assets/6aed0f38-625b-4748-83e5-d384e79266c2" /> ## Test Selected fields from the generated JSONL: ```jsonl {"level":30,"type":"tool.invoked","toolId":"list-devices","toolInvocationId":"decb864f-51c1-41ee-91fc-15bc2494e268","msg":"Listing devices","time":"2026-07-29T10:37:19.896Z"} {"level":30,"type":"tool.completed","toolId":"list-devices","toolInvocationId":"decb864f-51c1-41ee-91fc-15bc2494e268","durationMs":96.77333299999918,"msg":"Listed 22 devices and 0 AVDs","time":"2026-07-29T10:37:19.993Z"} {"level":30,"type":"tool.invoked","toolId":"screenshot","toolInvocationId":"8504abb8-83ed-4490-8210-3355d6c638c9","msg":"Capturing screenshot","time":"2026-07-29T10:37:24.503Z"} {"level":50,"type":"tool.failed","toolId":"screenshot","toolInvocationId":"8504abb8-83ed-4490-8210-3355d6c638c9","failureSignal":{"error_code":"SIMULATOR_SERVER_READY_EXITED","failure_stage":"simulator_server_spawn_ready","failure_area":"tool_server","error_kind":"subprocess","failure_command":"simulator_server","failure_exit_code":1},"durationMs":750.4639999999999,"msg":"Failed to capture screenshot: SIMULATOR_SERVER_READY_EXITED","time":"2026-07-29T10:37:25.254Z"} {"level":30,"type":"tool.invoked","toolId":"screenshot","toolInvocationId":"63b938fc-3d86-4eb5-9972-a008474ffb01","msg":"Capturing screenshot","time":"2026-07-29T10:38:01.107Z"} {"level":30,"type":"tool.completed","toolId":"screenshot","toolInvocationId":"63b938fc-3d86-4eb5-9972-a008474ffb01","durationMs":25.509208000003127,"msg":"Captured screenshot argent-screenshot-chromium-cdp-9222-1785321481132-81477.png","time":"2026-07-29T10:38:01.133Z"} ```
106 lines
4.0 KiB
TypeScript
106 lines
4.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
FAILURE_CODES,
|
|
type FailureSignal,
|
|
type Registry,
|
|
type ToolDefinition,
|
|
} from "@argent/registry";
|
|
import { createRegistry } from "../src/utils/setup-registry";
|
|
import { pasteTool } from "../src/tools/paste";
|
|
import { simulatorServerTool } from "../src/tools/simulator/simulator-server";
|
|
import { createProposeVariantTool } from "../src/tools/variants/propose-variant";
|
|
import { awaitUserSelectionTool } from "../src/tools/variants/await-user-selection";
|
|
|
|
const failureSignal: FailureSignal = {
|
|
error_code: FAILURE_CODES.ARGENT_UNCLASSIFIED_FAILURE,
|
|
failure_stage: "interaction_message_test",
|
|
failure_area: "tool_server",
|
|
error_kind: "unknown",
|
|
};
|
|
|
|
function definitionsById(registry: Registry): Map<string, ToolDefinition<any, any>> {
|
|
const definitions = new Map<string, ToolDefinition<any, any>>();
|
|
for (const id of registry.getSnapshot().tools) {
|
|
definitions.set(id, registry.getTool(id)!);
|
|
}
|
|
|
|
// Lens tools are only registered on macOS; add them explicitly so this test
|
|
// covers the same catalog on every CI platform.
|
|
definitions.set("propose_variant", createProposeVariantTool(registry));
|
|
definitions.set("await_user_selection", awaitUserSelectionTool);
|
|
|
|
// These definitions intentionally exist outside createRegistry.
|
|
definitions.set("paste", pasteTool);
|
|
definitions.set("simulator-server", simulatorServerTool);
|
|
return definitions;
|
|
}
|
|
|
|
describe("tool interaction messages", () => {
|
|
it("defines all three formatters for every tool", () => {
|
|
const definitions = definitionsById(createRegistry());
|
|
expect(definitions.size).toBe(77);
|
|
|
|
for (const [id, definition] of definitions) {
|
|
expect(definition.interaction?.startedMsg, `${id}.startedMsg`).toBeTypeOf("function");
|
|
expect(definition.interaction?.completedMsg, `${id}.completedMsg`).toBeTypeOf("function");
|
|
expect(definition.interaction?.failedMsg, `${id}.failedMsg`).toBeTypeOf("function");
|
|
}
|
|
});
|
|
|
|
it("formats messages from parameters, results, and failure signals", () => {
|
|
const definitions = definitionsById(createRegistry());
|
|
|
|
expect(
|
|
definitions.get("gesture-tap")!.interaction!.completedMsg!({
|
|
params: { udid: "device-1", x: 0.5, y: 0.25, clickCount: 2 },
|
|
result: {},
|
|
})
|
|
).toBe("Double-tapped at (50%, 25%)");
|
|
|
|
expect(
|
|
definitions.get("screenshot")!.interaction!.completedMsg!({
|
|
params: { udid: "device-1" },
|
|
result: { image: { filename: "screenshot.png" } },
|
|
})
|
|
).toBe("Captured screenshot screenshot.png");
|
|
|
|
expect(
|
|
definitions.get("gesture-tap")!.interaction!.failedMsg!({
|
|
params: { udid: "device-1", x: 0.5, y: 0.25 },
|
|
error: new Error("raw error"),
|
|
failureSignal,
|
|
})
|
|
).toBe(`Failed to tap at (50%, 25%): ${failureSignal.error_code}`);
|
|
});
|
|
|
|
it("does not expose sensitive inputs", () => {
|
|
const definitions = definitionsById(createRegistry());
|
|
const secret = "INTERACTION_MESSAGE_SECRET";
|
|
const messages = [
|
|
definitions.get("keyboard")!.interaction!.startedMsg!({
|
|
params: { udid: "device-1", text: secret, key: secret },
|
|
}),
|
|
definitions.get("open-url")!.interaction!.startedMsg!({
|
|
params: {
|
|
udid: "device-1",
|
|
url: `https://user:${secret}@example.com/path?token=${secret}#fragment`,
|
|
},
|
|
}),
|
|
definitions.get("debugger-evaluate")!.interaction!.startedMsg!({
|
|
params: { device_id: "device-1", port: 8081, expression: secret },
|
|
}),
|
|
definitions.get("chromium-cookies")!.interaction!.completedMsg!({
|
|
params: { udid: "chromium-1", action: "set", name: "session", value: secret },
|
|
result: { set: true },
|
|
}),
|
|
definitions.get("flow-add-echo")!.interaction!.completedMsg!({
|
|
params: { message: secret },
|
|
result: { message: secret, flowFile: "/tmp/flow.yaml", savedTo: "project" },
|
|
}),
|
|
];
|
|
|
|
expect(messages.join("\n")).not.toContain(secret);
|
|
expect(messages).toContain("Opening example.com");
|
|
});
|
|
});
|