@relauts/spotcheck-service 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/NOTICE +19 -0
- package/README.md +169 -0
- package/dist/api/auth.d.ts +11 -0
- package/dist/api/auth.js +32 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/history.d.ts +46 -0
- package/dist/api/history.js +172 -0
- package/dist/api/history.js.map +1 -0
- package/dist/api/saved-run.d.ts +35 -0
- package/dist/api/saved-run.js +234 -0
- package/dist/api/saved-run.js.map +1 -0
- package/dist/api/saved.d.ts +33 -0
- package/dist/api/saved.js +209 -0
- package/dist/api/saved.js.map +1 -0
- package/dist/api/server.d.ts +23 -0
- package/dist/api/server.js +852 -0
- package/dist/api/server.js.map +1 -0
- package/dist/computer-use/actions.d.ts +14 -0
- package/dist/computer-use/actions.js +212 -0
- package/dist/computer-use/actions.js.map +1 -0
- package/dist/computer-use/args.d.ts +11 -0
- package/dist/computer-use/args.js +74 -0
- package/dist/computer-use/args.js.map +1 -0
- package/dist/computer-use/cli.d.ts +1 -0
- package/dist/computer-use/cli.js +8 -0
- package/dist/computer-use/cli.js.map +1 -0
- package/dist/computer-use/client.d.ts +3 -0
- package/dist/computer-use/client.js +68 -0
- package/dist/computer-use/client.js.map +1 -0
- package/dist/computer-use/coords.d.ts +5 -0
- package/dist/computer-use/coords.js +21 -0
- package/dist/computer-use/coords.js.map +1 -0
- package/dist/computer-use/history.d.ts +11 -0
- package/dist/computer-use/history.js +59 -0
- package/dist/computer-use/history.js.map +1 -0
- package/dist/computer-use/index.d.ts +17 -0
- package/dist/computer-use/index.js +75 -0
- package/dist/computer-use/index.js.map +1 -0
- package/dist/computer-use/keys.d.ts +3 -0
- package/dist/computer-use/keys.js +50 -0
- package/dist/computer-use/keys.js.map +1 -0
- package/dist/computer-use/loop.d.ts +22 -0
- package/dist/computer-use/loop.js +90 -0
- package/dist/computer-use/loop.js.map +1 -0
- package/dist/computer-use/safety.d.ts +15 -0
- package/dist/computer-use/safety.js +45 -0
- package/dist/computer-use/safety.js.map +1 -0
- package/dist/computer-use/screenshot.d.ts +5 -0
- package/dist/computer-use/screenshot.js +16 -0
- package/dist/computer-use/screenshot.js.map +1 -0
- package/dist/computer-use/system-prompt.d.ts +11 -0
- package/dist/computer-use/system-prompt.js +41 -0
- package/dist/computer-use/system-prompt.js.map +1 -0
- package/dist/computer-use/types.d.ts +83 -0
- package/dist/computer-use/types.js +31 -0
- package/dist/computer-use/types.js.map +1 -0
- package/dist/playwright/actions.d.ts +81 -0
- package/dist/playwright/actions.js +170 -0
- package/dist/playwright/actions.js.map +1 -0
- package/dist/playwright/chromium.d.ts +10 -0
- package/dist/playwright/chromium.js +27 -0
- package/dist/playwright/chromium.js.map +1 -0
- package/dist/playwright/index.d.ts +2 -0
- package/dist/playwright/index.js +64 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/playwright/processed.d.ts +11 -0
- package/dist/playwright/processed.js +183 -0
- package/dist/playwright/processed.js.map +1 -0
- package/dist/playwright/session.d.ts +28 -0
- package/dist/playwright/session.js +165 -0
- package/dist/playwright/session.js.map +1 -0
- package/dist/shared/config.d.ts +38 -0
- package/dist/shared/config.js +227 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/cost.d.ts +15 -0
- package/dist/shared/cost.js +40 -0
- package/dist/shared/cost.js.map +1 -0
- package/dist/shared/logger.d.ts +4 -0
- package/dist/shared/logger.js +10 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/main-module.d.ts +1 -0
- package/dist/shared/main-module.js +19 -0
- package/dist/shared/main-module.js.map +1 -0
- package/dist/shared/models.d.ts +12 -0
- package/dist/shared/models.js +40 -0
- package/dist/shared/models.js.map +1 -0
- package/dist/shared/telemetry.d.ts +9 -0
- package/dist/shared/telemetry.js +43 -0
- package/dist/shared/telemetry.js.map +1 -0
- package/files/model.json +26 -0
- package/files/system_prompt.txt +15 -0
- package/openapi.yaml +901 -0
- package/package.json +60 -0
- package/relauts-spotcheck-service-config.example.json +19 -0
- package/src/api/auth.ts +40 -0
- package/src/api/history.ts +251 -0
- package/src/api/saved-run.ts +346 -0
- package/src/api/saved.ts +275 -0
- package/src/api/server.ts +1198 -0
- package/src/computer-use/actions.ts +273 -0
- package/src/computer-use/args.ts +97 -0
- package/src/computer-use/cli.ts +8 -0
- package/src/computer-use/client.ts +81 -0
- package/src/computer-use/coords.ts +26 -0
- package/src/computer-use/history.ts +80 -0
- package/src/computer-use/index.ts +121 -0
- package/src/computer-use/keys.ts +54 -0
- package/src/computer-use/loop.ts +140 -0
- package/src/computer-use/safety.ts +59 -0
- package/src/computer-use/screenshot.ts +20 -0
- package/src/computer-use/system-prompt.ts +65 -0
- package/src/computer-use/types.ts +126 -0
- package/src/playwright/actions.ts +332 -0
- package/src/playwright/chromium.ts +30 -0
- package/src/playwright/index.ts +77 -0
- package/src/playwright/processed.ts +253 -0
- package/src/playwright/session.ts +220 -0
- package/src/shared/config.ts +320 -0
- package/src/shared/cost.ts +58 -0
- package/src/shared/logger.ts +9 -0
- package/src/shared/main-module.ts +20 -0
- package/src/shared/models.ts +62 -0
- package/src/shared/telemetry.ts +63 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createGeminiInteractionClient } from "./client.js";
|
|
2
|
+
import { parseAgentTask } from "./cli.js";
|
|
3
|
+
import { runComputerUseLoop } from "./loop.js";
|
|
4
|
+
import { confirmSafetyInTerminal } from "./safety.js";
|
|
5
|
+
import { defaultSystemPromptVars, loadSystemPrompt } from "./system-prompt.js";
|
|
6
|
+
import { AgentRunError } from "./types.js";
|
|
7
|
+
import { createProcessedScreenshotSaver } from "../playwright/processed.js";
|
|
8
|
+
import { BROWSER_SESSION_RESET_MESSAGE, createBrowserSession, } from "../playwright/session.js";
|
|
9
|
+
import { loadConfig, requireGeminiApiKey } from "../shared/config.js";
|
|
10
|
+
import { logger } from "../shared/logger.js";
|
|
11
|
+
import { isMainModule } from "../shared/main-module.js";
|
|
12
|
+
export { AgentRunError, BROWSER_SESSION_RESET_MESSAGE };
|
|
13
|
+
const agentSession = createBrowserSession();
|
|
14
|
+
let shuttingDown = false;
|
|
15
|
+
export async function closeAgentSession() {
|
|
16
|
+
await agentSession.close();
|
|
17
|
+
}
|
|
18
|
+
async function shutdown(exitCode, reason) {
|
|
19
|
+
if (shuttingDown) {
|
|
20
|
+
process.exit(exitCode);
|
|
21
|
+
}
|
|
22
|
+
shuttingDown = true;
|
|
23
|
+
logger.info(reason);
|
|
24
|
+
await closeAgentSession();
|
|
25
|
+
process.exit(exitCode);
|
|
26
|
+
}
|
|
27
|
+
export async function runAgent(task, config = loadConfig(), confirmSafety = confirmSafetyInTerminal, session = agentSession, model = config.geminiModel, extras = {}) {
|
|
28
|
+
requireGeminiApiKey(config);
|
|
29
|
+
logger.info(`Computer-use model=${model} thinking=${config.geminiThinkingLevel}` +
|
|
30
|
+
(config.geminiSeed !== undefined ? ` seed=${config.geminiSeed}` : ""));
|
|
31
|
+
const { page, sessionReset } = await session.ensurePage(config);
|
|
32
|
+
if (sessionReset) {
|
|
33
|
+
logger.info(BROWSER_SESSION_RESET_MESSAGE);
|
|
34
|
+
}
|
|
35
|
+
const systemInstruction = await loadSystemPrompt(defaultSystemPromptVars(config.viewportWidth, config.viewportHeight));
|
|
36
|
+
const result = await runComputerUseLoop({
|
|
37
|
+
client: createGeminiInteractionClient(config, model, systemInstruction),
|
|
38
|
+
page,
|
|
39
|
+
saveScreenshot: createProcessedScreenshotSaver(page, config.processedDir),
|
|
40
|
+
confirmSafety: extras.confirmSafety ?? confirmSafety,
|
|
41
|
+
screenWidth: config.viewportWidth,
|
|
42
|
+
screenHeight: config.viewportHeight,
|
|
43
|
+
maxTurns: config.agentMaxTurns,
|
|
44
|
+
onIntent: extras.onIntent,
|
|
45
|
+
signal: extras.signal,
|
|
46
|
+
}, task);
|
|
47
|
+
logger.info(`Computer-use status=${result.status} turns=${result.turns}`);
|
|
48
|
+
return { text: result.finalText, sessionReset, usage: result.usage };
|
|
49
|
+
}
|
|
50
|
+
function registerShutdownHandlers() {
|
|
51
|
+
const onSignal = (signal) => {
|
|
52
|
+
void shutdown(0, `Received ${signal}, shutting down`);
|
|
53
|
+
};
|
|
54
|
+
process.once("SIGINT", onSignal);
|
|
55
|
+
process.once("SIGTERM", onSignal);
|
|
56
|
+
}
|
|
57
|
+
async function waitUntilStopped() {
|
|
58
|
+
logger.info("Task finished. Browser stays open until Ctrl+C");
|
|
59
|
+
await new Promise(() => {
|
|
60
|
+
// Shutdown handlers call process.exit.
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async function main() {
|
|
64
|
+
registerShutdownHandlers();
|
|
65
|
+
const task = parseAgentTask(process.argv);
|
|
66
|
+
await runAgent(task);
|
|
67
|
+
await waitUntilStopped();
|
|
68
|
+
}
|
|
69
|
+
if (isMainModule(import.meta.url)) {
|
|
70
|
+
main().catch((error) => {
|
|
71
|
+
logger.error("Fatal error", error);
|
|
72
|
+
void shutdown(1, "Exiting after fatal error");
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/computer-use/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const KEY_ALIASES = {
|
|
2
|
+
return: "Enter",
|
|
3
|
+
enter: "Enter",
|
|
4
|
+
esc: "Escape",
|
|
5
|
+
escape: "Escape",
|
|
6
|
+
ctrl: "Control",
|
|
7
|
+
control: "Control",
|
|
8
|
+
cmd: "Meta",
|
|
9
|
+
command: "Meta",
|
|
10
|
+
super: "Meta",
|
|
11
|
+
meta: "Meta",
|
|
12
|
+
alt: "Alt",
|
|
13
|
+
option: "Alt",
|
|
14
|
+
space: "Space",
|
|
15
|
+
spacebar: "Space",
|
|
16
|
+
backspace: "Backspace",
|
|
17
|
+
tab: "Tab",
|
|
18
|
+
del: "Delete",
|
|
19
|
+
delete: "Delete",
|
|
20
|
+
up: "ArrowUp",
|
|
21
|
+
down: "ArrowDown",
|
|
22
|
+
left: "ArrowLeft",
|
|
23
|
+
right: "ArrowRight",
|
|
24
|
+
arrowup: "ArrowUp",
|
|
25
|
+
arrowdown: "ArrowDown",
|
|
26
|
+
arrowleft: "ArrowLeft",
|
|
27
|
+
arrowright: "ArrowRight",
|
|
28
|
+
pageup: "PageUp",
|
|
29
|
+
pagedown: "PageDown",
|
|
30
|
+
home: "Home",
|
|
31
|
+
end: "End",
|
|
32
|
+
shift: "Shift",
|
|
33
|
+
};
|
|
34
|
+
export function mapGeminiKey(key) {
|
|
35
|
+
const trimmed = key.trim();
|
|
36
|
+
if (!trimmed) {
|
|
37
|
+
throw new Error("Key must be a non-empty string");
|
|
38
|
+
}
|
|
39
|
+
if (trimmed.length === 1) {
|
|
40
|
+
return trimmed;
|
|
41
|
+
}
|
|
42
|
+
return KEY_ALIASES[trimmed.toLowerCase()] ?? trimmed;
|
|
43
|
+
}
|
|
44
|
+
export function mapGeminiKeys(keys) {
|
|
45
|
+
return keys.map(mapGeminiKey);
|
|
46
|
+
}
|
|
47
|
+
export function selectAllShortcut(platform = process.platform) {
|
|
48
|
+
return platform === "darwin" ? "Meta+A" : "Control+A";
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/computer-use/keys.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAA2B;IAC1C,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,QAAQ;IACb,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,MAAM;IACX,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,OAAO;IACjB,SAAS,EAAE,WAAW;IACtB,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,QAAQ;IACb,MAAM,EAAE,QAAQ;IAChB,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,YAAY;IACnB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,UAAU,EAAE,YAAY;IACxB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,OAAO;CACf,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,OAAO,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ;IAC3D,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type TokenUsage } from "../shared/cost.js";
|
|
2
|
+
import { type ComputerUsePage, type IntentListener, type InteractionClient, type SafetyConfirmer, type ScreenshotSaver, type Sleeper } from "./types.js";
|
|
3
|
+
export interface AgentLoopDeps {
|
|
4
|
+
client: InteractionClient;
|
|
5
|
+
page: ComputerUsePage;
|
|
6
|
+
saveScreenshot: ScreenshotSaver;
|
|
7
|
+
confirmSafety: SafetyConfirmer;
|
|
8
|
+
screenWidth: number;
|
|
9
|
+
screenHeight: number;
|
|
10
|
+
maxTurns: number;
|
|
11
|
+
sleep?: Sleeper;
|
|
12
|
+
readScreenshot?: (filePath: string) => Promise<string>;
|
|
13
|
+
onIntent?: IntentListener;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
export interface AgentLoopResult {
|
|
17
|
+
status: "completed" | "max_turns" | "safety_denied";
|
|
18
|
+
turns: number;
|
|
19
|
+
finalText: string;
|
|
20
|
+
usage: TokenUsage;
|
|
21
|
+
}
|
|
22
|
+
export declare function runComputerUseLoop(deps: AgentLoopDeps, task: string): Promise<AgentLoopResult>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { buildFunctionResults, executeFunctionCalls } from "./actions.js";
|
|
2
|
+
import { compactOldScreenshots, extractModelText, getFunctionCalls } from "./history.js";
|
|
3
|
+
import { logger } from "../shared/logger.js";
|
|
4
|
+
import { addUsage, EMPTY_USAGE } from "../shared/cost.js";
|
|
5
|
+
import { readWebpAsBase64 } from "./screenshot.js";
|
|
6
|
+
import { AgentRunError, } from "./types.js";
|
|
7
|
+
async function screenshotBase64(saveScreenshot, actionName, readScreenshot) {
|
|
8
|
+
const filePath = await saveScreenshot(actionName);
|
|
9
|
+
return readScreenshot(filePath);
|
|
10
|
+
}
|
|
11
|
+
async function throwIfAborted(signal, usage) {
|
|
12
|
+
if (signal?.aborted) {
|
|
13
|
+
throw new AgentRunError("Agent stopped", usage);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function runComputerUseLoop(deps, task) {
|
|
17
|
+
const readScreenshot = deps.readScreenshot ?? readWebpAsBase64;
|
|
18
|
+
await throwIfAborted(deps.signal, EMPTY_USAGE);
|
|
19
|
+
const initialImage = await screenshotBase64(deps.saveScreenshot, "start", readScreenshot);
|
|
20
|
+
const history = [
|
|
21
|
+
{
|
|
22
|
+
type: "user_input",
|
|
23
|
+
content: [
|
|
24
|
+
{ type: "text", text: task },
|
|
25
|
+
{ type: "image", data: initialImage, mime_type: "image/webp" },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
let finalText = "";
|
|
30
|
+
let usage = EMPTY_USAGE;
|
|
31
|
+
for (let turn = 1; turn <= deps.maxTurns; turn += 1) {
|
|
32
|
+
await throwIfAborted(deps.signal, usage);
|
|
33
|
+
logger.info(`Computer-use turn ${turn}/${deps.maxTurns}`);
|
|
34
|
+
let interaction;
|
|
35
|
+
try {
|
|
36
|
+
interaction = await deps.client.create([...history]);
|
|
37
|
+
usage = addUsage(usage, interaction.usage ?? EMPTY_USAGE);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (deps.signal?.aborted) {
|
|
41
|
+
throw new AgentRunError("Agent stopped", usage);
|
|
42
|
+
}
|
|
43
|
+
logger.error("Gemini API call failed", error);
|
|
44
|
+
if (error instanceof AgentRunError) {
|
|
45
|
+
throw new AgentRunError(error.message, addUsage(usage, error.usage));
|
|
46
|
+
}
|
|
47
|
+
throw new AgentRunError(error instanceof Error ? error.message : String(error), usage);
|
|
48
|
+
}
|
|
49
|
+
await throwIfAborted(deps.signal, usage);
|
|
50
|
+
history.push(...interaction.steps);
|
|
51
|
+
const calls = getFunctionCalls(interaction.steps);
|
|
52
|
+
if (calls.length === 0) {
|
|
53
|
+
finalText = extractModelText(interaction.steps);
|
|
54
|
+
logger.info(`Agent finished: ${finalText || "(no text)"}`);
|
|
55
|
+
return { status: "completed", turns: turn, finalText, usage };
|
|
56
|
+
}
|
|
57
|
+
let results;
|
|
58
|
+
let terminated;
|
|
59
|
+
let lastScreenshotPath;
|
|
60
|
+
try {
|
|
61
|
+
({ results, terminated, lastScreenshotPath } = await executeFunctionCalls(calls, {
|
|
62
|
+
page: deps.page,
|
|
63
|
+
screenWidth: deps.screenWidth,
|
|
64
|
+
screenHeight: deps.screenHeight,
|
|
65
|
+
saveScreenshot: deps.saveScreenshot,
|
|
66
|
+
confirmSafety: deps.confirmSafety,
|
|
67
|
+
sleep: deps.sleep,
|
|
68
|
+
onIntent: deps.onIntent,
|
|
69
|
+
signal: deps.signal,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error instanceof AgentRunError && error.message === "Agent stopped") {
|
|
74
|
+
throw new AgentRunError("Agent stopped", usage);
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
if (terminated) {
|
|
79
|
+
logger.info("Agent stopped after safety denial");
|
|
80
|
+
return { status: "safety_denied", turns: turn, finalText, usage };
|
|
81
|
+
}
|
|
82
|
+
const screenshotPath = lastScreenshotPath ?? (await deps.saveScreenshot("state"));
|
|
83
|
+
const image = await readScreenshot(screenshotPath);
|
|
84
|
+
history.push(...buildFunctionResults(results, deps.page.url(), image));
|
|
85
|
+
compactOldScreenshots(history);
|
|
86
|
+
}
|
|
87
|
+
logger.info(`Agent stopped at max turns (${deps.maxTurns})`);
|
|
88
|
+
return { status: "max_turns", turns: deps.maxTurns, finalText, usage };
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/computer-use/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SafetyDecision {
|
|
2
|
+
readonly decision: string;
|
|
3
|
+
readonly explanation: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function readSafetyDecision(args: Record<string, unknown>): SafetyDecision | undefined;
|
|
6
|
+
export declare function isSafetyBlocked(decision: SafetyDecision | undefined): boolean;
|
|
7
|
+
export declare function requiresSafetyConfirmation(decision: SafetyDecision | undefined): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Fallback confirmer for the web UI when no interactive confirmer is wired up
|
|
10
|
+
* (e.g. tests, or callers that don't pass a per-request confirmer). Auto-approving
|
|
11
|
+
* here is NOT safe for real production traffic; startWebServer always supplies a
|
|
12
|
+
* real popup-backed confirmer per request, see createWebSafetyConfirmer in server.ts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function confirmSafetyForWeb(explanation: string, actionName: string): Promise<boolean>;
|
|
15
|
+
export declare function confirmSafetyInTerminal(explanation: string, actionName: string): Promise<boolean>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import readline from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import { logger } from "../shared/logger.js";
|
|
4
|
+
export function readSafetyDecision(args) {
|
|
5
|
+
const raw = args.safety_decision;
|
|
6
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const record = raw;
|
|
10
|
+
return {
|
|
11
|
+
decision: typeof record.decision === "string" ? record.decision : "",
|
|
12
|
+
explanation: typeof record.explanation === "string" ? record.explanation : "",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function isSafetyBlocked(decision) {
|
|
16
|
+
return decision?.decision === "blocked";
|
|
17
|
+
}
|
|
18
|
+
export function requiresSafetyConfirmation(decision) {
|
|
19
|
+
return decision?.decision === "require_confirmation";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Fallback confirmer for the web UI when no interactive confirmer is wired up
|
|
23
|
+
* (e.g. tests, or callers that don't pass a per-request confirmer). Auto-approving
|
|
24
|
+
* here is NOT safe for real production traffic; startWebServer always supplies a
|
|
25
|
+
* real popup-backed confirmer per request, see createWebSafetyConfirmer in server.ts.
|
|
26
|
+
*/
|
|
27
|
+
export async function confirmSafetyForWeb(explanation, actionName) {
|
|
28
|
+
logger.info(`Safety confirmation auto-approved (web fallback): ${actionName} - ${explanation || "No explanation provided"}`);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
export async function confirmSafetyInTerminal(explanation, actionName) {
|
|
32
|
+
if (!input.isTTY) {
|
|
33
|
+
logger.error("Safety confirmation required but stdin is not a TTY");
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const rl = readline.createInterface({ input, output });
|
|
37
|
+
try {
|
|
38
|
+
const answer = await rl.question(`Safety confirmation required for ${actionName}: ${explanation || "No explanation provided"}\nProceed? [y/N] `);
|
|
39
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
rl.close();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/computer-use/safety.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAO7C,MAAM,UAAU,kBAAkB,CAAC,IAA6B;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC;IACjC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,GAAoD,CAAC;IACpE,OAAO;QACL,QAAQ,EAAE,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;QACpE,WAAW,EAAE,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;KAC9E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAoC;IAClE,OAAO,QAAQ,EAAE,QAAQ,KAAK,SAAS,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAoC;IAC7E,OAAO,QAAQ,EAAE,QAAQ,KAAK,sBAAsB,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB,EAAE,UAAkB;IAC/E,MAAM,CAAC,IAAI,CACT,qDAAqD,UAAU,MAAM,WAAW,IAAI,yBAAyB,EAAE,CAChH,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,WAAmB,EAAE,UAAkB;IACnF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACpE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAC9B,oCAAoC,UAAU,KAAK,WAAW,IAAI,yBAAyB,mBAAmB,CAC/G,CAAC;QACF,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { getLatestWebpPath } from "../playwright/processed.js";
|
|
3
|
+
export async function readWebpAsBase64(filePath) {
|
|
4
|
+
return fs.readFile(filePath, { encoding: "base64" });
|
|
5
|
+
}
|
|
6
|
+
export async function loadLatestWebpBase64(directory) {
|
|
7
|
+
const filePath = await getLatestWebpPath(directory);
|
|
8
|
+
if (!filePath) {
|
|
9
|
+
throw new Error("No processed webp screenshot found");
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
path: filePath,
|
|
13
|
+
data: await readWebpAsBase64(filePath),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=screenshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/computer-use/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAkB;IAElB,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,MAAM,gBAAgB,CAAC,QAAQ,CAAC;KACvC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const SYSTEM_PROMPT_PATH: string;
|
|
2
|
+
export interface SystemPromptVars {
|
|
3
|
+
readonly os: string;
|
|
4
|
+
readonly displayWidth: number;
|
|
5
|
+
readonly displayHeight: number;
|
|
6
|
+
readonly keyboardLayout: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function osLabel(platform?: NodeJS.Platform): string;
|
|
9
|
+
export declare function defaultSystemPromptVars(displayWidth: number, displayHeight: number, platform?: NodeJS.Platform, locale?: string): SystemPromptVars;
|
|
10
|
+
export declare function renderSystemPrompt(template: string, vars: SystemPromptVars): string;
|
|
11
|
+
export declare function loadSystemPrompt(vars: SystemPromptVars, filePath?: string): Promise<string>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
export const SYSTEM_PROMPT_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../files/system_prompt.txt");
|
|
5
|
+
export function osLabel(platform = process.platform) {
|
|
6
|
+
if (platform === "darwin") {
|
|
7
|
+
return "Chromium on macOS";
|
|
8
|
+
}
|
|
9
|
+
if (platform === "win32") {
|
|
10
|
+
return "Chromium on Windows";
|
|
11
|
+
}
|
|
12
|
+
if (platform === "linux") {
|
|
13
|
+
return "Chromium on Linux";
|
|
14
|
+
}
|
|
15
|
+
return `Chromium on ${platform}`;
|
|
16
|
+
}
|
|
17
|
+
export function defaultSystemPromptVars(displayWidth, displayHeight, platform = process.platform, locale = Intl.DateTimeFormat().resolvedOptions().locale) {
|
|
18
|
+
return {
|
|
19
|
+
os: osLabel(platform),
|
|
20
|
+
displayWidth,
|
|
21
|
+
displayHeight,
|
|
22
|
+
keyboardLayout: locale,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function renderSystemPrompt(template, vars) {
|
|
26
|
+
return template
|
|
27
|
+
.replaceAll("{{os}}", vars.os)
|
|
28
|
+
.replaceAll("{{display_width}}", String(vars.displayWidth))
|
|
29
|
+
.replaceAll("{{display_height}}", String(vars.displayHeight))
|
|
30
|
+
.replaceAll("{{keyboard_layout}}", vars.keyboardLayout)
|
|
31
|
+
.trim();
|
|
32
|
+
}
|
|
33
|
+
export async function loadSystemPrompt(vars, filePath = SYSTEM_PROMPT_PATH) {
|
|
34
|
+
const template = await fs.readFile(filePath, "utf8");
|
|
35
|
+
const rendered = renderSystemPrompt(template, vars);
|
|
36
|
+
if (!rendered) {
|
|
37
|
+
throw new Error("system_prompt.txt is empty");
|
|
38
|
+
}
|
|
39
|
+
return rendered;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=system-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/computer-use/system-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAC5C,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAC5C,+BAA+B,CAChC,CAAC;AASF,MAAM,UAAU,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ;IACjD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IACD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IACD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED,OAAO,eAAe,QAAQ,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,YAAoB,EACpB,aAAqB,EACrB,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAC3B,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,MAAM;IAEvD,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC;QACrB,YAAY;QACZ,aAAa;QACb,cAAc,EAAE,MAAM;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,IAAsB;IACzE,OAAO,QAAQ;SACZ,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;SAC7B,UAAU,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;SAC1D,UAAU,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;SAC5D,UAAU,CAAC,qBAAqB,EAAE,IAAI,CAAC,cAAc,CAAC;SACtD,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAsB,EACtB,QAAQ,GAAG,kBAAkB;IAE7B,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { TokenUsage } from "../shared/cost.js";
|
|
2
|
+
export declare const BROWSER_ACTION_NAMES: readonly ["click", "double_click", "triple_click", "middle_click", "right_click", "mouse_down", "mouse_up", "move", "type", "drag_and_drop", "wait", "press_key", "key_down", "key_up", "hotkey", "take_screenshot", "scroll", "go_back", "navigate", "go_forward"];
|
|
3
|
+
export type BrowserActionName = (typeof BROWSER_ACTION_NAMES)[number];
|
|
4
|
+
export type MouseButton = "left" | "right" | "middle";
|
|
5
|
+
export interface ComputerUseMouse {
|
|
6
|
+
click(x: number, y: number, options?: {
|
|
7
|
+
button?: MouseButton;
|
|
8
|
+
clickCount?: number;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
dblclick(x: number, y: number): Promise<void>;
|
|
11
|
+
move(x: number, y: number): Promise<void>;
|
|
12
|
+
down(): Promise<void>;
|
|
13
|
+
up(): Promise<void>;
|
|
14
|
+
wheel(deltaX: number, deltaY: number): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export interface ComputerUseKeyboard {
|
|
17
|
+
type(text: string): Promise<void>;
|
|
18
|
+
press(key: string): Promise<void>;
|
|
19
|
+
down(key: string): Promise<void>;
|
|
20
|
+
up(key: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export interface ComputerUsePage {
|
|
23
|
+
url(): string;
|
|
24
|
+
goto(url: string): Promise<unknown>;
|
|
25
|
+
goBack(): Promise<unknown>;
|
|
26
|
+
goForward(): Promise<unknown>;
|
|
27
|
+
mouse: ComputerUseMouse;
|
|
28
|
+
keyboard: ComputerUseKeyboard;
|
|
29
|
+
}
|
|
30
|
+
export interface ContentBlock {
|
|
31
|
+
type: string;
|
|
32
|
+
text?: string;
|
|
33
|
+
data?: string;
|
|
34
|
+
mime_type?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface InteractionStep {
|
|
37
|
+
type: string;
|
|
38
|
+
id?: string;
|
|
39
|
+
name?: string;
|
|
40
|
+
call_id?: string;
|
|
41
|
+
arguments?: Record<string, unknown>;
|
|
42
|
+
content?: ContentBlock[];
|
|
43
|
+
result?: unknown;
|
|
44
|
+
is_error?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface FunctionCallStep extends InteractionStep {
|
|
47
|
+
type: "function_call";
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
arguments: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
export interface FunctionResultStep extends InteractionStep {
|
|
53
|
+
type: "function_result";
|
|
54
|
+
call_id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
is_error?: boolean;
|
|
57
|
+
result: ContentBlock[];
|
|
58
|
+
}
|
|
59
|
+
export interface InteractionResponse {
|
|
60
|
+
steps: InteractionStep[];
|
|
61
|
+
usage?: TokenUsage;
|
|
62
|
+
}
|
|
63
|
+
export declare class AgentRunError extends Error {
|
|
64
|
+
readonly usage: TokenUsage;
|
|
65
|
+
constructor(message: string, usage: TokenUsage);
|
|
66
|
+
}
|
|
67
|
+
export interface InteractionClient {
|
|
68
|
+
create(input: InteractionStep[]): Promise<InteractionResponse>;
|
|
69
|
+
}
|
|
70
|
+
export type ScreenshotSaver = (actionName: string) => Promise<string>;
|
|
71
|
+
export type SafetyConfirmer = (explanation: string, actionName: string) => Promise<boolean>;
|
|
72
|
+
export type Sleeper = (ms: number) => Promise<void>;
|
|
73
|
+
export type IntentListener = (label: string) => void | Promise<void>;
|
|
74
|
+
export interface ActionResult {
|
|
75
|
+
name: string;
|
|
76
|
+
callId: string;
|
|
77
|
+
payload: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
export interface ExecuteTurnResult {
|
|
80
|
+
results: ActionResult[];
|
|
81
|
+
terminated: boolean;
|
|
82
|
+
lastScreenshotPath: string | undefined;
|
|
83
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const BROWSER_ACTION_NAMES = [
|
|
2
|
+
"click",
|
|
3
|
+
"double_click",
|
|
4
|
+
"triple_click",
|
|
5
|
+
"middle_click",
|
|
6
|
+
"right_click",
|
|
7
|
+
"mouse_down",
|
|
8
|
+
"mouse_up",
|
|
9
|
+
"move",
|
|
10
|
+
"type",
|
|
11
|
+
"drag_and_drop",
|
|
12
|
+
"wait",
|
|
13
|
+
"press_key",
|
|
14
|
+
"key_down",
|
|
15
|
+
"key_up",
|
|
16
|
+
"hotkey",
|
|
17
|
+
"take_screenshot",
|
|
18
|
+
"scroll",
|
|
19
|
+
"go_back",
|
|
20
|
+
"navigate",
|
|
21
|
+
"go_forward",
|
|
22
|
+
];
|
|
23
|
+
export class AgentRunError extends Error {
|
|
24
|
+
usage;
|
|
25
|
+
constructor(message, usage) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.usage = usage;
|
|
28
|
+
this.name = "AgentRunError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/computer-use/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,OAAO;IACP,cAAc;IACd,cAAc;IACd,cAAc;IACd,aAAa;IACb,YAAY;IACZ,UAAU;IACV,MAAM;IACN,MAAM;IACN,eAAe;IACf,MAAM;IACN,WAAW;IACX,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,iBAAiB;IACjB,QAAQ;IACR,SAAS;IACT,UAAU;IACV,YAAY;CACJ,CAAC;AAyEX,MAAM,OAAO,aAAc,SAAQ,KAAK;IAG3B;IAFX,YACE,OAAe,EACN,KAAiB;QAE1B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFN,UAAK,GAAL,KAAK,CAAY;QAG1B,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Locator, Page } from "playwright";
|
|
2
|
+
export type Selector = string | Locator;
|
|
3
|
+
export interface Coordinates {
|
|
4
|
+
readonly x: number;
|
|
5
|
+
readonly y: number;
|
|
6
|
+
}
|
|
7
|
+
type MouseClickOptions = Parameters<Page["mouse"]["click"]>[2];
|
|
8
|
+
type MouseDblclickOptions = Parameters<Page["mouse"]["dblclick"]>[2];
|
|
9
|
+
type MouseMoveOptions = Parameters<Page["mouse"]["move"]>[2];
|
|
10
|
+
export declare const PLAYWRIGHT_ACTION_NAMES: readonly ["goto", "goBack", "goForward", "reload", "setContent", "click", "dblclick", "tap", "fill", "clear", "type", "pressSequentially", "press", "check", "uncheck", "setChecked", "selectOption", "selectText", "hover", "focus", "blur", "dragTo", "setInputFiles", "scrollIntoViewIfNeeded", "highlight", "screenshot", "dispatchEvent", "keyboard", "mouse", "touchscreen"];
|
|
11
|
+
export type PlaywrightActionName = (typeof PLAYWRIGHT_ACTION_NAMES)[number];
|
|
12
|
+
export interface PlaywrightActions {
|
|
13
|
+
goto: Page["goto"];
|
|
14
|
+
goBack: Page["goBack"];
|
|
15
|
+
goForward: Page["goForward"];
|
|
16
|
+
reload: Page["reload"];
|
|
17
|
+
setContent: Page["setContent"];
|
|
18
|
+
click: {
|
|
19
|
+
(x: number, y: number, options?: MouseClickOptions): Promise<void>;
|
|
20
|
+
(coords: Coordinates, options?: MouseClickOptions): Promise<void>;
|
|
21
|
+
(target: Selector, options?: Parameters<Locator["click"]>[0]): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
dblclick: {
|
|
24
|
+
(x: number, y: number, options?: MouseDblclickOptions): Promise<void>;
|
|
25
|
+
(coords: Coordinates, options?: MouseDblclickOptions): Promise<void>;
|
|
26
|
+
(target: Selector, options?: Parameters<Locator["dblclick"]>[0]): Promise<void>;
|
|
27
|
+
};
|
|
28
|
+
tap: {
|
|
29
|
+
(x: number, y: number): Promise<void>;
|
|
30
|
+
(coords: Coordinates): Promise<void>;
|
|
31
|
+
(target: Selector, options?: Parameters<Locator["tap"]>[0]): Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
fill: (target: Selector, ...args: Parameters<Locator["fill"]>) => Promise<void>;
|
|
34
|
+
clear: (target: Selector, ...args: Parameters<Locator["clear"]>) => Promise<void>;
|
|
35
|
+
type: (target: Selector, ...args: Parameters<Locator["type"]>) => Promise<void>;
|
|
36
|
+
pressSequentially: (target: Selector, ...args: Parameters<Locator["pressSequentially"]>) => Promise<void>;
|
|
37
|
+
press: (target: Selector, ...args: Parameters<Locator["press"]>) => Promise<void>;
|
|
38
|
+
check: (target: Selector, ...args: Parameters<Locator["check"]>) => Promise<void>;
|
|
39
|
+
uncheck: (target: Selector, ...args: Parameters<Locator["uncheck"]>) => Promise<void>;
|
|
40
|
+
setChecked: (target: Selector, ...args: Parameters<Locator["setChecked"]>) => Promise<void>;
|
|
41
|
+
selectOption: (target: Selector, ...args: Parameters<Locator["selectOption"]>) => Promise<Array<string>>;
|
|
42
|
+
selectText: (target: Selector, ...args: Parameters<Locator["selectText"]>) => Promise<void>;
|
|
43
|
+
hover: {
|
|
44
|
+
(x: number, y: number, options?: MouseMoveOptions): Promise<void>;
|
|
45
|
+
(coords: Coordinates, options?: MouseMoveOptions): Promise<void>;
|
|
46
|
+
(target: Selector, options?: Parameters<Locator["hover"]>[0]): Promise<void>;
|
|
47
|
+
};
|
|
48
|
+
focus: (target: Selector, ...args: Parameters<Locator["focus"]>) => Promise<void>;
|
|
49
|
+
blur: (target: Selector, ...args: Parameters<Locator["blur"]>) => Promise<void>;
|
|
50
|
+
dragTo: {
|
|
51
|
+
(from: Coordinates, to: Coordinates): Promise<void>;
|
|
52
|
+
(source: Selector, target: Selector, options?: Parameters<Locator["dragTo"]>[1]): Promise<void>;
|
|
53
|
+
(source: Selector | Coordinates, target: Selector | Coordinates): Promise<void>;
|
|
54
|
+
};
|
|
55
|
+
setInputFiles: (target: Selector, ...args: Parameters<Locator["setInputFiles"]>) => Promise<void>;
|
|
56
|
+
scrollIntoViewIfNeeded: (target: Selector, ...args: Parameters<Locator["scrollIntoViewIfNeeded"]>) => Promise<void>;
|
|
57
|
+
highlight: (target: Selector, ...args: Parameters<Locator["highlight"]>) => Promise<void>;
|
|
58
|
+
screenshot: (target?: Selector, options?: Parameters<Locator["screenshot"]>[0]) => Promise<Buffer>;
|
|
59
|
+
dispatchEvent: (target: Selector, ...args: Parameters<Locator["dispatchEvent"]>) => Promise<void>;
|
|
60
|
+
keyboard: {
|
|
61
|
+
down: Page["keyboard"]["down"];
|
|
62
|
+
up: Page["keyboard"]["up"];
|
|
63
|
+
insertText: Page["keyboard"]["insertText"];
|
|
64
|
+
type: Page["keyboard"]["type"];
|
|
65
|
+
press: Page["keyboard"]["press"];
|
|
66
|
+
};
|
|
67
|
+
mouse: {
|
|
68
|
+
move: Page["mouse"]["move"];
|
|
69
|
+
down: Page["mouse"]["down"];
|
|
70
|
+
up: Page["mouse"]["up"];
|
|
71
|
+
click: Page["mouse"]["click"];
|
|
72
|
+
dblclick: Page["mouse"]["dblclick"];
|
|
73
|
+
wheel: Page["mouse"]["wheel"];
|
|
74
|
+
};
|
|
75
|
+
touchscreen: {
|
|
76
|
+
tap: Page["touchscreen"]["tap"];
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export declare function isCoordinates(value: unknown): value is Coordinates;
|
|
80
|
+
export declare function createPageActions(page: Page, directory?: string): PlaywrightActions;
|
|
81
|
+
export {};
|